diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d1b26a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +bin/* +objs/* diff --git a/COPYING.txt b/COPYING.txt new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/COPYING.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1356841 --- /dev/null +++ b/Makefile @@ -0,0 +1,191 @@ +########################################################################### +# user-configurable section +########################################################################### + +# common locations for the OpenEXR libraries; may need to be updated +# for unusual installation locations +HAVE_EXR=1 +EXR_INCLUDES=-I/usr/local/include/OpenEXR -I/usr/include/OpenEXR -I/opt/local/include/OpenEXR +EXR_LIBDIR=-L/usr/local/lib -L/opt/local/lib + +HAVE_LIBTIFF=1 +TIFF_INCLUDES=-I/usr/local/include -I/opt/local/include +TIFF_LIBDIR=-L/usr/local/lib -L/opt/local/lib + +HAVE_DTRACE=0 + +# remove -DPBRT_HAS_OPENEXR to build without OpenEXR support +DEFS=-DPBRT_HAS_OPENEXR + +# 32 bit +#MARCH=-m32 -msse2 -mfpmath=sse + +# 64 bit +MARCH=-m64 + +# change this to -g3 for debug builds +OPT=-O2 +# comment out this line to enable assertions at runtime +DEFS += -DNDEBUG + +######################################################################### +# nothing below this line should need to be changed (usually) +######################################################################### + +ARCH = $(shell uname) + +LEX=flex +YACC=bison -d -v -t +LEXLIB = -lfl + +ifeq ($(HAVE_DTRACE),1) + DEFS += -DPBRT_PROBES_DTRACE +else + DEFS += -DPBRT_PROBES_NONE +endif + +EXRLIBS=$(EXR_LIBDIR) -Bstatic -lIex -lIlmImf -lIlmThread -lImath -lIex -lHalf -Bdynamic +ifeq ($(ARCH),Linux) + EXRLIBS += -lpthread +endif +ifeq ($(ARCH),OpenBSD) + EXRLIBS += -lpthread +endif +ifeq ($(ARCH),Darwin) + EXRLIBS += -lz +endif + +CC=gcc +CXX=g++ +LD=$(CXX) $(OPT) $(MARCH) +INCLUDE=-I. -Icore $(EXR_INCLUDES) $(TIFF_INCLUDES) +WARN=-Wall +CWD=$(shell pwd) +CXXFLAGS=$(OPT) $(MARCH) $(INCLUDE) $(WARN) $(DEFS) +CCFLAGS=$(CXXFLAGS) +LIBS=$(LEXLIB) $(EXR_LIBDIR) $(EXRLIBS) -lm + +LIBSRCS=$(wildcard core/*.cpp) core/pbrtlex.cpp core/pbrtparse.cpp +LIBSRCS += $(wildcard accelerators/*.cpp cameras/*.cpp film/*.cpp filters/*.cpp ) +LIBSRCS += $(wildcard integrators/*.cpp lights/*.cpp materials/*.cpp renderers/*.cpp ) +LIBSRCS += $(wildcard samplers/*.cpp shapes/*.cpp textures/*.cpp volumes/*.cpp) + +LIBOBJS=$(addprefix objs/, $(subst /,_,$(LIBSRCS:.cpp=.o))) + +HEADERS = $(wildcard */*.h) + +TOOLS = bin/bsdftest bin/exravg bin/exrdiff +ifeq ($(HAVE_LIBTIFF),1) + TOOLS += bin/exrtotiff +endif + +default: dirs bin/pbrt $(TOOLS) + +bin/%: dirs + +pbrt: bin/pbrt + +dirs: + /bin/mkdir -p bin objs + +$(LIBOBJS): $(HEADERS) + +.PHONY: dirs tools + +objs/libpbrt.a: $(LIBOBJS) + @echo "Building the core rendering library (libpbrt.a)" + @ar rcs $@ $(LIBOBJS) + +objs/accelerators_%.o: accelerators/%.cpp + @echo "Building object $@" + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +objs/cameras_%.o: cameras/%.cpp + @echo "Building object $@" + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +objs/core_%.o: core/%.cpp + @echo "Building object $@" + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +objs/film_%.o: film/%.cpp + @echo "Building object $@" + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +objs/filters_%.o: filters/%.cpp + @echo "Building object $@" + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +objs/integrators_%.o: integrators/%.cpp + @echo "Building object $@" + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +objs/lights_%.o: lights/%.cpp + @echo "Building object $@" + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +objs/main_%.o: main/%.cpp + @echo "Building object $@" + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +objs/materials_%.o: materials/%.cpp + @echo "Building object $@" + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +objs/renderers_%.o: renderers/%.cpp + @echo "Building object $@" + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +objs/samplers_%.o: samplers/%.cpp + @echo "Building object $@" + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +objs/shapes_%.o: shapes/%.cpp + @echo "Building object $@" + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +objs/textures_%.o: textures/%.cpp + @echo "Building object $@" + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +objs/volumes_%.o: volumes/%.cpp + @echo "Building object $@" + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +objs/pbrt.o: main/pbrt.cpp + @echo "Building object $@" + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +objs/%.o: tools/%.cpp + @echo "Building object $@" + @$(CXX) $(CXXFLAGS) -o $@ -c $< + +bin/%: objs/%.o objs/libpbrt.a + @echo "Linking $@" + @$(CXX) $(CXXFLAGS) -o $@ $^ $(LIBS) + +bin/exrtotiff: objs/exrtotiff.o + @echo "Linking $@" + @$(CXX) $(CXXFLAGS) -o $@ $^ $(TIFF_LIBDIR) -ltiff $(LIBS) + +core/pbrtlex.cpp: core/pbrtlex.ll core/pbrtparse.cpp + @echo "Lex'ing pbrtlex.ll" + @$(LEX) -o$@ core/pbrtlex.ll + +core/pbrtparse.cpp: core/pbrtparse.yy + @echo "YACC'ing pbrtparse.yy" + @$(YACC) -o $@ core/pbrtparse.yy + @if [ -e core/pbrtparse.cpp.h ]; then /bin/mv core/pbrtparse.cpp.h core/pbrtparse.hpp; fi + @if [ -e core/pbrtparse.hh ]; then /bin/mv core/pbrtparse.hh core/pbrtparse.hpp; fi + +ifeq ($(HAVE_DTRACE),1) +core/dtrace.h: core/dtrace.d + /usr/sbin/dtrace -h -s $^ -o $@ + +$(LIBOBJS): core/dtrace.h +endif + +$(RENDERER_BINARY): $(RENDERER_OBJS) $(CORE_LIB) + +clean: + rm -f objs/* bin/* core/pbrtlex.[ch]* core/pbrtparse.[ch]* diff --git a/README_BUILDING.txt b/README_BUILDING.txt new file mode 100644 index 0000000..a3c6970 --- /dev/null +++ b/README_BUILDING.txt @@ -0,0 +1,90 @@ + +pbrt is designed to be easily ported to various platforms; the authors +regularly compile it on Mac OS X, Windows, and a variety of Linux variants. +pbrt users have sent patches to ensure that it compiles cleanly on FreeBSD, +OpenBSD, and other systems. We will happily incorporate patches to make +the system build on other platforms! (Please send patches or other notes +about issues with building pbrt to authors@pbrt.org.) + +=== Building The System === + +--- Windows --- + +Please see the file README_BUILDING_MSVC2008.txt or +README_BUILDING_MSVC2010.txt, as appropriate for the version of Visual +Studio you're using. + +There is not currently support for building pbrt with the Cygwin gcc +compiler, but patches would be happily accepted. + +--- Linux --- + +On Linux and other Unix platforms, pbrt can be compiled with either the +provided Makefile or the provided SCons build files (see http://scons.org +for information about SCons). Please see the notes below about installing +OpenEXR libraries on your system before building pbrt. + +The SCons build files build both debug and release configurations of the +system, while the Makefile only builds a release build. See comment at the +top of the Makefile for how to modify it to do a debug build instead. + +--- Mac OS X --- + +Please see the notes below about installing OpenEXR libraries on your +system before building pbrt. + +In addition to the Makefile and SCons files described in the "Linux" +section, there is also is also an XCode project file for Mac OS X, +pbrt.xcodeproj. + + +=== Build Options and Configuration === + +The remainder of this document has notes about the two main build +configuration options: using the OpenEXR and TIFF image formats or not, and +how pbrt collects and reports statistics. It then has sections about each +of the main target platforms (Linux, Mac OS X, and Windows). + +--- OpenEXR --- + +If you have the OpenEXR image library installed (see http://openexr.com), +then pbrt will read and write OpenEXR format images. A number of the +example scenes use OpenEXR image files. If you do have OpenEXR installed, +then PBRT_HAS_OPENEXR should be #defined and the paths to the OpenEXR +headers and libraries should be set in the build rules as appropriate. + +On Mac OS X and Linux, OpenEXR compiles easily from the distribution from +the OpenEXR website. Alternatively, most package or "ports" systems +provide an OpenEXR installation. + +--- TIFF --- + +We provide a utility program to convert from high dynamic range EXR images +to low dynamic range TIFF images, exrtotiff. This program includes a +rudimentary tone mapping pipeline and support for image bloom and gamma +correction. To build this program, modify the user configuration section +appropriately in either Makefile or SCons file (depending on how you're +building the system.) There is not currently any support for building this +from the MSVC solution file on Windows. + +More comprehensive sets of programs to work with EXR images are available +from http://scanline.ca/exrtools/ and http://pfstools.sourceforge.net/. + +--- Probes and Statistics --- + +pbrt no longer collects runtime rendering statistics by default. (Updating +shared statistics counters can cause a substantial performance impact with +multi-threaded execution.) To override this, change the definition of the +PBRT_PROBES_NONE preprocessor #define to either PBRT_PROBES_DTRACE or +PBRT_PROBES_COUNTERS. + +If your system supports dtrace (OSX, FreeBSD, and Solaris, currently--see +http://en.wikipedia.org/wiki/DTrace for more information), then pbrt is +instrumented to provide a large number of dtrace probes that can be +analyzed with dtrace scripts; building with dtrace support is supported if +you set the PBRT_PROBES_DTRACE preprocessor #define. See the dtrace/ +directory for a number of example dtrace scripts to use with pbrt. + +Alternatively, PBRT_PROBES_COUNTERS can be set to compile the system to +gather a number of statistics with shared counters, incurring the +corresponding performance penalty. diff --git a/SConscript b/SConscript new file mode 100644 index 0000000..678580c --- /dev/null +++ b/SConscript @@ -0,0 +1,117 @@ +# -*- mode: python -*- + +import sys +arch = sys.platform + +Import('env', 'has_dtrace', 'parallel_libs', 'exr_libs', 'tiff_libs') + +if has_dtrace == True: + env.DTrace('core/dtrace.h', 'core/dtrace.d') + env.Depends('core/dtrace.h', 'core/dtrace.d') + +renderer_src = [ 'main/pbrt.cpp' ] + +core_src = [ 'core/api.cpp', 'core/camera.cpp', 'core/diffgeom.cpp', + 'core/error.cpp', 'core/film.cpp', 'core/fileutil.cpp', + 'core/filter.cpp', + 'core/floatfile.cpp', 'core/geometry.cpp', 'core/imageio.cpp', + 'core/integrator.cpp', 'core/intersection.cpp', 'core/light.cpp', + 'core/material.cpp', 'core/memory.cpp', 'core/montecarlo.cpp', + 'core/paramset.cpp', 'core/parser.cpp', 'core/primitive.cpp', + 'core/parallel.cpp', 'core/probes.cpp', 'core/progressreporter.cpp', + 'core/quaternion.cpp', 'core/reflection.cpp', 'core/renderer.cpp', + 'core/rng.cpp', 'core/sampler.cpp', 'core/scene.cpp', + 'core/sh.cpp', 'core/shrots.cpp', 'core/shape.cpp', + 'core/spectrum.cpp', 'core/texture.cpp', 'core/timer.cpp', + 'core/transform.cpp', 'core/volume.cpp' ] + +parser_flex = env.CXXFile('core/pbrtlex.ll') +parser_bison = env.CXXFile('core/pbrtparse.yy') +env.Depends('core/pbrtlex.ll', parser_bison) +parser_bison.pop() # yuck a muck, but stop trying to link in pbrtparse.hh! +core_src = [ parser_flex, parser_bison ] + core_src + + +accelerators_src = [ 'accelerators/bvh.cpp', + 'accelerators/grid.cpp', + 'accelerators/kdtreeaccel.cpp' ] +cameras_src = [ 'cameras/environment.cpp', + 'cameras/orthographic.cpp', + 'cameras/perspective.cpp' ] +film_src = [ 'film/image.cpp' ] +filters_src = [ 'filters/box.cpp', 'filters/gaussian.cpp', + 'filters/mitchell.cpp', 'filters/sinc.cpp', + 'filters/triangle.cpp' ] +integrators_src = [ 'integrators/ambientocclusion.cpp', 'integrators/diffuseprt.cpp', + 'integrators/dipolesubsurface.cpp', 'integrators/directlighting.cpp', + 'integrators/emission.cpp', 'integrators/glossyprt.cpp', + 'integrators/igi.cpp', 'integrators/irradiancecache.cpp', + 'integrators/path.cpp', 'integrators/photonmap.cpp', + 'integrators/single.cpp', 'integrators/useprobes.cpp', + 'integrators/whitted.cpp' ] +lights_src = [ 'lights/diffuse.cpp', 'lights/distant.cpp', + 'lights/goniometric.cpp', 'lights/infinite.cpp', + 'lights/point.cpp', 'lights/projection.cpp', + 'lights/spot.cpp' ] +materials_src = [ 'materials/glass.cpp', 'materials/kdsubsurface.cpp', + 'materials/matte.cpp', 'materials/measured.cpp', + 'materials/metal.cpp', 'materials/mirror.cpp', + 'materials/mixmat.cpp', 'materials/plastic.cpp', + 'materials/substrate.cpp', 'materials/subsurface.cpp', + 'materials/translucent.cpp', 'materials/uber.cpp', + 'materials/shinymetal.cpp', + ] +renderers_src = [ 'renderers/aggregatetest.cpp', 'renderers/createprobes.cpp', + 'renderers/metropolis.cpp', 'renderers/samplerrenderer.cpp', + 'renderers/surfacepoints.cpp' ] +samplers_src = [ 'samplers/adaptive.cpp', 'samplers/bestcandidate.cpp', + 'samplers/halton.cpp', 'samplers/lowdiscrepancy.cpp', + 'samplers/random.cpp', 'samplers/stratified.cpp' ] +shapes_src = [ 'shapes/cone.cpp', 'shapes/cylinder.cpp', + 'shapes/disk.cpp', 'shapes/heightfield.cpp', + 'shapes/hyperboloid.cpp', 'shapes/loopsubdiv.cpp', + 'shapes/nurbs.cpp', 'shapes/paraboloid.cpp', + 'shapes/sphere.cpp', 'shapes/trianglemesh.cpp' ] +textures_src = [ 'textures/bilerp.cpp', 'textures/checkerboard.cpp', + 'textures/constant.cpp', 'textures/dots.cpp', + 'textures/fbm.cpp', 'textures/imagemap.cpp', + 'textures/marble.cpp', 'textures/mix.cpp', + 'textures/scale.cpp', 'textures/uv.cpp', + 'textures/windy.cpp', 'textures/wrinkled.cpp' ] +volumes_src = [ 'volumes/exponential.cpp', 'volumes/homogeneous.cpp', + 'volumes/volumegrid.cpp' ] + + +lib_src = [ core_src + accelerators_src + cameras_src + film_src + filters_src + + integrators_src + lights_src + materials_src + renderers_src + + samplers_src + shapes_src + textures_src + volumes_src ] + +output = { } +output['pbrt_lib'] = env.StaticLibrary('libpbrt', lib_src) + +env_libs = [ ] +output['pbrt'] = env.Program('pbrt', renderer_src + output['pbrt_lib'], + LIBS = env_libs + exr_libs + parallel_libs) +if arch == 'win32': + env.AddPostAction(output['pbrt'], + 'mt.exe /outputresource:"$TARGET;#1" /manifest "${TARGET}.manifest" /nologo') +output['defaults'] = [ output['pbrt' ] ] + + +if len(exr_libs) > 0: + output['exrdiff'] = env.Program('exrdiff', [ 'tools/exrdiff.cpp' ], + LIBS = env_libs + exr_libs) + output['exravg'] = env.Program('exravg', [ 'tools/exravg.cpp' ], + LIBS = env_libs + exr_libs) + output['bsdftest'] = env.Program('bsdftest', [ 'tools/bsdftest.cpp' ] + + output['pbrt_lib'], + LIBS = env_libs + exr_libs + parallel_libs) + output['defaults'] = output['defaults'] + \ + [ output['exrdiff'], output['exravg'], output['bsdftest'] ] + +if len(exr_libs) > 0 and len(tiff_libs) > 0: + output['exrtotiff'] = env.Program('exrtotiff', [ 'tools/exrtotiff.cpp' ], + LIBS = env_libs + exr_libs + tiff_libs) + output['defaults'] = output['defaults'] + output['exrtotiff'] + +Return('output') diff --git a/SConstruct b/SConstruct new file mode 100644 index 0000000..c6c1d87 --- /dev/null +++ b/SConstruct @@ -0,0 +1,115 @@ +# -*- mode: python -*- + +import sys, platform +arch = sys.platform + +###################################################################### +# user-configurable section + +has_openexr = True +exr_includes = [ '/usr/local/include', '/opt/local/include', '/opt/local/include/OpenEXR', + '/usr/local/include/OpenEXR', '/usr/include/OpenEXR' ] +exr_libdir = [ '/opt/local/lib' ] + +has_dtrace = (arch == 'darwin') +Export('has_dtrace') + +#has_gcd = float(platform.mac_ver()[0][:4] >= 10.6) +has_gcd = False + +build_64bit = True + +parallel_libs = [ 'pthread' ] +Export('parallel_libs') + +tiff_libs = [ ] +# tiff_libs = [ 'tiff' ] +tiff_includes = [ ] +tiff_libdir = [ ] +Export('tiff_libs') + +###################################################################### +## Configure generic environment + +Decider('MD5-timestamp') +#CacheDir('scons-cache') + +#import os +#print "Pruning scons cache..." +#os.system('cd scons-cache && find . -type f -atime +1 -delete') + +def setup_nice_print(env): + if ARGUMENTS.get('VERBOSE') != '1': + env['YACCCOMSTR'] = "Compiling $TARGET" + env['LEXCOMSTR'] = "Compiling $TARGET" + env['CCCOMSTR'] = "Compiling $TARGET" + env['CXXCOMSTR'] = "Compiling $TARGET" + env['LINKCOMSTR'] = "Linking $TARGET" + env['ARCOMSTR'] = "Linking $TARGET" + +env = Environment(CCFLAGS = [ '-Wall', '-g' ], + CPPPATH = [ '#core', '#', '.' ] + tiff_includes, + LIBPATH = tiff_libdir, + YACCFLAGS = [ '-d', '-v', '-t' ], + YACCHXXFILESUFFIX = '.hh', + ENV = { 'PATH' : [ '/usr/local/bin', '/usr/bin', '/bin', + '/usr/sbin', '/sbin' ] }) +if build_64bit: + env.Append(CCFLAGS = [ '-m64' ], + LINKFLAGS = [ '-m64' ]) + +setup_nice_print(env) + +if has_openexr: + env.Append(CPPPATH = exr_includes) + env.Append(LIBPATH = exr_libdir) + env.Append(CPPDEFINES = [ 'PBRT_HAS_OPENEXR' ]) + if arch != 'darwin': + exr_libs = [ 'Iex', 'IlmImf', 'Imath', 'Iex', 'IlmThread', 'Half' ] + else: + exr_libs = [ 'Iex', 'IlmImf', 'Imath', 'Iex', 'IlmThread', 'Half', 'z' ] +else: + exr_libs = [ ] +Export('exr_libs') + +if has_dtrace: + env.Append(BUILDERS = { 'DTrace' : + Builder(action = '/usr/sbin/dtrace -h -s $SOURCE -o $TARGET')}) + +if has_gcd: + env.Append(CPPDEFINES = [ 'PBRT_USE_GRAND_CENTRAL_DISPATCH' ]) + +###################################################################### + +build_envs = { } + +debug_env = env.Clone() +debug_env.Append(CPPDEFINES = [ 'DEBUG' ]) +if has_dtrace: + debug_env.Append(CPPDEFINES = [ 'PBRT_PROBES_DTRACE' ]) +else: + debug_env.Append(CPPDEFINES = [ 'PBRT_PROBES_NONE' ]) +build_envs['debug'] = debug_env + +release_env = env.Clone() +release_env.Append(CCFLAGS = [ '-O2', '-finline-functions' ]) +release_env.Append(CCFLAGS = [ '-msse3', '-mfpmath=sse', '-march=nocona' ]) +release_env.Append(CPPDEFINES = [ 'NDEBUG' ]) +build_envs['release'] = release_env + +stats_env = release_env.Clone() +if has_dtrace: + stats_env.Append(CPPDEFINES = [ 'PBRT_PROBES_DTRACE' ]) +else: + stats_env.Append(CPPDEFINES = [ 'PBRT_PROBES_COUNTERS' ]) +build_envs['stats'] = stats_env + +release_env.Append(CPPDEFINES = [ 'PBRT_PROBES_NONE' ]) + +for target in build_envs: + env = build_envs[target] + Export('env') + output = SConscript(dirs = '.', + variant_dir = 'build/' + arch + '-' + target) + env.Alias(target, output['defaults']) + env.Default(target) diff --git a/accelerators/bvh.cpp b/accelerators/bvh.cpp new file mode 100644 index 0000000..299ddc7 --- /dev/null +++ b/accelerators/bvh.cpp @@ -0,0 +1,491 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// accelerators/bvh.cpp* +#include "stdafx.h" +#include "accelerators/bvh.h" +#include "probes.h" +#include "paramset.h" + +// BVHAccel Local Declarations +struct BVHPrimitiveInfo { + BVHPrimitiveInfo() { } + BVHPrimitiveInfo(int pn, const BBox &b) + : primitiveNumber(pn), bounds(b) { + centroid = .5f * b.pMin + .5f * b.pMax; + } + int primitiveNumber; + Point centroid; + BBox bounds; +}; + + +struct BVHBuildNode { + // BVHBuildNode Public Methods + BVHBuildNode() { children[0] = children[1] = NULL; } + void InitLeaf(uint32_t first, uint32_t n, const BBox &b) { + firstPrimOffset = first; + nPrimitives = n; + bounds = b; + } + void InitInterior(uint32_t axis, BVHBuildNode *c0, BVHBuildNode *c1) { + children[0] = c0; + children[1] = c1; + bounds = Union(c0->bounds, c1->bounds); + splitAxis = axis; + nPrimitives = 0; + } + BBox bounds; + BVHBuildNode *children[2]; + uint32_t splitAxis, firstPrimOffset, nPrimitives; +}; + + +struct CompareToMid { + CompareToMid(int d, float m) { dim = d; mid = m; } + int dim; + float mid; + bool operator()(const BVHPrimitiveInfo &a) const { + return a.centroid[dim] < mid; + } +}; + + +struct ComparePoints { + ComparePoints(int d) { dim = d; } + int dim; + bool operator()(const BVHPrimitiveInfo &a, + const BVHPrimitiveInfo &b) const { + return a.centroid[dim] < b.centroid[dim]; + } +}; + + +struct CompareToBucket { + CompareToBucket(int split, int num, int d, const BBox &b) + : centroidBounds(b) + { splitBucket = split; nBuckets = num; dim = d; } + bool operator()(const BVHPrimitiveInfo &p) const; + + int splitBucket, nBuckets, dim; + const BBox ¢roidBounds; +}; + + +bool CompareToBucket::operator()(const BVHPrimitiveInfo &p) const { + int b = nBuckets * ((p.centroid[dim] - centroidBounds.pMin[dim]) / + (centroidBounds.pMax[dim] - centroidBounds.pMin[dim])); + if (b == nBuckets) b = nBuckets-1; + Assert(b >= 0 && b < nBuckets); + return b <= splitBucket; +} + + +struct LinearBVHNode { + BBox bounds; + union { + uint32_t primitivesOffset; // leaf + uint32_t secondChildOffset; // interior + }; + + uint8_t nPrimitives; // 0 -> interior node + uint8_t axis; // interior node: xyz + uint8_t pad[2]; // ensure 32 byte total size +}; + + +static inline bool IntersectP(const BBox &bounds, const Ray &ray, + const Vector &invDir, const uint32_t dirIsNeg[3]) { + // Check for ray intersection against $x$ and $y$ slabs + float tmin = (bounds[ dirIsNeg[0]].x - ray.o.x) * invDir.x; + float tmax = (bounds[1-dirIsNeg[0]].x - ray.o.x) * invDir.x; + float tymin = (bounds[ dirIsNeg[1]].y - ray.o.y) * invDir.y; + float tymax = (bounds[1-dirIsNeg[1]].y - ray.o.y) * invDir.y; + if ((tmin > tymax) || (tymin > tmax)) + return false; + if (tymin > tmin) tmin = tymin; + if (tymax < tmax) tmax = tymax; + + // Check for ray intersection against $z$ slab + float tzmin = (bounds[ dirIsNeg[2]].z - ray.o.z) * invDir.z; + float tzmax = (bounds[1-dirIsNeg[2]].z - ray.o.z) * invDir.z; + if ((tmin > tzmax) || (tzmin > tmax)) + return false; + if (tzmin > tmin) + tmin = tzmin; + if (tzmax < tmax) + tmax = tzmax; + return (tmin < ray.maxt) && (tmax > ray.mint); +} + + + +// BVHAccel Method Definitions +BVHAccel::BVHAccel(const vector > &p, + uint32_t mp, const string &sm) { + maxPrimsInNode = min(255u, mp); + for (uint32_t i = 0; i < p.size(); ++i) + p[i]->FullyRefine(primitives); + if (sm == "sah") splitMethod = SPLIT_SAH; + else if (sm == "middle") splitMethod = SPLIT_MIDDLE; + else if (sm == "equal") splitMethod = SPLIT_EQUAL_COUNTS; + else { + Warning("BVH split method \"%s\" unknown. Using \"sah\".", + sm.c_str()); + splitMethod = SPLIT_SAH; + } + + if (primitives.size() == 0) { + nodes = NULL; + return; + } + // Build BVH from _primitives_ + PBRT_BVH_STARTED_CONSTRUCTION(this, primitives.size()); + + // Initialize _buildData_ array for primitives + vector buildData; + buildData.reserve(primitives.size()); + for (uint32_t i = 0; i < primitives.size(); ++i) { + BBox bbox = primitives[i]->WorldBound(); + buildData.push_back(BVHPrimitiveInfo(i, bbox)); + } + + // Recursively build BVH tree for primitives + MemoryArena buildArena; + uint32_t totalNodes = 0; + vector > orderedPrims; + orderedPrims.reserve(primitives.size()); + BVHBuildNode *root = recursiveBuild(buildArena, buildData, 0, + primitives.size(), &totalNodes, + orderedPrims); + primitives.swap(orderedPrims); + Info("BVH created with %d nodes for %d primitives (%.2f MB)", totalNodes, + (int)primitives.size(), float(totalNodes * sizeof(LinearBVHNode))/(1024.f*1024.f)); + + // Compute representation of depth-first traversal of BVH tree + nodes = AllocAligned(totalNodes); + for (uint32_t i = 0; i < totalNodes; ++i) + new (&nodes[i]) LinearBVHNode; + uint32_t offset = 0; + flattenBVHTree(root, &offset); + Assert(offset == totalNodes); + PBRT_BVH_FINISHED_CONSTRUCTION(this); +} + + +BBox BVHAccel::WorldBound() const { + return nodes ? nodes[0].bounds : BBox(); +} + + +BVHBuildNode *BVHAccel::recursiveBuild(MemoryArena &buildArena, + vector &buildData, uint32_t start, + uint32_t end, uint32_t *totalNodes, + vector > &orderedPrims) { + Assert(start != end); + (*totalNodes)++; + BVHBuildNode *node = buildArena.Alloc(); + // Compute bounds of all primitives in BVH node + BBox bbox; + for (uint32_t i = start; i < end; ++i) + bbox = Union(bbox, buildData[i].bounds); + uint32_t nPrimitives = end - start; + if (nPrimitives == 1) { + // Create leaf _BVHBuildNode_ + uint32_t firstPrimOffset = orderedPrims.size(); + for (uint32_t i = start; i < end; ++i) { + uint32_t primNum = buildData[i].primitiveNumber; + orderedPrims.push_back(primitives[primNum]); + } + node->InitLeaf(firstPrimOffset, nPrimitives, bbox); + } + else { + // Compute bound of primitive centroids, choose split dimension _dim_ + BBox centroidBounds; + for (uint32_t i = start; i < end; ++i) + centroidBounds = Union(centroidBounds, buildData[i].centroid); + int dim = centroidBounds.MaximumExtent(); + + // Partition primitives into two sets and build children + uint32_t mid = (start + end) / 2; + if (centroidBounds.pMax[dim] == centroidBounds.pMin[dim]) { + // Create leaf _BVHBuildNode_ + uint32_t firstPrimOffset = orderedPrims.size(); + for (uint32_t i = start; i < end; ++i) { + uint32_t primNum = buildData[i].primitiveNumber; + orderedPrims.push_back(primitives[primNum]); + } + node->InitLeaf(firstPrimOffset, nPrimitives, bbox); + return node; + } + + // Partition primitives based on _splitMethod_ + switch (splitMethod) { + case SPLIT_MIDDLE: { + // Partition primitives through node's midpoint + float pmid = .5f * (centroidBounds.pMin[dim] + centroidBounds.pMax[dim]); + BVHPrimitiveInfo *midPtr = std::partition(&buildData[start], + &buildData[end-1]+1, + CompareToMid(dim, pmid)); + mid = midPtr - &buildData[0]; + if (mid != start && mid != end) + // for lots of prims with large overlapping bounding boxes, this + // may fail to partition; in that case don't break and fall through + // to SPLIT_EQUAL_COUNTS + break; + } + case SPLIT_EQUAL_COUNTS: { + // Partition primitives into equally-sized subsets + mid = (start + end) / 2; + std::nth_element(&buildData[start], &buildData[mid], + &buildData[end-1]+1, ComparePoints(dim)); + break; + } + case SPLIT_SAH: default: { + // Partition primitives using approximate SAH + if (nPrimitives <= 4) { + // Partition primitives into equally-sized subsets + mid = (start + end) / 2; + std::nth_element(&buildData[start], &buildData[mid], + &buildData[end-1]+1, ComparePoints(dim)); + } + else { + // Allocate _BucketInfo_ for SAH partition buckets + const int nBuckets = 12; + struct BucketInfo { + BucketInfo() { count = 0; } + int count; + BBox bounds; + }; + BucketInfo buckets[nBuckets]; + + // Initialize _BucketInfo_ for SAH partition buckets + for (uint32_t i = start; i < end; ++i) { + int b = nBuckets * + ((buildData[i].centroid[dim] - centroidBounds.pMin[dim]) / + (centroidBounds.pMax[dim] - centroidBounds.pMin[dim])); + if (b == nBuckets) b = nBuckets-1; + Assert(b >= 0 && b < nBuckets); + buckets[b].count++; + buckets[b].bounds = Union(buckets[b].bounds, buildData[i].bounds); + } + + // Compute costs for splitting after each bucket + float cost[nBuckets-1]; + for (int i = 0; i < nBuckets-1; ++i) { + BBox b0, b1; + int count0 = 0, count1 = 0; + for (int j = 0; j <= i; ++j) { + b0 = Union(b0, buckets[j].bounds); + count0 += buckets[j].count; + } + for (int j = i+1; j < nBuckets; ++j) { + b1 = Union(b1, buckets[j].bounds); + count1 += buckets[j].count; + } + cost[i] = .125f + (count0*b0.SurfaceArea() + count1*b1.SurfaceArea()) / + bbox.SurfaceArea(); + } + + // Find bucket to split at that minimizes SAH metric + float minCost = cost[0]; + uint32_t minCostSplit = 0; + for (int i = 1; i < nBuckets-1; ++i) { + if (cost[i] < minCost) { + minCost = cost[i]; + minCostSplit = i; + } + } + + // Either create leaf or split primitives at selected SAH bucket + if (nPrimitives > maxPrimsInNode || + minCost < nPrimitives) { + BVHPrimitiveInfo *pmid = std::partition(&buildData[start], + &buildData[end-1]+1, + CompareToBucket(minCostSplit, nBuckets, dim, centroidBounds)); + mid = pmid - &buildData[0]; + } + + else { + // Create leaf _BVHBuildNode_ + uint32_t firstPrimOffset = orderedPrims.size(); + for (uint32_t i = start; i < end; ++i) { + uint32_t primNum = buildData[i].primitiveNumber; + orderedPrims.push_back(primitives[primNum]); + } + node->InitLeaf(firstPrimOffset, nPrimitives, bbox); + return node; + } + } + break; + } + } + node->InitInterior(dim, + recursiveBuild(buildArena, buildData, start, mid, + totalNodes, orderedPrims), + recursiveBuild(buildArena, buildData, mid, end, + totalNodes, orderedPrims)); + } + return node; +} + + +uint32_t BVHAccel::flattenBVHTree(BVHBuildNode *node, uint32_t *offset) { + LinearBVHNode *linearNode = &nodes[*offset]; + linearNode->bounds = node->bounds; + uint32_t myOffset = (*offset)++; + if (node->nPrimitives > 0) { + Assert(!node->children[0] && !node->children[1]); + linearNode->primitivesOffset = node->firstPrimOffset; + linearNode->nPrimitives = node->nPrimitives; + } + else { + // Creater interior flattened BVH node + linearNode->axis = node->splitAxis; + linearNode->nPrimitives = 0; + flattenBVHTree(node->children[0], offset); + linearNode->secondChildOffset = flattenBVHTree(node->children[1], + offset); + } + return myOffset; +} + + +BVHAccel::~BVHAccel() { + FreeAligned(nodes); +} + + +bool BVHAccel::Intersect(const Ray &ray, Intersection *isect) const { + if (!nodes) return false; + PBRT_BVH_INTERSECTION_STARTED(const_cast(this), const_cast(&ray)); + bool hit = false; + Point origin = ray(ray.mint); + Vector invDir(1.f / ray.d.x, 1.f / ray.d.y, 1.f / ray.d.z); + uint32_t dirIsNeg[3] = { invDir.x < 0, invDir.y < 0, invDir.z < 0 }; + // Follow ray through BVH nodes to find primitive intersections + uint32_t todoOffset = 0, nodeNum = 0; + uint32_t todo[64]; + while (true) { + const LinearBVHNode *node = &nodes[nodeNum]; + // Check ray against BVH node + if (::IntersectP(node->bounds, ray, invDir, dirIsNeg)) { + if (node->nPrimitives > 0) { + // Intersect ray with primitives in leaf BVH node + PBRT_BVH_INTERSECTION_TRAVERSED_LEAF_NODE(const_cast(node)); + for (uint32_t i = 0; i < node->nPrimitives; ++i) + { + PBRT_BVH_INTERSECTION_PRIMITIVE_TEST(const_cast(primitives[node->primitivesOffset+i].GetPtr())); + if (primitives[node->primitivesOffset+i]->Intersect(ray, isect)) + { + PBRT_BVH_INTERSECTION_PRIMITIVE_HIT(const_cast(primitives[node->primitivesOffset+i].GetPtr())); + hit = true; + } + else { + PBRT_BVH_INTERSECTION_PRIMITIVE_MISSED(const_cast(primitives[node->primitivesOffset+i].GetPtr())); + } + } + if (todoOffset == 0) break; + nodeNum = todo[--todoOffset]; + } + else { + // Put far BVH node on _todo_ stack, advance to near node + PBRT_BVH_INTERSECTION_TRAVERSED_INTERIOR_NODE(const_cast(node)); + if (dirIsNeg[node->axis]) { + todo[todoOffset++] = nodeNum + 1; + nodeNum = node->secondChildOffset; + } + else { + todo[todoOffset++] = node->secondChildOffset; + nodeNum = nodeNum + 1; + } + } + } + else { + if (todoOffset == 0) break; + nodeNum = todo[--todoOffset]; + } + } + PBRT_BVH_INTERSECTION_FINISHED(); + return hit; +} + + +bool BVHAccel::IntersectP(const Ray &ray) const { + if (!nodes) return false; + PBRT_BVH_INTERSECTIONP_STARTED(const_cast(this), const_cast(&ray)); + Vector invDir(1.f / ray.d.x, 1.f / ray.d.y, 1.f / ray.d.z); + uint32_t dirIsNeg[3] = { invDir.x < 0, invDir.y < 0, invDir.z < 0 }; + uint32_t todo[64]; + uint32_t todoOffset = 0, nodeNum = 0; + while (true) { + const LinearBVHNode *node = &nodes[nodeNum]; + if (::IntersectP(node->bounds, ray, invDir, dirIsNeg)) { + // Process BVH node _node_ for traversal + if (node->nPrimitives > 0) { + PBRT_BVH_INTERSECTIONP_TRAVERSED_LEAF_NODE(const_cast(node)); + for (uint32_t i = 0; i < node->nPrimitives; ++i) { + PBRT_BVH_INTERSECTIONP_PRIMITIVE_TEST(const_cast(primitives[node->primitivesOffset + i].GetPtr())); + if (primitives[node->primitivesOffset+i]->IntersectP(ray)) { + PBRT_BVH_INTERSECTIONP_PRIMITIVE_HIT(const_cast(primitives[node->primitivesOffset+i].GetPtr())); + return true; + } + else { + PBRT_BVH_INTERSECTIONP_PRIMITIVE_MISSED(const_cast(primitives[node->primitivesOffset + i].GetPtr())); + } + } + if (todoOffset == 0) break; + nodeNum = todo[--todoOffset]; + } + else { + PBRT_BVH_INTERSECTIONP_TRAVERSED_INTERIOR_NODE(const_cast(node)); + if (dirIsNeg[node->axis]) { + /// second child first + todo[todoOffset++] = nodeNum + 1; + nodeNum = node->secondChildOffset; + } + else { + todo[todoOffset++] = node->secondChildOffset; + nodeNum = nodeNum + 1; + } + } + } + else { + if (todoOffset == 0) break; + nodeNum = todo[--todoOffset]; + } + } + PBRT_BVH_INTERSECTIONP_FINISHED(); + return false; +} + + +BVHAccel *CreateBVHAccelerator(const vector > &prims, + const ParamSet &ps) { + string splitMethod = ps.FindOneString("splitmethod", "sah"); + uint32_t maxPrimsInNode = ps.FindOneInt("maxnodeprims", 4); + return new BVHAccel(prims, maxPrimsInNode, splitMethod); +} + + diff --git a/accelerators/bvh.h b/accelerators/bvh.h new file mode 100644 index 0000000..9c7c115 --- /dev/null +++ b/accelerators/bvh.h @@ -0,0 +1,70 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_ACCELERATORS_BVH_H +#define PBRT_ACCELERATORS_BVH_H + +// accelerators/bvh.h* +#include "pbrt.h" +#include "primitive.h" +struct BVHBuildNode; + +// BVHAccel Forward Declarations +struct BVHPrimitiveInfo; +struct LinearBVHNode; + +// BVHAccel Declarations +class BVHAccel : public Aggregate { +public: + // BVHAccel Public Methods + BVHAccel(const vector > &p, uint32_t maxPrims = 1, + const string &sm = "sah"); + BBox WorldBound() const; + bool CanIntersect() const { return true; } + ~BVHAccel(); + bool Intersect(const Ray &ray, Intersection *isect) const; + bool IntersectP(const Ray &ray) const; +private: + // BVHAccel Private Methods + BVHBuildNode *recursiveBuild(MemoryArena &buildArena, + vector &buildData, uint32_t start, uint32_t end, + uint32_t *totalNodes, vector > &orderedPrims); + uint32_t flattenBVHTree(BVHBuildNode *node, uint32_t *offset); + + // BVHAccel Private Data + uint32_t maxPrimsInNode; + enum SplitMethod { SPLIT_MIDDLE, SPLIT_EQUAL_COUNTS, SPLIT_SAH }; + SplitMethod splitMethod; + vector > primitives; + LinearBVHNode *nodes; +}; + + +BVHAccel *CreateBVHAccelerator(const vector > &prims, + const ParamSet &ps); + +#endif // PBRT_ACCELERATORS_BVH_H diff --git a/accelerators/grid.cpp b/accelerators/grid.cpp new file mode 100644 index 0000000..8327bcc --- /dev/null +++ b/accelerators/grid.cpp @@ -0,0 +1,320 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// accelerators/grid.cpp* +#include "stdafx.h" +#include "accelerators/grid.h" +#include "probes.h" +#include "paramset.h" + +// GridAccel Method Definitions +GridAccel::GridAccel(const vector > &p, + bool refineImmediately) { + PBRT_GRID_STARTED_CONSTRUCTION(this, p.size()); + // Initialize _primitives_ with primitives for grid + if (refineImmediately) + for (uint32_t i = 0; i < p.size(); ++i) + p[i]->FullyRefine(primitives); + else + primitives = p; + + // Compute bounds and choose grid resolution + for (uint32_t i = 0; i < primitives.size(); ++i) + bounds = Union(bounds, primitives[i]->WorldBound()); + Vector delta = bounds.pMax - bounds.pMin; + + // Find _voxelsPerUnitDist_ for grid + int maxAxis = bounds.MaximumExtent(); + float invMaxWidth = 1.f / delta[maxAxis]; + Assert(invMaxWidth > 0.f); + float cubeRoot = 3.f * powf(float(primitives.size()), 1.f/3.f); + float voxelsPerUnitDist = cubeRoot * invMaxWidth; + for (int axis = 0; axis < 3; ++axis) { + nVoxels[axis] = Round2Int(delta[axis] * voxelsPerUnitDist); + nVoxels[axis] = Clamp(nVoxels[axis], 1, 64); + } + PBRT_GRID_BOUNDS_AND_RESOLUTION(&bounds, nVoxels); + + // Compute voxel widths and allocate voxels + for (int axis = 0; axis < 3; ++axis) { + width[axis] = delta[axis] / nVoxels[axis]; + invWidth[axis] = (width[axis] == 0.f) ? 0.f : 1.f / width[axis]; + } + int nv = nVoxels[0] * nVoxels[1] * nVoxels[2]; + voxels = AllocAligned(nv); + memset(voxels, 0, nv * sizeof(Voxel *)); + + // Add primitives to grid voxels + for (uint32_t i = 0; i < primitives.size(); ++i) { + // Find voxel extent of primitive + BBox pb = primitives[i]->WorldBound(); + int vmin[3], vmax[3]; + for (int axis = 0; axis < 3; ++axis) { + vmin[axis] = posToVoxel(pb.pMin, axis); + vmax[axis] = posToVoxel(pb.pMax, axis); + } + + // Add primitive to overlapping voxels + PBRT_GRID_VOXELIZED_PRIMITIVE(vmin, vmax); + for (int z = vmin[2]; z <= vmax[2]; ++z) + for (int y = vmin[1]; y <= vmax[1]; ++y) + for (int x = vmin[0]; x <= vmax[0]; ++x) { + int o = offset(x, y, z); + if (!voxels[o]) { + // Allocate new voxel and store primitive in it + voxels[o] = voxelArena.Alloc(); + *voxels[o] = Voxel(primitives[i]); + } + else { + // Add primitive to already-allocated voxel + voxels[o]->AddPrimitive(primitives[i]); + } + } + } + + // Create reader-writer mutex for grid + rwMutex = RWMutex::Create(); + PBRT_GRID_FINISHED_CONSTRUCTION(this); +} + + +BBox GridAccel::WorldBound() const { + return bounds; +} + + +GridAccel::~GridAccel() { + for (int i = 0; i < nVoxels[0]*nVoxels[1]*nVoxels[2]; ++i) + if (voxels[i]) voxels[i]->~Voxel(); + FreeAligned(voxels); + RWMutex::Destroy(rwMutex); +} + + +bool GridAccel::Intersect(const Ray &ray, Intersection *isect) const { + PBRT_GRID_INTERSECTION_TEST(const_cast(this), const_cast(&ray)); + // Check ray against overall grid bounds + float rayT; + if (bounds.Inside(ray(ray.mint))) + rayT = ray.mint; + else if (!bounds.IntersectP(ray, &rayT)) + { + PBRT_GRID_RAY_MISSED_BOUNDS(); + return false; + } + Point gridIntersect = ray(rayT); + + // Set up 3D DDA for ray + float NextCrossingT[3], DeltaT[3]; + int Step[3], Out[3], Pos[3]; + for (int axis = 0; axis < 3; ++axis) { + // Compute current voxel for axis + Pos[axis] = posToVoxel(gridIntersect, axis); + if (ray.d[axis] >= 0) { + // Handle ray with positive direction for voxel stepping + NextCrossingT[axis] = rayT + + (voxelToPos(Pos[axis]+1, axis) - gridIntersect[axis]) / ray.d[axis]; + DeltaT[axis] = width[axis] / ray.d[axis]; + Step[axis] = 1; + Out[axis] = nVoxels[axis]; + } + else { + // Handle ray with negative direction for voxel stepping + NextCrossingT[axis] = rayT + + (voxelToPos(Pos[axis], axis) - gridIntersect[axis]) / ray.d[axis]; + DeltaT[axis] = -width[axis] / ray.d[axis]; + Step[axis] = -1; + Out[axis] = -1; + } + } + + // Walk ray through voxel grid + RWMutexLock lock(*rwMutex, READ); + bool hitSomething = false; + for (;;) { + // Check for intersection in current voxel and advance to next + Voxel *voxel = voxels[offset(Pos[0], Pos[1], Pos[2])]; + PBRT_GRID_RAY_TRAVERSED_VOXEL(Pos, voxel ? voxel->size() : 0); + if (voxel != NULL) + hitSomething |= voxel->Intersect(ray, isect, lock); + + // Advance to next voxel + + // Find _stepAxis_ for stepping to next voxel + int bits = ((NextCrossingT[0] < NextCrossingT[1]) << 2) + + ((NextCrossingT[0] < NextCrossingT[2]) << 1) + + ((NextCrossingT[1] < NextCrossingT[2])); + const int cmpToAxis[8] = { 2, 1, 2, 1, 2, 2, 0, 0 }; + int stepAxis = cmpToAxis[bits]; + if (ray.maxt < NextCrossingT[stepAxis]) + break; + Pos[stepAxis] += Step[stepAxis]; + if (Pos[stepAxis] == Out[stepAxis]) + break; + NextCrossingT[stepAxis] += DeltaT[stepAxis]; + } + return hitSomething; +} + + +bool Voxel::Intersect(const Ray &ray, Intersection *isect, + RWMutexLock &lock) { + // Refine primitives in voxel if needed + if (!allCanIntersect) { + lock.UpgradeToWrite(); + for (uint32_t i = 0; i < primitives.size(); ++i) { + Reference &prim = primitives[i]; + // Refine primitive _prim_ if it's not intersectable + if (!prim->CanIntersect()) { + vector > p; + prim->FullyRefine(p); + Assert(p.size() > 0); + if (p.size() == 1) + primitives[i] = p[0]; + else + primitives[i] = new GridAccel(p, false); + } + } + allCanIntersect = true; + lock.DowngradeToRead(); + } + + // Loop over primitives in voxel and find intersections + bool hitSomething = false; + for (uint32_t i = 0; i < primitives.size(); ++i) { + Reference &prim = primitives[i]; + PBRT_GRID_RAY_PRIMITIVE_INTERSECTION_TEST(const_cast(prim.GetPtr())); + if (prim->Intersect(ray, isect)) + { + PBRT_GRID_RAY_PRIMITIVE_HIT(const_cast(prim.GetPtr())); + hitSomething = true; + } + } + return hitSomething; +} + + +bool GridAccel::IntersectP(const Ray &ray) const { + PBRT_GRID_INTERSECTIONP_TEST(const_cast(this), const_cast(&ray)); + RWMutexLock lock(*rwMutex, READ); + // Check ray against overall grid bounds + float rayT; + if (bounds.Inside(ray(ray.mint))) + rayT = ray.mint; + else if (!bounds.IntersectP(ray, &rayT)) + { + PBRT_GRID_RAY_MISSED_BOUNDS(); + return false; + } + Point gridIntersect = ray(rayT); + + // Set up 3D DDA for ray + float NextCrossingT[3], DeltaT[3]; + int Step[3], Out[3], Pos[3]; + for (int axis = 0; axis < 3; ++axis) { + // Compute current voxel for axis + Pos[axis] = posToVoxel(gridIntersect, axis); + if (ray.d[axis] >= 0) { + // Handle ray with positive direction for voxel stepping + NextCrossingT[axis] = rayT + + (voxelToPos(Pos[axis]+1, axis) - gridIntersect[axis]) / ray.d[axis]; + DeltaT[axis] = width[axis] / ray.d[axis]; + Step[axis] = 1; + Out[axis] = nVoxels[axis]; + } + else { + // Handle ray with negative direction for voxel stepping + NextCrossingT[axis] = rayT + + (voxelToPos(Pos[axis], axis) - gridIntersect[axis]) / ray.d[axis]; + DeltaT[axis] = -width[axis] / ray.d[axis]; + Step[axis] = -1; + Out[axis] = -1; + } + } + + // Walk grid for shadow ray + for (;;) { + int o = offset(Pos[0], Pos[1], Pos[2]); + Voxel *voxel = voxels[o]; + PBRT_GRID_RAY_TRAVERSED_VOXEL(Pos, voxel ? voxel->size() : 0); + if (voxel && voxel->IntersectP(ray, lock)) + return true; + // Advance to next voxel + + // Find _stepAxis_ for stepping to next voxel + int bits = ((NextCrossingT[0] < NextCrossingT[1]) << 2) + + ((NextCrossingT[0] < NextCrossingT[2]) << 1) + + ((NextCrossingT[1] < NextCrossingT[2])); + const int cmpToAxis[8] = { 2, 1, 2, 1, 2, 2, 0, 0 }; + int stepAxis = cmpToAxis[bits]; + if (ray.maxt < NextCrossingT[stepAxis]) + break; + Pos[stepAxis] += Step[stepAxis]; + if (Pos[stepAxis] == Out[stepAxis]) + break; + NextCrossingT[stepAxis] += DeltaT[stepAxis]; + } + return false; +} + + +bool Voxel::IntersectP(const Ray &ray, RWMutexLock &lock) { + // Refine primitives in voxel if needed + if (!allCanIntersect) { + lock.UpgradeToWrite(); + for (uint32_t i = 0; i < primitives.size(); ++i) { + Reference &prim = primitives[i]; + // Refine primitive _prim_ if it's not intersectable + if (!prim->CanIntersect()) { + vector > p; + prim->FullyRefine(p); + Assert(p.size() > 0); + if (p.size() == 1) + primitives[i] = p[0]; + else + primitives[i] = new GridAccel(p, false); + } + } + allCanIntersect = true; + lock.DowngradeToRead(); + } + for (uint32_t i = 0; i < primitives.size(); ++i) { + Reference &prim = primitives[i]; + PBRT_GRID_RAY_PRIMITIVE_INTERSECTIONP_TEST(const_cast(prim.GetPtr())); + if (prim->IntersectP(ray)) { + PBRT_GRID_RAY_PRIMITIVE_HIT(const_cast(prim.GetPtr())); + return true; + } + } + return false; +} + + +GridAccel *CreateGridAccelerator(const vector > &prims, + const ParamSet &ps) { + bool refineImmediately = ps.FindOneBool("refineimmediately", false); + return new GridAccel(prims, refineImmediately); +} + + diff --git a/accelerators/grid.h b/accelerators/grid.h new file mode 100644 index 0000000..81492b1 --- /dev/null +++ b/accelerators/grid.h @@ -0,0 +1,97 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_ACCELERATORS_GRID_H +#define PBRT_ACCELERATORS_GRID_H + +// accelerators/grid.h* +#include "pbrt.h" +#include "primitive.h" + +// GridAccel Forward Declarations +struct Voxel; + +// Voxel Declarations +struct Voxel { + // Voxel Public Methods + uint32_t size() const { return primitives.size(); } + Voxel() { } + Voxel(Reference op) { + allCanIntersect = false; + primitives.push_back(op); + } + void AddPrimitive(Reference prim) { + primitives.push_back(prim); + } + bool Intersect(const Ray &ray, Intersection *isect, RWMutexLock &lock); + bool IntersectP(const Ray &ray, RWMutexLock &lock); +private: + vector > primitives; + bool allCanIntersect; +}; + + + +// GridAccel Declarations +class GridAccel : public Aggregate { +public: + // GridAccel Public Methods + GridAccel(const vector > &p, bool refineImmediately); + BBox WorldBound() const; + bool CanIntersect() const { return true; } + ~GridAccel(); + bool Intersect(const Ray &ray, Intersection *isect) const; + bool IntersectP(const Ray &ray) const; +private: + // GridAccel Private Methods + int posToVoxel(const Point &P, int axis) const { + int v = Float2Int((P[axis] - bounds.pMin[axis]) * + invWidth[axis]); + return Clamp(v, 0, nVoxels[axis]-1); + } + float voxelToPos(int p, int axis) const { + return bounds.pMin[axis] + p * width[axis]; + } + inline int offset(int x, int y, int z) const { + return z*nVoxels[0]*nVoxels[1] + y*nVoxels[0] + x; + } + + // GridAccel Private Data + vector > primitives; + int nVoxels[3]; + BBox bounds; + Vector width, invWidth; + Voxel **voxels; + MemoryArena voxelArena; + mutable RWMutex *rwMutex; +}; + + +GridAccel *CreateGridAccelerator(const vector > &prims, + const ParamSet &ps); + +#endif // PBRT_ACCELERATORS_GRID_H diff --git a/accelerators/kdtreeaccel.cpp b/accelerators/kdtreeaccel.cpp new file mode 100644 index 0000000..4f13f89 --- /dev/null +++ b/accelerators/kdtreeaccel.cpp @@ -0,0 +1,476 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// accelerators/kdtreeaccel.cpp* +#include "stdafx.h" +#include "accelerators/kdtreeaccel.h" +#include "paramset.h" + +// KdTreeAccel Local Declarations +struct KdAccelNode { + // KdAccelNode Methods + void initLeaf(uint32_t *primNums, int np, MemoryArena &arena); + void initInterior(uint32_t axis, uint32_t ac, float s) { + split = s; + flags = axis; + aboveChild |= (ac << 2); + } + float SplitPos() const { return split; } + uint32_t nPrimitives() const { return nPrims >> 2; } + uint32_t SplitAxis() const { return flags & 3; } + bool IsLeaf() const { return (flags & 3) == 3; } + uint32_t AboveChild() const { return aboveChild >> 2; } + union { + float split; // Interior + uint32_t onePrimitive; // Leaf + uint32_t *primitives; // Leaf + }; + +private: + union { + uint32_t flags; // Both + uint32_t nPrims; // Leaf + uint32_t aboveChild; // Interior + }; +}; + + +struct BoundEdge { + // BoundEdge Public Methods + BoundEdge() { } + BoundEdge(float tt, int pn, bool starting) { + t = tt; + primNum = pn; + type = starting ? START : END; + } + bool operator<(const BoundEdge &e) const { + if (t == e.t) + return (int)type < (int)e.type; + else return t < e.t; + } + float t; + int primNum; + enum { START, END } type; +}; + + + +// KdTreeAccel Method Definitions +KdTreeAccel::KdTreeAccel(const vector > &p, + int icost, int tcost, float ebonus, int maxp, + int md) + : isectCost(icost), traversalCost(tcost), maxPrims(maxp), maxDepth(md), + emptyBonus(ebonus) { + PBRT_KDTREE_STARTED_CONSTRUCTION(this, p.size()); + for (uint32_t i = 0; i < p.size(); ++i) + p[i]->FullyRefine(primitives); + // Build kd-tree for accelerator + nextFreeNode = nAllocedNodes = 0; + if (maxDepth <= 0) + maxDepth = Round2Int(8 + 1.3f * Log2Int(float(primitives.size()))); + + // Compute bounds for kd-tree construction + vector primBounds; + primBounds.reserve(primitives.size()); + for (uint32_t i = 0; i < primitives.size(); ++i) { + BBox b = primitives[i]->WorldBound(); + bounds = Union(bounds, b); + primBounds.push_back(b); + } + + // Allocate working memory for kd-tree construction + BoundEdge *edges[3]; + for (int i = 0; i < 3; ++i) + edges[i] = new BoundEdge[2*primitives.size()]; + uint32_t *prims0 = new uint32_t[primitives.size()]; + uint32_t *prims1 = new uint32_t[(maxDepth+1) * primitives.size()]; + + // Initialize _primNums_ for kd-tree construction + uint32_t *primNums = new uint32_t[primitives.size()]; + for (uint32_t i = 0; i < primitives.size(); ++i) + primNums[i] = i; + + // Start recursive construction of kd-tree + buildTree(0, bounds, primBounds, primNums, primitives.size(), + maxDepth, edges, prims0, prims1); + + // Free working memory for kd-tree construction + delete[] primNums; + for (int i = 0; i < 3; ++i) + delete[] edges[i]; + delete[] prims0; + delete[] prims1; + PBRT_KDTREE_FINISHED_CONSTRUCTION(this); +} + + +void KdAccelNode::initLeaf(uint32_t *primNums, int np, + MemoryArena &arena) { + flags = 3; + nPrims |= (np << 2); + // Store primitive ids for leaf node + if (np == 0) + onePrimitive = 0; + else if (np == 1) + onePrimitive = primNums[0]; + else { + primitives = arena.Alloc(np); + for (int i = 0; i < np; ++i) + primitives[i] = primNums[i]; + } +} + + +KdTreeAccel::~KdTreeAccel() { + FreeAligned(nodes); +} + + +void KdTreeAccel::buildTree(int nodeNum, const BBox &nodeBounds, + const vector &allPrimBounds, uint32_t *primNums, + int nPrimitives, int depth, BoundEdge *edges[3], + uint32_t *prims0, uint32_t *prims1, int badRefines) { + Assert(nodeNum == nextFreeNode); + // Get next free node from _nodes_ array + if (nextFreeNode == nAllocedNodes) { + int nAlloc = max(2 * nAllocedNodes, 512); + KdAccelNode *n = AllocAligned(nAlloc); + if (nAllocedNodes > 0) { + memcpy(n, nodes, nAllocedNodes * sizeof(KdAccelNode)); + FreeAligned(nodes); + } + nodes = n; + nAllocedNodes = nAlloc; + } + ++nextFreeNode; + + // Initialize leaf node if termination criteria met + if (nPrimitives <= maxPrims || depth == 0) { + PBRT_KDTREE_CREATED_LEAF(nPrimitives, maxDepth-depth); + nodes[nodeNum].initLeaf(primNums, nPrimitives, arena); + return; + } + + // Initialize interior node and continue recursion + + // Choose split axis position for interior node + int bestAxis = -1, bestOffset = -1; + float bestCost = INFINITY; + float oldCost = isectCost * float(nPrimitives); + float totalSA = nodeBounds.SurfaceArea(); + float invTotalSA = 1.f / totalSA; + Vector d = nodeBounds.pMax - nodeBounds.pMin; + + // Choose which axis to split along + uint32_t axis = nodeBounds.MaximumExtent(); + int retries = 0; + retrySplit: + + // Initialize edges for _axis_ + for (int i = 0; i < nPrimitives; ++i) { + int pn = primNums[i]; + const BBox &bbox = allPrimBounds[pn]; + edges[axis][2*i] = BoundEdge(bbox.pMin[axis], pn, true); + edges[axis][2*i+1] = BoundEdge(bbox.pMax[axis], pn, false); + } + sort(&edges[axis][0], &edges[axis][2*nPrimitives]); + + // Compute cost of all splits for _axis_ to find best + int nBelow = 0, nAbove = nPrimitives; + for (int i = 0; i < 2*nPrimitives; ++i) { + if (edges[axis][i].type == BoundEdge::END) --nAbove; + float edget = edges[axis][i].t; + if (edget > nodeBounds.pMin[axis] && + edget < nodeBounds.pMax[axis]) { + // Compute cost for split at _i_th edge + uint32_t otherAxis0 = (axis + 1) % 3, otherAxis1 = (axis + 2) % 3; + float belowSA = 2 * (d[otherAxis0] * d[otherAxis1] + + (edget - nodeBounds.pMin[axis]) * + (d[otherAxis0] + d[otherAxis1])); + float aboveSA = 2 * (d[otherAxis0] * d[otherAxis1] + + (nodeBounds.pMax[axis] - edget) * + (d[otherAxis0] + d[otherAxis1])); + float pBelow = belowSA * invTotalSA; + float pAbove = aboveSA * invTotalSA; + float eb = (nAbove == 0 || nBelow == 0) ? emptyBonus : 0.f; + float cost = traversalCost + + isectCost * (1.f - eb) * (pBelow * nBelow + pAbove * nAbove); + + // Update best split if this is lowest cost so far + if (cost < bestCost) { + bestCost = cost; + bestAxis = axis; + bestOffset = i; + } + } + if (edges[axis][i].type == BoundEdge::START) ++nBelow; + } + Assert(nBelow == nPrimitives && nAbove == 0); + + // Create leaf if no good splits were found + if (bestAxis == -1 && retries < 2) { + ++retries; + axis = (axis+1) % 3; + goto retrySplit; + } + if (bestCost > oldCost) ++badRefines; + if ((bestCost > 4.f * oldCost && nPrimitives < 16) || + bestAxis == -1 || badRefines == 3) { + PBRT_KDTREE_CREATED_LEAF(nPrimitives, maxDepth-depth); + nodes[nodeNum].initLeaf(primNums, nPrimitives, arena); + return; + } + + // Classify primitives with respect to split + int n0 = 0, n1 = 0; + for (int i = 0; i < bestOffset; ++i) + if (edges[bestAxis][i].type == BoundEdge::START) + prims0[n0++] = edges[bestAxis][i].primNum; + for (int i = bestOffset+1; i < 2*nPrimitives; ++i) + if (edges[bestAxis][i].type == BoundEdge::END) + prims1[n1++] = edges[bestAxis][i].primNum; + + // Recursively initialize children nodes + float tsplit = edges[bestAxis][bestOffset].t; + PBRT_KDTREE_CREATED_INTERIOR_NODE(bestAxis, tsplit); + BBox bounds0 = nodeBounds, bounds1 = nodeBounds; + bounds0.pMax[bestAxis] = bounds1.pMin[bestAxis] = tsplit; + buildTree(nodeNum+1, bounds0, + allPrimBounds, prims0, n0, depth-1, edges, + prims0, prims1 + nPrimitives, badRefines); + uint32_t aboveChild = nextFreeNode; + nodes[nodeNum].initInterior(bestAxis, aboveChild, tsplit); + buildTree(aboveChild, bounds1, allPrimBounds, prims1, n1, + depth-1, edges, prims0, prims1 + nPrimitives, badRefines); +} + + +bool KdTreeAccel::Intersect(const Ray &ray, + Intersection *isect) const { + PBRT_KDTREE_INTERSECTION_TEST(const_cast(this), const_cast(&ray)); + // Compute initial parametric range of ray inside kd-tree extent + float tmin, tmax; + if (!bounds.IntersectP(ray, &tmin, &tmax)) + { + PBRT_KDTREE_RAY_MISSED_BOUNDS(); + return false; + } + + // Prepare to traverse kd-tree for ray + Vector invDir(1.f/ray.d.x, 1.f/ray.d.y, 1.f/ray.d.z); +#define MAX_TODO 64 + KdToDo todo[MAX_TODO]; + int todoPos = 0; + + // Traverse kd-tree nodes in order for ray + bool hit = false; + const KdAccelNode *node = &nodes[0]; + while (node != NULL) { + // Bail out if we found a hit closer than the current node + if (ray.maxt < tmin) break; + if (!node->IsLeaf()) { + PBRT_KDTREE_INTERSECTION_TRAVERSED_INTERIOR_NODE(const_cast(node)); + // Process kd-tree interior node + + // Compute parametric distance along ray to split plane + int axis = node->SplitAxis(); + float tplane = (node->SplitPos() - ray.o[axis]) * invDir[axis]; + + // Get node children pointers for ray + const KdAccelNode *firstChild, *secondChild; + int belowFirst = (ray.o[axis] < node->SplitPos()) || + (ray.o[axis] == node->SplitPos() && ray.d[axis] <= 0); + if (belowFirst) { + firstChild = node + 1; + secondChild = &nodes[node->AboveChild()]; + } + else { + firstChild = &nodes[node->AboveChild()]; + secondChild = node + 1; + } + + // Advance to next child node, possibly enqueue other child + if (tplane > tmax || tplane <= 0) + node = firstChild; + else if (tplane < tmin) + node = secondChild; + else { + // Enqueue _secondChild_ in todo list + todo[todoPos].node = secondChild; + todo[todoPos].tmin = tplane; + todo[todoPos].tmax = tmax; + ++todoPos; + node = firstChild; + tmax = tplane; + } + } + else { + PBRT_KDTREE_INTERSECTION_TRAVERSED_LEAF_NODE(const_cast(node), node->nPrimitives()); + // Check for intersections inside leaf node + uint32_t nPrimitives = node->nPrimitives(); + if (nPrimitives == 1) { + const Reference &prim = primitives[node->onePrimitive]; + // Check one primitive inside leaf node + PBRT_KDTREE_INTERSECTION_PRIMITIVE_TEST(const_cast(prim.GetPtr())); + if (prim->Intersect(ray, isect)) + { + PBRT_KDTREE_INTERSECTION_HIT(const_cast(prim.GetPtr())); + hit = true; + } + } + else { + uint32_t *prims = node->primitives; + for (uint32_t i = 0; i < nPrimitives; ++i) { + const Reference &prim = primitives[prims[i]]; + // Check one primitive inside leaf node + PBRT_KDTREE_INTERSECTION_PRIMITIVE_TEST(const_cast(prim.GetPtr())); + if (prim->Intersect(ray, isect)) + { + PBRT_KDTREE_INTERSECTION_HIT(const_cast(prim.GetPtr())); + hit = true; + } + } + } + + // Grab next node to process from todo list + if (todoPos > 0) { + --todoPos; + node = todo[todoPos].node; + tmin = todo[todoPos].tmin; + tmax = todo[todoPos].tmax; + } + else + break; + } + } + PBRT_KDTREE_INTERSECTION_FINISHED(); + return hit; +} + + +bool KdTreeAccel::IntersectP(const Ray &ray) const { + PBRT_KDTREE_INTERSECTIONP_TEST(const_cast(this), const_cast(&ray)); + // Compute initial parametric range of ray inside kd-tree extent + float tmin, tmax; + if (!bounds.IntersectP(ray, &tmin, &tmax)) + { + PBRT_KDTREE_RAY_MISSED_BOUNDS(); + return false; + } + + // Prepare to traverse kd-tree for ray + Vector invDir(1.f/ray.d.x, 1.f/ray.d.y, 1.f/ray.d.z); +#define MAX_TODO 64 + KdToDo todo[MAX_TODO]; + int todoPos = 0; + const KdAccelNode *node = &nodes[0]; + while (node != NULL) { + if (node->IsLeaf()) { + PBRT_KDTREE_INTERSECTIONP_TRAVERSED_LEAF_NODE(const_cast(node), node->nPrimitives()); + // Check for shadow ray intersections inside leaf node + uint32_t nPrimitives = node->nPrimitives(); + if (nPrimitives == 1) { + const Reference &prim = primitives[node->onePrimitive]; + PBRT_KDTREE_INTERSECTIONP_PRIMITIVE_TEST(const_cast(prim.GetPtr())); + if (prim->IntersectP(ray)) { + PBRT_KDTREE_INTERSECTIONP_HIT(const_cast(prim.GetPtr())); + return true; + } + } + else { + uint32_t *prims = node->primitives; + for (uint32_t i = 0; i < nPrimitives; ++i) { + const Reference &prim = primitives[prims[i]]; + PBRT_KDTREE_INTERSECTIONP_PRIMITIVE_TEST(const_cast(prim.GetPtr())); + if (prim->IntersectP(ray)) { + PBRT_KDTREE_INTERSECTIONP_HIT(const_cast(prim.GetPtr())); + return true; + } + } + } + + // Grab next node to process from todo list + if (todoPos > 0) { + --todoPos; + node = todo[todoPos].node; + tmin = todo[todoPos].tmin; + tmax = todo[todoPos].tmax; + } + else + break; + } + else { + PBRT_KDTREE_INTERSECTIONP_TRAVERSED_INTERIOR_NODE(const_cast(node)); + // Process kd-tree interior node + + // Compute parametric distance along ray to split plane + int axis = node->SplitAxis(); + float tplane = (node->SplitPos() - ray.o[axis]) * invDir[axis]; + + // Get node children pointers for ray + const KdAccelNode *firstChild, *secondChild; + int belowFirst = (ray.o[axis] < node->SplitPos()) || + (ray.o[axis] == node->SplitPos() && ray.d[axis] <= 0); + if (belowFirst) { + firstChild = node + 1; + secondChild = &nodes[node->AboveChild()]; + } + else { + firstChild = &nodes[node->AboveChild()]; + secondChild = node + 1; + } + + // Advance to next child node, possibly enqueue other child + if (tplane > tmax || tplane <= 0) + node = firstChild; + else if (tplane < tmin) + node = secondChild; + else { + // Enqueue _secondChild_ in todo list + todo[todoPos].node = secondChild; + todo[todoPos].tmin = tplane; + todo[todoPos].tmax = tmax; + ++todoPos; + node = firstChild; + tmax = tplane; + } + } + } + PBRT_KDTREE_INTERSECTIONP_MISSED(); + return false; +} + + +KdTreeAccel *CreateKdTreeAccelerator(const vector > &prims, + const ParamSet &ps) { + int isectCost = ps.FindOneInt("intersectcost", 80); + int travCost = ps.FindOneInt("traversalcost", 1); + float emptyBonus = ps.FindOneFloat("emptybonus", 0.5f); + int maxPrims = ps.FindOneInt("maxprims", 1); + int maxDepth = ps.FindOneInt("maxdepth", -1); + return new KdTreeAccel(prims, isectCost, travCost, + emptyBonus, maxPrims, maxDepth); +} + + diff --git a/accelerators/kdtreeaccel.h b/accelerators/kdtreeaccel.h new file mode 100644 index 0000000..8776ee7 --- /dev/null +++ b/accelerators/kdtreeaccel.h @@ -0,0 +1,75 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_ACCELERATORS_KDTREEACCEL_H +#define PBRT_ACCELERATORS_KDTREEACCEL_H + +// accelerators/kdtreeaccel.h* +#include "pbrt.h" +#include "primitive.h" + +// KdTreeAccel Declarations +struct KdAccelNode; +struct BoundEdge; +class KdTreeAccel : public Aggregate { +public: + // KdTreeAccel Public Methods + KdTreeAccel(const vector > &p, + int icost = 80, int scost = 1, float ebonus = 0.5f, int maxp = 1, + int maxDepth = -1); + BBox WorldBound() const { return bounds; } + bool CanIntersect() const { return true; } + ~KdTreeAccel(); + bool Intersect(const Ray &ray, Intersection *isect) const; + bool IntersectP(const Ray &ray) const; +private: + // KdTreeAccel Private Methods + void buildTree(int nodeNum, const BBox &bounds, + const vector &primBounds, uint32_t *primNums, int nprims, int depth, + BoundEdge *edges[3], uint32_t *prims0, uint32_t *prims1, int badRefines = 0); + + // KdTreeAccel Private Data + int isectCost, traversalCost, maxPrims, maxDepth; + float emptyBonus; + vector > primitives; + KdAccelNode *nodes; + int nAllocedNodes, nextFreeNode; + BBox bounds; + MemoryArena arena; +}; + + +struct KdToDo { + const KdAccelNode *node; + float tmin, tmax; +}; + + +KdTreeAccel *CreateKdTreeAccelerator(const vector > &prims, + const ParamSet &ps); + +#endif // PBRT_ACCELERATORS_KDTREEACCEL_H diff --git a/cameras/environment.cpp b/cameras/environment.cpp new file mode 100644 index 0000000..8ef569d --- /dev/null +++ b/cameras/environment.cpp @@ -0,0 +1,82 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// cameras/environment.cpp* +#include "stdafx.h" +#include "cameras/environment.h" +#include "paramset.h" +#include "sampler.h" + +// EnvironmentCamera Method Definitions +float EnvironmentCamera::GenerateRay(const CameraSample &sample, + Ray *ray) const { + float time = Lerp(sample.time, shutterOpen, shutterClose); + // Compute environment camera ray direction + float theta = M_PI * sample.imageY / film->yResolution; + float phi = 2 * M_PI * sample.imageX / film->xResolution; + Vector dir(sinf(theta) * cosf(phi), cosf(theta), + sinf(theta) * sinf(phi)); + *ray = Ray(Point(0,0,0), dir, 0.f, INFINITY, time); + CameraToWorld(*ray, ray); + return 1.f; +} + + +EnvironmentCamera *CreateEnvironmentCamera(const ParamSet ¶ms, + const AnimatedTransform &cam2world, Film *film) { + // Extract common camera parameters from _ParamSet_ + float shutteropen = params.FindOneFloat("shutteropen", 0.f); + float shutterclose = params.FindOneFloat("shutterclose", 1.f); + if (shutterclose < shutteropen) { + Warning("Shutter close time [%f] < shutter open [%f]. Swapping them.", + shutterclose, shutteropen); + swap(shutterclose, shutteropen); + } + float lensradius = params.FindOneFloat("lensradius", 0.f); + float focaldistance = params.FindOneFloat("focaldistance", 1e30f); + float frame = params.FindOneFloat("frameaspectratio", + float(film->xResolution)/float(film->yResolution)); + float screen[4]; + if (frame > 1.f) { + screen[0] = -frame; + screen[1] = frame; + screen[2] = -1.f; + screen[3] = 1.f; + } + else { + screen[0] = -1.f; + screen[1] = 1.f; + screen[2] = -1.f / frame; + screen[3] = 1.f / frame; + } + int swi; + const float *sw = params.FindFloat("screenwindow", &swi); + if (sw && swi == 4) + memcpy(screen, sw, 4*sizeof(float)); + (void) lensradius; // don't need this + (void) focaldistance; // don't need this + return new EnvironmentCamera(cam2world, shutteropen, shutterclose, film); +} + + diff --git a/cameras/environment.h b/cameras/environment.h new file mode 100644 index 0000000..c652038 --- /dev/null +++ b/cameras/environment.h @@ -0,0 +1,50 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CAMERAS_ENVIRONMENT_H +#define PBRT_CAMERAS_ENVIRONMENT_H + +// cameras/environment.h* +#include "camera.h" +#include "film.h" + +// EnvironmentCamera Declarations +class EnvironmentCamera : public Camera { +public: + // EnvironmentCamera Public Methods + EnvironmentCamera(const AnimatedTransform &cam2world, float sopen, + float sclose, Film *film) + : Camera(cam2world, sopen, sclose, film) { + } + float GenerateRay(const CameraSample &sample, Ray *) const; +}; + + +EnvironmentCamera *CreateEnvironmentCamera(const ParamSet ¶ms, + const AnimatedTransform &cam2world, Film *film); + +#endif // PBRT_CAMERAS_ENVIRONMENT_H diff --git a/cameras/orthographic.cpp b/cameras/orthographic.cpp new file mode 100644 index 0000000..2d2bf72 --- /dev/null +++ b/cameras/orthographic.cpp @@ -0,0 +1,143 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// cameras/orthographic.cpp* +#include "stdafx.h" +#include "cameras/orthographic.h" +#include "paramset.h" +#include "sampler.h" +#include "montecarlo.h" + +// OrthographicCamera Definitions +OrthoCamera::OrthoCamera(const AnimatedTransform &cam2world, + const float screenWindow[4], float sopen, float sclose, + float lensr, float focald, Film *f) + : ProjectiveCamera(cam2world, Orthographic(0., 1.), screenWindow, + sopen, sclose, lensr, focald, f) { + // Compute differential changes in origin for ortho camera rays + dxCamera = RasterToCamera(Vector(1, 0, 0)); + dyCamera = RasterToCamera(Vector(0, 1, 0)); +} + + +float OrthoCamera::GenerateRay(const CameraSample &sample, Ray *ray) const { + // Generate raster and camera samples + Point Pras(sample.imageX, sample.imageY, 0); + Point Pcamera; + RasterToCamera(Pras, &Pcamera); + *ray = Ray(Pcamera, Vector(0,0,1), 0.f, INFINITY); + // Modify ray for depth of field + if (lensRadius > 0.) { + // Sample point on lens + float lensU, lensV; + ConcentricSampleDisk(sample.lensU, sample.lensV, &lensU, &lensV); + lensU *= lensRadius; + lensV *= lensRadius; + + // Compute point on plane of focus + float ft = focalDistance / ray->d.z; + Point Pfocus = (*ray)(ft); + + // Update ray for effect of lens + ray->o = Point(lensU, lensV, 0.f); + ray->d = Normalize(Pfocus - ray->o); + } + ray->time = Lerp(sample.time, shutterOpen, shutterClose); + CameraToWorld(*ray, ray); + return 1.f; +} + + +float OrthoCamera::GenerateRayDifferential(const CameraSample &sample, + RayDifferential *ray) const { + // Compute main orthographic viewing ray + + // Generate raster and camera samples + Point Pras(sample.imageX, sample.imageY, 0); + Point Pcamera; + RasterToCamera(Pras, &Pcamera); + *ray = RayDifferential(Pcamera, Vector(0,0,1), 0., INFINITY); + + // Modify ray for depth of field + if (lensRadius > 0.) { + // Sample point on lens + float lensU, lensV; + ConcentricSampleDisk(sample.lensU, sample.lensV, &lensU, &lensV); + lensU *= lensRadius; + lensV *= lensRadius; + + // Compute point on plane of focus + float ft = focalDistance / ray->d.z; + Point Pfocus = (*ray)(ft); + + // Update ray for effect of lens + ray->o = Point(lensU, lensV, 0.f); + ray->d = Normalize(Pfocus - ray->o); + } + ray->time = Lerp(sample.time, shutterOpen, shutterClose); + ray->rxOrigin = ray->o + dxCamera; + ray->ryOrigin = ray->o + dyCamera; + ray->rxDirection = ray->ryDirection = ray->d; + ray->hasDifferentials = true; + CameraToWorld(*ray, ray); + return 1.f; +} + + +OrthoCamera *CreateOrthographicCamera(const ParamSet ¶ms, + const AnimatedTransform &cam2world, Film *film) { + // Extract common camera parameters from _ParamSet_ + float shutteropen = params.FindOneFloat("shutteropen", 0.f); + float shutterclose = params.FindOneFloat("shutterclose", 1.f); + if (shutterclose < shutteropen) { + Warning("Shutter close time [%f] < shutter open [%f]. Swapping them.", + shutterclose, shutteropen); + swap(shutterclose, shutteropen); + } + float lensradius = params.FindOneFloat("lensradius", 0.f); + float focaldistance = params.FindOneFloat("focaldistance", 1e30f); + float frame = params.FindOneFloat("frameaspectratio", + float(film->xResolution)/float(film->yResolution)); + float screen[4]; + if (frame > 1.f) { + screen[0] = -frame; + screen[1] = frame; + screen[2] = -1.f; + screen[3] = 1.f; + } + else { + screen[0] = -1.f; + screen[1] = 1.f; + screen[2] = -1.f / frame; + screen[3] = 1.f / frame; + } + int swi; + const float *sw = params.FindFloat("screenwindow", &swi); + if (sw && swi == 4) + memcpy(screen, sw, 4*sizeof(float)); + return new OrthoCamera(cam2world, screen, shutteropen, shutterclose, + lensradius, focaldistance, film); +} + + diff --git a/cameras/orthographic.h b/cameras/orthographic.h new file mode 100644 index 0000000..ab97979 --- /dev/null +++ b/cameras/orthographic.h @@ -0,0 +1,53 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CAMERAS_ORTHOGRAPHIC_H +#define PBRT_CAMERAS_ORTHOGRAPHIC_H + +// cameras/orthographic.h* +#include "pbrt.h" +#include "camera.h" +#include "film.h" + +// OrthographicCamera Declarations +class OrthoCamera : public ProjectiveCamera { +public: + // OrthoCamera Public Methods + OrthoCamera(const AnimatedTransform &cam2world, const float screenWindow[4], + float sopen, float sclose, float lensr, float focald, Film *film); + float GenerateRay(const CameraSample &sample, Ray *) const; + float GenerateRayDifferential(const CameraSample &sample, RayDifferential *) const; +private: + // OrthoCamera Private Data + Vector dxCamera, dyCamera; +}; + + +OrthoCamera *CreateOrthographicCamera(const ParamSet ¶ms, + const AnimatedTransform &cam2world, Film *film); + +#endif // PBRT_CAMERAS_ORTHOGRAPHIC_H diff --git a/cameras/perspective.cpp b/cameras/perspective.cpp new file mode 100644 index 0000000..81756df --- /dev/null +++ b/cameras/perspective.cpp @@ -0,0 +1,147 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// cameras/perspective.cpp* +#include "stdafx.h" +#include "cameras/perspective.h" +#include "paramset.h" +#include "sampler.h" +#include "montecarlo.h" + +// PerspectiveCamera Method Definitions +PerspectiveCamera:: PerspectiveCamera(const AnimatedTransform &cam2world, + const float screenWindow[4], float sopen, float sclose, + float lensr, float focald, float fov, Film *f) + : ProjectiveCamera(cam2world, Perspective(fov, 1e-2f, 1000.f), + screenWindow, sopen, sclose, lensr, focald, f) { + // Compute differential changes in origin for perspective camera rays + dxCamera = RasterToCamera(Point(1,0,0)) - RasterToCamera(Point(0,0,0)); + dyCamera = RasterToCamera(Point(0,1,0)) - RasterToCamera(Point(0,0,0)); +} + + +float PerspectiveCamera::GenerateRay(const CameraSample &sample, + Ray *ray) const { + // Generate raster and camera samples + Point Pras(sample.imageX, sample.imageY, 0); + Point Pcamera; + RasterToCamera(Pras, &Pcamera); + *ray = Ray(Point(0,0,0), Normalize(Vector(Pcamera)), 0.f, INFINITY); + // Modify ray for depth of field + if (lensRadius > 0.) { + // Sample point on lens + float lensU, lensV; + ConcentricSampleDisk(sample.lensU, sample.lensV, &lensU, &lensV); + lensU *= lensRadius; + lensV *= lensRadius; + + // Compute point on plane of focus + float ft = focalDistance / ray->d.z; + Point Pfocus = (*ray)(ft); + + // Update ray for effect of lens + ray->o = Point(lensU, lensV, 0.f); + ray->d = Normalize(Pfocus - ray->o); + } + ray->time = Lerp(sample.time, shutterOpen, shutterClose); + CameraToWorld(*ray, ray); + return 1.f; +} + + +float PerspectiveCamera::GenerateRayDifferential(const CameraSample &sample, + RayDifferential *ray) const { + // Generate raster and camera samples + Point Pras(sample.imageX, sample.imageY, 0); + Point Pcamera; + RasterToCamera(Pras, &Pcamera); + Vector dir = Normalize(Vector(Pcamera.x, Pcamera.y, Pcamera.z)); + *ray = RayDifferential(Point(0,0,0), dir, 0.f, INFINITY); + // Modify ray for depth of field + if (lensRadius > 0.) { + // Sample point on lens + float lensU, lensV; + ConcentricSampleDisk(sample.lensU, sample.lensV, &lensU, &lensV); + lensU *= lensRadius; + lensV *= lensRadius; + + // Compute point on plane of focus + float ft = focalDistance / ray->d.z; + Point Pfocus = (*ray)(ft); + + // Update ray for effect of lens + ray->o = Point(lensU, lensV, 0.f); + ray->d = Normalize(Pfocus - ray->o); + } + + // Compute offset rays for _PerspectiveCamera_ ray differentials + ray->rxOrigin = ray->ryOrigin = ray->o; + ray->rxDirection = Normalize(Vector(Pcamera) + dxCamera); + ray->ryDirection = Normalize(Vector(Pcamera) + dyCamera); + ray->time = Lerp(sample.time, shutterOpen, shutterClose); + CameraToWorld(*ray, ray); + ray->hasDifferentials = true; + return 1.f; +} + + +PerspectiveCamera *CreatePerspectiveCamera(const ParamSet ¶ms, + const AnimatedTransform &cam2world, Film *film) { + // Extract common camera parameters from _ParamSet_ + float shutteropen = params.FindOneFloat("shutteropen", 0.f); + float shutterclose = params.FindOneFloat("shutterclose", 1.f); + if (shutterclose < shutteropen) { + Warning("Shutter close time [%f] < shutter open [%f]. Swapping them.", + shutterclose, shutteropen); + swap(shutterclose, shutteropen); + } + float lensradius = params.FindOneFloat("lensradius", 0.f); + float focaldistance = params.FindOneFloat("focaldistance", 1e30f); + float frame = params.FindOneFloat("frameaspectratio", + float(film->xResolution)/float(film->yResolution)); + float screen[4]; + if (frame > 1.f) { + screen[0] = -frame; + screen[1] = frame; + screen[2] = -1.f; + screen[3] = 1.f; + } + else { + screen[0] = -1.f; + screen[1] = 1.f; + screen[2] = -1.f / frame; + screen[3] = 1.f / frame; + } + int swi; + const float *sw = params.FindFloat("screenwindow", &swi); + if (sw && swi == 4) + memcpy(screen, sw, 4*sizeof(float)); + float fov = params.FindOneFloat("fov", 90.); + float halffov = params.FindOneFloat("halffov", -1.f); + if (halffov > 0.f) + // hack for structure synth, which exports half of the full fov + fov = 2.f * halffov; + return new PerspectiveCamera(cam2world, screen, shutteropen, + shutterclose, lensradius, focaldistance, fov, film); +} diff --git a/cameras/perspective.h b/cameras/perspective.h new file mode 100644 index 0000000..724da8a --- /dev/null +++ b/cameras/perspective.h @@ -0,0 +1,55 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CAMERAS_PERSPECTIVE_H +#define PBRT_CAMERAS_PERSPECTIVE_H + +// cameras/perspective.h* +#include "pbrt.h" +#include "camera.h" +#include "film.h" + +// PerspectiveCamera Declarations +class PerspectiveCamera : public ProjectiveCamera { +public: + // PerspectiveCamera Public Methods + PerspectiveCamera(const AnimatedTransform &cam2world, + const float screenWindow[4], float sopen, float sclose, + float lensr, float focald, float fov, Film *film); + float GenerateRay(const CameraSample &sample, Ray *) const; + float GenerateRayDifferential(const CameraSample &sample, + RayDifferential *ray) const; +private: + // PerspectiveCamera Private Data + Vector dxCamera, dyCamera; +}; + + +PerspectiveCamera *CreatePerspectiveCamera(const ParamSet ¶ms, + const AnimatedTransform &cam2world, Film *film); + +#endif // PBRT_CAMERAS_PERSPECTIVE_H diff --git a/cameras/realistic.cpp b/cameras/realistic.cpp new file mode 100644 index 0000000..7ebd526 --- /dev/null +++ b/cameras/realistic.cpp @@ -0,0 +1,239 @@ +// cameras/realistic.cpp* +#include "stdafx.h" +#include "cameras/realistic.h" +#include "paramset.h" +#include "sampler.h" +#include "montecarlo.h" +#include "filters/box.h" +#include "film/image.h" +#include "samplers/stratified.h" +#include "intersection.h" +#include "renderer.h" + +#include +#include +#include +#include +#include +#include + +#define _USE_MATH_DEFINES + +using namespace std; + + +void DebugPoint(const Point& P) { + cout << "(" << P.x << ", " << P.y << ", " << P.z << ")" << endl; +} + +void DebugVector(const Vector& V) { + cout << "<" << V.x << ", " << V.y << ", " << V.z << ">" << endl; +} + +void DebugRay(const Ray& R) { + cout << "(" << R.o.x << ", " << R.o.y << ", " << R.o.z << ") -> <" << R.d.x << ", " << R.d.y << ", " << R.d.z << ">" << endl; +} + +LensInterface::LensInterface(Transform &c2o, float radius, float n_i, float n_t, float aperture) { + this->c2o = c2o; + this->radius = radius; + this->n_i = n_i; + this->n_t = n_t; + this->aperture = aperture; +} + +LensInterface::~LensInterface() { +} + +bool LensInterface::Intersect(const Ray &r, float *tHit) const { + + Point phit; + // Transform _Ray_ to object space + Ray ray; + (c2o)(r, &ray); + + float thit; + if (radius != 0) { + + // Compute quadratic sphere coefficients + float A = ray.d.x*ray.d.x + ray.d.y*ray.d.y + ray.d.z*ray.d.z; + float B = 2 * (ray.d.x*ray.o.x + ray.d.y*ray.o.y + ray.d.z*ray.o.z); + float C = ray.o.x*ray.o.x + ray.o.y*ray.o.y + + ray.o.z*ray.o.z - radius*radius; + + // Solve quadratic equation for _t_ values + float t0, t1; + if (!Quadratic(A, B, C, &t0, &t1)) + return false; + + // Compute intersection distance along ray + if (t0 > ray.maxt || t1 < ray.mint) + return false; + + if (radius < 0) { + thit = t0; + if (thit < ray.mint) return false; + } + else if (radius > 0){ + thit = t1; + if (thit > ray.maxt) return false; + } + } + else { + thit = (0.f - ray.o.z)/ray.d.z; + if (thit > ray.maxt || thit < ray.mint) return false; + } + phit = ray(thit); + + // Do not include intersections outside the aperature + if (sqrt(pow(phit.x, 2) + pow(phit.y, 2)) > aperture/2.f) + return false; + + // Update _tHit_ for quadric intersection + *tHit = thit; + return true; +} + +bool LensInterface::RefractRay(const Ray &ray, Ray &rayOut) const { + + // Compute ray-sphere intersection + float tHit; + if (!Intersect(ray, &tHit)) return false; + + // Compute refracted ray + Point P = ray(tHit); + Vector I = Normalize(ray.d); + Vector N; + Point center; + (Inverse(c2o))(Point(0.f, 0.f, 0.f), ¢er); + if (radius < 0) N = Normalize(P - center); + else if (radius > 0) N = Normalize(center - P); + else N = Vector(0.f, 0.f, -1.f); + + // Snell's Law + float mu = n_i/n_t; + float coeff = 1 - pow(mu, 2)*(1- pow(Dot(I, N), 2)); + if (coeff < 0) return false; // Total internal reflection + + float gamma = -mu*Dot(I, N) - sqrt(coeff); + Vector T = Normalize(mu*I + gamma*N); + rayOut.o = P; + rayOut.d = T; + + return true; +} + +RealisticCamera *CreateRealisticCamera(const ParamSet ¶ms, + const AnimatedTransform &cam2world, Film *film) { + // Extract common camera parameters from \use{ParamSet} + float hither = params.FindOneFloat("hither", -1); + float yon = params.FindOneFloat("yon", -1); + float shutteropen = params.FindOneFloat("shutteropen", -1); + float shutterclose = params.FindOneFloat("shutterclose", -1); + + // Realistic camera-specific parameters + string specfile = params.FindOneString("specfile", ""); + float filmdistance = params.FindOneFloat("filmdistance", 70.0); // about 70 mm default to film + float fstop = params.FindOneFloat("aperture_diameter", 1.0); + float filmdiag = params.FindOneFloat("filmdiag", 35.0); + assert(hither != -1 && yon != -1 && shutteropen != -1 && + shutterclose != -1 && filmdistance!= -1); + if (specfile == "") { + Severe( "No lens spec file supplied!\n" ); + } + return new RealisticCamera(cam2world, hither, yon, + shutteropen, shutterclose, filmdistance, fstop, + specfile, filmdiag, film); +} + +RealisticCamera::RealisticCamera(const AnimatedTransform &cam2world, + float hither, float yon, + float sopen, float sclose, + float filmdistance, float aperture_diameter_, + const string &specfile, + float filmdiag, + Film *f) + : Camera(cam2world, sopen, sclose, f), + ShutterOpen(sopen), + ShutterClose(sclose), + film(f) +{ + ifstream file(specfile.c_str()); + string line; + float distance = 0.f; + float n_t = 1.f; + + // Build lens vector + while(getline(file, line)) + { + if (line[0] == '#') continue; + + stringstream linestream(line); + float radius; + float thickness; + float n_i; + float aperture; + + linestream >> radius >> thickness >> n_i >> aperture; + if (n_i == 0) n_i = 1.f; + if (radius == 0) aperture = aperture_diameter_; + + Transform c2o = Translate(Vector(0.f, 0.f, distance+radius)); + LensInterface *lens = new LensInterface(c2o, radius, n_i, n_t, aperture); + lenses.push_back(lens); + distance += thickness; + n_t = n_i; + } + + // Set attributes + distance += filmdistance; + filmZ = -distance; + filmDist = filmdistance; + filmDiag = filmdiag; +} + + +RealisticCamera::~RealisticCamera() +{ + +} + + +float RealisticCamera::GenerateRay(const CameraSample &sample, Ray *ray) const +{ + + // Sample film plane + float scale = filmDiag/sqrt(pow(film->xResolution,2) + pow(film->yResolution,2)); + float x = film->xResolution*scale/2 - sample.imageX*scale; + float y = sample.imageY*scale - film->yResolution*scale/2; + Point P = Point(x, y, filmZ); + + // Sample back lens for ray direction + float xp = 2*sample.lensU - 1; + float yp = 2*sample.lensV - 1; + float theta = xp/yp; + float r = yp * lenses[lenses.size()-1]->Aperture()/2.f; + Point Pp = Point(0.f, 0.f, filmZ+filmDist) + r*Vector(cos(theta), sin(theta), 0.f); + + // Generate ray + Ray rayIn = Ray(P, Normalize(Pp - P), 0.f); + Ray rayOut; + + // Trace ray through lenses + for (int i = lenses.size() - 1; i >= 0; i--) { + + LensInterface *lens = lenses[i]; + float thit; + if (!lens->Intersect(rayIn, &thit)) return 0.f; + if (!lens->RefractRay(rayIn, rayOut)) return 0.f; + rayIn = rayOut; + } + + // Transform ray to world space coordinates + (CameraToWorld)(rayOut, ray); + ray->d = Normalize(ray->d); + + // Return weight + float A = M_PI*pow(lenses[lenses.size()-1]->Aperture()/2.f, 2); + return A*pow(Dot(Normalize(Pp - P), Vector(0.f, 0.f, 1.f)), 4) / pow(filmDist, 2); +} diff --git a/cameras/realistic.h b/cameras/realistic.h new file mode 100644 index 0000000..32d600c --- /dev/null +++ b/cameras/realistic.h @@ -0,0 +1,51 @@ +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CAMERAS_REALISTIC_H +#define PBRT_CAMERAS_REALISTIC_H + +#include "pbrt.h" +#include "camera.h" +#include "film.h" + + +class LensInterface { +public: + LensInterface(Transform &c2o, float radius, float n_i, float n_t, float aperature); + ~LensInterface(); + bool Intersect(const Ray &ray, float *tHit) const; + bool RefractRay(const Ray &ray, Ray &rayOut) const; + float Aperture() {return aperture;} +private: + Transform c2o; + float radius; + float n_i, n_t; + float aperture; +}; + +class RealisticCamera : public Camera { +public: + RealisticCamera(const AnimatedTransform &cam2world, + float hither, float yon, float sopen, + float sclose, float filmdistance, float aperture_diameter, + const string &specfile, + float filmdiag, + Film *film); + ~RealisticCamera(); + float GenerateRay(const CameraSample &sample, Ray *) const; + +private: + float ShutterOpen; + float ShutterClose; + Film * film; + vector lenses; + float filmZ; + float filmDist; + float filmDiag; +}; + +RealisticCamera *CreateRealisticCamera(const ParamSet ¶ms, + const AnimatedTransform &cam2world, Film *film); + +#endif diff --git a/core/api.cpp b/core/api.cpp new file mode 100644 index 0000000..c5c2b9a --- /dev/null +++ b/core/api.cpp @@ -0,0 +1,1278 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/api.cpp* +#include "stdafx.h" +#include "api.h" +#include "parallel.h" +#include "paramset.h" +#include "spectrum.h" +#include "scene.h" +#include "renderer.h" +#include "film.h" +#include "volume.h" +#include "probes.h" + +// API Additional Headers +#include "accelerators/bvh.h" +#include "accelerators/grid.h" +#include "accelerators/kdtreeaccel.h" +#include "cameras/environment.h" +#include "cameras/orthographic.h" +#include "cameras/perspective.h" +#include "cameras/realistic.h" +#include "film/image.h" +#include "filters/box.h" +#include "filters/gaussian.h" +#include "filters/mitchell.h" +#include "filters/sinc.h" +#include "filters/triangle.h" +#include "integrators/ambientocclusion.h" +#include "integrators/diffuseprt.h" +#include "integrators/dipolesubsurface.h" +#include "integrators/directlighting.h" +#include "integrators/emission.h" +#include "integrators/glossyprt.h" +#include "integrators/igi.h" +#include "integrators/irradiancecache.h" +#include "integrators/path.h" +#include "integrators/photonmap.h" +#include "integrators/single.h" +#include "integrators/useprobes.h" +#include "integrators/whitted.h" +#include "lights/diffuse.h" +#include "lights/distant.h" +#include "lights/goniometric.h" +#include "lights/infinite.h" +#include "lights/point.h" +#include "lights/projection.h" +#include "lights/spot.h" +#include "materials/glass.h" +#include "materials/kdsubsurface.h" +#include "materials/matte.h" +#include "materials/measured.h" +#include "materials/metal.h" +#include "materials/mirror.h" +#include "materials/mixmat.h" +#include "materials/plastic.h" +#include "materials/substrate.h" +#include "materials/subsurface.h" +#include "materials/shinymetal.h" +#include "materials/translucent.h" +#include "materials/uber.h" +#include "renderers/aggregatetest.h" +#include "renderers/createprobes.h" +#include "renderers/metropolis.h" +#include "renderers/samplerrenderer.h" +#include "renderers/surfacepoints.h" +#include "samplers/adaptive.h" +#include "samplers/bestcandidate.h" +#include "samplers/halton.h" +#include "samplers/lowdiscrepancy.h" +#include "samplers/random.h" +#include "samplers/stratified.h" +#include "shapes/cone.h" +#include "shapes/cylinder.h" +#include "shapes/disk.h" +#include "shapes/heightfield.h" +#include "shapes/hyperboloid.h" +#include "shapes/loopsubdiv.h" +#include "shapes/nurbs.h" +#include "shapes/paraboloid.h" +#include "shapes/sphere.h" +#include "shapes/trianglemesh.h" +#include "textures/bilerp.h" +#include "textures/checkerboard.h" +#include "textures/constant.h" +#include "textures/dots.h" +#include "textures/fbm.h" +#include "textures/imagemap.h" +#include "textures/marble.h" +#include "textures/mix.h" +#include "textures/scale.h" +#include "textures/uv.h" +#include "textures/windy.h" +#include "textures/wrinkled.h" +#include "volumes/exponential.h" +#include "volumes/homogeneous.h" +#include "volumes/volumegrid.h" +#include + #if (_MSC_VER >= 1400) + #include + #define snprintf _snprintf + #endif +using std::map; + +// API Global Variables +Options PbrtOptions; + +// API Local Classes +#define MAX_TRANSFORMS 2 +#define START_TRANSFORM_BITS (1 << 0) +#define END_TRANSFORM_BITS (1 << 1) +#define ALL_TRANSFORMS_BITS ((1 << MAX_TRANSFORMS) - 1) +struct TransformSet { + // TransformSet Public Methods + Transform &operator[](int i) { + Assert(i >= 0 && i < MAX_TRANSFORMS); + return t[i]; + } + const Transform &operator[](int i) const { Assert(i >= 0 && i < MAX_TRANSFORMS); return t[i]; } + friend TransformSet Inverse(const TransformSet &ts) { + TransformSet t2; + for (int i = 0; i < MAX_TRANSFORMS; ++i) + t2.t[i] = Inverse(ts.t[i]); + return t2; + } + bool IsAnimated() const { + for (int i = 0; i < MAX_TRANSFORMS-1; ++i) + if (t[i] != t[i+1]) return true; + return false; + } +private: + Transform t[MAX_TRANSFORMS]; +}; + + +struct RenderOptions { + // RenderOptions Public Methods + RenderOptions(); + Scene *MakeScene(); + Camera *MakeCamera() const; + Renderer *MakeRenderer() const; + + // RenderOptions Public Data + float transformStartTime, transformEndTime; + string FilterName; + ParamSet FilterParams; + string FilmName; + ParamSet FilmParams; + string SamplerName; + ParamSet SamplerParams; + string AcceleratorName; + ParamSet AcceleratorParams; + string RendererName; + string SurfIntegratorName, VolIntegratorName; + ParamSet RendererParams; + ParamSet SurfIntegratorParams, VolIntegratorParams; + string CameraName; + ParamSet CameraParams; + TransformSet CameraToWorld; + vector lights; + vector > primitives; + mutable vector volumeRegions; + map > > instances; + vector > *currentInstance; +}; + + +RenderOptions::RenderOptions() { + // RenderOptions Constructor Implementation + transformStartTime = 0.f; + transformEndTime = 1.f; + FilterName = "box"; + FilmName = "image"; + SamplerName = "lowdiscrepancy"; + AcceleratorName = "bvh"; + RendererName = "sampler"; + SurfIntegratorName = "directlighting"; + VolIntegratorName = "emission"; + CameraName = "perspective"; + currentInstance = NULL; +} + + +struct GraphicsState { + // Graphics State Methods + GraphicsState(); + Reference CreateMaterial(const ParamSet ¶ms); + + // Graphics State + map > > floatTextures; + map > > spectrumTextures; + ParamSet materialParams; + string material; + map > namedMaterials; + string currentNamedMaterial; + ParamSet areaLightParams; + string areaLight; + bool reverseOrientation; +}; + + +GraphicsState::GraphicsState() { + // GraphicsState Constructor Implementation + material = "matte"; + reverseOrientation = false; +} + + +class TransformCache { +public: + // TransformCache Public Methods + void Lookup(const Transform &t, Transform **tCached, + Transform **tCachedInverse) { + map >::iterator iter; + iter = cache.find(t); + if (iter == cache.end()) { + Transform *tr = arena.Alloc(); + *tr = t; + Transform *tinv = arena.Alloc(); + *tinv = Transform(Inverse(t)); + cache[t] = std::make_pair(tr, tinv); + iter = cache.find(t); + PBRT_ALLOCATED_CACHED_TRANSFORM(); + } + else + PBRT_FOUND_CACHED_TRANSFORM(); + if (tCached) *tCached = iter->second.first; + if (tCachedInverse) *tCachedInverse = iter->second.second; + } + void Clear() { + arena.FreeAll(); + cache.erase(cache.begin(), cache.end()); + } +private: + // TransformCache Private Data + map > cache; + MemoryArena arena; +}; + + + +// API Static Data +#define STATE_UNINITIALIZED 0 +#define STATE_OPTIONS_BLOCK 1 +#define STATE_WORLD_BLOCK 2 +static int currentApiState = STATE_UNINITIALIZED; +static TransformSet curTransform; +static int activeTransformBits = ALL_TRANSFORMS_BITS; +static map namedCoordinateSystems; +static RenderOptions *renderOptions = NULL; +static GraphicsState graphicsState; +static vector pushedGraphicsStates; +static vector pushedTransforms; +static vector pushedActiveTransformBits; +static TransformCache transformCache; + +// API Macros +#define VERIFY_INITIALIZED(func) \ +if (currentApiState == STATE_UNINITIALIZED) { \ + Error("pbrtInit() must be before calling \"%s()\". " \ + "Ignoring.", func); \ + return; \ +} else /* swallow trailing semicolon */ +#define VERIFY_OPTIONS(func) \ +VERIFY_INITIALIZED(func); \ +if (currentApiState == STATE_WORLD_BLOCK) { \ + Error("Options cannot be set inside world block; " \ + "\"%s\" not allowed. Ignoring.", func); \ + return; \ +} else /* swallow trailing semicolon */ +#define VERIFY_WORLD(func) \ +VERIFY_INITIALIZED(func); \ +if (currentApiState == STATE_OPTIONS_BLOCK) { \ + Error("Scene description must be inside world block; " \ + "\"%s\" not allowed. Ignoring.", func); \ + return; \ +} else /* swallow trailing semicolon */ +#define FOR_ACTIVE_TRANSFORMS(expr) \ + for (int i = 0; i < MAX_TRANSFORMS; ++i) \ + if (activeTransformBits & (1 << i)) { expr } +#define WARN_IF_ANIMATED_TRANSFORM(func) \ +do { if (curTransform.IsAnimated()) \ + Warning("Animated transformations set; ignoring for \"%s\"" \ + "and using the start transform only", func); \ +} while (false) + +// Object Creation Function Definitions +Reference MakeShape(const string &name, + const Transform *object2world, const Transform *world2object, + bool reverseOrientation, const ParamSet ¶mSet) { + Shape *s = NULL; + + if (name == "sphere") + s = CreateSphereShape(object2world, world2object, + reverseOrientation, paramSet); + // Create remaining _Shape_ types + else if (name == "cylinder") + s = CreateCylinderShape(object2world, world2object, reverseOrientation, + paramSet); + else if (name == "disk") + s = CreateDiskShape(object2world, world2object, reverseOrientation, + paramSet); + else if (name == "cone") + s = CreateConeShape(object2world, world2object, reverseOrientation, + paramSet); + else if (name == "paraboloid") + s = CreateParaboloidShape(object2world, world2object, reverseOrientation, + paramSet); + else if (name == "hyperboloid") + s = CreateHyperboloidShape(object2world, world2object, reverseOrientation, + paramSet); + else if (name == "trianglemesh") + s = CreateTriangleMeshShape(object2world, world2object, reverseOrientation, + paramSet, &graphicsState.floatTextures); + else if (name == "heightfield") + s = CreateHeightfieldShape(object2world, world2object, reverseOrientation, + paramSet); + else if (name == "loopsubdiv") + s = CreateLoopSubdivShape(object2world, world2object, reverseOrientation, + paramSet); + else if (name == "nurbs") + s = CreateNURBSShape(object2world, world2object, reverseOrientation, + paramSet); + else + Warning("Shape \"%s\" unknown.", name.c_str()); + paramSet.ReportUnused(); + return s; +} + + +Reference MakeMaterial(const string &name, + const Transform &mtl2world, + const TextureParams &mp) { + Material *material = NULL; + if (name == "matte") + material = CreateMatteMaterial(mtl2world, mp); + else if (name == "plastic") + material = CreatePlasticMaterial(mtl2world, mp); + else if (name == "translucent") + material = CreateTranslucentMaterial(mtl2world, mp); + else if (name == "glass") + material = CreateGlassMaterial(mtl2world, mp); + else if (name == "mirror") + material = CreateMirrorMaterial(mtl2world, mp); + else if (name == "mix") { + string m1 = mp.FindString("namedmaterial1", ""); + string m2 = mp.FindString("namedmaterial2", ""); + Reference mat1 = graphicsState.namedMaterials[m1]; + Reference mat2 = graphicsState.namedMaterials[m2]; + if (!mat1) { + Error("Named material \"%s\" undefined. Using \"matte\"", + m1.c_str()); + mat1 = MakeMaterial("matte", curTransform[0], mp); + } + if (!mat2) { + Error("Named material \"%s\" undefined. Using \"matte\"", + m2.c_str()); + mat2 = MakeMaterial("matte", curTransform[0], mp); + } + + material = CreateMixMaterial(mtl2world, mp, mat1, mat2); + } + else if (name == "metal") + material = CreateMetalMaterial(mtl2world, mp); + else if (name == "substrate") + material = CreateSubstrateMaterial(mtl2world, mp); + else if (name == "uber") + material = CreateUberMaterial(mtl2world, mp); + else if (name == "subsurface") + material = CreateSubsurfaceMaterial(mtl2world, mp); + else if (name == "kdsubsurface") + material = CreateKdSubsurfaceMaterial(mtl2world, mp); + else if (name == "measured") + material = CreateMeasuredMaterial(mtl2world, mp); + else if (name == "shinymetal") + material = CreateShinyMetalMaterial(mtl2world, mp); + else + Warning("Material \"%s\" unknown.", name.c_str()); + mp.ReportUnused(); + if (!material) Error("Unable to create material \"%s\"", name.c_str()); + return material; +} + + +Reference > MakeFloatTexture(const string &name, + const Transform &tex2world, const TextureParams &tp) { + Texture *tex = NULL; + if (name == "constant") + tex = CreateConstantFloatTexture(tex2world, tp); + else if (name == "scale") + tex = CreateScaleFloatTexture(tex2world, tp); + else if (name == "mix") + tex = CreateMixFloatTexture(tex2world, tp); + else if (name == "bilerp") + tex = CreateBilerpFloatTexture(tex2world, tp); + else if (name == "imagemap") + tex = CreateImageFloatTexture(tex2world, tp); + else if (name == "uv") + tex = CreateUVFloatTexture(tex2world, tp); + else if (name == "checkerboard") + tex = CreateCheckerboardFloatTexture(tex2world, tp); + else if (name == "dots") + tex = CreateDotsFloatTexture(tex2world, tp); + else if (name == "fbm") + tex = CreateFBmFloatTexture(tex2world, tp); + else if (name == "wrinkled") + tex = CreateWrinkledFloatTexture(tex2world, tp); + else if (name == "marble") + tex = CreateMarbleFloatTexture(tex2world, tp); + else if (name == "windy") + tex = CreateWindyFloatTexture(tex2world, tp); + else + Warning("Float texture \"%s\" unknown.", name.c_str()); + tp.ReportUnused(); + return tex; +} + + +Reference > MakeSpectrumTexture(const string &name, + const Transform &tex2world, const TextureParams &tp) { + Texture *tex = NULL; + if (name == "constant") + tex = CreateConstantSpectrumTexture(tex2world, tp); + else if (name == "scale") + tex = CreateScaleSpectrumTexture(tex2world, tp); + else if (name == "mix") + tex = CreateMixSpectrumTexture(tex2world, tp); + else if (name == "bilerp") + tex = CreateBilerpSpectrumTexture(tex2world, tp); + else if (name == "imagemap") + tex = CreateImageSpectrumTexture(tex2world, tp); + else if (name == "uv") + tex = CreateUVSpectrumTexture(tex2world, tp); + else if (name == "checkerboard") + tex = CreateCheckerboardSpectrumTexture(tex2world, tp); + else if (name == "dots") + tex = CreateDotsSpectrumTexture(tex2world, tp); + else if (name == "fbm") + tex = CreateFBmSpectrumTexture(tex2world, tp); + else if (name == "wrinkled") + tex = CreateWrinkledSpectrumTexture(tex2world, tp); + else if (name == "marble") + tex = CreateMarbleSpectrumTexture(tex2world, tp); + else if (name == "windy") + tex = CreateWindySpectrumTexture(tex2world, tp); + else + Warning("Spectrum texture \"%s\" unknown.", name.c_str()); + tp.ReportUnused(); + return tex; +} + + +Light *MakeLight(const string &name, + const Transform &light2world, const ParamSet ¶mSet) { + Light *light = NULL; + if (name == "point") + light = CreatePointLight(light2world, paramSet); + else if (name == "spot") + light = CreateSpotLight(light2world, paramSet); + else if (name == "goniometric") + light = CreateGoniometricLight(light2world, paramSet); + else if (name == "projection") + light = CreateProjectionLight(light2world, paramSet); + else if (name == "distant") + light = CreateDistantLight(light2world, paramSet); + else if (name == "infinite" || name == "exinfinite") + light = CreateInfiniteLight(light2world, paramSet); + else + Warning("Light \"%s\" unknown.", name.c_str()); + paramSet.ReportUnused(); + return light; +} + + +AreaLight *MakeAreaLight(const string &name, + const Transform &light2world, const ParamSet ¶mSet, + const Reference &shape) { + AreaLight *area = NULL; + if (name == "area" || name == "diffuse") + area = CreateDiffuseAreaLight(light2world, paramSet, shape); + else + Warning("Area light \"%s\" unknown.", name.c_str()); + paramSet.ReportUnused(); + return area; +} + + +VolumeRegion *MakeVolumeRegion(const string &name, + const Transform &volume2world, const ParamSet ¶mSet) { + VolumeRegion *vr = NULL; + if (name == "homogeneous") + vr = CreateHomogeneousVolumeDensityRegion(volume2world, paramSet); + else if (name == "volumegrid") + vr = CreateGridVolumeRegion(volume2world, paramSet); + else if (name == "exponential") + vr = CreateExponentialVolumeRegion(volume2world, paramSet); + else + Warning("Volume region \"%s\" unknown.", name.c_str()); + paramSet.ReportUnused(); + return vr; +} + + +SurfaceIntegrator *MakeSurfaceIntegrator(const string &name, + const ParamSet ¶mSet) { + SurfaceIntegrator *si = NULL; + if (name == "whitted") + si = CreateWhittedSurfaceIntegrator(paramSet); + else if (name == "directlighting") + si = CreateDirectLightingIntegrator(paramSet); + else if (name == "path") + si = CreatePathSurfaceIntegrator(paramSet); + else if (name == "photonmap" || name == "exphotonmap") + si = CreatePhotonMapSurfaceIntegrator(paramSet); + else if (name == "irradiancecache") + si = CreateIrradianceCacheIntegrator(paramSet); + else if (name == "igi") + si = CreateIGISurfaceIntegrator(paramSet); + else if (name == "dipolesubsurface") + si = CreateDipoleSubsurfaceIntegrator(paramSet); + else if (name == "ambientocclusion") + si = CreateAmbientOcclusionIntegrator(paramSet); + else if (name == "useprobes") + si = CreateRadianceProbesSurfaceIntegrator(paramSet); + else if (name == "diffuseprt") + si = CreateDiffusePRTIntegratorSurfaceIntegrator(paramSet); + else if (name == "glossyprt") + si = CreateGlossyPRTIntegratorSurfaceIntegrator(paramSet); + else + Warning("Surface integrator \"%s\" unknown.", name.c_str()); + + paramSet.ReportUnused(); + return si; +} + + +VolumeIntegrator *MakeVolumeIntegrator(const string &name, + const ParamSet ¶mSet) { + VolumeIntegrator *vi = NULL; + if (name == "single") + vi = CreateSingleScatteringIntegrator(paramSet); + else if (name == "emission") + vi = CreateEmissionVolumeIntegrator(paramSet); + else + Warning("Volume integrator \"%s\" unknown.", name.c_str()); + paramSet.ReportUnused(); + return vi; +} + + +Primitive *MakeAccelerator(const string &name, + const vector > &prims, + const ParamSet ¶mSet) { + Primitive *accel = NULL; + if (name == "bvh") + accel = CreateBVHAccelerator(prims, paramSet); + else if (name == "grid") + accel = CreateGridAccelerator(prims, paramSet); + else if (name == "kdtree") + accel = CreateKdTreeAccelerator(prims, paramSet); + else + Warning("Accelerator \"%s\" unknown.", name.c_str()); + paramSet.ReportUnused(); + return accel; +} + + +Camera *MakeCamera(const string &name, + const ParamSet ¶mSet, + const TransformSet &cam2worldSet, float transformStart, + float transformEnd, Film *film) { + Camera *camera = NULL; + Assert(MAX_TRANSFORMS == 2); + Transform *cam2world[2]; + transformCache.Lookup(cam2worldSet[0], &cam2world[0], NULL); + transformCache.Lookup(cam2worldSet[1], &cam2world[1], NULL); + AnimatedTransform animatedCam2World(cam2world[0], transformStart, + cam2world[1], transformEnd); + if (name == "perspective") + camera = CreatePerspectiveCamera(paramSet, animatedCam2World, film); + else if (name == "orthographic") + camera = CreateOrthographicCamera(paramSet, animatedCam2World, film); + else if (name == "environment") + camera = CreateEnvironmentCamera(paramSet, animatedCam2World, film); + else if (name == "realistic") + camera = CreateRealisticCamera(paramSet, animatedCam2World, film); + else + Warning("Camera \"%s\" unknown.", name.c_str()); + paramSet.ReportUnused(); + return camera; +} + + +Sampler *MakeSampler(const string &name, + const ParamSet ¶mSet, const Film *film, const Camera *camera) { + Sampler *sampler = NULL; + if (name == "adaptive") + sampler = CreateAdaptiveSampler(paramSet, film, camera); + else if (name == "bestcandidate") + sampler = CreateBestCandidateSampler(paramSet, film, camera); + else if (name == "halton") + sampler = CreateHaltonSampler(paramSet, film, camera); + else if (name == "lowdiscrepancy") + sampler = CreateLowDiscrepancySampler(paramSet, film, camera); + else if (name == "random") + sampler = CreateRandomSampler(paramSet, film, camera); + else if (name == "stratified") + sampler = CreateStratifiedSampler(paramSet, film, camera); + else + Warning("Sampler \"%s\" unknown.", name.c_str()); + paramSet.ReportUnused(); + return sampler; +} + + +Filter *MakeFilter(const string &name, + const ParamSet ¶mSet) { + Filter *filter = NULL; + if (name == "box") + filter = CreateBoxFilter(paramSet); + else if (name == "gaussian") + filter = CreateGaussianFilter(paramSet); + else if (name == "mitchell") + filter = CreateMitchellFilter(paramSet); + else if (name == "sinc") + filter = CreateSincFilter(paramSet); + else if (name == "triangle") + filter = CreateTriangleFilter(paramSet); + else + Warning("Filter \"%s\" unknown.", name.c_str()); + paramSet.ReportUnused(); + return filter; +} + + +Film *MakeFilm(const string &name, + const ParamSet ¶mSet, Filter *filter) { + Film *film = NULL; + if (name == "image") + film = CreateImageFilm(paramSet, filter); + else + Warning("Film \"%s\" unknown.", name.c_str()); + paramSet.ReportUnused(); + return film; +} + + + +// API Function Definitions +void pbrtInit(const Options &opt) { + PbrtOptions = opt; + // API Initialization + if (currentApiState != STATE_UNINITIALIZED) + Error("pbrtInit() has already been called."); + currentApiState = STATE_OPTIONS_BLOCK; + renderOptions = new RenderOptions; + graphicsState = GraphicsState(); + SampledSpectrum::Init(); +} + + +void pbrtCleanup() { + ProbesCleanup(); + // API Cleanup + if (currentApiState == STATE_UNINITIALIZED) + Error("pbrtCleanup() called without pbrtInit()."); + else if (currentApiState == STATE_WORLD_BLOCK) + Error("pbrtCleanup() called while inside world block."); + currentApiState = STATE_UNINITIALIZED; + delete renderOptions; + renderOptions = NULL; +} + + +void pbrtIdentity() { + VERIFY_INITIALIZED("Identity"); + FOR_ACTIVE_TRANSFORMS(curTransform[i] = Transform();) +} + + +void pbrtTranslate(float dx, float dy, float dz) { + VERIFY_INITIALIZED("Translate"); + FOR_ACTIVE_TRANSFORMS(curTransform[i] = + curTransform[i] * Translate(Vector(dx, dy, dz));) +} + + +void pbrtTransform(float tr[16]) { + VERIFY_INITIALIZED("Transform"); + FOR_ACTIVE_TRANSFORMS(curTransform[i] = Transform(Matrix4x4( + tr[0], tr[4], tr[8], tr[12], + tr[1], tr[5], tr[9], tr[13], + tr[2], tr[6], tr[10], tr[14], + tr[3], tr[7], tr[11], tr[15]));) +} + + +void pbrtConcatTransform(float tr[16]) { + VERIFY_INITIALIZED("ConcatTransform"); + FOR_ACTIVE_TRANSFORMS(curTransform[i] = curTransform[i] * Transform( + Matrix4x4(tr[0], tr[4], tr[8], tr[12], + tr[1], tr[5], tr[9], tr[13], + tr[2], tr[6], tr[10], tr[14], + tr[3], tr[7], tr[11], tr[15]));) +} + + +void pbrtRotate(float angle, float dx, float dy, float dz) { + VERIFY_INITIALIZED("Rotate"); + FOR_ACTIVE_TRANSFORMS(curTransform[i] = curTransform[i] * Rotate(angle, Vector(dx, dy, dz));) +} + + +void pbrtScale(float sx, float sy, float sz) { + VERIFY_INITIALIZED("Scale"); + FOR_ACTIVE_TRANSFORMS(curTransform[i] = curTransform[i] * Scale(sx, sy, sz);) +} + + +void pbrtLookAt(float ex, float ey, float ez, float lx, float ly, + float lz, float ux, float uy, float uz) { + VERIFY_INITIALIZED("LookAt"); + FOR_ACTIVE_TRANSFORMS({ Warning("This version of pbrt fixes a bug in the LookAt transformation.\n" + "If your rendered images unexpectedly change, add a \"Scale -1 1 1\"\n" + "to the start of your scene file."); break; }) + FOR_ACTIVE_TRANSFORMS(curTransform[i] = + curTransform[i] * LookAt(Point(ex, ey, ez), Point(lx, ly, lz), Vector(ux, uy, uz));) +} + + +void pbrtCoordinateSystem(const string &name) { + VERIFY_INITIALIZED("CoordinateSystem"); + namedCoordinateSystems[name] = curTransform; +} + + +void pbrtCoordSysTransform(const string &name) { + VERIFY_INITIALIZED("CoordSysTransform"); + if (namedCoordinateSystems.find(name) != + namedCoordinateSystems.end()) + curTransform = namedCoordinateSystems[name]; + else + Warning("Couldn't find named coordinate system \"%s\"", + name.c_str()); +} + + +void pbrtActiveTransformAll() { + activeTransformBits = ALL_TRANSFORMS_BITS; +} + + +void pbrtActiveTransformEndTime() { + activeTransformBits = END_TRANSFORM_BITS; +} + + +void pbrtActiveTransformStartTime() { + activeTransformBits = START_TRANSFORM_BITS; +} + + +void pbrtTransformTimes(float start, float end) { + VERIFY_OPTIONS("TransformTimes"); + renderOptions->transformStartTime = start; + renderOptions->transformEndTime = end; +} + + +void pbrtPixelFilter(const string &name, const ParamSet ¶ms) { + VERIFY_OPTIONS("PixelFilter"); + renderOptions->FilterName = name; + renderOptions->FilterParams = params; +} + + +void pbrtFilm(const string &type, const ParamSet ¶ms) { + VERIFY_OPTIONS("Film"); + renderOptions->FilmParams = params; + renderOptions->FilmName = type; +} + + +void pbrtSampler(const string &name, const ParamSet ¶ms) { + VERIFY_OPTIONS("Sampler"); + renderOptions->SamplerName = name; + renderOptions->SamplerParams = params; +} + + +void pbrtAccelerator(const string &name, const ParamSet ¶ms) { + VERIFY_OPTIONS("Accelerator"); + renderOptions->AcceleratorName = name; + renderOptions->AcceleratorParams = params; +} + + +void pbrtSurfaceIntegrator(const string &name, const ParamSet ¶ms) { + VERIFY_OPTIONS("SurfaceIntegrator"); + renderOptions->SurfIntegratorName = name; + renderOptions->SurfIntegratorParams = params; +} + + +void pbrtVolumeIntegrator(const string &name, const ParamSet ¶ms) { + VERIFY_OPTIONS("VolumeIntegrator"); + renderOptions->VolIntegratorName = name; + renderOptions->VolIntegratorParams = params; +} + + +void pbrtRenderer(const string &name, const ParamSet ¶ms) { + VERIFY_OPTIONS("Renderer"); + renderOptions->RendererName = name; + renderOptions->RendererParams = params; +} + + +void pbrtCamera(const string &name, const ParamSet ¶ms) { + VERIFY_OPTIONS("Camera"); + renderOptions->CameraName = name; + renderOptions->CameraParams = params; + renderOptions->CameraToWorld = Inverse(curTransform); + namedCoordinateSystems["camera"] = renderOptions->CameraToWorld; +} + + +void pbrtWorldBegin() { + VERIFY_OPTIONS("WorldBegin"); + currentApiState = STATE_WORLD_BLOCK; + for (int i = 0; i < MAX_TRANSFORMS; ++i) + curTransform[i] = Transform(); + activeTransformBits = ALL_TRANSFORMS_BITS; + namedCoordinateSystems["world"] = curTransform; +} + + +void pbrtAttributeBegin() { + VERIFY_WORLD("AttributeBegin"); + pushedGraphicsStates.push_back(graphicsState); + pushedTransforms.push_back(curTransform); + pushedActiveTransformBits.push_back(activeTransformBits); +} + + +void pbrtAttributeEnd() { + VERIFY_WORLD("AttributeEnd"); + if (!pushedGraphicsStates.size()) { + Error("Unmatched pbrtAttributeEnd() encountered. " + "Ignoring it."); + return; + } + graphicsState = pushedGraphicsStates.back(); + pushedGraphicsStates.pop_back(); + curTransform = pushedTransforms.back(); + pushedTransforms.pop_back(); + activeTransformBits = pushedActiveTransformBits.back(); + pushedActiveTransformBits.pop_back(); +} + + +void pbrtTransformBegin() { + VERIFY_WORLD("TransformBegin"); + pushedTransforms.push_back(curTransform); + pushedActiveTransformBits.push_back(activeTransformBits); +} + + +void pbrtTransformEnd() { + VERIFY_WORLD("TransformEnd"); + if (!pushedTransforms.size()) { + Error("Unmatched pbrtTransformEnd() encountered. " + "Ignoring it."); + return; + } + curTransform = pushedTransforms.back(); + pushedTransforms.pop_back(); + activeTransformBits = pushedActiveTransformBits.back(); + pushedActiveTransformBits.pop_back(); +} + + +void pbrtTexture(const string &name, const string &type, + const string &texname, const ParamSet ¶ms) { + VERIFY_WORLD("Texture"); + TextureParams tp(params, params, graphicsState.floatTextures, + graphicsState.spectrumTextures); + if (type == "float") { + // Create _float_ texture and store in _floatTextures_ + if (graphicsState.floatTextures.find(name) != + graphicsState.floatTextures.end()) + Info("Texture \"%s\" being redefined", name.c_str()); + WARN_IF_ANIMATED_TRANSFORM("Texture"); + Reference > ft = MakeFloatTexture(texname, + curTransform[0], tp); + if (ft) graphicsState.floatTextures[name] = ft; + } + else if (type == "color" || type == "spectrum") { + // Create _color_ texture and store in _spectrumTextures_ + if (graphicsState.spectrumTextures.find(name) != graphicsState.spectrumTextures.end()) + Info("Texture \"%s\" being redefined", name.c_str()); + WARN_IF_ANIMATED_TRANSFORM("Texture"); + Reference > st = MakeSpectrumTexture(texname, + curTransform[0], tp); + if (st) graphicsState.spectrumTextures[name] = st; + } + else + Error("Texture type \"%s\" unknown.", type.c_str()); +} + + +void pbrtMaterial(const string &name, const ParamSet ¶ms) { + VERIFY_WORLD("Material"); + graphicsState.material = name; + graphicsState.materialParams = params; + graphicsState.currentNamedMaterial = ""; +} + + +void pbrtMakeNamedMaterial(const string &name, + const ParamSet ¶ms) { + VERIFY_WORLD("MakeNamedMaterial"); + // error checking, warning if replace, what to use for transform? + TextureParams mp(params, graphicsState.materialParams, + graphicsState.floatTextures, + graphicsState.spectrumTextures); + string matName = mp.FindString("type"); + WARN_IF_ANIMATED_TRANSFORM("MakeNamedMaterial"); + if (matName == "") Error("No parameter string \"type\" found in MakeNamedMaterial"); + else { + Reference mtl = MakeMaterial(matName, curTransform[0], mp); + if (mtl) graphicsState.namedMaterials[name] = mtl; + } +} + + + +void pbrtNamedMaterial(const string &name) { + VERIFY_WORLD("NamedMaterial"); + graphicsState.currentNamedMaterial = name; +} + + +void pbrtLightSource(const string &name, const ParamSet ¶ms) { + VERIFY_WORLD("LightSource"); + WARN_IF_ANIMATED_TRANSFORM("LightSource"); + Light *lt = MakeLight(name, curTransform[0], params); + if (lt == NULL) + Error("pbrtLightSource: light type \"%s\" unknown.", name.c_str()); + else + renderOptions->lights.push_back(lt); +} + + +void pbrtAreaLightSource(const string &name, + const ParamSet ¶ms) { + VERIFY_WORLD("AreaLightSource"); + graphicsState.areaLight = name; + graphicsState.areaLightParams = params; +} + + +void pbrtShape(const string &name, const ParamSet ¶ms) { + VERIFY_WORLD("Shape"); + Reference prim; + AreaLight *area = NULL; + if (!curTransform.IsAnimated()) { + // Create primitive for static shape + Transform *obj2world, *world2obj; + transformCache.Lookup(curTransform[0], &obj2world, &world2obj); + Reference shape = MakeShape(name, obj2world, world2obj, + graphicsState.reverseOrientation, params); + if (!shape) return; + Reference mtl = graphicsState.CreateMaterial(params); + params.ReportUnused(); + + // Possibly create area light for shape + if (graphicsState.areaLight != "") { + area = MakeAreaLight(graphicsState.areaLight, curTransform[0], + graphicsState.areaLightParams, shape); + } + prim = new GeometricPrimitive(shape, mtl, area); + } else { + // Create primitive for animated shape + + // Create initial _Shape_ for animated shape + if (graphicsState.areaLight != "") + Warning("Ignoring currently set area light when creating " + "animated shape"); + Transform *identity; + transformCache.Lookup(Transform(), &identity, NULL); + Reference shape = MakeShape(name, identity, identity, + graphicsState.reverseOrientation, params); + if (!shape) return; + Reference mtl = graphicsState.CreateMaterial(params); + params.ReportUnused(); + + // Get _animatedWorldToObject_ transform for shape + Assert(MAX_TRANSFORMS == 2); + Transform *world2obj[2]; + transformCache.Lookup(curTransform[0], NULL, &world2obj[0]); + transformCache.Lookup(curTransform[1], NULL, &world2obj[1]); + AnimatedTransform + animatedWorldToObject(world2obj[0], renderOptions->transformStartTime, + world2obj[1], renderOptions->transformEndTime); + Reference baseprim = new GeometricPrimitive(shape, mtl, NULL); + if (!baseprim->CanIntersect()) { + // Refine animated shape and create BVH if more than one shape created + vector > refinedPrimitives; + baseprim->FullyRefine(refinedPrimitives); + if (refinedPrimitives.size() == 0) return; + if (refinedPrimitives.size() > 1) + baseprim = new BVHAccel(refinedPrimitives); + else + baseprim = refinedPrimitives[0]; + } + prim = new TransformedPrimitive(baseprim, animatedWorldToObject); + } + // Add primitive to scene or current instance + if (renderOptions->currentInstance) { + if (area) + Warning("Area lights not supported with object instancing"); + renderOptions->currentInstance->push_back(prim); + } + + else { + renderOptions->primitives.push_back(prim); + if (area != NULL) { + renderOptions->lights.push_back(area); + } + } +} + + +Reference GraphicsState::CreateMaterial(const ParamSet ¶ms) { + TextureParams mp(params, materialParams, + floatTextures, + spectrumTextures); + Reference mtl; + if (currentNamedMaterial != "" && + namedMaterials.find(currentNamedMaterial) != namedMaterials.end()) + mtl = namedMaterials[graphicsState.currentNamedMaterial]; + if (!mtl) + mtl = MakeMaterial(material, curTransform[0], mp); + if (!mtl) + mtl = MakeMaterial("matte", curTransform[0], mp); + if (!mtl) + Severe("Unable to create \"matte\" material?!"); + return mtl; +} + + +void pbrtReverseOrientation() { + VERIFY_WORLD("ReverseOrientation"); + graphicsState.reverseOrientation = + !graphicsState.reverseOrientation; +} + + +void pbrtVolume(const string &name, const ParamSet ¶ms) { + VERIFY_WORLD("Volume"); + WARN_IF_ANIMATED_TRANSFORM("Volume"); + VolumeRegion *vr = MakeVolumeRegion(name, curTransform[0], params); + if (vr) renderOptions->volumeRegions.push_back(vr); +} + + +void pbrtObjectBegin(const string &name) { + VERIFY_WORLD("ObjectBegin"); + pbrtAttributeBegin(); + if (renderOptions->currentInstance) + Error("ObjectBegin called inside of instance definition"); + renderOptions->instances[name] = vector >(); + renderOptions->currentInstance = &renderOptions->instances[name]; +} + + +void pbrtObjectEnd() { + VERIFY_WORLD("ObjectEnd"); + if (!renderOptions->currentInstance) + Error("ObjectEnd called outside of instance definition"); + renderOptions->currentInstance = NULL; + pbrtAttributeEnd(); +} + + +void pbrtObjectInstance(const string &name) { + VERIFY_WORLD("ObjectInstance"); + // Object instance error checking + if (renderOptions->currentInstance) { + Error("ObjectInstance can't be called inside instance definition"); + return; + } + if (renderOptions->instances.find(name) == renderOptions->instances.end()) { + Error("Unable to find instance named \"%s\"", name.c_str()); + return; + } + vector > &in = renderOptions->instances[name]; + if (in.size() == 0) return; + if (in.size() > 1 || !in[0]->CanIntersect()) { + // Refine instance _Primitive_s and create aggregate + Reference accel = + MakeAccelerator(renderOptions->AcceleratorName, + in, renderOptions->AcceleratorParams); + if (!accel) accel = MakeAccelerator("bvh", in, ParamSet()); + if (!accel) Severe("Unable to create \"bvh\" accelerator"); + in.erase(in.begin(), in.end()); + in.push_back(accel); + } + Assert(MAX_TRANSFORMS == 2); + Transform *world2instance[2]; + transformCache.Lookup(curTransform[0], NULL, &world2instance[0]); + transformCache.Lookup(curTransform[1], NULL, &world2instance[1]); + AnimatedTransform animatedWorldToInstance(world2instance[0], + renderOptions->transformStartTime, + world2instance[1], renderOptions->transformEndTime); + Reference prim = + new TransformedPrimitive(in[0], animatedWorldToInstance); + renderOptions->primitives.push_back(prim); +} + + +void pbrtWorldEnd() { + VERIFY_WORLD("WorldEnd"); + // Ensure there are no pushed graphics states + while (pushedGraphicsStates.size()) { + Warning("Missing end to pbrtAttributeBegin()"); + pushedGraphicsStates.pop_back(); + pushedTransforms.pop_back(); + } + while (pushedTransforms.size()) { + Warning("Missing end to pbrtTransformBegin()"); + pushedTransforms.pop_back(); + } + + // Create scene and render + Renderer *renderer = renderOptions->MakeRenderer(); + Scene *scene = renderOptions->MakeScene(); + if (scene && renderer) renderer->Render(scene); + TasksCleanup(); + delete renderer; + delete scene; + + // Clean up after rendering + graphicsState = GraphicsState(); + transformCache.Clear(); + currentApiState = STATE_OPTIONS_BLOCK; + ProbesPrint(stdout); + for (int i = 0; i < MAX_TRANSFORMS; ++i) + curTransform[i] = Transform(); + activeTransformBits = ALL_TRANSFORMS_BITS; + namedCoordinateSystems.erase(namedCoordinateSystems.begin(), + namedCoordinateSystems.end()); + ImageTexture::ClearCache(); + ImageTexture::ClearCache(); +} + + +Scene *RenderOptions::MakeScene() { + // Initialize _volumeRegion_ from volume region(s) + VolumeRegion *volumeRegion; + if (volumeRegions.size() == 0) + volumeRegion = NULL; + else if (volumeRegions.size() == 1) + volumeRegion = volumeRegions[0]; + else + volumeRegion = new AggregateVolume(volumeRegions); + Primitive *accelerator = MakeAccelerator(AcceleratorName, + primitives, AcceleratorParams); + if (!accelerator) + accelerator = MakeAccelerator("bvh", primitives, ParamSet()); + if (!accelerator) + Severe("Unable to create \"bvh\" accelerator."); + Scene *scene = new Scene(accelerator, lights, volumeRegion); + // Erase primitives, lights, and volume regions from _RenderOptions_ + primitives.erase(primitives.begin(), primitives.end()); + lights.erase(lights.begin(), lights.end()); + volumeRegions.erase(volumeRegions.begin(), volumeRegions.end()); + return scene; +} + + +Renderer *RenderOptions::MakeRenderer() const { + Renderer *renderer = NULL; + Camera *camera = MakeCamera(); + if (RendererName == "metropolis") { + renderer = CreateMetropolisRenderer(RendererParams, camera); + RendererParams.ReportUnused(); + // Warn if no light sources are defined + if (lights.size() == 0) + Warning("No light sources defined in scene; " + "possibly rendering a black image."); + } + // Create remaining _Renderer_ types + else if (RendererName == "createprobes") { + // Create surface and volume integrators + SurfaceIntegrator *surfaceIntegrator = MakeSurfaceIntegrator(SurfIntegratorName, + SurfIntegratorParams); + if (!surfaceIntegrator) Severe("Unable to create surface integrator."); + VolumeIntegrator *volumeIntegrator = MakeVolumeIntegrator(VolIntegratorName, + VolIntegratorParams); + if (!volumeIntegrator) Severe("Unable to create volume integrator."); + renderer = CreateRadianceProbesRenderer(camera, surfaceIntegrator, volumeIntegrator, RendererParams); + RendererParams.ReportUnused(); + // Warn if no light sources are defined + if (lights.size() == 0) + Warning("No light sources defined in scene; " + "possibly rendering a black image."); + } + else if (RendererName == "aggregatetest") { + renderer = CreateAggregateTestRenderer(RendererParams, primitives); + RendererParams.ReportUnused(); + } + else if (RendererName == "surfacepoints") { + Point pCamera = camera->CameraToWorld(camera->shutterOpen, Point(0, 0, 0)); + renderer = CreateSurfacePointsRenderer(RendererParams, pCamera, camera->shutterOpen); + RendererParams.ReportUnused(); + } + else { + if (RendererName != "sampler") + Warning("Renderer type \"%s\" unknown. Using \"sampler\".", + RendererName.c_str()); + bool visIds = RendererParams.FindOneBool("visualizeobjectids", false); + RendererParams.ReportUnused(); + Sampler *sampler = MakeSampler(SamplerName, SamplerParams, camera->film, camera); + if (!sampler) Severe("Unable to create sampler."); + // Create surface and volume integrators + SurfaceIntegrator *surfaceIntegrator = MakeSurfaceIntegrator(SurfIntegratorName, + SurfIntegratorParams); + if (!surfaceIntegrator) Severe("Unable to create surface integrator."); + VolumeIntegrator *volumeIntegrator = MakeVolumeIntegrator(VolIntegratorName, + VolIntegratorParams); + if (!volumeIntegrator) Severe("Unable to create volume integrator."); + renderer = new SamplerRenderer(sampler, camera, surfaceIntegrator, + volumeIntegrator, visIds); + // Warn if no light sources are defined + if (lights.size() == 0) + Warning("No light sources defined in scene; " + "possibly rendering a black image."); + } + return renderer; +} + + +Camera *RenderOptions::MakeCamera() const { + Filter *filter = MakeFilter(FilterName, FilterParams); + Film *film = MakeFilm(FilmName, FilmParams, filter); + if (!film) Severe("Unable to create film."); + Camera *camera = ::MakeCamera(CameraName, CameraParams, + CameraToWorld, renderOptions->transformStartTime, + renderOptions->transformEndTime, film); + if (!camera) Severe("Unable to create camera."); + return camera; +} + + diff --git a/core/api.h b/core/api.h new file mode 100644 index 0000000..6391d40 --- /dev/null +++ b/core/api.h @@ -0,0 +1,80 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_API_H +#define PBRT_CORE_API_H + +// core/api.h* +#include "pbrt.h" + +// API Function Declarations +void pbrtInit(const Options &opt); +void pbrtCleanup(); +void pbrtIdentity(); +void pbrtTranslate(float dx, float dy, float dz); +void pbrtRotate(float angle, float ax, float ay, float az); +void pbrtScale(float sx, float sy, float sz); +void pbrtLookAt(float ex, float ey, float ez, + float lx, float ly, float lz, + float ux, float uy, float uz); +void pbrtConcatTransform(float transform[16]); +void pbrtTransform(float transform[16]); +void pbrtCoordinateSystem(const string &); +void pbrtCoordSysTransform(const string &); +void pbrtActiveTransformAll(); +void pbrtActiveTransformEndTime(); +void pbrtActiveTransformStartTime(); +void pbrtTransformTimes(float start, float end); +void pbrtPixelFilter(const string &name, const ParamSet ¶ms); +void pbrtFilm(const string &type, const ParamSet ¶ms); +void pbrtSampler(const string &name, const ParamSet ¶ms); +void pbrtAccelerator(const string &name, const ParamSet ¶ms); +void pbrtSurfaceIntegrator(const string &name, const ParamSet ¶ms); +void pbrtVolumeIntegrator(const string &name, const ParamSet ¶ms); +void pbrtRenderer(const string &name, const ParamSet ¶ms); +void pbrtCamera(const string &, const ParamSet &cameraParams); +void pbrtWorldBegin(); +void pbrtAttributeBegin(); +void pbrtAttributeEnd(); +void pbrtTransformBegin(); +void pbrtTransformEnd(); +void pbrtTexture(const string &name, const string &type, + const string &texname, const ParamSet ¶ms); +void pbrtMaterial(const string &name, const ParamSet ¶ms); +void pbrtMakeNamedMaterial(const string &name, const ParamSet ¶ms); +void pbrtNamedMaterial(const string &name); +void pbrtLightSource(const string &name, const ParamSet ¶ms); +void pbrtAreaLightSource(const string &name, const ParamSet ¶ms); +void pbrtShape(const string &name, const ParamSet ¶ms); +void pbrtReverseOrientation(); +void pbrtVolume(const string &name, const ParamSet ¶ms); +void pbrtObjectBegin(const string &name); +void pbrtObjectEnd(); +void pbrtObjectInstance(const string &name); +void pbrtWorldEnd(); + +#endif // PBRT_CORE_API_H diff --git a/core/camera.cpp b/core/camera.cpp new file mode 100644 index 0000000..f71b991 --- /dev/null +++ b/core/camera.cpp @@ -0,0 +1,96 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/camera.cpp* +#include "stdafx.h" +#include "camera.h" +#include "film.h" +#include "montecarlo.h" +#include "sampler.h" + +// Camera Method Definitions +Camera::~Camera() { + delete film; +} + + +Camera::Camera(const AnimatedTransform &cam2world, + float sopen, float sclose, Film *f) + : CameraToWorld(cam2world), shutterOpen(sopen), shutterClose(sclose) { + film = f; + if (CameraToWorld.HasScale()) + Warning("Scaling detected in world-to-camera transformation!\n" + "The system has numerous assumptions, implicit and explicit,\n" + "that this transform will have no scale factors in it.\n" + "Proceed at your own risk; your image may have errors or\n" + "the system may crash as a result of this."); +} + + +float Camera::GenerateRayDifferential(const CameraSample &sample, + RayDifferential *rd) const { + float wt = GenerateRay(sample, rd); + // Find ray after shifting one pixel in the $x$ direction + CameraSample sshift = sample; + ++(sshift.imageX); + Ray rx; + float wtx = GenerateRay(sshift, &rx); + rd->rxOrigin = rx.o; + rd->rxDirection = rx.d; + + // Find ray after shifting one pixel in the $y$ direction + --(sshift.imageX); + ++(sshift.imageY); + Ray ry; + float wty = GenerateRay(sshift, &ry); + rd->ryOrigin = ry.o; + rd->ryDirection = ry.d; + if (wtx == 0.f || wty == 0.f) return 0.f; + rd->hasDifferentials = true; + return wt; +} + + +ProjectiveCamera::ProjectiveCamera(const AnimatedTransform &cam2world, + const Transform &proj, const float screenWindow[4], float sopen, + float sclose, float lensr, float focald, Film *f) + : Camera(cam2world, sopen, sclose, f) { + // Initialize depth of field parameters + lensRadius = lensr; + focalDistance = focald; + + // Compute projective camera transformations + CameraToScreen = proj; + + // Compute projective camera screen transformations + ScreenToRaster = Scale(float(film->xResolution), + float(film->yResolution), 1.f) * + Scale(1.f / (screenWindow[1] - screenWindow[0]), + 1.f / (screenWindow[2] - screenWindow[3]), 1.f) * + Translate(Vector(-screenWindow[0], -screenWindow[3], 0.f)); + RasterToScreen = Inverse(ScreenToRaster); + RasterToCamera = Inverse(CameraToScreen) * RasterToScreen; +} + + diff --git a/core/camera.h b/core/camera.h new file mode 100644 index 0000000..992cd9e --- /dev/null +++ b/core/camera.h @@ -0,0 +1,69 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_CAMERA_H +#define PBRT_CORE_CAMERA_H + +// core/camera.h* +#include "pbrt.h" +#include "geometry.h" +#include "transform.h" + +// Camera Declarations +class Camera { +public: + // Camera Interface + Camera(const AnimatedTransform &cam2world, float sopen, float sclose, + Film *film); + virtual ~Camera(); + virtual float GenerateRay(const CameraSample &sample, + Ray *ray) const = 0; + virtual float GenerateRayDifferential(const CameraSample &sample, RayDifferential *rd) const; + + // Camera Public Data + AnimatedTransform CameraToWorld; + const float shutterOpen, shutterClose; + Film *film; +}; + + +class ProjectiveCamera : public Camera { +public: + // ProjectiveCamera Public Methods + ProjectiveCamera(const AnimatedTransform &cam2world, + const Transform &proj, const float screenWindow[4], + float sopen, float sclose, float lensr, float focald, Film *film); +protected: + // ProjectiveCamera Protected Data + Transform CameraToScreen, RasterToCamera; + Transform ScreenToRaster, RasterToScreen; + float lensRadius, focalDistance; +}; + + + +#endif // PBRT_CORE_CAMERA_H diff --git a/core/diffgeom.cpp b/core/diffgeom.cpp new file mode 100644 index 0000000..011ea3f --- /dev/null +++ b/core/diffgeom.cpp @@ -0,0 +1,107 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/diffgeom.cpp* +#include "stdafx.h" +#include "diffgeom.h" +#include "transform.h" +#include "shape.h" + +// DifferentialGeometry Method Definitions +DifferentialGeometry::DifferentialGeometry(const Point &P, + const Vector &DPDU, const Vector &DPDV, + const Normal &DNDU, const Normal &DNDV, + float uu, float vv, const Shape *sh) + : p(P), dpdu(DPDU), dpdv(DPDV), dndu(DNDU), dndv(DNDV) { + // Initialize _DifferentialGeometry_ from parameters + nn = Normal(Normalize(Cross(dpdu, dpdv))); + u = uu; + v = vv; + shape = sh; + dudx = dvdx = dudy = dvdy = 0; + + // Adjust normal based on orientation and handedness + if (shape && (shape->ReverseOrientation ^ shape->TransformSwapsHandedness)) + nn *= -1.f; +} + + +void DifferentialGeometry::ComputeDifferentials( + const RayDifferential &ray) const { + if (ray.hasDifferentials) { + // Estimate screen space change in $\pt{}$ and $(u,v)$ + + // Compute auxiliary intersection points with plane + float d = -Dot(nn, Vector(p.x, p.y, p.z)); + Vector rxv(ray.rxOrigin.x, ray.rxOrigin.y, ray.rxOrigin.z); + float tx = -(Dot(nn, rxv) + d) / Dot(nn, ray.rxDirection); + if (isnan(tx)) goto fail; + Point px = ray.rxOrigin + tx * ray.rxDirection; + Vector ryv(ray.ryOrigin.x, ray.ryOrigin.y, ray.ryOrigin.z); + float ty = -(Dot(nn, ryv) + d) / Dot(nn, ray.ryDirection); + if (isnan(ty)) goto fail; + Point py = ray.ryOrigin + ty * ray.ryDirection; + dpdx = px - p; + dpdy = py - p; + + // Compute $(u,v)$ offsets at auxiliary points + + // Initialize _A_, _Bx_, and _By_ matrices for offset computation + float A[2][2], Bx[2], By[2]; + int axes[2]; + if (fabsf(nn.x) > fabsf(nn.y) && fabsf(nn.x) > fabsf(nn.z)) { + axes[0] = 1; axes[1] = 2; + } + else if (fabsf(nn.y) > fabsf(nn.z)) { + axes[0] = 0; axes[1] = 2; + } + else { + axes[0] = 0; axes[1] = 1; + } + + // Initialize matrices for chosen projection plane + A[0][0] = dpdu[axes[0]]; + A[0][1] = dpdv[axes[0]]; + A[1][0] = dpdu[axes[1]]; + A[1][1] = dpdv[axes[1]]; + Bx[0] = px[axes[0]] - p[axes[0]]; + Bx[1] = px[axes[1]] - p[axes[1]]; + By[0] = py[axes[0]] - p[axes[0]]; + By[1] = py[axes[1]] - p[axes[1]]; + if (!SolveLinearSystem2x2(A, Bx, &dudx, &dvdx)) { + dudx = 0.; dvdx = 0.; + } + if (!SolveLinearSystem2x2(A, By, &dudy, &dvdy)) { + dudy = 0.; dvdy = 0.; + } + } + else { +fail: + dudx = dvdx = 0.; + dudy = dvdy = 0.; + dpdx = dpdy = Vector(0,0,0); + } +} + + diff --git a/core/diffgeom.h b/core/diffgeom.h new file mode 100644 index 0000000..01ed287 --- /dev/null +++ b/core/diffgeom.h @@ -0,0 +1,61 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_DIFFGEOM_H +#define PBRT_CORE_DIFFGEOM_H + +// core/diffgeom.h* +#include "pbrt.h" +#include "geometry.h" + +// DifferentialGeometry Declarations +struct DifferentialGeometry { + DifferentialGeometry() { + u = v = dudx = dvdx = dudy = dvdy = 0.; + shape = NULL; + } + // DifferentialGeometry Public Methods + DifferentialGeometry(const Point &P, const Vector &DPDU, + const Vector &DPDV, const Normal &DNDU, + const Normal &DNDV, float uu, float vv, + const Shape *sh); + void ComputeDifferentials(const RayDifferential &r) const; + + // DifferentialGeometry Public Data + Point p; + Normal nn; + float u, v; + const Shape *shape; + Vector dpdu, dpdv; + Normal dndu, dndv; + mutable Vector dpdx, dpdy; + mutable float dudx, dvdx, dudy, dvdy; +}; + + + +#endif // PBRT_CORE_DIFFGEOM_H diff --git a/core/dtrace.d b/core/dtrace.d new file mode 100644 index 0000000..fde54b2 --- /dev/null +++ b/core/dtrace.d @@ -0,0 +1,212 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +provider PBRT { +probe started_ray_intersection(const struct Ray *); +probe finished_ray_intersection(const struct Ray *, + const struct Intersection *, int hit); +probe started_ray_intersectionp(const struct Ray *); +probe finished_ray_intersectionp(const struct Ray *, int hit); +probe atomic_memory_op(); + +probe started_parsing(); +probe finished_parsing(); +probe allocated_cached_transform(); +probe found_cached_transform(); + +probe started_preprocessing(); +probe finished_preprocessing(); + +probe started_task(const struct Task *); +probe finished_task(const struct Task *); + +probe started_generating_camera_ray(const struct CameraSample *); +probe finished_generating_camera_ray(const struct CameraSample *, const struct RayDifferential *, float weight); + +probe sample_outside_image_extent(const struct CameraSample *); + +probe started_rendering(); +probe finished_rendering(); +probe started_rendertask(int num); +probe finished_rendertask(int num); +probe started_camera_ray_integration(const struct RayDifferential *, const struct Sample *); +probe finished_camera_ray_integration(const struct RayDifferential *, const struct Sample *, const void *L); + +probe started_specular_reflection_ray(const struct RayDifferential *); +probe finished_specular_reflection_ray(const struct RayDifferential *); +probe started_specular_refraction_ray(const struct RayDifferential *); +probe finished_specular_refraction_ray(const struct RayDifferential *); + +probe started_adding_image_sample(const struct Sample *, const struct RayDifferential *, const void *L, const void *T); +probe finished_adding_image_sample(); +probe created_shape(struct Shape *); +probe created_triangle(struct Triangle *); + +probe ray_triangle_intersection_test(const struct Ray *, const struct Triangle *); +probe ray_triangle_intersection_hit(const struct Ray *, float t); +probe ray_triangle_intersectionp_test(const struct Ray *, const struct Triangle *); +probe ray_triangle_intersectionp_hit(const struct Ray *, float t); + +probe started_trilinear_texture_lookup(float s, float t); +probe finished_trilinear_texture_lookup(); +probe started_ewa_texture_lookup(float s, float t); +probe finished_ewa_texture_lookup(); + +probe loaded_image_map(const char *filename, int width, int height, int elementSize, void *mipPtr); +probe mipmap_trilinear_filter(void *mipPtr, float s, float t, float width, float level, int nLevels); +probe mipmap_ewa_filter(void *mipPtr, float s, float t, float ds0, float ds1, float dt0, float dt1, float minorLength, float majorLength, float level, int nLevels); +probe accessed_texel(void *mipPtr, int level, int s, int t); + +probe started_bsdf_shading(const struct Ray *); +probe finished_bsdf_shading(const struct Ray *, const struct BSDF *); +probe started_bssrdf_shading(const struct Ray *); +probe finished_bssrdf_shading(const struct Ray *, const struct BSSRDF *); + +probe grid_started_construction(struct GridAccel *, unsigned int numPrimitives); +probe grid_finished_construction(struct GridAccel *); +probe grid_voxelized_primitive(const int *vmin, const int *vmax); +probe grid_bounds_and_resolution(const struct BBox *bbox, const int *nvoxels); +probe grid_intersection_test(const struct GridAccel *, const struct Ray *); +probe grid_intersectionp_test(const struct GridAccel *, const struct Ray *); +probe grid_ray_missed_bounds(); +probe grid_ray_traversed_voxel(const int v[3], int nprims); +probe grid_ray_primitive_intersection_test(const struct Primitive *); +probe grid_ray_primitive_intersectionp_test(const struct Primitive *); +probe grid_ray_primitive_hit(const struct Primitive *); + +probe kdtree_started_construction(struct KdTreeAccel *, int nprims); +probe kdtree_finished_construction(struct KdTreeAccel *); +probe kdtree_created_leaf(int nprims, int depth); +probe kdtree_created_interior_node(int axis, float split); +probe kdtree_intersection_test(const struct KdTreeAccel *, const struct Ray *); +probe kdtree_intersectionp_test(const struct KdTreeAccel *, const struct Ray *); +probe kdtree_ray_missed_bounds(); +probe kdtree_intersection_traversed_interior_node(const struct KdAccelNode *); +probe kdtree_intersection_traversed_leaf_node(const struct KdAccelNode *, int nprims); +probe kdtree_intersectionp_traversed_interior_node(const struct KdAccelNode *); +probe kdtree_intersectionp_traversed_leaf_node(const struct KdAccelNode *, int nprims); +probe kdtree_intersection_hit(const struct Primitive *); +probe kdtree_intersectionp_missed(); +probe kdtree_intersectionp_hit(const struct Primitive *); +probe kdtree_intersection_finished(); +probe kdtree_intersectionp_primitive_test(const struct Primitive *); +probe kdtree_intersection_primitive_test(const struct Primitive *); + +probe bvh_started_construction(struct BVHAccel *, int nprims); +probe bvh_finished_construction(struct BVHAccel *); +probe bvh_intersection_started(const struct BVHAccel *, const struct Ray *); +probe bvh_intersection_traversed_interior_node(const struct LinearBVHNode *); +probe bvh_intersection_traversed_leaf_node(const struct LinearBVHNode *); +probe bvh_intersection_primitive_test(const struct Primitive *); +probe bvh_intersection_primitive_hit(const struct Primitive *); +probe bvh_intersection_primitive_missed(const struct Primitive *); +probe bvh_intersection_finished(); +probe bvh_intersectionp_started(const struct BVHAccel *, const struct Ray *); +probe bvh_intersectionp_traversed_interior_node(const struct LinearBVHNode *); +probe bvh_intersectionp_traversed_leaf_node(const struct LinearBVHNode *); +probe bvh_intersectionp_primitive_test(const struct Primitive *); +probe bvh_intersectionp_primitive_hit(const struct Primitive *); +probe bvh_intersectionp_primitive_missed(const struct Primitive *); +probe bvh_intersectionp_finished(); + +probe supersample_pixel_yes(int xpos, int ypos); +probe supersample_pixel_no(int xpos, int ypos); + +probe irradiance_cache_started_ray(const struct RayDifferential *); +probe irradiance_cache_finished_ray(const struct RayDifferential *, float dist, const void *L); +probe irradiance_cache_added_new_sample(const struct Point *, const struct Normal *, float maxDist, const void *E, const struct Vector *primaryDir, float pixelSpacing); +probe irradiance_cache_started_interpolation(const struct Point *p, const struct Normal *n); +probe irradiance_cache_finished_interpolation(const struct Point *p, const struct Normal *n, int successful, int nfound); +probe irradiance_cache_checked_sample(const struct IrradianceSample *, float perr, float nerr); +probe irradiance_cache_started_computing_irradiance(const struct Point *P, const struct Normal *N); +probe irradiance_cache_finished_computing_irradiance(const struct Point *P, const struct Normal *N); + +probe photon_map_started_ray_path(const struct RayDifferential *, const void *alpha); +probe photon_map_finished_ray_path(const struct RayDifferential *, const void *alpha); +probe photon_map_deposited_direct_photon(const struct DifferentialGeometry *, const void *alpha, const struct Vector *wo); +probe photon_map_deposited_indirect_photon(const struct DifferentialGeometry *, const void *alpha, const struct Vector *wo); +probe photon_map_deposited_caustic_photon(const struct DifferentialGeometry *, const void *alpha, const struct Vector *wo); +probe photon_map_started_gather_ray(const struct RayDifferential *); +probe photon_map_finished_gather_ray(const struct RayDifferential *); +probe photon_map_started_lookup(const struct DifferentialGeometry *); +probe photon_map_finished_lookup(const struct DifferentialGeometry *, int nFound, int nWanted, const void *L); + +probe subsurface_started_rays_for_points(); +probe subsurface_finished_rays_for_points(int totalRaysTraced, int numPointsAdded); +probe subsurface_added_point_to_octree(const struct SurfacePoint *, float minSampleDist); +probe subsurface_computed_irradiance_at_point(const struct SurfacePoint *, const void *E); +probe subsurface_added_interior_contribution(const struct SubsurfaceOctreeNode *node); +probe subsurface_added_point_contribution(const struct IrradiancePoint *node); +probe subsurface_started_computing_irradiance_values(); +probe subsurface_finished_computing_irradiance_values(); +probe subsurface_started_octree_lookup(const struct Point *); +probe subsurface_finished_octree_lookup(); + +probe mlt_accepted_mutation(float a, const struct MLTSample *current, const struct MLTSample *proposed); +probe mlt_rejected_mutation(float a, const struct MLTSample *current, const struct MLTSample *proposed); +probe mlt_started_mlt_task(struct MLTTask *); +probe mlt_finished_mlt_task(struct MLTTask *); +probe mlt_started_rendering(); +probe mlt_finished_rendering(); +probe mlt_started_directlighting(); +probe mlt_finished_directlighting(); +probe mlt_started_bootstrapping(int count); +probe mlt_finished_bootstrapping(float b); +probe mlt_started_mutation(); +probe mlt_finished_mutation(); +probe mlt_started_sample_splat(); +probe mlt_finished_sample_splat(); +probe mlt_started_generate_path(); +probe mlt_finished_generate_path(); +probe mlt_started_lpath(); +probe mlt_finished_lpath(); +probe mlt_started_lbidir(); +probe mlt_finished_lbidir(); +probe mlt_started_task_init(); +probe mlt_finished_task_init(); +probe mlt_started_display_update(); +probe mlt_finished_display_update(); +probe mlt_started_sample_light_for_bidir(); +probe mlt_finished_sample_light_for_bidir(); +probe mlt_started_estimate_direct(); +probe mlt_finished_estimate_direct(); + +probe rng_started_random_float(); +probe rng_finished_random_float(); +probe rng_finished_tablegen(); +probe rng_started_tablegen(); +probe started_bsdf_eval(); +probe finished_bsdf_eval(); +probe started_bsdf_sample(); +probe finished_bsdf_sample(); +probe started_bsdf_pdf(); +probe finished_bsdf_pdf(); +probe area_light_started_sample(); +probe area_light_finished_sample(); +probe infinite_light_started_sample(); +probe infinite_light_finished_sample(); +probe infinite_light_started_pdf(); +probe infinite_light_finished_pdf(); +}; + + diff --git a/core/error.cpp b/core/error.cpp new file mode 100644 index 0000000..aba3ecc --- /dev/null +++ b/core/error.cpp @@ -0,0 +1,137 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/error.cpp* +#include "stdafx.h" +#include "progressreporter.h" + +// Error Reporting Includes +#include + +// Error Reporting Definitions +#define PBRT_ERROR_IGNORE 0 +#define PBRT_ERROR_CONTINUE 1 +#define PBRT_ERROR_ABORT 2 + +const char *findWordEnd(const char *buf) { + while (*buf != '\0' && !isspace(*buf)) + ++buf; + return buf; +} + +// Error Reporting Functions +static void processError(const char *format, va_list args, + const char *message, int disposition) { +#if !defined(PBRT_IS_WINDOWS) + char *errorBuf; + if (vasprintf(&errorBuf, format, args) == -1) { + fprintf(stderr, "vasprintf() unable to allocate memory!\n"); + abort(); + } +#else + char errorBuf[2048]; + vsnprintf_s(errorBuf, sizeof(errorBuf), _TRUNCATE, format, args); +#endif + // Report error + if (disposition == PBRT_ERROR_IGNORE) + return; + else { + // PBRT_ERROR_CONTINUE, PBRT_ERROR_ABORT + // Print formatted error message + extern int line_num; + int column = 0; + int width = max(20, TerminalWidth() - 2); + if (line_num != 0) { + extern string current_file; + column += fprintf(stderr, "%s(%d): ", current_file.c_str(), line_num); + } + fputs(message, stderr); + fputs(": ", stderr); + column += strlen(message) + 2; + const char *msgPos = errorBuf; + while (true) { + while (*msgPos != '\0' && isspace(*msgPos)) + ++msgPos; + if (*msgPos == '\0') + break; + + const char *wordEnd = findWordEnd(msgPos); + if (column + wordEnd - msgPos > width) + column = fprintf(stderr, "\n "); + while (msgPos != wordEnd) { + fputc(*msgPos++, stderr); + ++column; + } + fputc(' ', stderr); + ++column; + } + fputs("\n", stderr); + } + if (disposition == PBRT_ERROR_ABORT) { +#if defined(PBRT_IS_WINDOWS) + __debugbreak(); +#else + abort(); +#endif + } +#if !defined(PBRT_IS_WINDOWS) + free(errorBuf); +#endif +} + + +void Info(const char *format, ...) { + if (!PbrtOptions.verbose || PbrtOptions.quiet) return; + va_list args; + va_start(args, format); + processError(format, args, "Notice", PBRT_ERROR_CONTINUE); + va_end(args); +} + + +void Warning(const char *format, ...) { + if (PbrtOptions.quiet) return; + va_list args; + va_start(args, format); + processError(format, args, "Warning", PBRT_ERROR_CONTINUE); + va_end(args); +} + + +void Error(const char *format, ...) { + va_list args; + va_start(args, format); + processError(format, args, "Error", PBRT_ERROR_CONTINUE); + va_end(args); +} + + +void Severe(const char *format, ...) { + va_list args; + va_start(args, format); + processError(format, args, "Fatal Error", PBRT_ERROR_ABORT); + va_end(args); +} + + diff --git a/core/error.h b/core/error.h new file mode 100644 index 0000000..4b1dd87 --- /dev/null +++ b/core/error.h @@ -0,0 +1,47 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_ERROR_H +#define PBRT_CORE_ERROR_H + +// core/error.h* + +// Error Reporting Declarations + +// Setup printf format +#ifdef __GNUG__ +#define PRINTF_FUNC __attribute__ \ + ((__format__ (__printf__, 1, 2))) +#else +#define PRINTF_FUNC +#endif // __GNUG__ +void Info(const char *, ...) PRINTF_FUNC; +void Warning(const char *, ...) PRINTF_FUNC; +void Error(const char *, ...) PRINTF_FUNC; +void Severe(const char *, ...) PRINTF_FUNC; + +#endif // PBRT_CORE_ERROR_H diff --git a/core/fileutil.cpp b/core/fileutil.cpp new file mode 100644 index 0000000..a1e7c32 --- /dev/null +++ b/core/fileutil.cpp @@ -0,0 +1,133 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#include "stdafx.h" +#include "fileutil.h" +#include +#include +#ifndef PBRT_IS_WINDOWS +#include +#endif + +static string searchDirectory; + +#ifdef PBRT_IS_WINDOWS +bool IsAbsolutePath(const string &filename) +{ + if (filename.size() == 0) + return false; + return (filename[0] == '\\' || filename[0] == '/' || filename.find(':') != string::npos); +} + + +string AbsolutePath(const string &filename) +{ + char full[_MAX_PATH]; + if (_fullpath(full, filename.c_str(), _MAX_PATH) != NULL) + return std::string(full); + else + return filename; +} + + +string ResolveFilename(const string &filename) +{ + if (searchDirectory.size() == 0 || filename.size() == 0) + return filename; + else if (IsAbsolutePath(filename)) + return filename; + + char searchDirectoryEnd = searchDirectory[searchDirectory.size() - 1]; + if (searchDirectoryEnd == '\\' || searchDirectoryEnd == '/') + return searchDirectory + filename; + else + return searchDirectory + "\\" + filename; +} + + +string DirectoryContaining(const string &filename) +{ + // This code isn't tested but I believe it should work. Might need to add + // some const_casts to make it compile though. + char drive[_MAX_DRIVE]; + char dir[_MAX_DIR]; + char ext[_MAX_EXT]; + + errno_t err = _splitpath_s( filename.c_str(), + drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, ext, _MAX_EXT ); + if (err == 0) { + char fullDir[_MAX_PATH]; + err = _makepath_s(fullDir, _MAX_PATH, drive, dir, NULL, NULL); + if (err == 0) + return std::string(fullDir); + } + return filename; +} + +#else + +bool IsAbsolutePath(const string &filename) +{ + return (filename.size() > 0) && filename[0] == '/'; +} + + +string AbsolutePath(const string &filename) +{ + char full[PATH_MAX]; + if (realpath(filename.c_str(), full) != NULL) + return std::string(full); + else + return filename; +} + + +string ResolveFilename(const string &filename) +{ + if (searchDirectory.size() == 0 || filename.size() == 0) + return filename; + else if (IsAbsolutePath(filename)) + return filename; + else if (searchDirectory[searchDirectory.size() - 1] == '/') + return searchDirectory + filename; + else + return searchDirectory + "/" + filename; +} + + +string DirectoryContaining(const string &filename) +{ + // dirname requires a char*, not a const char*, hence the const_cast. It + // doesn't modify it though (according to the docs on OS X). + string result = dirname(const_cast(filename.c_str())); + return result; +} + +#endif + +void SetSearchDirectory(const string &dirname) { + searchDirectory = dirname; +} + + + diff --git a/core/fileutil.h b/core/fileutil.h new file mode 100644 index 0000000..8cf1bc3 --- /dev/null +++ b/core/fileutil.h @@ -0,0 +1,43 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_FILEUTIL_H +#define PBRT_CORE_FILEUTIL_H + +#include +using std::string; + +// Platform independent filename-handling functions. + +bool IsAbsolutePath(const string &filename); +string AbsolutePath(const string &filename); +string ResolveFilename(const string &filename); +string DirectoryContaining(const string &filename); +void SetSearchDirectory(const string &dirname); + +#endif // PBRT_CORE_FILEUTIL_H + diff --git a/core/film.cpp b/core/film.cpp new file mode 100644 index 0000000..a02f1de --- /dev/null +++ b/core/film.cpp @@ -0,0 +1,39 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/film.cpp* +#include "stdafx.h" +#include "film.h" +#include "paramset.h" + +// Film Method Definitions +Film::~Film() { +} + + +void Film::UpdateDisplay(int x0, int y0, int x1, int y1, + float splatScale) { +} + + diff --git a/core/film.h b/core/film.h new file mode 100644 index 0000000..c99bec4 --- /dev/null +++ b/core/film.h @@ -0,0 +1,57 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_FILM_H +#define PBRT_CORE_FILM_H + +// core/film.h* +#include "pbrt.h" + +// Film Declarations +class Film { +public: + // Film Interface + Film(int xres, int yres) + : xResolution(xres), yResolution(yres) { } + virtual ~Film(); + virtual void AddSample(const CameraSample &sample, + const Spectrum &L) = 0; + virtual void Splat(const CameraSample &sample, const Spectrum &L) = 0; + virtual void GetSampleExtent(int *xstart, int *xend, + int *ystart, int *yend) const = 0; + virtual void GetPixelExtent(int *xstart, int *xend, + int *ystart, int *yend) const = 0; + virtual void UpdateDisplay(int x0, int y0, int x1, int y1, float splatScale = 1.f); + virtual void WriteImage(float splatScale = 1.f) = 0; + + // Film Public Data + const int xResolution, yResolution; +}; + + + +#endif // PBRT_CORE_FILM_H diff --git a/core/filter.cpp b/core/filter.cpp new file mode 100644 index 0000000..415584c --- /dev/null +++ b/core/filter.cpp @@ -0,0 +1,33 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/filter.cpp* +#include "stdafx.h" +#include "filter.h" + +// Filter Method Definitions +Filter::~Filter() { +} + + diff --git a/core/filter.h b/core/filter.h new file mode 100644 index 0000000..6a8f027 --- /dev/null +++ b/core/filter.h @@ -0,0 +1,51 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_FILTER_H +#define PBRT_CORE_FILTER_H + +// core/filter.h* +#include "pbrt.h" + +// Filter Declarations +class Filter { +public: + // Filter Interface + virtual ~Filter(); + Filter(float xw, float yw) + : xWidth(xw), yWidth(yw), invXWidth(1.f/xw), invYWidth(1.f/yw) { + } + virtual float Evaluate(float x, float y) const = 0; + + // Filter Public Data + const float xWidth, yWidth; + const float invXWidth, invYWidth; +}; + + + +#endif // PBRT_CORE_FILTER_H diff --git a/core/floatfile.cpp b/core/floatfile.cpp new file mode 100644 index 0000000..500ed78 --- /dev/null +++ b/core/floatfile.cpp @@ -0,0 +1,76 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/floatfile.cpp* +#include "stdafx.h" +#include "floatfile.h" +#include +#include + +bool ReadFloatFile(const char *filename, vector *values) { + FILE *f = fopen(filename, "r"); + if (!f) { + Error("Unable to open file \"%s\"", filename); + return false; + } + + int c; + bool inNumber = false; + char curNumber[32]; + int curNumberPos = 0; + int lineNumber = 1; + while ((c = getc(f)) != EOF) { + if (c == '\n') ++lineNumber; + if (inNumber) { + if (isdigit(c) || c == '.' || c == 'e' || c == '-' || c == '+') + curNumber[curNumberPos++] = c; + else { + curNumber[curNumberPos++] = '\0'; + values->push_back(atof(curNumber)); + Assert(curNumberPos < (int)sizeof(curNumber)); + inNumber = false; + curNumberPos = 0; + } + } + else { + if (isdigit(c) || c == '.' || c == '-' || c == '+') { + inNumber = true; + curNumber[curNumberPos++] = c; + } + else if (c == '#') { + while ((c = getc(f)) != '\n' && c != EOF) + ; + ++lineNumber; + } + else if (!isspace(c)) { + Warning("Unexpected text found at line %d of float file \"%s\"", + lineNumber, filename); + } + } + } + fclose(f); + return true; +} + + diff --git a/core/floatfile.h b/core/floatfile.h new file mode 100644 index 0000000..4966c82 --- /dev/null +++ b/core/floatfile.h @@ -0,0 +1,35 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_FLOATFILE_H +#define PBRT_CORE_FLOATFILE_H + +// core/floatfile.h* +#include "pbrt.h" +bool ReadFloatFile(const char *filename, vector *values); + +#endif // PBRT_CORE_FLOATFILE_H diff --git a/core/geometry.cpp b/core/geometry.cpp new file mode 100644 index 0000000..1c0f650 --- /dev/null +++ b/core/geometry.cpp @@ -0,0 +1,80 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/geometry.cpp* +#include "stdafx.h" +#include "geometry.h" + +// BBox Method Definitions +BBox Union(const BBox &b, const Point &p) { + BBox ret = b; + ret.pMin.x = min(b.pMin.x, p.x); + ret.pMin.y = min(b.pMin.y, p.y); + ret.pMin.z = min(b.pMin.z, p.z); + ret.pMax.x = max(b.pMax.x, p.x); + ret.pMax.y = max(b.pMax.y, p.y); + ret.pMax.z = max(b.pMax.z, p.z); + return ret; +} + + +BBox Union(const BBox &b, const BBox &b2) { + BBox ret; + ret.pMin.x = min(b.pMin.x, b2.pMin.x); + ret.pMin.y = min(b.pMin.y, b2.pMin.y); + ret.pMin.z = min(b.pMin.z, b2.pMin.z); + ret.pMax.x = max(b.pMax.x, b2.pMax.x); + ret.pMax.y = max(b.pMax.y, b2.pMax.y); + ret.pMax.z = max(b.pMax.z, b2.pMax.z); + return ret; +} + + +void BBox::BoundingSphere(Point *c, float *rad) const { + *c = .5f * pMin + .5f * pMax; + *rad = Inside(*c) ? Distance(*c, pMax) : 0.f; +} + + +bool BBox::IntersectP(const Ray &ray, float *hitt0, + float *hitt1) const { + float t0 = ray.mint, t1 = ray.maxt; + for (int i = 0; i < 3; ++i) { + // Update interval for _i_th bounding box slab + float invRayDir = 1.f / ray.d[i]; + float tNear = (pMin[i] - ray.o[i]) * invRayDir; + float tFar = (pMax[i] - ray.o[i]) * invRayDir; + + // Update parametric interval from slab intersection $t$s + if (tNear > tFar) swap(tNear, tFar); + t0 = tNear > t0 ? tNear : t0; + t1 = tFar < t1 ? tFar : t1; + if (t0 > t1) return false; + } + if (hitt0) *hitt0 = t0; + if (hitt1) *hitt1 = t1; + return true; +} + + diff --git a/core/geometry.h b/core/geometry.h new file mode 100644 index 0000000..e78b4c1 --- /dev/null +++ b/core/geometry.h @@ -0,0 +1,644 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_GEOMETRY_H +#define PBRT_CORE_GEOMETRY_H + +// core/geometry.h* +#include "pbrt.h" + +// Geometry Declarations +class Vector { +public: + // Vector Public Methods + Vector() { x = y = z = 0.f; } + Vector(float xx, float yy, float zz) + : x(xx), y(yy), z(zz) { + Assert(!HasNaNs()); + } + bool HasNaNs() const { return isnan(x) || isnan(y) || isnan(z); } + explicit Vector(const Point &p); +#ifndef NDEBUG + // The default versions of these are fine for release builds; for debug + // we define them so that we can add the Assert checks. + Vector(const Vector &v) { + Assert(!v.HasNaNs()); + x = v.x; y = v.y; z = v.z; + } + + Vector &operator=(const Vector &v) { + Assert(!v.HasNaNs()); + x = v.x; y = v.y; z = v.z; + return *this; + } +#endif // !NDEBUG + Vector operator+(const Vector &v) const { + Assert(!v.HasNaNs()); + return Vector(x + v.x, y + v.y, z + v.z); + } + + Vector& operator+=(const Vector &v) { + Assert(!v.HasNaNs()); + x += v.x; y += v.y; z += v.z; + return *this; + } + Vector operator-(const Vector &v) const { + Assert(!v.HasNaNs()); + return Vector(x - v.x, y - v.y, z - v.z); + } + + Vector& operator-=(const Vector &v) { + Assert(!v.HasNaNs()); + x -= v.x; y -= v.y; z -= v.z; + return *this; + } + Vector operator*(float f) const { return Vector(f*x, f*y, f*z); } + + Vector &operator*=(float f) { + Assert(!isnan(f)); + x *= f; y *= f; z *= f; + return *this; + } + Vector operator/(float f) const { + Assert(f != 0); + float inv = 1.f / f; + return Vector(x * inv, y * inv, z * inv); + } + + Vector &operator/=(float f) { + Assert(f != 0); + float inv = 1.f / f; + x *= inv; y *= inv; z *= inv; + return *this; + } + Vector operator-() const { return Vector(-x, -y, -z); } + float operator[](int i) const { + Assert(i >= 0 && i <= 2); + return (&x)[i]; + } + + float &operator[](int i) { + Assert(i >= 0 && i <= 2); + return (&x)[i]; + } + float LengthSquared() const { return x*x + y*y + z*z; } + float Length() const { return sqrtf(LengthSquared()); } + explicit Vector(const Normal &n); + + bool operator==(const Vector &v) const { + return x == v.x && y == v.y && z == v.z; + } + bool operator!=(const Vector &v) const { + return x != v.x || y != v.y || z != v.z; + } + + // Vector Public Data + float x, y, z; +}; + + +class Point { +public: + // Point Public Methods + Point() { x = y = z = 0.f; } + Point(float xx, float yy, float zz) + : x(xx), y(yy), z(zz) { + Assert(!HasNaNs()); + } +#ifndef NDEBUG + Point(const Point &p) { + Assert(!p.HasNaNs()); + x = p.x; y = p.y; z = p.z; + } + + Point &operator=(const Point &p) { + Assert(!p.HasNaNs()); + x = p.x; y = p.y; z = p.z; + return *this; + } +#endif // !NDEBUG + Point operator+(const Vector &v) const { + Assert(!v.HasNaNs()); + return Point(x + v.x, y + v.y, z + v.z); + } + + Point &operator+=(const Vector &v) { + Assert(!v.HasNaNs()); + x += v.x; y += v.y; z += v.z; + return *this; + } + Vector operator-(const Point &p) const { + Assert(!p.HasNaNs()); + return Vector(x - p.x, y - p.y, z - p.z); + } + + Point operator-(const Vector &v) const { + Assert(!v.HasNaNs()); + return Point(x - v.x, y - v.y, z - v.z); + } + + Point &operator-=(const Vector &v) { + Assert(!v.HasNaNs()); + x -= v.x; y -= v.y; z -= v.z; + return *this; + } + Point &operator+=(const Point &p) { + Assert(!p.HasNaNs()); + x += p.x; y += p.y; z += p.z; + return *this; + } + Point operator+(const Point &p) const { + Assert(!p.HasNaNs()); + return Point(x + p.x, y + p.y, z + p.z); + } + Point operator* (float f) const { + return Point(f*x, f*y, f*z); + } + Point &operator*=(float f) { + x *= f; y *= f; z *= f; + return *this; + } + Point operator/ (float f) const { + float inv = 1.f/f; + return Point(inv*x, inv*y, inv*z); + } + Point &operator/=(float f) { + float inv = 1.f/f; + x *= inv; y *= inv; z *= inv; + return *this; + } + float operator[](int i) const { + Assert(i >= 0 && i <= 2); + return (&x)[i]; + } + + float &operator[](int i) { + Assert(i >= 0 && i <= 2); + return (&x)[i]; + } + bool HasNaNs() const { + return isnan(x) || isnan(y) || isnan(z); + } + + bool operator==(const Point &p) const { + return x == p.x && y == p.y && z == p.z; + } + bool operator!=(const Point &p) const { + return x != p.x || y != p.y || z != p.z; + } + + // Point Public Data + float x, y, z; +}; + + +class Normal { +public: + // Normal Public Methods + Normal() { x = y = z = 0.f; } + Normal(float xx, float yy, float zz) + : x(xx), y(yy), z(zz) { + Assert(!HasNaNs()); + } + Normal operator-() const { + return Normal(-x, -y, -z); + } + Normal operator+ (const Normal &n) const { + Assert(!n.HasNaNs()); + return Normal(x + n.x, y + n.y, z + n.z); + } + + Normal& operator+=(const Normal &n) { + Assert(!n.HasNaNs()); + x += n.x; y += n.y; z += n.z; + return *this; + } + Normal operator- (const Normal &n) const { + Assert(!n.HasNaNs()); + return Normal(x - n.x, y - n.y, z - n.z); + } + + Normal& operator-=(const Normal &n) { + Assert(!n.HasNaNs()); + x -= n.x; y -= n.y; z -= n.z; + return *this; + } + bool HasNaNs() const { + return isnan(x) || isnan(y) || isnan(z); + } + Normal operator*(float f) const { + return Normal(f*x, f*y, f*z); + } + + Normal &operator*=(float f) { + x *= f; y *= f; z *= f; + return *this; + } + Normal operator/(float f) const { + Assert(f != 0); + float inv = 1.f/f; + return Normal(x * inv, y * inv, z * inv); + } + + Normal &operator/=(float f) { + Assert(f != 0); + float inv = 1.f/f; + x *= inv; y *= inv; z *= inv; + return *this; + } + float LengthSquared() const { return x*x + y*y + z*z; } + float Length() const { return sqrtf(LengthSquared()); } + +#ifndef NDEBUG + Normal(const Normal &n) { + Assert(!n.HasNaNs()); + x = n.x; y = n.y; z = n.z; + } + + Normal &operator=(const Normal &n) { + Assert(!n.HasNaNs()); + x = n.x; y = n.y; z = n.z; + return *this; + } +#endif // !NDEBUG + explicit Normal(const Vector &v) + : x(v.x), y(v.y), z(v.z) { + Assert(!v.HasNaNs()); + } + float operator[](int i) const { + Assert(i >= 0 && i <= 2); + return (&x)[i]; + } + + float &operator[](int i) { + Assert(i >= 0 && i <= 2); + return (&x)[i]; + } + + bool operator==(const Normal &n) const { + return x == n.x && y == n.y && z == n.z; + } + bool operator!=(const Normal &n) const { + return x != n.x || y != n.y || z != n.z; + } + + // Normal Public Data + float x, y, z; +}; + + +class Ray { +public: + // Ray Public Methods + Ray() : mint(0.f), maxt(INFINITY), time(0.f), depth(0) { } + Ray(const Point &origin, const Vector &direction, + float start, float end = INFINITY, float t = 0.f, int d = 0) + : o(origin), d(direction), mint(start), maxt(end), time(t), depth(d) { } + Ray(const Point &origin, const Vector &direction, const Ray &parent, + float start, float end = INFINITY) + : o(origin), d(direction), mint(start), maxt(end), + time(parent.time), depth(parent.depth+1) { } + Point operator()(float t) const { return o + d * t; } + bool HasNaNs() const { + return (o.HasNaNs() || d.HasNaNs() || + isnan(mint) || isnan(maxt)); + } + + // Ray Public Data + Point o; + Vector d; + mutable float mint, maxt; + float time; + int depth; +}; + + +class RayDifferential : public Ray { +public: + // RayDifferential Public Methods + RayDifferential() { hasDifferentials = false; } + RayDifferential(const Point &org, const Vector &dir, float start, + float end = INFINITY, float t = 0.f, int d = 0) + : Ray(org, dir, start, end, t, d) { + hasDifferentials = false; + } + RayDifferential(const Point &org, const Vector &dir, const Ray &parent, + float start, float end = INFINITY) + : Ray(org, dir, start, end, parent.time, parent.depth+1) { + hasDifferentials = false; + } + explicit RayDifferential(const Ray &ray) : Ray(ray) { + hasDifferentials = false; + } + bool HasNaNs() const { + return Ray::HasNaNs() || + (hasDifferentials && (rxOrigin.HasNaNs() || ryOrigin.HasNaNs() || + rxDirection.HasNaNs() || ryDirection.HasNaNs())); + } + void ScaleDifferentials(float s) { + rxOrigin = o + (rxOrigin - o) * s; + ryOrigin = o + (ryOrigin - o) * s; + rxDirection = d + (rxDirection - d) * s; + ryDirection = d + (ryDirection - d) * s; + } + + // RayDifferential Public Data + bool hasDifferentials; + Point rxOrigin, ryOrigin; + Vector rxDirection, ryDirection; +}; + + +class BBox { +public: + // BBox Public Methods + BBox() { + pMin = Point( INFINITY, INFINITY, INFINITY); + pMax = Point(-INFINITY, -INFINITY, -INFINITY); + } + BBox(const Point &p) : pMin(p), pMax(p) { } + BBox(const Point &p1, const Point &p2) { + pMin = Point(min(p1.x, p2.x), min(p1.y, p2.y), min(p1.z, p2.z)); + pMax = Point(max(p1.x, p2.x), max(p1.y, p2.y), max(p1.z, p2.z)); + } + friend BBox Union(const BBox &b, const Point &p); + friend BBox Union(const BBox &b, const BBox &b2); + bool Overlaps(const BBox &b) const { + bool x = (pMax.x >= b.pMin.x) && (pMin.x <= b.pMax.x); + bool y = (pMax.y >= b.pMin.y) && (pMin.y <= b.pMax.y); + bool z = (pMax.z >= b.pMin.z) && (pMin.z <= b.pMax.z); + return (x && y && z); + } + bool Inside(const Point &pt) const { + return (pt.x >= pMin.x && pt.x <= pMax.x && + pt.y >= pMin.y && pt.y <= pMax.y && + pt.z >= pMin.z && pt.z <= pMax.z); + } + void Expand(float delta) { + pMin -= Vector(delta, delta, delta); + pMax += Vector(delta, delta, delta); + } + float SurfaceArea() const { + Vector d = pMax - pMin; + return 2.f * (d.x * d.y + d.x * d.z + d.y * d.z); + } + float Volume() const { + Vector d = pMax - pMin; + return d.x * d.y * d.z; + } + int MaximumExtent() const { + Vector diag = pMax - pMin; + if (diag.x > diag.y && diag.x > diag.z) + return 0; + else if (diag.y > diag.z) + return 1; + else + return 2; + } + const Point &operator[](int i) const; + Point &operator[](int i); + Point Lerp(float tx, float ty, float tz) const { + return Point(::Lerp(tx, pMin.x, pMax.x), ::Lerp(ty, pMin.y, pMax.y), + ::Lerp(tz, pMin.z, pMax.z)); + } + Vector Offset(const Point &p) const { + return Vector((p.x - pMin.x) / (pMax.x - pMin.x), + (p.y - pMin.y) / (pMax.y - pMin.y), + (p.z - pMin.z) / (pMax.z - pMin.z)); + } + void BoundingSphere(Point *c, float *rad) const; + bool IntersectP(const Ray &ray, float *hitt0 = NULL, float *hitt1 = NULL) const; + + bool operator==(const BBox &b) const { + return b.pMin == pMin && b.pMax == pMax; + } + bool operator!=(const BBox &b) const { + return b.pMin != pMin || b.pMax != pMax; + } + + // BBox Public Data + Point pMin, pMax; +}; + + + +// Geometry Inline Functions +inline Vector::Vector(const Point &p) + : x(p.x), y(p.y), z(p.z) { + Assert(!HasNaNs()); +} + + +inline Vector operator*(float f, const Vector &v) { return v*f; } +inline float Dot(const Vector &v1, const Vector &v2) { + Assert(!v1.HasNaNs() && !v2.HasNaNs()); + return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; +} + + +inline float AbsDot(const Vector &v1, const Vector &v2) { + Assert(!v1.HasNaNs() && !v2.HasNaNs()); + return fabsf(Dot(v1, v2)); +} + + +inline Vector Cross(const Vector &v1, const Vector &v2) { + Assert(!v1.HasNaNs() && !v2.HasNaNs()); + double v1x = v1.x, v1y = v1.y, v1z = v1.z; + double v2x = v2.x, v2y = v2.y, v2z = v2.z; + return Vector((v1y * v2z) - (v1z * v2y), + (v1z * v2x) - (v1x * v2z), + (v1x * v2y) - (v1y * v2x)); +} + + +inline Vector Cross(const Vector &v1, const Normal &v2) { + Assert(!v1.HasNaNs() && !v2.HasNaNs()); + double v1x = v1.x, v1y = v1.y, v1z = v1.z; + double v2x = v2.x, v2y = v2.y, v2z = v2.z; + return Vector((v1y * v2z) - (v1z * v2y), + (v1z * v2x) - (v1x * v2z), + (v1x * v2y) - (v1y * v2x)); +} + + +inline Vector Cross(const Normal &v1, const Vector &v2) { + Assert(!v1.HasNaNs() && !v2.HasNaNs()); + double v1x = v1.x, v1y = v1.y, v1z = v1.z; + double v2x = v2.x, v2y = v2.y, v2z = v2.z; + return Vector((v1y * v2z) - (v1z * v2y), + (v1z * v2x) - (v1x * v2z), + (v1x * v2y) - (v1y * v2x)); +} + + +inline Vector Normalize(const Vector &v) { return v / v.Length(); } +inline void CoordinateSystem(const Vector &v1, Vector *v2, Vector *v3) { + if (fabsf(v1.x) > fabsf(v1.y)) { + float invLen = 1.f / sqrtf(v1.x*v1.x + v1.z*v1.z); + *v2 = Vector(-v1.z * invLen, 0.f, v1.x * invLen); + } + else { + float invLen = 1.f / sqrtf(v1.y*v1.y + v1.z*v1.z); + *v2 = Vector(0.f, v1.z * invLen, -v1.y * invLen); + } + *v3 = Cross(v1, *v2); +} + + +inline float Distance(const Point &p1, const Point &p2) { + return (p1 - p2).Length(); +} + + +inline float DistanceSquared(const Point &p1, const Point &p2) { + return (p1 - p2).LengthSquared(); +} + + +inline Point operator*(float f, const Point &p) { + Assert(!p.HasNaNs()); + return p*f; +} + + +inline Normal operator*(float f, const Normal &n) { + return Normal(f*n.x, f*n.y, f*n.z); +} + + +inline Normal Normalize(const Normal &n) { + return n / n.Length(); +} + + +inline Vector::Vector(const Normal &n) + : x(n.x), y(n.y), z(n.z) { + Assert(!n.HasNaNs()); +} + + +inline float Dot(const Normal &n1, const Vector &v2) { + Assert(!n1.HasNaNs() && !v2.HasNaNs()); + return n1.x * v2.x + n1.y * v2.y + n1.z * v2.z; +} + + +inline float Dot(const Vector &v1, const Normal &n2) { + Assert(!v1.HasNaNs() && !n2.HasNaNs()); + return v1.x * n2.x + v1.y * n2.y + v1.z * n2.z; +} + + +inline float Dot(const Normal &n1, const Normal &n2) { + Assert(!n1.HasNaNs() && !n2.HasNaNs()); + return n1.x * n2.x + n1.y * n2.y + n1.z * n2.z; +} + + +inline float AbsDot(const Normal &n1, const Vector &v2) { + Assert(!n1.HasNaNs() && !v2.HasNaNs()); + return fabsf(n1.x * v2.x + n1.y * v2.y + n1.z * v2.z); +} + + +inline float AbsDot(const Vector &v1, const Normal &n2) { + Assert(!v1.HasNaNs() && !n2.HasNaNs()); + return fabsf(v1.x * n2.x + v1.y * n2.y + v1.z * n2.z); +} + + +inline float AbsDot(const Normal &n1, const Normal &n2) { + Assert(!n1.HasNaNs() && !n2.HasNaNs()); + return fabsf(n1.x * n2.x + n1.y * n2.y + n1.z * n2.z); +} + + +inline Normal Faceforward(const Normal &n, const Vector &v) { + return (Dot(n, v) < 0.f) ? -n : n; +} + + +inline Normal Faceforward(const Normal &n, const Normal &n2) { + return (Dot(n, n2) < 0.f) ? -n : n; +} + + + +inline Vector Faceforward(const Vector &v, const Vector &v2) { + return (Dot(v, v2) < 0.f) ? -v : v; +} + + + +inline Vector Faceforward(const Vector &v, const Normal &n2) { + return (Dot(v, n2) < 0.f) ? -v : v; +} + + +inline const Point &BBox::operator[](int i) const { + Assert(i == 0 || i == 1); + return (&pMin)[i]; +} + + + +inline Point &BBox::operator[](int i) { + Assert(i == 0 || i == 1); + return (&pMin)[i]; +} + + +inline Vector SphericalDirection(float sintheta, + float costheta, float phi) { + return Vector(sintheta * cosf(phi), + sintheta * sinf(phi), + costheta); +} + + +inline Vector SphericalDirection(float sintheta, float costheta, + float phi, const Vector &x, + const Vector &y, const Vector &z) { + return sintheta * cosf(phi) * x + + sintheta * sinf(phi) * y + costheta * z; +} + + +inline float SphericalTheta(const Vector &v) { + return acosf(Clamp(v.z, -1.f, 1.f)); +} + + +inline float SphericalPhi(const Vector &v) { + float p = atan2f(v.y, v.x); + return (p < 0.f) ? p + 2.f*M_PI : p; +} + + + +#endif // PBRT_CORE_GEOMETRY_H diff --git a/core/imageio.cpp b/core/imageio.cpp new file mode 100644 index 0000000..d0a7a45 --- /dev/null +++ b/core/imageio.cpp @@ -0,0 +1,729 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/imageio.cpp* +#include "stdafx.h" +#include "imageio.h" +#include "spectrum.h" + +// ImageIO Local Declarations +static RGBSpectrum *ReadImageEXR(const string &name, int *width, int *height); +static void WriteImageEXR(const string &name, float *pixels, + float *alpha, int xRes, int yRes, + int totalXRes, int totalYRes, + int xOffset, int yOffset); +static void WriteImageTGA(const string &name, float *pixels, + float *alpha, int xRes, int yRes, + int totalXRes, int totalYRes, + int xOffset, int yOffset); +static RGBSpectrum *ReadImageTGA(const string &name, int *w, int *h); +static bool WriteImagePFM(const string &filename, const float *rgb, int xres, int yres); +static RGBSpectrum *ReadImagePFM(const string &filename, int *xres, int *yres); + +// ImageIO Function Definitions +RGBSpectrum *ReadImage(const string &name, int *width, int *height) { + if (name.size() >= 5) { + uint32_t suffixOffset = name.size() - 4; +#ifdef PBRT_HAS_OPENEXR + if (!strcmp(name.c_str() + suffixOffset, ".exr") || + !strcmp(name.c_str() + suffixOffset, ".EXR")) + return ReadImageEXR(name, width, height); +#endif // PBRT_HAS_OPENEXR + if (!strcmp(name.c_str() + suffixOffset, ".tga") || + !strcmp(name.c_str() + suffixOffset, ".TGA")) + return ReadImageTGA(name, width, height); + if (!strcmp(name.c_str() + suffixOffset, ".pfm") || + !strcmp(name.c_str() + suffixOffset, ".PFM")) + return ReadImagePFM(name, width, height); + } + Error("Can't determine image file type from suffix of filename \"%s\"", + name.c_str()); + RGBSpectrum *ret = new RGBSpectrum[1]; + ret[0] = 0.5f; + *width = *height = 1; + return ret; +} + + +void WriteImage(const string &name, float *pixels, float *alpha, int xRes, + int yRes, int totalXRes, int totalYRes, int xOffset, int yOffset) { + if (name.size() >= 5) { + uint32_t suffixOffset = name.size() - 4; +#ifdef PBRT_HAS_OPENEXR + if (!strcmp(name.c_str() + suffixOffset, ".exr") || + !strcmp(name.c_str() + suffixOffset, ".EXR")) { + WriteImageEXR(name, pixels, alpha, xRes, yRes, totalXRes, + totalYRes, xOffset, yOffset); + return; + } +#endif // PBRT_HAS_OPENEXR + if (!strcmp(name.c_str() + suffixOffset, ".tga") || + !strcmp(name.c_str() + suffixOffset, ".TGA")) { + WriteImageTGA(name, pixels, alpha, xRes, yRes, totalXRes, + totalYRes, xOffset, yOffset); + return; + } + if (!strcmp(name.c_str() + suffixOffset, ".pfm") || + !strcmp(name.c_str() + suffixOffset, ".PFM")) { + WriteImagePFM(name, pixels, xRes, yRes); + return; + } + } + Error("Can't determine image file type from suffix of filename \"%s\"", + name.c_str()); +} + + +#ifdef PBRT_HAS_OPENEXR +#if defined(PBRT_IS_WINDOWS) +#define hypotf hypot // For the OpenEXR headers +#endif +#include +#include +#include +#include +#include +using namespace Imf; +using namespace Imath; + +// EXR Function Definitions +static RGBSpectrum *ReadImageEXR(const string &name, int *width, int *height) { + try { + InputFile file(name.c_str()); + Box2i dw = file.header().dataWindow(); + *width = dw.max.x - dw.min.x + 1; + *height = dw.max.y - dw.min.y + 1; + + half *rgb = new half[3 * *width * *height]; + + FrameBuffer frameBuffer; + frameBuffer.insert("R", Slice(HALF, (char *)rgb, + 3*sizeof(half), *width * 3 * sizeof(half), 1, 1, 0.0)); + frameBuffer.insert("G", Slice(HALF, (char *)rgb+sizeof(half), + 3*sizeof(half), *width * 3 * sizeof(half), 1, 1, 0.0)); + frameBuffer.insert("B", Slice(HALF, (char *)rgb+2*sizeof(half), + 3*sizeof(half), *width * 3 * sizeof(half), 1, 1, 0.0)); + + file.setFrameBuffer(frameBuffer); + file.readPixels(dw.min.y, dw.max.y); + + RGBSpectrum *ret = new RGBSpectrum[*width * *height]; + for (int i = 0; i < *width * *height; ++i) { + float frgb[3] = { rgb[3*i], rgb[3*i+1], rgb[3*i+2] }; + ret[i] = RGBSpectrum::FromRGB(frgb); + } + delete[] rgb; + Info("Read EXR image %s (%d x %d)", name.c_str(), *width, *height); + return ret; + } catch (const std::exception &e) { + Error("Unable to read image file \"%s\": %s", name.c_str(), + e.what()); + return NULL; + } +} + + +static void WriteImageEXR(const string &name, float *pixels, + float *alpha, int xRes, int yRes, + int totalXRes, int totalYRes, + int xOffset, int yOffset) { + Rgba *hrgba = new Rgba[xRes * yRes]; + for (int i = 0; i < xRes * yRes; ++i) + hrgba[i] = Rgba(pixels[3*i], pixels[3*i+1], pixels[3*i+2], + alpha ? alpha[i]: 1.f); + + Box2i displayWindow(V2i(0,0), V2i(totalXRes-1, totalYRes-1)); + Box2i dataWindow(V2i(xOffset, yOffset), V2i(xOffset + xRes - 1, yOffset + yRes - 1)); + + try { + RgbaOutputFile file(name.c_str(), displayWindow, dataWindow, WRITE_RGBA); + file.setFrameBuffer(hrgba - xOffset - yOffset * xRes, 1, xRes); + file.writePixels(yRes); + } + catch (const std::exception &e) { + Error("Unable to write image file \"%s\": %s", name.c_str(), + e.what()); + } + + delete[] hrgba; +} + + +#endif // PBRT_HAS_OPENEXR + +// TGA Function Definitions +/**\file + *\section License + * License: GPL + * Online License Link: http://www.gnu.org/licenses/gpl.html + * + *\author Copyright (c) 2003-2009 Jaakko Keranen + *\author Copyright (c) 2009 Daniel Swanson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * gl_tga.c: TGA file format (TARGA) reader/writer. + */ + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include +#if defined(PBRT_IS_WINDOWS) +typedef unsigned char byte; +#else +#include +typedef uint8_t byte; +#endif + +typedef unsigned char uchar; + +// MACROS ------------------------------------------------------------------ + +#undef SHORT +#ifdef __BIG_ENDIAN__ +#define SHORT(x) shortSwap(x) +# else // Little-endian. +#define SHORT(x) (x) +#endif + +// TYPES ------------------------------------------------------------------- + +typedef struct { + uchar idLength; // Identification field size in bytes. + uchar colorMapType; // Type of the color map. + uchar imageType; // Image type code. +} tga_header_t; + +// Color map specification. +typedef struct { + int16_t index; // Index of first color map entry. + int16_t length; // Number of color map entries. + uchar entrySize; // Number of bits in a color map entry (16/24/32). +} tga_colormapspec_t; + +// Image specification. +typedef struct { + int16_t xOrigin; // X coordinate of lower left corner. + int16_t yOrigin; // Y coordinate of lower left corner. + int16_t width; // Width of the image in pixels. + int16_t height; // Height of the image in pixels. + uchar pixelDepth; // Number of bits in a pixel (16/24/32). + uchar attributeBits; +} tga_imagespec_t; + + +#ifdef __BIG_ENDIAN__ +static int16_t shortSwap(int16_t n) +{ + return ((n & 0xff) << 8) | ((n & 0xff00) >> 8); +} + + +#endif + +static bool writeByte(FILE* f, uchar b) +{ + return (fwrite(&b, 1, 1, f) == 1); +} + + + +static bool writeShort(FILE* f, int16_t s) +{ + int16_t v = SHORT(s); + return (fwrite(&v, sizeof(v), 1, f) == 1); +} + + + +static uchar readByte(FILE* f) +{ + uchar v; + fread(&v, sizeof(v), 1, f); + return v; +} + + + +static int16_t readShort(FILE* f) +{ + int16_t v; + fread(&v, sizeof(v), 1, f); + return v; +} + + + +/** + * @param idLength Identification field size in bytes (max 255). + * @c 0 indicates no identification field. + * @param colorMapType Type of the color map, @c 0 or @c 1: + * @c 0 = color map data is not present. + * @c 1 = color map data IS present. + * @param imageType Image data type code, one of: + * @c 0 = no image data is present. + * @c 1 = uncompressed, color mapped image. + * @c 2 = uncompressed, true-color image. + * @c 3 = uncompressed, grayscale image. + * @c 9 = run-length encoded, color mapped image. + * @c 10 = run-length encoded, true-color image. + * @c 11 = run-length encoded, grayscale image. + * @param file Handle to the file to be written to. + */ +static void writeHeader(uchar idLength, uchar colorMapType, uchar imageType, + FILE* file) +{ + writeByte(file, idLength); + writeByte(file, colorMapType? 1 : 0); + writeByte(file, imageType); +} + + + +static void readHeader(tga_header_t* dst, FILE* file) +{ + dst->idLength = readByte(file); + dst->colorMapType = readByte(file); + dst->imageType = readByte(file); +} + + + +/** + * @param index Index of first color map entry. + * @param length Total number of color map entries. + * @param entrySize Number of bits in a color map entry; 15/16/24/32. + * @param file Handle to the file to be written to. + */ +static void writeColorMapSpec(int16_t index, int16_t length, + uchar entrySize, FILE* file) +{ + writeShort(file, index); + writeShort(file, length); + writeByte(file, entrySize); +} + + + +static void readColorMapSpec(tga_colormapspec_t* dst, FILE* file) +{ + dst->index = readShort(file); + dst->length = readShort(file); + dst->entrySize = readByte(file); +} + + + +/** + * @param xOrigin X coordinate of lower left corner. + * @param yOrigin Y coordinate of lower left corner. + * @param width Width of the image in pixels. + * @param height Height of the image in pixels. + * @param pixDepth Number of bits per pixel, one of; 16/24/32. + * @param file Handle to the file to be written to. + */ +static void writeImageSpec(int16_t xOrigin, int16_t yOrigin, + int16_t width, int16_t height, uchar pixDepth, + FILE* file) +{ + writeShort(file, xOrigin); + writeShort(file, yOrigin); + writeShort(file, width); + writeShort(file, height); + writeByte(file, pixDepth); + + /** + * attributeBits:4; // Attribute bits associated with each pixel. + * reserved:1; // A reserved bit; must be 0. + * screenOrigin:1; // Location of screen origin; must be 0. + * dataInterleave:2; // TGA_INTERLEAVE_* + */ + writeByte(file, 0); +} + + + +static void readImageSpec(tga_imagespec_t* dst, FILE* file) +{ + dst->xOrigin = readShort(file); + dst->yOrigin = readShort(file); + dst->width = readShort(file); + dst->height = readShort(file); + dst->pixelDepth = readByte(file); + dst->attributeBits = readByte(file); +} + + +/** + * Save the rgb8888 buffer as Targa 24. + * + * @param filename Path to the file to be written to (need not exist). + * @param w Width of the image in pixels. + * @param h Height of the image in pixels. + * @param buf Ptr to the image data to be written. + * + * @return Non-zero iff successful. + */ +void WriteImageTGA(const string &name, float *pixels, + float *alpha, int xRes, int yRes, + int totalXRes, int totalYRes, + int xOffset, int yOffset) +{ + FILE* file; + uchar* outBuf; + + if ((file = fopen(name.c_str(), "wb")) == NULL) { + Error("Unable to open output filename \"%s\"", name.c_str()); + return; + } + + // No identification field, no color map, Targa type 2 (unmapped RGB). + writeHeader(0, 0, 2, file); + writeColorMapSpec(0, 0, 0, file); + writeImageSpec(0, 0, xRes, yRes, 24, file); + + // The save format is BGR. + outBuf = (uchar *)malloc(xRes * yRes * 3); + uchar *dst = outBuf; + for (int y = yRes-1; y >= 0; --y) { + for (int x = 0; x < xRes; ++x) { +#define TO_BYTE(v) (uint8_t(Clamp(255.f * powf((v), 1.f/2.3f), 0.f, 255.f))) + dst[0] = TO_BYTE(pixels[3*(y*xRes+x)+2]); + dst[1] = TO_BYTE(pixels[3*(y*xRes+x)+1]); + dst[2] = TO_BYTE(pixels[3*(y*xRes+x)+0]); + dst += 3; + } + } + if (fwrite(outBuf, 1, 3 * xRes * yRes, file) != uint32_t(3*xRes*yRes)) + Error("Error writing TGA image file \"%s\"", name.c_str()); + free(outBuf); + fclose(file); +} + + + + +/** + * Loads a TGA image (not the RLE types though) + */ +static RGBSpectrum *ReadImageTGA(const string &name, int *width, int *height) +{ + int x, y, pixbytes; + tga_header_t header; + tga_colormapspec_t colorMapSpec; + tga_imagespec_t imageSpec; + uchar* srcBuf; + const uchar* src; + + FILE *file = fopen(name.c_str(), "rb"); + if (!file) { + Error("Unable to open TGA file \"%s\"", name.c_str()); + return NULL; + } + + // Read and check the header. + readHeader(&header, file); + readColorMapSpec(&colorMapSpec, file); + readImageSpec(&imageSpec, file); + + if (((imageSpec.attributeBits & 0xf) != 8 && // num attribute bits + (imageSpec.attributeBits & 0xf) != 0) || + ((imageSpec.attributeBits & 0xc0) != 0) || // no interleaving + (header.imageType == 2 && + (imageSpec.pixelDepth != 32 && imageSpec.pixelDepth != 24)) || + (header.imageType == 3 && + (imageSpec.pixelDepth != 8)) || + (header.imageType != 2 && header.imageType != 3)) { + Error("ReadImageTGA: I don't know this format " + "(type=%i pxsize=%i abits=%i)", header.imageType, + imageSpec.pixelDepth, + imageSpec.attributeBits); + fclose(file); + return NULL; + } + + *width = imageSpec.width; + *height = imageSpec.height; + + // Determine format. + if (imageSpec.pixelDepth == 32) + pixbytes = 4; + else if (imageSpec.pixelDepth == 24) + pixbytes = 3; + else { + Assert(imageSpec.pixelDepth == 8); + pixbytes = 1; + } + + // Read the pixel data. + int size = *width * *height * pixbytes; + srcBuf = (uchar *)malloc(size); + if (fread(srcBuf, 1, size, file) != (uint32_t)size) { + Error("Premature end-of-file when reading TGA image \"%s\"", name.c_str()); + free(srcBuf); + fclose(file); + return NULL; + } + + // "Unpack" the pixels (origin in the lower left corner). + // TGA pixels are in BGRA format. + src = srcBuf; + RGBSpectrum *ret = new RGBSpectrum[*width * *height]; + RGBSpectrum *dst = ret; + for (y = *height - 1; y >= 0; y--) + for (x = 0; x < *width; x++) { + if (pixbytes == 1) + *dst++ = RGBSpectrum((*src++) / 255.f); + else { + float c[3]; + c[2] = (*src++) / 255.f; + c[1] = (*src++) / 255.f; + c[0] = (*src++) / 255.f; + *dst++ = RGBSpectrum::FromRGB(c); + if (pixbytes == 4) + ++src; + } + } + + bool flipH = ((imageSpec.attributeBits & 0x10) == 0x10); + bool flipV = ((imageSpec.attributeBits & 0x20) == 0x20); + if (flipH) { + for (y = 0; y < *height; ++y) + for (x = 0; x < *width / 2; ++x) + swap(ret[y * *width + x], ret[y * *width + (*width - 1 - x)]); + } + if (flipV) { + for (y = 0; y < *height/2; ++y) + for (x = 0; x < *width; ++x) + swap(ret[y * *width + x], ret[(*height - 1 - y) * *width + x]); + } + free(srcBuf); + fclose(file); + Info("Read TGA image %s (%d x %d)", name.c_str(), *width, *height); + return ret; +} + + + +// PFM Function Definitions +/* + * PFM reader/writer code courtesy Jiawen "Kevin" Chen (http://people.csail.mit.edu/jiawen/) + */ + +static bool hostLittleEndian = +#if defined(__LITTLE_ENDIAN__) || defined(__i386__) || defined(__x86_64__) || defined(PBRT_IS_WINDOWS) +true +#elif defined(__BIG_ENDIAN__) +false +#else +#error "Can't detect machine endian-ness at compile-time." +#endif + ; + +#define BUFFER_SIZE 80 + +static inline int isWhitespace( char c ) +{ + return c == ' ' || c == '\n' || c == '\t'; +} + + + +// reads a "word" from the fp and puts it into buffer +// and adds a null terminator +// i.e. it keeps reading until a whitespace is reached +// returns the number of characters read +// *not* including the whitespace +// return -1 on an error +static int readWord(FILE* fp, char* buffer, int bufferLength) { + int n; + char c; + + if (bufferLength < 1) + return -1; + + n = 0; + c = fgetc( fp ); + while( c != EOF && !isWhitespace( c ) && n < bufferLength ) { + buffer[ n ] = c; + ++n; + c = fgetc( fp ); + } + + if( n < bufferLength ) { + buffer[ n ] = '\0'; + return n; + } + + return -1; +} + + + +static RGBSpectrum *ReadImagePFM(const string &filename, int *xres, int *yres) { + float *data = NULL; + RGBSpectrum *rgb = NULL; + char buffer[ BUFFER_SIZE ]; + unsigned int nFloats; + int nChannels, width, height; + float scale; + bool fileLittleEndian; + + FILE *fp = fopen(filename.c_str(), "rb"); + if (!fp) + goto fail; + + // read either "Pf" or "PF" + if (readWord( fp, buffer, BUFFER_SIZE ) == -1) + goto fail; + + if (strcmp( buffer, "Pf" ) == 0) + nChannels = 1; + else if (strcmp( buffer, "PF" ) == 0) + nChannels = 3; + else + goto fail; + + // read the rest of the header + // read width + if (readWord( fp, buffer, BUFFER_SIZE ) == -1) + goto fail; + width = atoi( buffer ); + *xres = width; + + // read height + if (readWord( fp, buffer, BUFFER_SIZE ) == -1) + goto fail; + height = atoi( buffer ); + *yres = height; + + // read scale + if (readWord( fp, buffer, BUFFER_SIZE ) == -1) + goto fail; + sscanf( buffer, "%f", &scale ); + + // read the data + nFloats = nChannels * width * height; + data = new float[nFloats]; + if (fread(data, sizeof( float ), nFloats, fp ) != nFloats) + goto fail; + + // apply endian conversian and scale if appropriate + fileLittleEndian = (scale < 0.f); + if (hostLittleEndian ^ fileLittleEndian) { + uint8_t bytes[4]; + for (unsigned int i = 0; i < nFloats; ++i) { + memcpy(bytes, &data[i], 4); + swap(bytes[0], bytes[3]); + swap(bytes[1], bytes[2]); + memcpy(&data[i], bytes, 4); + } + } + if (fabsf(scale) != 1.f) + for (unsigned int i = 0; i < nFloats; ++i) + data[i] *= fabsf(scale); + + // create RGBs... + rgb = new RGBSpectrum[width*height]; + if (nChannels == 1) { + for (int i = 0; i < width * height; ++i) + rgb[i] = data[i]; + } + else { + for (int i = 0; i < width * height; ++i) + rgb[i] = RGBSpectrum::FromRGB(&data[3*i]); + } + + delete[] data; + fclose(fp); + return rgb; + + fail: + Error("Error reading PFM file \"%s\"", filename.c_str()); + fclose(fp); + delete[] data; + delete[] rgb; + return NULL; +} + + + + +static bool WriteImagePFM(const string &filename, const float *rgb, + int width, int height) { + FILE* fp; + unsigned int nFloats; + float scale; + + fp = fopen(filename.c_str(), "wb"); + if (!fp) { + Error("Unable to open output PFM file \"%s\"", filename.c_str()); + return false; + } + + // only write 3 channel PFMs here... + if (fprintf(fp, "PF\n") < 0) + goto fail; + + // write the width and height, which must be positive + if (fprintf(fp, "%d %d\n", width, height) < 0) + goto fail; + + // write the scale, which encodes endianness + scale = hostLittleEndian ? -1.f : 1.f; + if (fprintf(fp, "%f\n", scale) < 0) + goto fail; + + // write the data + nFloats = 3 * width * height; + if (fwrite(rgb, sizeof(float), nFloats, fp) < nFloats) + goto fail; + + fclose(fp); + return true; + + fail: + Error("Error writing PFM file \"%s\"", filename.c_str()); + fclose(fp); + return false; +} + + diff --git a/core/imageio.h b/core/imageio.h new file mode 100644 index 0000000..854fb24 --- /dev/null +++ b/core/imageio.h @@ -0,0 +1,40 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_IMAGEIO_H +#define PBRT_CORE_IMAGEIO_H + +// core/imageio.h* +#include "pbrt.h" + +// ImageIO Declarations +RGBSpectrum *ReadImage(const string &name, int *xSize, int *ySize); +void WriteImage(const string &name, float *pixels, float *alpha, + int XRes, int YRes, int totalXRes, int totalYRes, int xOffset, + int yOffset); + +#endif // PBRT_CORE_IMAGEIO_H diff --git a/core/integrator.cpp b/core/integrator.cpp new file mode 100644 index 0000000..441f873 --- /dev/null +++ b/core/integrator.cpp @@ -0,0 +1,262 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/integrator.cpp* +#include "stdafx.h" +#include "integrator.h" +#include "scene.h" +#include "intersection.h" +#include "montecarlo.h" + +// Integrator Method Definitions +Integrator::~Integrator() { +} + + + +// Integrator Utility Functions +Spectrum UniformSampleAllLights(const Scene *scene, + const Renderer *renderer, MemoryArena &arena, const Point &p, + const Normal &n, const Vector &wo, float rayEpsilon, + float time, BSDF *bsdf, const Sample *sample, RNG &rng, + const LightSampleOffsets *lightSampleOffsets, + const BSDFSampleOffsets *bsdfSampleOffsets) { + Spectrum L(0.); + for (uint32_t i = 0; i < scene->lights.size(); ++i) { + Light *light = scene->lights[i]; + int nSamples = lightSampleOffsets ? + lightSampleOffsets[i].nSamples : 1; + // Estimate direct lighting from _light_ samples + Spectrum Ld(0.); + for (int j = 0; j < nSamples; ++j) { + // Find light and BSDF sample values for direct lighting estimate + LightSample lightSample; + BSDFSample bsdfSample; + if (lightSampleOffsets != NULL && bsdfSampleOffsets != NULL) { + lightSample = LightSample(sample, lightSampleOffsets[i], j); + bsdfSample = BSDFSample(sample, bsdfSampleOffsets[i], j); + } + else { + lightSample = LightSample(rng); + bsdfSample = BSDFSample(rng); + } + Ld += EstimateDirect(scene, renderer, arena, light, p, n, wo, + rayEpsilon, time, bsdf, rng, lightSample, bsdfSample, + BxDFType(BSDF_ALL & ~BSDF_SPECULAR)); + } + L += Ld / nSamples; + } + return L; +} + + +Spectrum UniformSampleOneLight(const Scene *scene, + const Renderer *renderer, MemoryArena &arena, const Point &p, + const Normal &n, const Vector &wo, float rayEpsilon, float time, + BSDF *bsdf, const Sample *sample, RNG &rng, int lightNumOffset, + const LightSampleOffsets *lightSampleOffset, + const BSDFSampleOffsets *bsdfSampleOffset) { + // Randomly choose a single light to sample, _light_ + int nLights = int(scene->lights.size()); + if (nLights == 0) return Spectrum(0.); + int lightNum; + if (lightNumOffset != -1) + lightNum = Floor2Int(sample->oneD[lightNumOffset][0] * nLights); + else + lightNum = Floor2Int(rng.RandomFloat() * nLights); + lightNum = min(lightNum, nLights-1); + Light *light = scene->lights[lightNum]; + + // Initialize light and bsdf samples for single light sample + LightSample lightSample; + BSDFSample bsdfSample; + if (lightSampleOffset != NULL && bsdfSampleOffset != NULL) { + lightSample = LightSample(sample, *lightSampleOffset, 0); + bsdfSample = BSDFSample(sample, *bsdfSampleOffset, 0); + } + else { + lightSample = LightSample(rng); + bsdfSample = BSDFSample(rng); + } + return (float)nLights * + EstimateDirect(scene, renderer, arena, light, p, n, wo, + rayEpsilon, time, bsdf, rng, lightSample, + bsdfSample, BxDFType(BSDF_ALL & ~BSDF_SPECULAR)); +} + + +Spectrum EstimateDirect(const Scene *scene, const Renderer *renderer, + MemoryArena &arena, const Light *light, const Point &p, + const Normal &n, const Vector &wo, float rayEpsilon, float time, + const BSDF *bsdf, RNG &rng, const LightSample &lightSample, + const BSDFSample &bsdfSample, BxDFType flags) { + Spectrum Ld(0.); + // Sample light source with multiple importance sampling + Vector wi; + float lightPdf, bsdfPdf; + VisibilityTester visibility; + Spectrum Li = light->Sample_L(p, rayEpsilon, lightSample, time, + &wi, &lightPdf, &visibility); + if (lightPdf > 0. && !Li.IsBlack()) { + Spectrum f = bsdf->f(wo, wi, flags); + if (!f.IsBlack() && visibility.Unoccluded(scene)) { + // Add light's contribution to reflected radiance + Li *= visibility.Transmittance(scene, renderer, NULL, rng, arena); + if (light->IsDeltaLight()) + Ld += f * Li * (AbsDot(wi, n) / lightPdf); + else { + bsdfPdf = bsdf->Pdf(wo, wi, flags); + float weight = PowerHeuristic(1, lightPdf, 1, bsdfPdf); + Ld += f * Li * (AbsDot(wi, n) * weight / lightPdf); + } + } + } + + // Sample BSDF with multiple importance sampling + if (!light->IsDeltaLight()) { + BxDFType sampledType; + Spectrum f = bsdf->Sample_f(wo, &wi, bsdfSample, &bsdfPdf, flags, + &sampledType); + if (!f.IsBlack() && bsdfPdf > 0.) { + float weight = 1.f; + if (!(sampledType & BSDF_SPECULAR)) { + lightPdf = light->Pdf(p, wi); + if (lightPdf == 0.) + return Ld; + weight = PowerHeuristic(1, bsdfPdf, 1, lightPdf); + } + // Add light contribution from BSDF sampling + Intersection lightIsect; + Spectrum Li(0.f); + RayDifferential ray(p, wi, rayEpsilon, INFINITY, time); + if (scene->Intersect(ray, &lightIsect)) { + if (lightIsect.primitive->GetAreaLight() == light) + Li = lightIsect.Le(-wi); + } + else + Li = light->Le(ray); + if (!Li.IsBlack()) { + Li *= renderer->Transmittance(scene, ray, NULL, rng, arena); + Ld += f * Li * AbsDot(wi, n) * weight / bsdfPdf; + } + } + } + return Ld; +} + + +Spectrum SpecularReflect(const RayDifferential &ray, BSDF *bsdf, + RNG &rng, const Intersection &isect, const Renderer *renderer, + const Scene *scene, const Sample *sample, MemoryArena &arena) { + Vector wo = -ray.d, wi; + float pdf; + const Point &p = bsdf->dgShading.p; + const Normal &n = bsdf->dgShading.nn; + Spectrum f = bsdf->Sample_f(wo, &wi, BSDFSample(rng), &pdf, + BxDFType(BSDF_REFLECTION | BSDF_SPECULAR)); + Spectrum L = 0.f; + if (pdf > 0.f && !f.IsBlack() && AbsDot(wi, n) != 0.f) { + // Compute ray differential _rd_ for specular reflection + RayDifferential rd(p, wi, ray, isect.rayEpsilon); + if (ray.hasDifferentials) { + rd.hasDifferentials = true; + rd.rxOrigin = p + isect.dg.dpdx; + rd.ryOrigin = p + isect.dg.dpdy; + // Compute differential reflected directions + Normal dndx = bsdf->dgShading.dndu * bsdf->dgShading.dudx + + bsdf->dgShading.dndv * bsdf->dgShading.dvdx; + Normal dndy = bsdf->dgShading.dndu * bsdf->dgShading.dudy + + bsdf->dgShading.dndv * bsdf->dgShading.dvdy; + Vector dwodx = -ray.rxDirection - wo, dwody = -ray.ryDirection - wo; + float dDNdx = Dot(dwodx, n) + Dot(wo, dndx); + float dDNdy = Dot(dwody, n) + Dot(wo, dndy); + rd.rxDirection = wi - dwodx + 2 * Vector(Dot(wo, n) * dndx + + dDNdx * n); + rd.ryDirection = wi - dwody + 2 * Vector(Dot(wo, n) * dndy + + dDNdy * n); + } + PBRT_STARTED_SPECULAR_REFLECTION_RAY(const_cast(&rd)); + Spectrum Li = renderer->Li(scene, rd, sample, rng, arena); + L = f * Li * AbsDot(wi, n) / pdf; + PBRT_FINISHED_SPECULAR_REFLECTION_RAY(const_cast(&rd)); + } + return L; +} + + +Spectrum SpecularTransmit(const RayDifferential &ray, BSDF *bsdf, + RNG &rng, const Intersection &isect, const Renderer *renderer, + const Scene *scene, const Sample *sample, MemoryArena &arena) { + Vector wo = -ray.d, wi; + float pdf; + const Point &p = bsdf->dgShading.p; + const Normal &n = bsdf->dgShading.nn; + Spectrum f = bsdf->Sample_f(wo, &wi, BSDFSample(rng), &pdf, + BxDFType(BSDF_TRANSMISSION | BSDF_SPECULAR)); + Spectrum L = 0.f; + if (pdf > 0.f && !f.IsBlack() && AbsDot(wi, n) != 0.f) { + // Compute ray differential _rd_ for specular transmission + RayDifferential rd(p, wi, ray, isect.rayEpsilon); + if (ray.hasDifferentials) { + rd.hasDifferentials = true; + rd.rxOrigin = p + isect.dg.dpdx; + rd.ryOrigin = p + isect.dg.dpdy; + + float eta = bsdf->eta; + Vector w = -wo; + if (Dot(wo, n) < 0) eta = 1.f / eta; + + Normal dndx = bsdf->dgShading.dndu * bsdf->dgShading.dudx + bsdf->dgShading.dndv * bsdf->dgShading.dvdx; + Normal dndy = bsdf->dgShading.dndu * bsdf->dgShading.dudy + bsdf->dgShading.dndv * bsdf->dgShading.dvdy; + + Vector dwodx = -ray.rxDirection - wo, dwody = -ray.ryDirection - wo; + float dDNdx = Dot(dwodx, n) + Dot(wo, dndx); + float dDNdy = Dot(dwody, n) + Dot(wo, dndy); + + float mu = eta * Dot(w, n) - Dot(wi, n); + float dmudx = (eta - (eta*eta*Dot(w,n))/Dot(wi, n)) * dDNdx; + float dmudy = (eta - (eta*eta*Dot(w,n))/Dot(wi, n)) * dDNdy; + + rd.rxDirection = wi + eta * dwodx - Vector(mu * dndx + dmudx * n); + rd.ryDirection = wi + eta * dwody - Vector(mu * dndy + dmudy * n); + } + PBRT_STARTED_SPECULAR_REFRACTION_RAY(const_cast(&rd)); + Spectrum Li = renderer->Li(scene, rd, sample, rng, arena); + L = f * Li * AbsDot(wi, n) / pdf; + PBRT_FINISHED_SPECULAR_REFRACTION_RAY(const_cast(&rd)); + } + return L; +} + + +Distribution1D *ComputeLightSamplingCDF(const Scene *scene) { + uint32_t nLights = int(scene->lights.size()); + Assert(nLights > 0); + vectorlightPower(nLights, 0.f); + for (uint32_t i = 0; i < nLights; ++i) + lightPower[i] = scene->lights[i]->Power(scene).y(); + return new Distribution1D(&lightPower[0], nLights); +} + + diff --git a/core/integrator.h b/core/integrator.h new file mode 100644 index 0000000..4d8b24e --- /dev/null +++ b/core/integrator.h @@ -0,0 +1,89 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_INTEGRATOR_H +#define PBRT_CORE_INTEGRATOR_H + +// core/integrator.h* +#include "pbrt.h" +#include "primitive.h" +#include "spectrum.h" +#include "light.h" +#include "reflection.h" +#include "sampler.h" +#include "material.h" +#include "probes.h" +#include "renderer.h" + +// Integrator Declarations +class Integrator { +public: + // Integrator Interface + virtual ~Integrator(); + virtual void Preprocess(const Scene *scene, const Camera *camera, + const Renderer *renderer) { + } + virtual void RequestSamples(Sampler *sampler, Sample *sample, + const Scene *scene) { + } +}; + + +class SurfaceIntegrator : public Integrator { +public: + // SurfaceIntegrator Interface + virtual Spectrum Li(const Scene *scene, const Renderer *renderer, + const RayDifferential &ray, const Intersection &isect, + const Sample *sample, RNG &rng, MemoryArena &arena) const = 0; +}; + + +Spectrum UniformSampleAllLights(const Scene *scene, const Renderer *renderer, + MemoryArena &arena, const Point &p, const Normal &n, const Vector &wo, + float rayEpsilon, float time, BSDF *bsdf, const Sample *sample, RNG &rng, + const LightSampleOffsets *lightSampleOffsets, + const BSDFSampleOffsets *bsdfSampleOffsets); +Spectrum UniformSampleOneLight(const Scene *scene, const Renderer *renderer, + MemoryArena &arena, const Point &p, const Normal &n, const Vector &wo, + float rayEpsilon, float time, BSDF *bsdf, + const Sample *sample, RNG &rng, int lightNumOffset = -1, + const LightSampleOffsets *lightSampleOffset = NULL, + const BSDFSampleOffsets *bsdfSampleOffset = NULL); +Spectrum EstimateDirect(const Scene *scene, const Renderer *renderer, + MemoryArena &arena, const Light *light, const Point &p, + const Normal &n, const Vector &wo, float rayEpsilon, float time, const BSDF *bsdf, + RNG &rng, const LightSample &lightSample, const BSDFSample &bsdfSample, + BxDFType flags); +Spectrum SpecularReflect(const RayDifferential &ray, BSDF *bsdf, RNG &rng, + const Intersection &isect, const Renderer *renderer, const Scene *scene, + const Sample *sample, MemoryArena &arena); +Spectrum SpecularTransmit(const RayDifferential &ray, BSDF *bsdf, RNG &rng, + const Intersection &isect, const Renderer *renderer, const Scene *scene, + const Sample *sample, MemoryArena &arena); +Distribution1D *ComputeLightSamplingCDF(const Scene *scene); + +#endif // PBRT_CORE_INTEGRATOR_H diff --git a/core/intersection.cpp b/core/intersection.cpp new file mode 100644 index 0000000..424ac98 --- /dev/null +++ b/core/intersection.cpp @@ -0,0 +1,58 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/intersection.cpp* +#include "stdafx.h" +#include "intersection.h" +#include "shape.h" +#include "primitive.h" +#include "light.h" + +// Intersection Method Definitions +BSDF *Intersection::GetBSDF(const RayDifferential &ray, + MemoryArena &arena) const { + PBRT_STARTED_BSDF_SHADING(const_cast(&ray)); + dg.ComputeDifferentials(ray); + BSDF *bsdf = primitive->GetBSDF(dg, ObjectToWorld, arena); + PBRT_FINISHED_BSDF_SHADING(const_cast(&ray), bsdf); + return bsdf; +} + + +BSSRDF *Intersection::GetBSSRDF(const RayDifferential &ray, + MemoryArena &arena) const { + PBRT_STARTED_BSSRDF_SHADING(const_cast(&ray)); + dg.ComputeDifferentials(ray); + BSSRDF *bssrdf = primitive->GetBSSRDF(dg, ObjectToWorld, arena); + PBRT_FINISHED_BSSRDF_SHADING(const_cast(&ray), bssrdf); + return bssrdf; +} + + +Spectrum Intersection::Le(const Vector &w) const { + const AreaLight *area = primitive->GetAreaLight(); + return area ? area->L(dg.p, dg.nn, w) : Spectrum(0.); +} + + diff --git a/core/intersection.h b/core/intersection.h new file mode 100644 index 0000000..d93e6e8 --- /dev/null +++ b/core/intersection.h @@ -0,0 +1,58 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_INTERSECTION_H +#define PBRT_CORE_INTERSECTION_H + +// core/intersection.h* +#include "pbrt.h" +#include "diffgeom.h" +#include "transform.h" + +// Intersection Declarations +struct Intersection { + // Intersection Public Methods + Intersection() { + primitive = NULL; + shapeId = primitiveId = 0; + rayEpsilon = 0.f; + } + BSDF *GetBSDF(const RayDifferential &ray, MemoryArena &arena) const; + BSSRDF *GetBSSRDF(const RayDifferential &ray, MemoryArena &arena) const; + Spectrum Le(const Vector &wo) const; + + // Intersection Public Data + DifferentialGeometry dg; + const Primitive *primitive; + Transform WorldToObject, ObjectToWorld; + uint32_t shapeId, primitiveId; + float rayEpsilon; +}; + + + +#endif // PBRT_CORE_INTERSECTION_H diff --git a/core/kdtree.h b/core/kdtree.h new file mode 100644 index 0000000..6798ae3 --- /dev/null +++ b/core/kdtree.h @@ -0,0 +1,179 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_KDTREE_H +#define PBRT_CORE_KDTREE_H + +// core/kdtree.h* +#include "pbrt.h" +#include "geometry.h" + +// KdTree Declarations +struct KdNode { + void init(float p, uint32_t a) { + splitPos = p; + splitAxis = a; + rightChild = (1<<29)-1; + hasLeftChild = 0; + } + void initLeaf() { + splitAxis = 3; + rightChild = (1<<29)-1; + hasLeftChild = 0; + } + // KdNode Data + float splitPos; + uint32_t splitAxis:2; + uint32_t hasLeftChild:1, rightChild:29; +}; + + +template class KdTree { +public: + // KdTree Public Methods + KdTree(const vector &data); + ~KdTree() { + FreeAligned(nodes); + FreeAligned(nodeData); + } + template void Lookup(const Point &p, + LookupProc &process, float &maxDistSquared) const; +private: + // KdTree Private Methods + void recursiveBuild(uint32_t nodeNum, int start, int end, + const NodeData **buildNodes); + template void privateLookup(uint32_t nodeNum, + const Point &p, LookupProc &process, float &maxDistSquared) const; + + // KdTree Private Data + KdNode *nodes; + NodeData *nodeData; + uint32_t nNodes, nextFreeNode; +}; + + +template struct CompareNode { + CompareNode(int a) { axis = a; } + int axis; + bool operator()(const NodeData *d1, const NodeData *d2) const { + return d1->p[axis] == d2->p[axis] ? (d1 < d2) : + d1->p[axis] < d2->p[axis]; + } +}; + + + +// KdTree Method Definitions +template +KdTree::KdTree(const vector &d) { + nNodes = d.size(); + nextFreeNode = 1; + nodes = AllocAligned(nNodes); + nodeData = AllocAligned(nNodes); + vector buildNodes(nNodes, NULL); + for (uint32_t i = 0; i < nNodes; ++i) + buildNodes[i] = &d[i]; + // Begin the KdTree building process + recursiveBuild(0, 0, nNodes, &buildNodes[0]); +} + + +template void +KdTree::recursiveBuild(uint32_t nodeNum, int start, int end, + const NodeData **buildNodes) { + // Create leaf node of kd-tree if we've reached the bottom + if (start + 1 == end) { + nodes[nodeNum].initLeaf(); + nodeData[nodeNum] = *buildNodes[start]; + return; + } + + // Choose split direction and partition data + + // Compute bounds of data from _start_ to _end_ + BBox bound; + for (int i = start; i < end; ++i) + bound = Union(bound, buildNodes[i]->p); + int splitAxis = bound.MaximumExtent(); + int splitPos = (start+end)/2; + std::nth_element(&buildNodes[start], &buildNodes[splitPos], + &buildNodes[end], CompareNode(splitAxis)); + + // Allocate kd-tree node and continue recursively + nodes[nodeNum].init(buildNodes[splitPos]->p[splitAxis], splitAxis); + nodeData[nodeNum] = *buildNodes[splitPos]; + if (start < splitPos) { + nodes[nodeNum].hasLeftChild = 1; + uint32_t childNum = nextFreeNode++; + recursiveBuild(childNum, start, splitPos, buildNodes); + } + if (splitPos+1 < end) { + nodes[nodeNum].rightChild = nextFreeNode++; + recursiveBuild(nodes[nodeNum].rightChild, splitPos+1, + end, buildNodes); + } +} + + +template template +void KdTree::Lookup(const Point &p, LookupProc &proc, + float &maxDistSquared) const { + privateLookup(0, p, proc, maxDistSquared); +} + + +template template +void KdTree::privateLookup(uint32_t nodeNum, const Point &p, + LookupProc &process, float &maxDistSquared) const { + KdNode *node = &nodes[nodeNum]; + // Process kd-tree node's children + int axis = node->splitAxis; + if (axis != 3) { + float dist2 = (p[axis] - node->splitPos) * (p[axis] - node->splitPos); + if (p[axis] <= node->splitPos) { + if (node->hasLeftChild) + privateLookup(nodeNum+1, p, process, maxDistSquared); + if (dist2 < maxDistSquared && node->rightChild < nNodes) + privateLookup(node->rightChild, p, process, maxDistSquared); + } + else { + if (node->rightChild < nNodes) + privateLookup(node->rightChild, p, process, maxDistSquared); + if (dist2 < maxDistSquared && node->hasLeftChild) + privateLookup(nodeNum+1, p, process, maxDistSquared); + } + } + + // Hand kd-tree node to processing function + float dist2 = DistanceSquared(nodeData[nodeNum].p, p); + if (dist2 < maxDistSquared) + process(p, nodeData[nodeNum], dist2, maxDistSquared); +} + + + +#endif // PBRT_CORE_KDTREE_H diff --git a/core/light.cpp b/core/light.cpp new file mode 100644 index 0000000..87bdda7 --- /dev/null +++ b/core/light.cpp @@ -0,0 +1,174 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/light.cpp* +#include "stdafx.h" +#include "light.h" +#include "scene.h" +#include "montecarlo.h" +#include "paramset.h" +#include "sh.h" + +// Light Method Definitions +Light::~Light() { +} + + +bool VisibilityTester::Unoccluded(const Scene *scene) const { + return !scene->IntersectP(r); +} + + +Spectrum VisibilityTester::Transmittance(const Scene *scene, + const Renderer *renderer, const Sample *sample, + RNG &rng, MemoryArena &arena) const { + return renderer->Transmittance(scene, RayDifferential(r), sample, + rng, arena); +} + + +Spectrum Light::Le(const RayDifferential &) const { + return Spectrum(0.); +} + + +LightSampleOffsets::LightSampleOffsets(int count, Sample *sample) { + nSamples = count; + componentOffset = sample->Add1D(nSamples); + posOffset = sample->Add2D(nSamples); +} + + +LightSample::LightSample(const Sample *sample, + const LightSampleOffsets &offsets, uint32_t n) { + Assert(n < sample->n2D[offsets.posOffset]); + Assert(n < sample->n1D[offsets.componentOffset]); + uPos[0] = sample->twoD[offsets.posOffset][2*n]; + uPos[1] = sample->twoD[offsets.posOffset][2*n+1]; + uComponent = sample->oneD[offsets.componentOffset][n]; + Assert(uPos[0] >= 0.f && uPos[0] < 1.f); + Assert(uPos[1] >= 0.f && uPos[1] < 1.f); + Assert(uComponent >= 0.f && uComponent < 1.f); +} + + +void Light::SHProject(const Point &p, float pEpsilon, int lmax, + const Scene *scene, bool computeLightVisibility, float time, + RNG &rng, Spectrum *coeffs) const { + for (int i = 0; i < SHTerms(lmax); ++i) + coeffs[i] = 0.f; + uint32_t ns = RoundUpPow2(nSamples); + uint32_t scramble1D = rng.RandomUInt(); + uint32_t scramble2D[2] = { rng.RandomUInt(), rng.RandomUInt() }; + float *Ylm = ALLOCA(float, SHTerms(lmax)); + for (uint32_t i = 0; i < ns; ++i) { + // Compute incident radiance sample from _light_, update SH _coeffs_ + float u[2], pdf; + Sample02(i, scramble2D, u); + LightSample lightSample(u[0], u[1], VanDerCorput(i, scramble1D)); + Vector wi; + VisibilityTester vis; + Spectrum Li = Sample_L(p, pEpsilon, lightSample, time, &wi, &pdf, &vis); + if (!Li.IsBlack() && pdf > 0.f && + (!computeLightVisibility || vis.Unoccluded(scene))) { + // Add light sample contribution to MC estimate of SH coefficients + SHEvaluate(wi, lmax, Ylm); + for (int j = 0; j < SHTerms(lmax); ++j) + coeffs[j] += Li * Ylm[j] / (pdf * ns); + } + } +} + + + +// ShapeSet Method Definitions +ShapeSet::ShapeSet(const Reference &s) { + vector > todo; + todo.push_back(s); + while (todo.size()) { + Reference sh = todo.back(); + todo.pop_back(); + if (sh->CanIntersect()) + shapes.push_back(sh); + else + sh->Refine(todo); + } + if (shapes.size() > 64) + Warning("Area light geometry turned into %d shapes; " + "may be very inefficient.", (int)shapes.size()); + + // Compute total area of shapes in _ShapeSet_ and area CDF + sumArea = 0.f; + for (uint32_t i = 0; i < shapes.size(); ++i) { + float a = shapes[i]->Area(); + areas.push_back(a); + sumArea += a; + } + areaDistribution = new Distribution1D(&areas[0], areas.size()); +} + + +ShapeSet::~ShapeSet() { + delete areaDistribution; +} + + +Point ShapeSet::Sample(const Point &p, const LightSample &ls, + Normal *Ns) const { + int sn = areaDistribution->SampleDiscrete(ls.uComponent, NULL); + Point pt = shapes[sn]->Sample(p, ls.uPos[0], ls.uPos[1], Ns); + // Find closest intersection of ray with shapes in _ShapeSet_ + Ray r(p, pt-p, 1e-3f, INFINITY); + float rayEps, thit = 1.f; + bool anyHit = false; + DifferentialGeometry dg; + for (uint32_t i = 0; i < shapes.size(); ++i) + anyHit |= shapes[i]->Intersect(r, &thit, &rayEps, &dg); + if (anyHit) *Ns = dg.nn; + return r(thit); +} + + +Point ShapeSet::Sample(const LightSample &ls, Normal *Ns) const { + int sn = areaDistribution->SampleDiscrete(ls.uComponent, NULL); + return shapes[sn]->Sample(ls.uPos[0], ls.uPos[1], Ns); +} + + +float ShapeSet::Pdf(const Point &p, const Vector &wi) const { + float pdf = 0.f; + for (uint32_t i = 0; i < shapes.size(); ++i) + pdf += areas[i] * shapes[i]->Pdf(p, wi); + return pdf / sumArea; +} + + +float ShapeSet::Pdf(const Point &p) const { + float pdf = 0.f; + for (uint32_t i = 0; i < shapes.size(); ++i) + pdf += areas[i] * shapes[i]->Pdf(p); + return pdf / sumArea; +} + + diff --git a/core/light.h b/core/light.h new file mode 100644 index 0000000..f8e17b2 --- /dev/null +++ b/core/light.h @@ -0,0 +1,154 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_LIGHT_H +#define PBRT_CORE_LIGHT_H + +// core/light.h* +#include "pbrt.h" +#include "geometry.h" +#include "transform.h" +#include "spectrum.h" +#include "rng.h" +#include "memory.h" + +// Light Declarations +class Light { +public: + // Light Interface + virtual ~Light(); + Light(const Transform &l2w, int ns = 1) + : nSamples(max(1, ns)), LightToWorld(l2w), + WorldToLight(Inverse(l2w)) { + // Warn if light has transformation with scale + if (WorldToLight.HasScale()) + Warning("Scaling detected in world to light transformation!\n" + "The system has numerous assumptions, implicit and explicit,\n" + "that this transform will have no scale factors in it.\n" + "Proceed at your own risk; your image may have errors or\n" + "the system may crash as a result of this."); + } + virtual Spectrum Sample_L(const Point &p, float pEpsilon, + const LightSample &ls, float time, Vector *wi, float *pdf, + VisibilityTester *vis) const = 0; + virtual Spectrum Power(const Scene *) const = 0; + virtual bool IsDeltaLight() const = 0; + virtual Spectrum Le(const RayDifferential &r) const; + virtual float Pdf(const Point &p, const Vector &wi) const = 0; + virtual Spectrum Sample_L(const Scene *scene, const LightSample &ls, + float u1, float u2, float time, Ray *ray, + Normal *Ns, float *pdf) const = 0; + virtual void SHProject(const Point &p, float pEpsilon, int lmax, + const Scene *scene, bool computeLightVisibility, float time, + RNG &rng, Spectrum *coeffs) const; + + // Light Public Data + const int nSamples; +protected: + // Light Protected Data + const Transform LightToWorld, WorldToLight; +}; + + +struct VisibilityTester { + // VisibilityTester Public Methods + void SetSegment(const Point &p1, float eps1, + const Point &p2, float eps2, float time) { + float dist = Distance(p1, p2); + r = Ray(p1, (p2-p1) / dist, eps1, dist * (1.f - eps2), time); + Assert(!r.HasNaNs()); + } + void SetRay(const Point &p, float eps, const Vector &w, float time) { + r = Ray(p, w, eps, INFINITY, time); + Assert(!r.HasNaNs()); + } + bool Unoccluded(const Scene *scene) const; + Spectrum Transmittance(const Scene *scene, const Renderer *renderer, + const Sample *sample, RNG &rng, MemoryArena &arena) const; + Ray r; +}; + + +class AreaLight : public Light { +public: + // AreaLight Interface + AreaLight(const Transform &l2w, int ns) : Light(l2w, ns) { } + virtual Spectrum L(const Point &p, const Normal &n, + const Vector &w) const = 0; +}; + + +struct LightSample { + // LightSample Public Methods + LightSample() { } + LightSample(const Sample *sample, const LightSampleOffsets &offsets, uint32_t num); + LightSample(RNG &rng) { + uPos[0] = rng.RandomFloat(); + uPos[1] = rng.RandomFloat(); + uComponent = rng.RandomFloat(); + } + LightSample(float up0, float up1, float ucomp) { + Assert(up0 >= 0.f && up0 < 1.f); + Assert(up1 >= 0.f && up1 < 1.f); + Assert(ucomp >= 0.f && ucomp < 1.f); + uPos[0] = up0; uPos[1] = up1; + uComponent = ucomp; + } + float uPos[2], uComponent; +}; + + +struct LightSampleOffsets { + LightSampleOffsets() { } + LightSampleOffsets(int count, Sample *sample); + int nSamples, componentOffset, posOffset; +}; + + + +// ShapeSet Declarations +class ShapeSet { +public: + // ShapeSet Public Methods + ShapeSet(const Reference &s); + float Area() const { return sumArea; } + ~ShapeSet(); + Point Sample(const Point &p, const LightSample &ls, Normal *Ns) const; + Point Sample(const LightSample &ls, Normal *Ns) const; + float Pdf(const Point &p, const Vector &wi) const; + float Pdf(const Point &p) const; +private: + // ShapeSet Private Data + vector > shapes; + float sumArea; + vector areas; + Distribution1D *areaDistribution; +}; + + + +#endif // PBRT_CORE_LIGHT_H diff --git a/core/material.cpp b/core/material.cpp new file mode 100644 index 0000000..9242bd1 --- /dev/null +++ b/core/material.cpp @@ -0,0 +1,79 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/material.cpp* +#include "stdafx.h" +#include "material.h" +#include "primitive.h" +#include "texture.h" +#include "spectrum.h" +#include "reflection.h" + +// Material Method Definitions +Material::~Material() { +} + + +void Material::Bump(const Reference > &d, + const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgs, + DifferentialGeometry *dgBump) { + // Compute offset positions and evaluate displacement texture + DifferentialGeometry dgEval = dgs; + + // Shift _dgEval_ _du_ in the $u$ direction + float du = .5f * (fabsf(dgs.dudx) + fabsf(dgs.dudy)); + if (du == 0.f) du = .01f; + dgEval.p = dgs.p + du * dgs.dpdu; + dgEval.u = dgs.u + du; + dgEval.nn = Normalize((Normal)Cross(dgs.dpdu, dgs.dpdv) + + du * dgs.dndu); + float uDisplace = d->Evaluate(dgEval); + + // Shift _dgEval_ _dv_ in the $v$ direction + float dv = .5f * (fabsf(dgs.dvdx) + fabsf(dgs.dvdy)); + if (dv == 0.f) dv = .01f; + dgEval.p = dgs.p + dv * dgs.dpdv; + dgEval.u = dgs.u; + dgEval.v = dgs.v + dv; + dgEval.nn = Normalize((Normal)Cross(dgs.dpdu, dgs.dpdv) + + dv * dgs.dndv); + float vDisplace = d->Evaluate(dgEval); + float displace = d->Evaluate(dgs); + + // Compute bump-mapped differential geometry + *dgBump = dgs; + dgBump->dpdu = dgs.dpdu + (uDisplace - displace) / du * Vector(dgs.nn) + + displace * Vector(dgs.dndu); + dgBump->dpdv = dgs.dpdv + (vDisplace - displace) / dv * Vector(dgs.nn) + + displace * Vector(dgs.dndv); + dgBump->nn = Normal(Normalize(Cross(dgBump->dpdu, dgBump->dpdv))); + if (dgs.shape->ReverseOrientation ^ dgs.shape->TransformSwapsHandedness) + dgBump->nn *= -1.f; + + // Orient shading normal to match geometric normal + dgBump->nn = Faceforward(dgBump->nn, dgGeom.nn); +} + + diff --git a/core/material.h b/core/material.h new file mode 100644 index 0000000..57ff7fe --- /dev/null +++ b/core/material.h @@ -0,0 +1,54 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_MATERIAL_H +#define PBRT_CORE_MATERIAL_H + +// core/material.h* +#include "pbrt.h" +#include "memory.h" + +// Material Declarations +class Material : public ReferenceCounted { +public: + // Material Interface + virtual BSDF *GetBSDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, + MemoryArena &arena) const = 0; + virtual BSSRDF *GetBSSRDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, + MemoryArena &arena) const { + return NULL; + } + virtual ~Material(); + static void Bump(const Reference > &d, const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, DifferentialGeometry *dgBump); +}; + + + +#endif // PBRT_CORE_MATERIAL_H diff --git a/core/memory.cpp b/core/memory.cpp new file mode 100644 index 0000000..531ed54 --- /dev/null +++ b/core/memory.cpp @@ -0,0 +1,63 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/memory.cpp* +#include "stdafx.h" +#include "memory.h" + +// Memory Allocation Functions +void *AllocAligned(size_t size) { +#if defined(PBRT_IS_WINDOWS) + return _aligned_malloc(size, PBRT_L1_CACHE_LINE_SIZE); +#elif defined (PBRT_IS_OPENBSD) || defined(PBRT_IS_APPLE) + // Allocate excess memory to ensure an aligned pointer can be returned + void *mem = malloc(size + (PBRT_L1_CACHE_LINE_SIZE-1) + sizeof(void*)); + char *amem = ((char*)mem) + sizeof(void*); +#if (PBRT_POINTER_SIZE == 8) + amem += PBRT_L1_CACHE_LINE_SIZE - (reinterpret_cast(amem) & + (PBRT_L1_CACHE_LINE_SIZE - 1)); +#else + amem += PBRT_L1_CACHE_LINE_SIZE - (reinterpret_cast(amem) & + (PBRT_L1_CACHE_LINE_SIZE - 1)); +#endif + ((void**)amem)[-1] = mem; + return amem; +#else + return memalign(PBRT_L1_CACHE_LINE_SIZE, size); +#endif +} + + +void FreeAligned(void *ptr) { + if (!ptr) return; +#if defined(PBRT_IS_WINDOWS) + _aligned_free(ptr); +#elif defined (PBRT_IS_OPENBSD) || defined(PBRT_IS_APPLE) + free(((void**)ptr)[-1]); +#else + free(ptr); +#endif +} + + diff --git a/core/memory.h b/core/memory.h new file mode 100644 index 0000000..c0d84a1 --- /dev/null +++ b/core/memory.h @@ -0,0 +1,202 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_MEMORY_H +#define PBRT_CORE_MEMORY_H + +// core/memory.h* +#include "pbrt.h" +#include "parallel.h" + +// Memory Declarations +class ReferenceCounted { +public: + ReferenceCounted() { nReferences = 0; } + AtomicInt32 nReferences; +private: + ReferenceCounted(const ReferenceCounted &); + ReferenceCounted &operator=(const ReferenceCounted &); +}; + + +template class Reference { +public: + // Reference Public Methods + Reference(T *p = NULL) { + ptr = p; + if (ptr) AtomicAdd(&ptr->nReferences, 1); + } + Reference(const Reference &r) { + ptr = r.ptr; + if (ptr) AtomicAdd(&ptr->nReferences, 1); + } + Reference &operator=(const Reference &r) { + if (r.ptr) AtomicAdd(&r.ptr->nReferences, 1); + if (ptr && AtomicAdd(&ptr->nReferences, -1) == 0) delete ptr; + ptr = r.ptr; + return *this; + } + Reference &operator=(T *p) { + if (p) AtomicAdd(&p->nReferences, 1); + if (ptr && AtomicAdd(&ptr->nReferences, -1) == 0) delete ptr; + ptr = p; + return *this; + } + ~Reference() { + if (ptr && AtomicAdd(&ptr->nReferences, -1) == 0) + delete ptr; + } + T *operator->() { return ptr; } + const T *operator->() const { return ptr; } + operator bool() const { return ptr != NULL; } + const T *GetPtr() const { return ptr; } +private: + T *ptr; +}; + + +void *AllocAligned(size_t size); +template T *AllocAligned(uint32_t count) { + return (T *)AllocAligned(count * sizeof(T)); +} + + +void FreeAligned(void *); +class MemoryArena { +public: + // MemoryArena Public Methods + MemoryArena(uint32_t bs = 32768) { + blockSize = bs; + curBlockPos = 0; + currentBlock = AllocAligned(blockSize); + } + ~MemoryArena() { + FreeAligned(currentBlock); + for (uint32_t i = 0; i < usedBlocks.size(); ++i) + FreeAligned(usedBlocks[i]); + for (uint32_t i = 0; i < availableBlocks.size(); ++i) + FreeAligned(availableBlocks[i]); + } + void *Alloc(uint32_t sz) { + // Round up _sz_ to minimum machine alignment + sz = ((sz + 15) & (~15)); + if (curBlockPos + sz > blockSize) { + // Get new block of memory for _MemoryArena_ + usedBlocks.push_back(currentBlock); + if (availableBlocks.size() && sz <= blockSize) { + currentBlock = availableBlocks.back(); + availableBlocks.pop_back(); + } + else + currentBlock = AllocAligned(max(sz, blockSize)); + curBlockPos = 0; + } + void *ret = currentBlock + curBlockPos; + curBlockPos += sz; + return ret; + } + template T *Alloc(uint32_t count = 1) { + T *ret = (T *)Alloc(count * sizeof(T)); + for (uint32_t i = 0; i < count; ++i) + new (&ret[i]) T(); + return ret; + } + void FreeAll() { + curBlockPos = 0; + while (usedBlocks.size()) { + #ifndef NDEBUG + memset(usedBlocks.back(), 0xfa, blockSize); + #endif + availableBlocks.push_back(usedBlocks.back()); + usedBlocks.pop_back(); + } + } +private: + // MemoryArena Private Data + uint32_t curBlockPos, blockSize; + char *currentBlock; + vector usedBlocks, availableBlocks; +}; + + +template class BlockedArray { +public: + // BlockedArray Public Methods + BlockedArray(uint32_t nu, uint32_t nv, const T *d = NULL) { + uRes = nu; + vRes = nv; + uBlocks = RoundUp(uRes) >> logBlockSize; + uint32_t nAlloc = RoundUp(uRes) * RoundUp(vRes); + data = AllocAligned(nAlloc); + for (uint32_t i = 0; i < nAlloc; ++i) + new (&data[i]) T(); + if (d) + for (uint32_t v = 0; v < vRes; ++v) + for (uint32_t u = 0; u < uRes; ++u) + (*this)(u, v) = d[v * uRes + u]; + } + uint32_t BlockSize() const { return 1 << logBlockSize; } + uint32_t RoundUp(uint32_t x) const { + return (x + BlockSize() - 1) & ~(BlockSize() - 1); + } + uint32_t uSize() const { return uRes; } + uint32_t vSize() const { return vRes; } + ~BlockedArray() { + for (uint32_t i = 0; i < uRes * vRes; ++i) + data[i].~T(); + FreeAligned(data); + } + uint32_t Block(uint32_t a) const { return a >> logBlockSize; } + uint32_t Offset(uint32_t a) const { return (a & (BlockSize() - 1)); } + T &operator()(uint32_t u, uint32_t v) { + uint32_t bu = Block(u), bv = Block(v); + uint32_t ou = Offset(u), ov = Offset(v); + uint32_t offset = BlockSize() * BlockSize() * (uBlocks * bv + bu); + offset += BlockSize() * ov + ou; + return data[offset]; + } + const T &operator()(uint32_t u, uint32_t v) const { + uint32_t bu = Block(u), bv = Block(v); + uint32_t ou = Offset(u), ov = Offset(v); + uint32_t offset = BlockSize() * BlockSize() * (uBlocks * bv + bu); + offset += BlockSize() * ov + ou; + return data[offset]; + } + void GetLinearArray(T *a) const { + for (uint32_t v = 0; v < vRes; ++v) + for (uint32_t u = 0; u < uRes; ++u) + *a++ = (*this)(u, v); + } +private: + // BlockedArray Private Data + T *data; + uint32_t uRes, vRes, uBlocks; +}; + + + +#endif // PBRT_CORE_MEMORY_H diff --git a/core/mipmap.h b/core/mipmap.h new file mode 100644 index 0000000..61b0482 --- /dev/null +++ b/core/mipmap.h @@ -0,0 +1,364 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_MIPMAP_H +#define PBRT_CORE_MIPMAP_H + +// core/mipmap.h* +#include "pbrt.h" +#include "spectrum.h" +#include "texture.h" + +// MIPMap Declarations +typedef enum { + TEXTURE_REPEAT, + TEXTURE_BLACK, + TEXTURE_CLAMP +} ImageWrap; +template class MIPMap { +public: + // MIPMap Public Methods + MIPMap() { pyramid = NULL; width = height = nLevels = 0; } + MIPMap(uint32_t xres, uint32_t yres, const T *data, bool doTri = false, + float maxAniso = 8.f, ImageWrap wrapMode = TEXTURE_REPEAT); + ~MIPMap(); + uint32_t Width() const { return width; } + uint32_t Height() const { return height; } + uint32_t Levels() const { return nLevels; } + const T &Texel(uint32_t level, int s, int t) const; + T Lookup(float s, float t, float width = 0.f) const; + T Lookup(float s, float t, float ds0, float dt0, + float ds1, float dt1) const; +private: + // MIPMap Private Methods + struct ResampleWeight; + ResampleWeight *resampleWeights(uint32_t oldres, uint32_t newres) { + Assert(newres >= oldres); + ResampleWeight *wt = new ResampleWeight[newres]; + float filterwidth = 2.f; + for (uint32_t i = 0; i < newres; ++i) { + // Compute image resampling weights for _i_th texel + float center = (i + .5f) * oldres / newres; + wt[i].firstTexel = Floor2Int((center - filterwidth) + 0.5f); + for (int j = 0; j < 4; ++j) { + float pos = wt[i].firstTexel + j + .5f; + wt[i].weight[j] = Lanczos((pos - center) / filterwidth); + } + + // Normalize filter weights for texel resampling + float invSumWts = 1.f / (wt[i].weight[0] + wt[i].weight[1] + + wt[i].weight[2] + wt[i].weight[3]); + for (uint32_t j = 0; j < 4; ++j) + wt[i].weight[j] *= invSumWts; + } + return wt; + } + float clamp(float v) { return Clamp(v, 0.f, INFINITY); } + RGBSpectrum clamp(const RGBSpectrum &v) { return v.Clamp(0.f, INFINITY); } + SampledSpectrum clamp(const SampledSpectrum &v) { return v.Clamp(0.f, INFINITY); } + T triangle(uint32_t level, float s, float t) const; + T EWA(uint32_t level, float s, float t, float ds0, float dt0, float ds1, float dt1) const; + + // MIPMap Private Data + bool doTrilinear; + float maxAnisotropy; + ImageWrap wrapMode; + struct ResampleWeight { + int firstTexel; + float weight[4]; + }; + BlockedArray **pyramid; + uint32_t width, height, nLevels; +#define WEIGHT_LUT_SIZE 128 + static float *weightLut; +}; + + + +// MIPMap Method Definitions +template +MIPMap::MIPMap(uint32_t sres, uint32_t tres, const T *img, bool doTri, + float maxAniso, ImageWrap wm) { + doTrilinear = doTri; + maxAnisotropy = maxAniso; + wrapMode = wm; + T *resampledImage = NULL; + if (!IsPowerOf2(sres) || !IsPowerOf2(tres)) { + // Resample image to power-of-two resolution + uint32_t sPow2 = RoundUpPow2(sres), tPow2 = RoundUpPow2(tres); + + // Resample image in $s$ direction + ResampleWeight *sWeights = resampleWeights(sres, sPow2); + resampledImage = new T[sPow2 * tPow2]; + + // Apply _sWeights_ to zoom in $s$ direction + for (uint32_t t = 0; t < tres; ++t) { + for (uint32_t s = 0; s < sPow2; ++s) { + // Compute texel $(s,t)$ in $s$-zoomed image + resampledImage[t*sPow2+s] = 0.; + for (int j = 0; j < 4; ++j) { + int origS = sWeights[s].firstTexel + j; + if (wrapMode == TEXTURE_REPEAT) + origS = Mod(origS, sres); + else if (wrapMode == TEXTURE_CLAMP) + origS = Clamp(origS, 0, sres-1); + if (origS >= 0 && origS < (int)sres) + resampledImage[t*sPow2+s] += sWeights[s].weight[j] * + img[t*sres + origS]; + } + } + } + delete[] sWeights; + + // Resample image in $t$ direction + ResampleWeight *tWeights = resampleWeights(tres, tPow2); + T *workData = new T[tPow2]; + for (uint32_t s = 0; s < sPow2; ++s) { + for (uint32_t t = 0; t < tPow2; ++t) { + workData[t] = 0.; + for (uint32_t j = 0; j < 4; ++j) { + int offset = tWeights[t].firstTexel + j; + if (wrapMode == TEXTURE_REPEAT) offset = Mod(offset, tres); + else if (wrapMode == TEXTURE_CLAMP) offset = Clamp(offset, 0, tres-1); + if (offset >= 0 && offset < (int)tres) + workData[t] += tWeights[t].weight[j] * + resampledImage[offset*sPow2 + s]; + } + } + for (uint32_t t = 0; t < tPow2; ++t) + resampledImage[t*sPow2 + s] = clamp(workData[t]); + } + delete[] workData; + delete[] tWeights; + img = resampledImage; + sres = sPow2; + tres = tPow2; + } + width = sres; + height = tres; + // Initialize levels of MIPMap from image + nLevels = 1 + Log2Int(float(max(sres, tres))); + pyramid = new BlockedArray *[nLevels]; + + // Initialize most detailed level of MIPMap + pyramid[0] = new BlockedArray(sres, tres, img); + for (uint32_t i = 1; i < nLevels; ++i) { + // Initialize $i$th MIPMap level from $i-1$st level + uint32_t sRes = max(1u, pyramid[i-1]->uSize()/2); + uint32_t tRes = max(1u, pyramid[i-1]->vSize()/2); + pyramid[i] = new BlockedArray(sRes, tRes); + + // Filter four texels from finer level of pyramid + for (uint32_t t = 0; t < tRes; ++t) + for (uint32_t s = 0; s < sRes; ++s) + (*pyramid[i])(s, t) = .25f * + (Texel(i-1, 2*s, 2*t) + Texel(i-1, 2*s+1, 2*t) + + Texel(i-1, 2*s, 2*t+1) + Texel(i-1, 2*s+1, 2*t+1)); + } + if (resampledImage) delete[] resampledImage; + // Initialize EWA filter weights if needed + if (!weightLut) { + weightLut = AllocAligned(WEIGHT_LUT_SIZE); + for (int i = 0; i < WEIGHT_LUT_SIZE; ++i) { + float alpha = 2; + float r2 = float(i) / float(WEIGHT_LUT_SIZE - 1); + weightLut[i] = expf(-alpha * r2) - expf(-alpha); + } + } +} + + +template +const T &MIPMap::Texel(uint32_t level, int s, int t) const { + Assert(level < nLevels); + const BlockedArray &l = *pyramid[level]; + // Compute texel $(s,t)$ accounting for boundary conditions + switch (wrapMode) { + case TEXTURE_REPEAT: + s = Mod(s, l.uSize()); + t = Mod(t, l.vSize()); + break; + case TEXTURE_CLAMP: + s = Clamp(s, 0, l.uSize() - 1); + t = Clamp(t, 0, l.vSize() - 1); + break; + case TEXTURE_BLACK: { + static const T black = 0.f; + if (s < 0 || s >= (int)l.uSize() || + t < 0 || t >= (int)l.vSize()) + return black; + break; + } + } + PBRT_ACCESSED_TEXEL(const_cast *>(this), level, s, t); + return l(s, t); +} + + +template +MIPMap::~MIPMap() { + for (uint32_t i = 0; i < nLevels; ++i) + delete pyramid[i]; + delete[] pyramid; +} + + +template +T MIPMap::Lookup(float s, float t, float width) const { + // Compute MIPMap level for trilinear filtering + float level = nLevels - 1 + Log2(max(width, 1e-8f)); + + // Perform trilinear interpolation at appropriate MIPMap level + PBRT_MIPMAP_TRILINEAR_FILTER(const_cast *>(this), s, t, width, level, nLevels); + if (level < 0) + return triangle(0, s, t); + else if (level >= nLevels - 1) + return Texel(nLevels-1, 0, 0); + else { + uint32_t iLevel = Floor2Int(level); + float delta = level - iLevel; + return (1.f-delta) * triangle(iLevel, s, t) + + delta * triangle(iLevel+1, s, t); + } +} + + +template +T MIPMap::triangle(uint32_t level, float s, float t) const { + level = Clamp(level, 0, nLevels-1); + s = s * pyramid[level]->uSize() - 0.5f; + t = t * pyramid[level]->vSize() - 0.5f; + int s0 = Floor2Int(s), t0 = Floor2Int(t); + float ds = s - s0, dt = t - t0; + return (1.f-ds) * (1.f-dt) * Texel(level, s0, t0) + + (1.f-ds) * dt * Texel(level, s0, t0+1) + + ds * (1.f-dt) * Texel(level, s0+1, t0) + + ds * dt * Texel(level, s0+1, t0+1); +} + + +template +T MIPMap::Lookup(float s, float t, float ds0, float dt0, + float ds1, float dt1) const { + if (doTrilinear) { + PBRT_STARTED_TRILINEAR_TEXTURE_LOOKUP(s, t); + T val = Lookup(s, t, + 2.f * max(max(fabsf(ds0), fabsf(dt0)), + max(fabsf(ds1), fabsf(dt1)))); + PBRT_FINISHED_TRILINEAR_TEXTURE_LOOKUP(); + return val; + } + PBRT_STARTED_EWA_TEXTURE_LOOKUP(s, t); + // Compute ellipse minor and major axes + if (ds0*ds0 + dt0*dt0 < ds1*ds1 + dt1*dt1) { + swap(ds0, ds1); + swap(dt0, dt1); + } + float majorLength = sqrtf(ds0*ds0 + dt0*dt0); + float minorLength = sqrtf(ds1*ds1 + dt1*dt1); + + // Clamp ellipse eccentricity if too large + if (minorLength * maxAnisotropy < majorLength && minorLength > 0.f) { + float scale = majorLength / (minorLength * maxAnisotropy); + ds1 *= scale; + dt1 *= scale; + minorLength *= scale; + } + if (minorLength == 0.f) { + PBRT_FINISHED_EWA_TEXTURE_LOOKUP(); + PBRT_STARTED_TRILINEAR_TEXTURE_LOOKUP(s, t); + T val = triangle(0, s, t); + PBRT_FINISHED_TRILINEAR_TEXTURE_LOOKUP(); + return val; + } + + // Choose level of detail for EWA lookup and perform EWA filtering + float lod = max(0.f, nLevels - 1.f + Log2(minorLength)); + uint32_t ilod = Floor2Int(lod); + PBRT_MIPMAP_EWA_FILTER(const_cast *>(this), s, t, ds0, ds1, dt0, dt1, minorLength, majorLength, lod, nLevels); + float d = lod - ilod; + T val = (1.f - d) * EWA(ilod, s, t, ds0, dt0, ds1, dt1) + + d * EWA(ilod+1, s, t, ds0, dt0, ds1, dt1); + PBRT_FINISHED_EWA_TEXTURE_LOOKUP(); + return val; +} + + +template +T MIPMap::EWA(uint32_t level, float s, float t, float ds0, float dt0, + float ds1, float dt1) const { + if (level >= nLevels) return Texel(nLevels-1, 0, 0); + // Convert EWA coordinates to appropriate scale for level + s = s * pyramid[level]->uSize() - 0.5f; + t = t * pyramid[level]->vSize() - 0.5f; + ds0 *= pyramid[level]->uSize(); + dt0 *= pyramid[level]->vSize(); + ds1 *= pyramid[level]->uSize(); + dt1 *= pyramid[level]->vSize(); + + // Compute ellipse coefficients to bound EWA filter region + float A = dt0*dt0 + dt1*dt1 + 1; + float B = -2.f * (ds0*dt0 + ds1*dt1); + float C = ds0*ds0 + ds1*ds1 + 1; + float invF = 1.f / (A*C - B*B*0.25f); + A *= invF; + B *= invF; + C *= invF; + + // Compute the ellipse's $(s,t)$ bounding box in texture space + float det = -B*B + 4.f*A*C; + float invDet = 1.f / det; + float uSqrt = sqrtf(det * C), vSqrt = sqrtf(A * det); + int s0 = Ceil2Int (s - 2.f * invDet * uSqrt); + int s1 = Floor2Int(s + 2.f * invDet * uSqrt); + int t0 = Ceil2Int (t - 2.f * invDet * vSqrt); + int t1 = Floor2Int(t + 2.f * invDet * vSqrt); + + // Scan over ellipse bound and compute quadratic equation + T sum(0.); + float sumWts = 0.f; + for (int it = t0; it <= t1; ++it) { + float tt = it - t; + for (int is = s0; is <= s1; ++is) { + float ss = is - s; + // Compute squared radius and filter texel if inside ellipse + float r2 = A*ss*ss + B*ss*tt + C*tt*tt; + if (r2 < 1.) { + float weight = weightLut[min(Float2Int(r2 * WEIGHT_LUT_SIZE), + WEIGHT_LUT_SIZE-1)]; + sum += Texel(level, is, it) * weight; + sumWts += weight; + } + } + } + return sum / sumWts; +} + + +template float *MIPMap::weightLut = NULL; + +#endif // PBRT_CORE_MIPMAP_H diff --git a/core/montecarlo.cpp b/core/montecarlo.cpp new file mode 100644 index 0000000..f13f8bb --- /dev/null +++ b/core/montecarlo.cpp @@ -0,0 +1,436 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/montecarlo.cpp* +#include "stdafx.h" +#include "montecarlo.h" +#include "geometry.h" +#include "shape.h" +#include "volume.h" + +// Sampling Local Definitions +static const int primes[] = { + // First 1000 prime numbers + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, + 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, + 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, + 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, + 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, + 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, + 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, + 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, + 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, + 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, + 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, + 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, + 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, + 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, + 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, + 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, + 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, + 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, + 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, + 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, + 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, + 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, + 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, + 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, + 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, + 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, + 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, + 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, + 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, + 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, + 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, + 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, + 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, + 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, + 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, + 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, + 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, + 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, + 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, + 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, + 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, + 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, + 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, + 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, + 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, + 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, + 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, + 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, + 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, + 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, + 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, + 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, + 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, + 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, + 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, + 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, + 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, + 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, + 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, + 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, + 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, + 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, + 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, + 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, + 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, + 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, + 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, + 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, + 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, + 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, + 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, + 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, + 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, + 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, + 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, + 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, + 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, + 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, + 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, + 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, + 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, + 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, + 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, + 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, + 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, + 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, + 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, + 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, + 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, + 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, + 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, + 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, + 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, + 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, + 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, + 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, + 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, + 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, + 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, + 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919 +}; + + + +// Sampling Function Definitions +void StratifiedSample1D(float *samp, int nSamples, RNG &rng, + bool jitter) { + float invTot = 1.f / nSamples; + for (int i = 0; i < nSamples; ++i) { + float delta = jitter ? rng.RandomFloat() : 0.5f; + *samp++ = min((i + delta) * invTot, OneMinusEpsilon); + } +} + + +void StratifiedSample2D(float *samp, int nx, int ny, RNG &rng, + bool jitter) { + float dx = 1.f / nx, dy = 1.f / ny; + for (int y = 0; y < ny; ++y) + for (int x = 0; x < nx; ++x) { + float jx = jitter ? rng.RandomFloat() : 0.5f; + float jy = jitter ? rng.RandomFloat() : 0.5f; + *samp++ = min((x + jx) * dx, OneMinusEpsilon); + *samp++ = min((y + jy) * dy, OneMinusEpsilon); + } +} + + +void LatinHypercube(float *samples, uint32_t nSamples, uint32_t nDim, + RNG &rng) { + // Generate LHS samples along diagonal + float delta = 1.f / nSamples; + for (uint32_t i = 0; i < nSamples; ++i) + for (uint32_t j = 0; j < nDim; ++j) + samples[nDim * i + j] = min((i + (rng.RandomFloat())) * delta, + OneMinusEpsilon); + + // Permute LHS samples in each dimension + for (uint32_t i = 0; i < nDim; ++i) { + for (uint32_t j = 0; j < nSamples; ++j) { + uint32_t other = j + (rng.RandomUInt() % (nSamples - j)); + swap(samples[nDim * j + i], samples[nDim * other + i]); + } + } +} + + +int LDPixelSampleFloatsNeeded(const Sample *sample, int nPixelSamples) { + int n = 5; // 2 lens + 2 pixel + time + for (uint32_t i = 0; i < sample->n1D.size(); ++i) + n += sample->n1D[i]; + for (uint32_t i = 0; i < sample->n2D.size(); ++i) + n += 2 * sample->n2D[i]; + return nPixelSamples * n; +} + + +void LDPixelSample(int xPos, int yPos, float shutterOpen, + float shutterClose, int nPixelSamples, Sample *samples, + float *buf, RNG &rng) { + // Prepare temporary array pointers for low-discrepancy camera samples + float *imageSamples = buf; buf += 2 * nPixelSamples; + float *lensSamples = buf; buf += 2 * nPixelSamples; + float *timeSamples = buf; buf += nPixelSamples; + + // Prepare temporary array pointers for low-discrepancy integrator samples + uint32_t count1D = samples[0].n1D.size(); + uint32_t count2D = samples[0].n2D.size(); + const uint32_t *n1D = count1D > 0 ? &samples[0].n1D[0] : NULL; + const uint32_t *n2D = count2D > 0 ? &samples[0].n2D[0] : NULL; + float **oneDSamples = ALLOCA(float *, count1D); + float **twoDSamples = ALLOCA(float *, count2D); + for (uint32_t i = 0; i < count1D; ++i) { + oneDSamples[i] = buf; + buf += n1D[i] * nPixelSamples; + } + for (uint32_t i = 0; i < count2D; ++i) { + twoDSamples[i] = buf; + buf += 2 * n2D[i] * nPixelSamples; + } + + // Generate low-discrepancy pixel samples + LDShuffleScrambled2D(1, nPixelSamples, imageSamples, rng); + LDShuffleScrambled2D(1, nPixelSamples, lensSamples, rng); + LDShuffleScrambled1D(1, nPixelSamples, timeSamples, rng); + for (uint32_t i = 0; i < count1D; ++i) + LDShuffleScrambled1D(n1D[i], nPixelSamples, oneDSamples[i], rng); + for (uint32_t i = 0; i < count2D; ++i) + LDShuffleScrambled2D(n2D[i], nPixelSamples, twoDSamples[i], rng); + + // Initialize _samples_ with computed sample values + for (int i = 0; i < nPixelSamples; ++i) { + samples[i].imageX = xPos + imageSamples[2*i]; + samples[i].imageY = yPos + imageSamples[2*i+1]; + samples[i].time = Lerp(timeSamples[i], shutterOpen, shutterClose); + samples[i].lensU = lensSamples[2*i]; + samples[i].lensV = lensSamples[2*i+1]; + // Copy integrator samples into _samples[i]_ + for (uint32_t j = 0; j < count1D; ++j) { + int startSamp = n1D[j] * i; + for (uint32_t k = 0; k < n1D[j]; ++k) + samples[i].oneD[j][k] = oneDSamples[j][startSamp+k]; + } + for (uint32_t j = 0; j < count2D; ++j) { + int startSamp = 2 * n2D[j] * i; + for (uint32_t k = 0; k < 2*n2D[j]; ++k) + samples[i].twoD[j][k] = twoDSamples[j][startSamp+k]; + } + } +} + + + +// Monte Carlo Function Definitions +void RejectionSampleDisk(float *x, float *y, RNG &rng) { + float sx, sy; + do { + sx = 1.f - 2.f * rng.RandomFloat(); + sy = 1.f - 2.f * rng.RandomFloat(); + } while (sx*sx + sy*sy > 1.f); + *x = sx; + *y = sy; +} + + +Vector UniformSampleHemisphere(float u1, float u2) { + float z = u1; + float r = sqrtf(max(0.f, 1.f - z*z)); + float phi = 2 * M_PI * u2; + float x = r * cosf(phi); + float y = r * sinf(phi); + return Vector(x, y, z); +} + + +float UniformHemispherePdf() { + return INV_TWOPI; +} + + +Vector UniformSampleSphere(float u1, float u2) { + float z = 1.f - 2.f * u1; + float r = sqrtf(max(0.f, 1.f - z*z)); + float phi = 2.f * M_PI * u2; + float x = r * cosf(phi); + float y = r * sinf(phi); + return Vector(x, y, z); +} + + +float UniformSpherePdf() { + return 1.f / (4.f * M_PI); +} + + +void UniformSampleDisk(float u1, float u2, float *x, float *y) { + float r = sqrtf(u1); + float theta = 2.0f * M_PI * u2; + *x = r * cosf(theta); + *y = r * sinf(theta); +} + + +void ConcentricSampleDisk(float u1, float u2, float *dx, float *dy) { + float r, theta; + // Map uniform random numbers to $[-1,1]^2$ + float sx = 2 * u1 - 1; + float sy = 2 * u2 - 1; + + // Map square to $(r,\theta)$ + + // Handle degeneracy at the origin + if (sx == 0.0 && sy == 0.0) { + *dx = 0.0; + *dy = 0.0; + return; + } + if (sx >= -sy) { + if (sx > sy) { + // Handle first region of disk + r = sx; + if (sy > 0.0) theta = sy/r; + else theta = 8.0f + sy/r; + } + else { + // Handle second region of disk + r = sy; + theta = 2.0f - sx/r; + } + } + else { + if (sx <= sy) { + // Handle third region of disk + r = -sx; + theta = 4.0f - sy/r; + } + else { + // Handle fourth region of disk + r = -sy; + theta = 6.0f + sx/r; + } + } + theta *= M_PI / 4.f; + *dx = r * cosf(theta); + *dy = r * sinf(theta); +} + + +void UniformSampleTriangle(float u1, float u2, float *u, float *v) { + float su1 = sqrtf(u1); + *u = 1.f - su1; + *v = u2 * su1; +} + + +Distribution2D::Distribution2D(const float *func, int nu, int nv) { + pConditionalV.reserve(nv); + for (int v = 0; v < nv; ++v) { + // Compute conditional sampling distribution for $\tilde{v}$ + pConditionalV.push_back(new Distribution1D(&func[v*nu], nu)); + } + // Compute marginal sampling distribution $p[\tilde{v}]$ + vector marginalFunc; + marginalFunc.reserve(nv); + for (int v = 0; v < nv; ++v) + marginalFunc.push_back(pConditionalV[v]->funcInt); + pMarginal = new Distribution1D(&marginalFunc[0], nv); +} + + +Distribution2D::~Distribution2D() { + delete pMarginal; + for (uint32_t i = 0; i < pConditionalV.size(); ++i) + delete pConditionalV[i]; +} + + +PermutedHalton::PermutedHalton(uint32_t d, RNG &rng) { + dims = d; + // Determine bases $b_i$ and their sum + b = new uint32_t[dims]; + uint32_t sumBases = 0; + for (uint32_t i = 0; i < dims; ++i) { + b[i] = primes[i]; + sumBases += b[i]; + } + + // Compute permutation tables for each base + permute = new uint32_t[sumBases]; + uint32_t *p = permute; + for (uint32_t i = 0; i < dims; ++i) { + GeneratePermutation(p, b[i], rng); + p += b[i]; + } +} + + +float UniformConePdf(float cosThetaMax) { + return 1.f / (2.f * M_PI * (1.f - cosThetaMax)); +} + + +Vector UniformSampleCone(float u1, float u2, float costhetamax) { + float costheta = (1.f - u1) + u1 * costhetamax; + float sintheta = sqrtf(1.f - costheta*costheta); + float phi = u2 * 2.f * M_PI; + return Vector(cosf(phi) * sintheta, sinf(phi) * sintheta, costheta); +} + + +Vector UniformSampleCone(float u1, float u2, float costhetamax, + const Vector &x, const Vector &y, const Vector &z) { + float costheta = Lerp(u1, costhetamax, 1.f); + float sintheta = sqrtf(1.f - costheta*costheta); + float phi = u2 * 2.f * M_PI; + return cosf(phi) * sintheta * x + sinf(phi) * sintheta * y + + costheta * z; +} + + +Vector SampleHG(const Vector &w, float g, float u1, float u2) { + float costheta; + if (fabsf(g) < 1e-3) + costheta = 1.f - 2.f * u1; + else { + float sqrTerm = (1.f - g * g) / + (1.f - g + 2.f * g * u1); + costheta = (1.f + g * g - sqrTerm * sqrTerm) / (2.f * g); + } + float sintheta = sqrtf(max(0.f, 1.f-costheta*costheta)); + float phi = 2.f * M_PI * u2; + Vector v1, v2; + CoordinateSystem(w, &v1, &v2); + return SphericalDirection(sintheta, costheta, phi, v1, v2, w); +} + + +float HGPdf(const Vector &w, const Vector &wp, float g) { + return PhaseHG(w, wp, g); +} + + diff --git a/core/montecarlo.h b/core/montecarlo.h new file mode 100644 index 0000000..a4cdbc5 --- /dev/null +++ b/core/montecarlo.h @@ -0,0 +1,319 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_MONTECARLO_H +#define PBRT_CORE_MONTECARLO_H + +// core/montecarlo.h* +#include "pbrt.h" +#include "geometry.h" +#include "rng.h" + +// smallest floating point value less than one; all canonical random samples +// should be <= this. +#ifdef PBRT_IS_WINDOWS +// sadly, MSVC2008 (at least) doesn't support hexidecimal fp constants... +static const float OneMinusEpsilon=0.9999999403953552f; +#else +static const float OneMinusEpsilon=0x1.fffffep-1; +#endif + +// Monte Carlo Utility Declarations +struct Distribution1D { + // Distribution1D Public Methods + Distribution1D(const float *f, int n) { + count = n; + func = new float[n]; + memcpy(func, f, n*sizeof(float)); + cdf = new float[n+1]; + // Compute integral of step function at $x_i$ + cdf[0] = 0.; + for (int i = 1; i < count+1; ++i) + cdf[i] = cdf[i-1] + func[i-1] / n; + + // Transform step function integral into CDF + funcInt = cdf[count]; + if (funcInt == 0.f) { + for (int i = 1; i < n+1; ++i) + cdf[i] = float(i) / float(n); + } + else { + for (int i = 1; i < n+1; ++i) + cdf[i] /= funcInt; + } + } + ~Distribution1D() { + delete[] func; + delete[] cdf; + } + float SampleContinuous(float u, float *pdf, int *off = NULL) const { + // Find surrounding CDF segments and _offset_ + float *ptr = std::upper_bound(cdf, cdf+count+1, u); + int offset = max(0, int(ptr-cdf-1)); + if (off) *off = offset; + Assert(offset < count); + Assert(u >= cdf[offset] && u < cdf[offset+1]); + + // Compute offset along CDF segment + float du = (u - cdf[offset]) / (cdf[offset+1] - cdf[offset]); + Assert(!isnan(du)); + + // Compute PDF for sampled offset + if (pdf) *pdf = func[offset] / funcInt; + + // Return $x\in{}[0,1)$ corresponding to sample + return (offset + du) / count; + } + int SampleDiscrete(float u, float *pdf) const { + // Find surrounding CDF segments and _offset_ + float *ptr = std::upper_bound(cdf, cdf+count+1, u); + int offset = max(0, int(ptr-cdf-1)); + Assert(offset < count); + Assert(u >= cdf[offset] && u < cdf[offset+1]); + if (pdf) *pdf = func[offset] / (funcInt * count); + return offset; + } +private: + friend struct Distribution2D; + // Distribution1D Private Data + float *func, *cdf; + float funcInt; + int count; +}; + + +void RejectionSampleDisk(float *x, float *y, RNG &rng); +Vector UniformSampleHemisphere(float u1, float u2); +float UniformHemispherePdf(); +Vector UniformSampleSphere(float u1, float u2); +float UniformSpherePdf(); +Vector UniformSampleCone(float u1, float u2, float thetamax); +Vector UniformSampleCone(float u1, float u2, float thetamax, + const Vector &x, const Vector &y, const Vector &z); +float UniformConePdf(float thetamax); +void UniformSampleDisk(float u1, float u2, float *x, float *y); +void ConcentricSampleDisk(float u1, float u2, float *dx, float *dy); +inline Vector CosineSampleHemisphere(float u1, float u2) { + Vector ret; + ConcentricSampleDisk(u1, u2, &ret.x, &ret.y); + ret.z = sqrtf(max(0.f, 1.f - ret.x*ret.x - ret.y*ret.y)); + return ret; +} + + +inline float CosineHemispherePdf(float costheta, float phi) { + return costheta * INV_PI; +} + + +void UniformSampleTriangle(float ud1, float ud2, float *u, float *v); +struct Distribution2D { + // Distribution2D Public Methods + Distribution2D(const float *data, int nu, int nv); + ~Distribution2D(); + void SampleContinuous(float u0, float u1, float uv[2], + float *pdf) const { + float pdfs[2]; + int v; + uv[1] = pMarginal->SampleContinuous(u1, &pdfs[1], &v); + uv[0] = pConditionalV[v]->SampleContinuous(u0, &pdfs[0]); + *pdf = pdfs[0] * pdfs[1]; + } + float Pdf(float u, float v) const { + int iu = Clamp(Float2Int(u * pConditionalV[0]->count), 0, + pConditionalV[0]->count-1); + int iv = Clamp(Float2Int(v * pMarginal->count), 0, + pMarginal->count-1); + if (pConditionalV[iv]->funcInt * pMarginal->funcInt == 0.f) return 0.f; + return (pConditionalV[iv]->func[iu] * pMarginal->func[iv]) / + (pConditionalV[iv]->funcInt * pMarginal->funcInt); + } +private: + // Distribution2D Private Data + vector pConditionalV; + Distribution1D *pMarginal; +}; + + +void StratifiedSample1D(float *samples, int nsamples, RNG &rng, + bool jitter = true); +void StratifiedSample2D(float *samples, int nx, int ny, RNG &rng, + bool jitter = true); +template +void Shuffle(T *samp, uint32_t count, uint32_t dims, RNG &rng) { + for (uint32_t i = 0; i < count; ++i) { + uint32_t other = i + (rng.RandomUInt() % (count - i)); + for (uint32_t j = 0; j < dims; ++j) + swap(samp[dims*i + j], samp[dims*other + j]); + } +} + + +void LatinHypercube(float *samples, uint32_t nSamples, uint32_t nDim, RNG &rng); +inline double RadicalInverse(int n, int base) { + double val = 0; + double invBase = 1. / base, invBi = invBase; + while (n > 0) { + // Compute next digit of radical inverse + int d_i = (n % base); + val += d_i * invBi; + n *= invBase; + invBi *= invBase; + } + return val; +} + + +inline void GeneratePermutation(uint32_t *buf, uint32_t b, RNG &rng) { + for (uint32_t i = 0; i < b; ++i) + buf[i] = i; + Shuffle(buf, b, 1, rng); +} + + +inline double PermutedRadicalInverse(uint32_t n, uint32_t base, + const uint32_t *p) { + double val = 0; + double invBase = 1. / base, invBi = invBase; + + while (n > 0) { + uint32_t d_i = p[n % base]; + val += d_i * invBi; + n *= invBase; + invBi *= invBase; + } + return val; +} + + +class PermutedHalton { +public: + // PermutedHalton Public Methods + PermutedHalton(uint32_t d, RNG &rng); + ~PermutedHalton() { + delete[] b; + delete[] permute; + } + void Sample(uint32_t n, float *out) const { + uint32_t *p = permute; + for (uint32_t i = 0; i < dims; ++i) { + out[i] = min(float(PermutedRadicalInverse(n, b[i], p)), + OneMinusEpsilon); + p += b[i]; + } + } +private: + // PermutedHalton Private Data + uint32_t dims; + uint32_t *b, *permute; + PermutedHalton(const PermutedHalton &); + PermutedHalton &operator=(const PermutedHalton &); +}; + + +inline float VanDerCorput(uint32_t n, uint32_t scramble = 0); +inline float Sobol2(uint32_t n, uint32_t scramble = 0); +inline float LarcherPillichshammer2(uint32_t n, uint32_t scramble = 0); +inline void Sample02(uint32_t n, const uint32_t scramble[2], float sample[2]); +int LDPixelSampleFloatsNeeded(const Sample *sample, int nPixelSamples); +void LDPixelSample(int xPos, int yPos, float shutterOpen, + float shutterClose, int nPixelSamples, Sample *samples, float *buf, RNG &rng); +Vector SampleHG(const Vector &w, float g, float u1, float u2); +float HGPdf(const Vector &w, const Vector &wp, float g); + +// Monte Carlo Inline Functions +inline float BalanceHeuristic(int nf, float fPdf, int ng, float gPdf) { + return (nf * fPdf) / (nf * fPdf + ng * gPdf); +} + + +inline float PowerHeuristic(int nf, float fPdf, int ng, float gPdf) { + float f = nf * fPdf, g = ng * gPdf; + return (f*f) / (f*f + g*g); +} + + + +// Sampling Inline Functions +inline void Sample02(uint32_t n, const uint32_t scramble[2], + float sample[2]) { + sample[0] = VanDerCorput(n, scramble[0]); + sample[1] = Sobol2(n, scramble[1]); +} + + +inline float VanDerCorput(uint32_t n, uint32_t scramble) { + // Reverse bits of _n_ + n = (n << 16) | (n >> 16); + n = ((n & 0x00ff00ff) << 8) | ((n & 0xff00ff00) >> 8); + n = ((n & 0x0f0f0f0f) << 4) | ((n & 0xf0f0f0f0) >> 4); + n = ((n & 0x33333333) << 2) | ((n & 0xcccccccc) >> 2); + n = ((n & 0x55555555) << 1) | ((n & 0xaaaaaaaa) >> 1); + n ^= scramble; + return min(((n>>8) & 0xffffff) / float(1 << 24), OneMinusEpsilon); +} + + +inline float Sobol2(uint32_t n, uint32_t scramble) { + for (uint32_t v = 1 << 31; n != 0; n >>= 1, v ^= v >> 1) + if (n & 0x1) scramble ^= v; + return min(((scramble>>8) & 0xffffff) / float(1 << 24), OneMinusEpsilon); +} + + +inline float +LarcherPillichshammer2(uint32_t n, uint32_t scramble) { + for (uint32_t v = 1 << 31; n != 0; n >>= 1, v |= v >> 1) + if (n & 0x1) scramble ^= v; + return min(((scramble>>8) & 0xffffff) / float(1 << 24), OneMinusEpsilon); +} + + +inline void LDShuffleScrambled1D(int nSamples, int nPixel, + float *samples, RNG &rng) { + uint32_t scramble = rng.RandomUInt(); + for (int i = 0; i < nSamples * nPixel; ++i) + samples[i] = VanDerCorput(i, scramble); + for (int i = 0; i < nPixel; ++i) + Shuffle(samples + i * nSamples, nSamples, 1, rng); + Shuffle(samples, nPixel, nSamples, rng); +} + + +inline void LDShuffleScrambled2D(int nSamples, int nPixel, + float *samples, RNG &rng) { + uint32_t scramble[2] = { rng.RandomUInt(), rng.RandomUInt() }; + for (int i = 0; i < nSamples * nPixel; ++i) + Sample02(i, scramble, &samples[2*i]); + for (int i = 0; i < nPixel; ++i) + Shuffle(samples + 2 * i * nSamples, nSamples, 2, rng); + Shuffle(samples, nPixel, 2 * nSamples, rng); +} + + + +#endif // PBRT_CORE_MONTECARLO_H diff --git a/core/octree.h b/core/octree.h new file mode 100644 index 0000000..78d7f57 --- /dev/null +++ b/core/octree.h @@ -0,0 +1,147 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_OCTREE_H +#define PBRT_CORE_OCTREE_H + +// core/octree.h* +#include "pbrt.h" +#include "geometry.h" + +// Octree Declarations +template struct OctNode { + OctNode() { + for (int i = 0; i < 8; ++i) + children[i] = NULL; + } + ~OctNode() { + for (int i = 0; i < 8; ++i) + delete children[i]; + } + OctNode *children[8]; + vector data; +}; + + +template class Octree { +public: + // Octree Public Methods + Octree(const BBox &b, int md = 16) + : maxDepth(md), bound(b) { } + void Add(const NodeData &dataItem, const BBox &dataBound) { + addPrivate(&root, bound, dataItem, dataBound, + DistanceSquared(dataBound.pMin, dataBound.pMax)); + } + template void Lookup(const Point &p, + LookupProc &process) { + if (!bound.Inside(p)) return; + lookupPrivate(&root, bound, p, process); + } +private: + // Octree Private Methods + void addPrivate(OctNode *node, const BBox &nodeBound, + const NodeData &dataItem, const BBox &dataBound, float diag2, + int depth = 0); + template bool lookupPrivate(OctNode *node, + const BBox &nodeBound, const Point &P, LookupProc &process); + + // Octree Private Data + int maxDepth; + BBox bound; + OctNode root; +}; + + +inline BBox octreeChildBound(int child, const BBox &nodeBound, + const Point &pMid) { + BBox childBound; + childBound.pMin.x = (child & 4) ? pMid.x : nodeBound.pMin.x; + childBound.pMax.x = (child & 4) ? nodeBound.pMax.x : pMid.x; + childBound.pMin.y = (child & 2) ? pMid.y : nodeBound.pMin.y; + childBound.pMax.y = (child & 2) ? nodeBound.pMax.y : pMid.y; + childBound.pMin.z = (child & 1) ? pMid.z : nodeBound.pMin.z; + childBound.pMax.z = (child & 1) ? nodeBound.pMax.z : pMid.z; + return childBound; +} + + + +// Octree Method Definitions +template +void Octree::addPrivate( + OctNode *node, const BBox &nodeBound, + const NodeData &dataItem, const BBox &dataBound, + float diag2, int depth) { + // Possibly add data item to current octree node + if (depth == maxDepth || + DistanceSquared(nodeBound.pMin, nodeBound.pMax) < diag2) { + node->data.push_back(dataItem); + return; + } + + // Otherwise add data item to octree children + Point pMid = .5 * nodeBound.pMin + .5 * nodeBound.pMax; + + // Determine which children the item overlaps + bool x[2] = { dataBound.pMin.x <= pMid.x, dataBound.pMax.x > pMid.x }; + bool y[2] = { dataBound.pMin.y <= pMid.y, dataBound.pMax.y > pMid.y }; + bool z[2] = { dataBound.pMin.z <= pMid.z, dataBound.pMax.z > pMid.z }; + bool over[8] = { x[0] & y[0] & z[0], x[0] & y[0] & z[1], + x[0] & y[1] & z[0], x[0] & y[1] & z[1], + x[1] & y[0] & z[0], x[1] & y[0] & z[1], + x[1] & y[1] & z[0], x[1] & y[1] & z[1] }; + for (int child = 0; child < 8; ++child) { + if (!over[child]) continue; + // Allocate octree node if needed and continue recursive traversal + if (!node->children[child]) + node->children[child] = new OctNode; + BBox childBound = octreeChildBound(child, nodeBound, pMid); + addPrivate(node->children[child], childBound, + dataItem, dataBound, diag2, depth+1); + } +} + + +template template +bool Octree::lookupPrivate(OctNode *node, + const BBox &nodeBound, const Point &p, LookupProc &process) { + for (uint32_t i = 0; i < node->data.size(); ++i) + if (!process(node->data[i])) + return false; + // Determine which octree child node _p_ is inside + Point pMid = .5f * nodeBound.pMin + .5f * nodeBound.pMax; + int child = (p.x > pMid.x ? 4 : 0) + (p.y > pMid.y ? 2 : 0) + + (p.z > pMid.z ? 1 : 0); + if (!node->children[child]) + return true; + BBox childBound = octreeChildBound(child, nodeBound, pMid); + return lookupPrivate(node->children[child], childBound, p, process); +} + + + +#endif // PBRT_CORE_OCTREE_H diff --git a/core/parallel.cpp b/core/parallel.cpp new file mode 100644 index 0000000..5caa0bf --- /dev/null +++ b/core/parallel.cpp @@ -0,0 +1,904 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/parallel.cpp* +#include "stdafx.h" +#include "parallel.h" +#include "memory.h" +#ifdef PBRT_USE_GRAND_CENTRAL_DISPATCH +#include +#endif // PBRT_USE_GRAND_CENTRAL_DISPATCH +#if !defined(PBRT_IS_WINDOWS) +#include +#include +#include +#include +#include +#include +#include +#endif +#include + +// Parallel Local Declarations +#if defined(PBRT_IS_WINDOWS) +static HANDLE *threads; +#elif !defined(PBRT_USE_GRAND_CENTRAL_DISPATCH) +static pthread_t *threads; +#endif +#ifdef PBRT_USE_GRAND_CENTRAL_DISPATCH +static dispatch_queue_t gcdQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); +static dispatch_group_t gcdGroup = dispatch_group_create(); +#else +static Mutex *taskQueueMutex = Mutex::Create(); +static std::vector taskQueue; +#endif // PBRT_USE_GRAND_CENTRAL_DISPATCH +#ifndef PBRT_USE_GRAND_CENTRAL_DISPATCH +static Semaphore *workerSemaphore; +static uint32_t numUnfinishedTasks; +static ConditionVariable *tasksRunningCondition; +#endif // PBRT_USE_GRAND_CENTRAL_DISPATCH +#ifndef PBRT_USE_GRAND_CENTRAL_DISPATCH +static +#if defined(PBRT_IS_WINDOWS) +DWORD WINAPI taskEntry(LPVOID arg); +#else +void *taskEntry(void *arg); +#endif +#endif // !PBRT_USE_GRAND_CENTRAL_DISPATCH + +// Parallel Definitions +#if !defined(PBRT_IS_WINDOWS) + +Mutex *Mutex::Create() { + int sz = sizeof(Mutex); + sz = (sz + (PBRT_L1_CACHE_LINE_SIZE-1)) & ~(PBRT_L1_CACHE_LINE_SIZE-1); + return new (AllocAligned(sz)) Mutex; +} + + + +void Mutex::Destroy(Mutex *m) { + m->~Mutex(); + FreeAligned(m); +} + + + +Mutex::Mutex() { + int err; + if ((err = pthread_mutex_init(&mutex, NULL)) != 0) + Severe("Error from pthread_mutex_init: %s", strerror(err)); +} + + + +Mutex::~Mutex() { + int err; + if ((err = pthread_mutex_destroy(&mutex)) != 0) + Severe("Error from pthread_mutex_destroy: %s", strerror(err)); +} + + + + +MutexLock::MutexLock(Mutex &m) : mutex(m) { + int err; + if ((err = pthread_mutex_lock(&m.mutex)) != 0) + Severe("Error from pthread_mutex_lock: %s", strerror(err)); +} + + + +MutexLock::~MutexLock() { + int err; + if ((err = pthread_mutex_unlock(&mutex.mutex)) != 0) + Severe("Error from pthread_mutex_unlock: %s", strerror(err)); +} + + + + +RWMutex *RWMutex::Create() { + int sz = sizeof(RWMutex); + sz = (sz + (PBRT_L1_CACHE_LINE_SIZE-1)) & ~(PBRT_L1_CACHE_LINE_SIZE-1); + return new (AllocAligned(sz)) RWMutex; +} + + + +void RWMutex::Destroy(RWMutex *m) { + m->~RWMutex(); + FreeAligned(m); +} + + + +RWMutex::RWMutex() { + int err; + if ((err = pthread_rwlock_init(&mutex, NULL)) != 0) + Severe("Error from pthread_rwlock_init: %s", strerror(err)); +} + + + +RWMutex::~RWMutex() { + int err; + if ((err = pthread_rwlock_destroy(&mutex)) != 0) + Severe("Error from pthread_rwlock_destroy: %s", strerror(err)); +} + + + + +RWMutexLock::RWMutexLock(RWMutex &m, RWMutexLockType t) : type(t), mutex(m) { + int err; + if (t == READ) err = pthread_rwlock_rdlock(&m.mutex); + else err = pthread_rwlock_wrlock(&m.mutex); +} + + + +RWMutexLock::~RWMutexLock() { + int err; + if ((err = pthread_rwlock_unlock(&mutex.mutex)) != 0) + Severe("Error from pthread_rwlock_unlock: %s", strerror(err)); +} + + + +void RWMutexLock::UpgradeToWrite() { + Assert(type == READ); + int err; + if ((err = pthread_rwlock_unlock(&mutex.mutex)) != 0) + Severe("Error from pthread_rwlock_unlock: %s", strerror(err)); + if ((err = pthread_rwlock_wrlock(&mutex.mutex)) != 0) + Severe("Error from pthread_rwlock_wrlock: %s", strerror(err)); + type = WRITE; +} + + + +void RWMutexLock::DowngradeToRead() { + Assert(type == WRITE); + int err; + if ((err = pthread_rwlock_unlock(&mutex.mutex)) != 0) + Severe("Error from pthread_rwlock_unlock: %s", strerror(err)); + if ((err = pthread_rwlock_rdlock(&mutex.mutex)) != 0) + Severe("Error from pthread_rwlock_rdlock: %s", strerror(err)); + type = READ; +} + + +#endif // !PBRT_IS_WINDOWS +#if defined(PBRT_IS_WINDOWS) + +Mutex *Mutex::Create() { + return new Mutex; +} + + + +void Mutex::Destroy(Mutex *m) { + delete m; +} + + + +Mutex::Mutex() { + InitializeCriticalSection(&criticalSection); +} + + + +Mutex::~Mutex() { + DeleteCriticalSection(&criticalSection); +} + + + +MutexLock::MutexLock(Mutex &m) : mutex(m) { + EnterCriticalSection(&mutex.criticalSection); +} + + + +MutexLock::~MutexLock() { + LeaveCriticalSection(&mutex.criticalSection); +} + + + +RWMutex *RWMutex::Create() { + return new RWMutex; +} + + + +void RWMutex::Destroy(RWMutex *m) { + delete m; +} + + + +// vista has 'slim reader/writer (SRW)' locks... sigh. + +RWMutex::RWMutex() { + numWritersWaiting = numReadersWaiting = activeWriterReaders = 0; + InitializeCriticalSection(&cs); + + hReadyToRead = CreateEvent(NULL, TRUE, FALSE, NULL); + if (hReadyToRead == NULL) { + Severe("Error creating event for RWMutex: %d", GetLastError()); + } + + hReadyToWrite = CreateSemaphore(NULL, 0, 1, NULL); + if (hReadyToWrite == NULL) { + DWORD lastError = GetLastError(); + CloseHandle(hReadyToRead); + Severe("Error creating semaphore for RWMutex: %d", lastError); + } +} + + + +RWMutex::~RWMutex() { + if (hReadyToRead) + CloseHandle(hReadyToRead); + if (hReadyToWrite != NULL) + CloseHandle(hReadyToWrite); + DeleteCriticalSection(&cs); +} + + + + +RWMutexLock::RWMutexLock(RWMutex &m, RWMutexLockType t) + : type(t), mutex(m) { + if (type == READ) mutex.AcquireRead(); + else mutex.AcquireWrite(); +} + + + +void +RWMutex::AcquireRead() { + bool fNotifyReaders = false; + + EnterCriticalSection(&cs); + + if ((numWritersWaiting > 0) || (HIWORD(activeWriterReaders) > 0)) { + ++numReadersWaiting; + + while (true) { + ResetEvent(hReadyToRead); + LeaveCriticalSection(&cs); + WaitForSingleObject(hReadyToRead, INFINITE); + EnterCriticalSection(&cs); + + // The reader is only allowed to read if there aren't + // any writers waiting and if a writer doesn't own the + // lock. + if ((numWritersWaiting == 0) && (HIWORD(activeWriterReaders) == 0)) + break; + } + + // Reader is done waiting. + --numReadersWaiting; + + // Reader can read. + ++activeWriterReaders; + } + else { + // Reader can read. + if ((++activeWriterReaders == 1) && (numReadersWaiting != 0)) { + // Set flag to notify other waiting readers + // outside of the critical section + // so that they don't when the threads + // are dispatched by the scheduler they + // don't immediately block on the critical + // section that this thread is holding. + fNotifyReaders = true; + } + } + + Assert(HIWORD(activeWriterReaders) == 0); + LeaveCriticalSection(&cs); + + if (fNotifyReaders) + SetEvent(hReadyToRead); +} + + + + +void +RWMutex::AcquireWrite() { + EnterCriticalSection(&cs); + + // Are there active readers? + if (activeWriterReaders != 0) { + ++numWritersWaiting; + + LeaveCriticalSection(&cs); + WaitForSingleObject(hReadyToWrite, INFINITE); + + // Upon wakeup theirs no need for the writer + // to acquire the critical section. It + // already has been transfered ownership of the + // lock by the signaler. + } + else { + Assert(activeWriterReaders == 0); + + // Set that the writer owns the lock. + activeWriterReaders = MAKELONG(0, 1); + + LeaveCriticalSection(&cs); + } +} + + + +void +RWMutex::ReleaseRead() { + EnterCriticalSection(&cs); + + // Assert that the lock isn't held by a writer. + Assert(HIWORD(activeWriterReaders) == 0); + + // Assert that the lock is held by readers. + Assert(LOWORD(activeWriterReaders > 0)); + + // Decrement the number of active readers. + if (--activeWriterReaders == 0) + ResetEvent(hReadyToRead); + + // if writers are waiting and this is the last reader + // hand owneership over to a writer. + if ((numWritersWaiting != 0) && (activeWriterReaders == 0)) { + // Decrement the number of waiting writers + --numWritersWaiting; + + // Pass ownership to a writer thread. + activeWriterReaders = MAKELONG(0, 1); + ReleaseSemaphore(hReadyToWrite, 1, NULL); + } + + LeaveCriticalSection(&cs); +} + + + +void +RWMutex::ReleaseWrite() { + bool fNotifyWriter = false; + bool fNotifyReaders = false; + + EnterCriticalSection(&cs); + + // Assert that the lock is owned by a writer. + Assert(HIWORD(activeWriterReaders) == 1); + + // Assert that the lock isn't owned by one or more readers + Assert(LOWORD(activeWriterReaders) == 0); + + if (numWritersWaiting != 0) { + // Writers waiting, decrement the number of + // waiting writers and release the semaphore + // which means ownership is passed to the thread + // that has been released. + --numWritersWaiting; + fNotifyWriter = true; + } + else { + // There aren't any writers waiting + // Release the exclusive hold on the lock. + activeWriterReaders = 0; + + // if readers are waiting set the flag + // that will cause the readers to be notified + // once the critical section is released. This + // is done so that an awakened reader won't immediately + // block on the critical section which is still being + // held by this thread. + if (numReadersWaiting != 0) + fNotifyReaders = true; + } + + LeaveCriticalSection(&cs); + + if (fNotifyWriter) + ReleaseSemaphore(hReadyToWrite, 1, NULL); + else if (fNotifyReaders) + SetEvent(hReadyToRead); +} + + + +RWMutexLock::~RWMutexLock() { + if (type == READ) mutex.ReleaseRead(); + else mutex.ReleaseWrite(); +} + + + +void RWMutexLock::UpgradeToWrite() { + Assert(type == READ); + mutex.ReleaseRead(); + mutex.AcquireWrite(); + type = WRITE; +} + + + +void RWMutexLock::DowngradeToRead() { + Assert(type == WRITE); + mutex.ReleaseWrite(); + mutex.AcquireRead(); + type = READ; +} + + +#endif +#if !defined(PBRT_IS_WINDOWS) +Semaphore::Semaphore() { +#ifdef PBRT_IS_OPENBSD + sem = (sem_t *)malloc(sizeof(sem_t)); + if (!sem) + Severe("Error from sem_open"); + int err = sem_init(sem, 0, 0); + if (err == -1) + Severe("Error from sem_init: %s", strerror(err)); +#else + char name[32]; + sprintf(name, "pbrt.%d-%d", (int)getpid(), count++); + sem = sem_open(name, O_CREAT, S_IRUSR|S_IWUSR, 0); + if (!sem) + Severe("Error from sem_open: %s", strerror(errno)); +#endif // !PBRT_IS_OPENBSD +} + + +#endif // !PBRT_IS_WINDOWS +#if defined(PBRT_IS_WINDOWS) +Semaphore::Semaphore() { + handle = CreateSemaphore(NULL, 0, 65535, NULL); + if (!handle) + Severe("Error from CreateSemaphore: %d", GetLastError()); +} + + +#endif // PBRT_IS_WINDOWS +#if !defined(PBRT_IS_WINDOWS) +int Semaphore::count = 0; +#endif // !PBRT_IS_WINDOWS +#if !defined(PBRT_IS_WINDOWS) +Semaphore::~Semaphore() { +#ifdef PBRT_IS_OPENBSD + int err = sem_destroy(sem); + free((void *)sem); + sem = NULL; + if (err != 0) + Severe("Error from sem_destroy: %s", strerror(err)); +#else + int err; + if ((err = sem_close(sem)) != 0) + Severe("Error from sem_close: %s", strerror(err)); +#endif // !PBRT_IS_OPENBSD +} + + +#endif // !PBRT_IS_WINDOWS +#if defined(PBRT_IS_WINDOWS) +Semaphore::~Semaphore() { + CloseHandle(handle); +} + + +#endif // PBRT_IS_WINDOWS +#if !defined(PBRT_IS_WINDOWS) +void Semaphore::Wait() { + int err; + if ((err = sem_wait(sem)) != 0) + Severe("Error from sem_wait: %s", strerror(err)); +} + + +#endif // !PBRT_IS_WINDOWS +#if !defined(PBRT_IS_WINDOWS) +bool Semaphore::TryWait() { + return (sem_trywait(sem) == 0); +} + + +#endif // !PBRT_IS_WINDOWS +#if !defined(PBRT_IS_WINDOWS) +void Semaphore::Post(int count) { + int err; + while (count-- > 0) + if ((err = sem_post(sem)) != 0) + Severe("Error from sem_post: %s", strerror(err)); +} + + +#endif // !PBRT_IS_WINDOWS +#if defined(PBRT_IS_WINDOWS) +void Semaphore::Wait() { + if (WaitForSingleObject(handle, INFINITE) == WAIT_FAILED) + Severe("Error from WaitForSingleObject: %d", GetLastError()); + +} + + +#endif // PBRT_IS_WINDOWS +#if defined(PBRT_IS_WINDOWS) +bool Semaphore::TryWait() { + return (WaitForSingleObject(handle, 0L) == WAIT_OBJECT_0); +} + + +#endif // PBRT_IS_WINDOWS +#if defined(PBRT_IS_WINDOWS) +void Semaphore::Post(int count) { + if (!ReleaseSemaphore(handle, count, NULL)) + Severe("Error from ReleaseSemaphore: %d", GetLastError()); +} + + +#endif // PBRT_IS_WINDOWS +#if !defined(PBRT_IS_WINDOWS) +ConditionVariable::ConditionVariable() { + int err; + if ((err = pthread_cond_init(&cond, NULL)) != 0) + Severe("Error from pthread_cond_init: %s", strerror(err)); + if ((err = pthread_mutex_init(&mutex, NULL)) != 0) + Severe("Error from pthread_mutex_init: %s", strerror(err)); +} + + +#endif // !PBRT_IS_WINDOWS +#if !defined(PBRT_IS_WINDOWS) +ConditionVariable::~ConditionVariable() { + pthread_cond_destroy(&cond); + pthread_mutex_destroy(&mutex); +} + + +#endif // !PBRT_IS_WINDOWS +#if !defined(PBRT_IS_WINDOWS) +void ConditionVariable::Lock() { + int err; + if ((err = pthread_mutex_lock(&mutex)) != 0) + Severe("Error from pthread_mutex_lock: %s", strerror(err)); +} + + +#endif // !PBRT_IS_WINDOWS +#if !(defined(PBRT_IS_WINDOWS)) +void ConditionVariable::Unlock() { + int err; + if ((err = pthread_mutex_unlock(&mutex)) != 0) + Severe("Error from pthread_mutex_unlock: %s", strerror(err)); +} + + +#endif // !PBRT_IS_WINDOWS +#if !defined(PBRT_IS_WINDOWS) +void ConditionVariable::Wait() { + int err; + if ((err = pthread_cond_wait(&cond, &mutex)) != 0) + Severe("Error from pthread_cond_wait: %s", strerror(err)); +} + + +#endif // !PBRT_IS_WINDOWS +#if !defined(PBRT_IS_WINDOWS) +void ConditionVariable::Signal() { + int err; + if ((err = pthread_cond_signal(&cond)) != 0) + Severe("Error from pthread_cond_signal: %s", strerror(err)); +} + + +#endif // !PBRT_IS_WINDOWS +#if defined(PBRT_IS_WINDOWS) + +// http://www.cs.wustl.edu/\~schmidt/win32-cv-1.html + +ConditionVariable::ConditionVariable() { + waitersCount = 0; + InitializeCriticalSection(&waitersCountMutex); + InitializeCriticalSection(&conditionMutex); + + events[SIGNAL] = CreateEvent (NULL, // no security + FALSE, // auto-reset event + FALSE, // non-signaled initially + NULL); // unnamed + events[BROADCAST] = CreateEvent (NULL, // no security + TRUE, // manual-reset + FALSE, // non-signaled initially + NULL); // unnamed + +} + + +#endif // PBRT_IS_WINDOWS +#if defined(PBRT_IS_WINDOWS) +ConditionVariable::~ConditionVariable() { + CloseHandle(events[SIGNAL]); + CloseHandle(events[BROADCAST]); +} + + +#endif // PBRT_IS_WINDOWS +#if defined(PBRT_IS_WINDOWS) +void ConditionVariable::Lock() { + EnterCriticalSection(&conditionMutex); +} + + +#endif // PBRT_IS_WINDOWS +#if defined(PBRT_IS_WINDOWS) +void ConditionVariable::Unlock() { + LeaveCriticalSection(&conditionMutex); +} + + +#endif // PBRT_IS_WINDOWS +#if defined(PBRT_IS_WINDOWS) +void ConditionVariable::Wait() { + // Avoid race conditions. + EnterCriticalSection(&waitersCountMutex); + waitersCount++; + LeaveCriticalSection(&waitersCountMutex); + + // It's ok to release the here since Win32 + // manual-reset events maintain state when used with + // . This avoids the "lost wakeup" bug... + LeaveCriticalSection(&conditionMutex); + + // Wait for either event to become signaled due to + // being called or being called. + int result = WaitForMultipleObjects(2, events, FALSE, INFINITE); + + EnterCriticalSection(&waitersCountMutex); + waitersCount--; + int last_waiter = (result == WAIT_OBJECT_0 + BROADCAST) && + (waitersCount == 0); + LeaveCriticalSection(&waitersCountMutex); + + // Some thread called . + if (last_waiter) + // We're the last waiter to be notified or to stop waiting, so + // reset the manual event. + ResetEvent(events[BROADCAST]); + + EnterCriticalSection(&conditionMutex); +} + + +#endif // PBRT_IS_WINDOWS +#if defined(PBRT_IS_WINDOWS) +void ConditionVariable::Signal() { + EnterCriticalSection(&waitersCountMutex); + int haveWaiters = (waitersCount > 0); + LeaveCriticalSection(&waitersCountMutex); + + if (haveWaiters) + SetEvent(events[SIGNAL]); +} + + +#endif // PBRT_IS_WINDOWS +void TasksInit() { + if (PbrtOptions.nCores == 1) + return; +#ifdef PBRT_USE_GRAND_CENTRAL_DISPATCH + return; +#else // PBRT_USE_GRAND_CENTRAL_DISPATCH + static const int nThreads = NumSystemCores(); + workerSemaphore = new Semaphore; + tasksRunningCondition = new ConditionVariable; +#if !defined(PBRT_IS_WINDOWS) + threads = new pthread_t[nThreads]; + for (int i = 0; i < nThreads; ++i) { + int err = pthread_create(&threads[i], NULL, &taskEntry, reinterpret_cast(i)); + if (err != 0) + Severe("Error from pthread_create: %s", strerror(err)); + } +#else + threads = new HANDLE[nThreads]; + for (int i = 0; i < nThreads; ++i) { + threads[i] = CreateThread(NULL, 0, taskEntry, reinterpret_cast(i), 0, NULL); + if (threads[i] == NULL) + Severe("Error from CreateThread"); + } +#endif // PBRT_IS_WINDOWS +#endif // PBRT_USE_GRAND_CENTRAL_DISPATCH +} + + +void TasksCleanup() { + if (PbrtOptions.nCores == 1) + return; +#ifdef PBRT_USE_GRAND_CENTRAL_DISPATCH + return; +#else // // PBRT_USE_GRAND_CENTRAL_DISPATCH + if (!taskQueueMutex || !workerSemaphore) + return; + { MutexLock lock(*taskQueueMutex); + Assert(taskQueue.size() == 0); + } + + static const int nThreads = NumSystemCores(); + if (workerSemaphore != NULL) + workerSemaphore->Post(nThreads); + + if (threads != NULL) { +#if !defined(PBRT_IS_WINDOWS) + for (int i = 0; i < nThreads; ++i) { + int err = pthread_join(threads[i], NULL); + if (err != 0) + Severe("Error from pthread_join: %s", strerror(err)); + } +#else + WaitForMultipleObjects(nThreads, threads, TRUE, INFINITE); + for (int i = 0; i < nThreads; ++i) { + CloseHandle(threads[i]); + } +#endif // PBRT_IS_WINDOWS + delete[] threads; + threads = NULL; + } +#endif // PBRT_USE_GRAND_CENTRAL_DISPATCH +} + + +Task::~Task() { +} + + +#ifdef PBRT_USE_GRAND_CENTRAL_DISPATCH +static void lRunTask(void *t) { + Task *task = (Task *)t; + PBRT_STARTED_TASK(task); + task->Run(); + PBRT_FINISHED_TASK(task); +} + + +#endif +void EnqueueTasks(const vector &tasks) { + if (PbrtOptions.nCores == 1) { + for (unsigned int i = 0; i < tasks.size(); ++i) + tasks[i]->Run(); + return; + } +#ifdef PBRT_USE_GRAND_CENTRAL_DISPATCH + for (uint32_t i = 0; i < tasks.size(); ++i) + dispatch_group_async_f(gcdGroup, gcdQueue, tasks[i], lRunTask); +#else + if (!threads) + TasksInit(); + + { MutexLock lock(*taskQueueMutex); + for (unsigned int i = 0; i < tasks.size(); ++i) + taskQueue.push_back(tasks[i]); + } + tasksRunningCondition->Lock(); + numUnfinishedTasks += tasks.size(); + tasksRunningCondition->Unlock(); + + workerSemaphore->Post(tasks.size()); +#endif +} + + +#ifndef PBRT_USE_GRAND_CENTRAL_DISPATCH +#if defined(PBRT_IS_WINDOWS) +static DWORD WINAPI taskEntry(LPVOID arg) { +#else +static void *taskEntry(void *arg) { +#endif + while (true) { + workerSemaphore->Wait(); + // Try to get task from task queue + Task *myTask = NULL; + { MutexLock lock(*taskQueueMutex); + if (taskQueue.size() == 0) + break; + myTask = taskQueue.back(); + taskQueue.pop_back(); + } + + // Do work for _myTask_ + PBRT_STARTED_TASK(myTask); + myTask->Run(); + PBRT_FINISHED_TASK(myTask); + tasksRunningCondition->Lock(); + int unfinished = --numUnfinishedTasks; + if (unfinished == 0) + tasksRunningCondition->Signal(); + tasksRunningCondition->Unlock(); + } + // Cleanup from task thread and exit +#if !defined(PBRT_IS_WINDOWS) + pthread_exit(NULL); +#endif // !PBRT_IS_WINDOWS + return 0; +} + + +#endif // !PBRT_USE_GRAND_CENTRAL_DISPATCH +void WaitForAllTasks() { + if (PbrtOptions.nCores == 1) + return; // enqueue just runs them immediately in this case +#ifdef PBRT_USE_GRAND_CENTRAL_DISPATCH + dispatch_group_wait(gcdGroup, DISPATCH_TIME_FOREVER); +#else + if (!tasksRunningCondition) + return; // no tasks have been enqueued, so TasksInit() never called + tasksRunningCondition->Lock(); + while (numUnfinishedTasks > 0) + tasksRunningCondition->Wait(); + tasksRunningCondition->Unlock(); +#endif +} + + +int NumSystemCores() { + if (PbrtOptions.nCores > 0) return PbrtOptions.nCores; +#if defined(PBRT_IS_WINDOWS) + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + return sysinfo.dwNumberOfProcessors; +#elif defined(PBRT_IS_LINUX) + return sysconf(_SC_NPROCESSORS_ONLN); +#else + // mac/bsds +#ifdef PBRT_IS_OPENBSD + int mib[2] = { CTL_HW, HW_NCPU }; +#else + int mib[2]; + mib[0] = CTL_HW; + size_t length = 2; + if (sysctlnametomib("hw.logicalcpu", mib, &length) == -1) { + Error("sysctlnametomib() filed. Guessing 2 CPU cores."); + return 2; + } + Assert(length == 2); +#endif + int nCores = 0; + size_t size = sizeof(nCores); + + /* get the number of CPUs from the system */ + if (sysctl(mib, 2, &nCores, &size, NULL, 0) == -1) { + Error("sysctl() to find number of cores present failed"); + return 2; + } + return nCores; +#endif +} + + diff --git a/core/parallel.h b/core/parallel.h new file mode 100644 index 0000000..5ea69e5 --- /dev/null +++ b/core/parallel.h @@ -0,0 +1,338 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_PARALLEL_H +#define PBRT_CORE_PARALLEL_H + +// core/parallel.h* +#include "pbrt.h" +#if defined(PBRT_IS_APPLE_PPC) +#include +#endif // PBRT_IS_APPLE_PPC + +#if defined(PBRT_IS_WINDOWS) +#include +#else +#include +#include +#endif +#include "core/probes.h" + +// Parallel Declarations +#if defined(PBRT_IS_WINDOWS) + #if _MSC_VER >= 1300 + extern "C" void _ReadWriteBarrier(); + #pragma intrinsic(_ReadWriteBarrier) + #else + #define _ReadWriteBarrier() + #endif + + typedef volatile LONG AtomicInt32; + + #ifdef PBRT_HAS_64_BIT_ATOMICS + typedef volatile LONGLONG AtomicInt64; + #endif // 64-bit +#else + typedef volatile int32_t AtomicInt32; + #ifdef PBRT_HAS_64_BIT_ATOMICS + typedef volatile int64_t AtomicInt64; + #endif +#endif // !PBRT_IS_WINDOWS +inline int32_t AtomicAdd(AtomicInt32 *v, int32_t delta) { + PBRT_ATOMIC_MEMORY_OP(); +#if defined(PBRT_IS_WINDOWS) + // Do atomic add with MSVC inline assembly +#if (PBRT_POINTER_SIZE == 8) + return InterlockedAdd(v, delta); +#else + int32_t result; + _ReadWriteBarrier(); + __asm { + __asm mov edx, v + __asm mov eax, delta + __asm lock xadd [edx], eax + __asm mov result, eax + } + _ReadWriteBarrier(); + return result + delta; +#endif +#elif defined(PBRT_IS_APPLE_PPC) + return OSAtomicAdd32Barrier(delta, v); +#else + // Do atomic add with gcc x86 inline assembly + int32_t origValue; + __asm__ __volatile__("lock\n" + "xaddl %0,%1" + : "=r"(origValue), "=m"(*v) : "0"(delta) + : "memory"); + return origValue + delta; +#endif +} + + +inline int32_t AtomicCompareAndSwap(AtomicInt32 *v, int32_t newValue, + int32_t oldValue); +inline int32_t AtomicCompareAndSwap(AtomicInt32 *v, int32_t newValue, int32_t oldValue) { + PBRT_ATOMIC_MEMORY_OP(); +#if defined(PBRT_IS_WINDOWS) + return InterlockedCompareExchange(v, newValue, oldValue); +#elif defined(PBRT_IS_APPLE_PPC) + return OSAtomicCompareAndSwap32Barrier(oldValue, newValue, v); +#else + int32_t result; + __asm__ __volatile__("lock\ncmpxchgl %2,%1" + : "=a"(result), "=m"(*v) + : "q"(newValue), "0"(oldValue) + : "memory"); + return result; +#endif +} + + +template +inline T *AtomicCompareAndSwapPointer(T **v, T *newValue, T *oldValue) { + PBRT_ATOMIC_MEMORY_OP(); +#if defined(PBRT_IS_WINDOWS) + return InterlockedCompareExchange(v, newValue, oldValue); +#elif defined(PBRT_IS_APPLE_PPC) + #ifdef PBRT_HAS_64_BIT_ATOMICS + return OSAtomicCompareAndSwap64Barrier(oldValue, newValue, v); + #else + return OSAtomicCompareAndSwap32Barrier(oldValue, newValue, v); + #endif +#else + T *result; + __asm__ __volatile__("lock\ncmpxchg" +#ifdef PBRT_HAS_64_BIT_ATOMICS + "q" +#else + "l" +#endif // 64 bit atomics + " %2,%1" + : "=a"(result), "=m"(*v) + : "q"(newValue), "0"(oldValue) + : "memory"); + return result; +#endif +} + + +#ifdef PBRT_HAS_64_BIT_ATOMICS +inline int64_t AtomicAdd(AtomicInt64 *v, int64_t delta) { + PBRT_ATOMIC_MEMORY_OP(); +#ifdef PBRT_IS_WINDOWS + return InterlockedAdd64(v, delta); +#elif defined(PBRT_IS_APPLE_PPC) + return OSAtomicAdd64Barrier(delta, v); +#else + int64_t result; + __asm__ __volatile__("lock\nxaddq %0,%1" + : "=r"(result), "=m"(*v) + : "0"(delta) + : "memory"); + return result + delta; +#endif +} + + + +inline int64_t AtomicCompareAndSwap(AtomicInt64 *v, int64_t newValue, int64_t oldValue) { + PBRT_ATOMIC_MEMORY_OP(); +#if defined(PBRT_IS_WINDOWS) + return InterlockedCompareExchange64(v, newValue, oldValue); +#elif defined(PBRT_IS_APPLE_PPC) + return OSAtomicCompareAndSwap64Barrier(oldValue, newValue, v); +#else + int64_t result; + __asm__ __volatile__("lock\ncmpxchgq %2,%1" + : "=a"(result), "=m"(*v) + : "q"(newValue), "0"(oldValue) + : "memory"); + return result; +#endif +} + + +#endif // PBRT_HAS_64_BIT_ATOMICS +inline float AtomicAdd(volatile float *val, float delta) { + PBRT_ATOMIC_MEMORY_OP(); + union bits { float f; int32_t i; }; + bits oldVal, newVal; + do { + // On IA32/x64, adding a PAUSE instruction in compare/exchange loops + // is recommended to improve performance. (And it does!) +#if (defined(__i386__) || defined(__amd64__)) + __asm__ __volatile__ ("pause\n"); +#endif + oldVal.f = *val; + newVal.f = oldVal.f + delta; + } while (AtomicCompareAndSwap(((AtomicInt32 *)val), + newVal.i, oldVal.i) != oldVal.i); + return newVal.f; +} + + +struct MutexLock; +class Mutex { +public: + static Mutex *Create(); + static void Destroy(Mutex *m); +private: + // Mutex Private Methods + Mutex(); + ~Mutex(); + friend struct MutexLock; + Mutex(Mutex &); + Mutex &operator=(const Mutex &); + + // System-dependent mutex implementation +#if defined(PBRT_IS_WINDOWS) + CRITICAL_SECTION criticalSection; +#else + pthread_mutex_t mutex; +#endif +}; + + +struct MutexLock { + MutexLock(Mutex &m); + ~MutexLock(); +private: + Mutex &mutex; + MutexLock(const MutexLock &); + MutexLock &operator=(const MutexLock &); +}; + + +class RWMutex { +public: + static RWMutex *Create(); + static void Destroy(RWMutex *m); +private: + // RWMutex Private Methods + RWMutex(); + ~RWMutex(); + friend struct RWMutexLock; + RWMutex(RWMutex &); + RWMutex &operator=(const RWMutex &); + + // System-dependent rw mutex implementation +#if defined(PBRT_IS_WINDOWS) + void AcquireRead(); + void ReleaseRead(); + void AcquireWrite(); + void ReleaseWrite(); + + LONG numWritersWaiting; + LONG numReadersWaiting; + + // HIWORD is writer active flag; + // LOWORD is readers active count; + DWORD activeWriterReaders; + + HANDLE hReadyToRead; + HANDLE hReadyToWrite; + CRITICAL_SECTION cs; +#else + pthread_rwlock_t mutex; +#endif +}; + + +enum RWMutexLockType { READ, WRITE }; +struct RWMutexLock { + RWMutexLock(RWMutex &m, RWMutexLockType t); + ~RWMutexLock(); + void UpgradeToWrite(); + void DowngradeToRead(); +private: + RWMutexLockType type; + RWMutex &mutex; + RWMutexLock(const RWMutexLock &); + RWMutexLock &operator=(const RWMutexLock &); +}; + + +class Semaphore { +public: + // Semaphore Public Methods + Semaphore(); + ~Semaphore(); + void Post(int count = 1); + void Wait(); + bool TryWait(); +private: + // Semaphore Private Data +#if defined(PBRT_IS_WINDOWS) + HANDLE handle; +#else + sem_t *sem; + static int count; +#endif +}; + + +class ConditionVariable { +public: + // ConditionVariable Public Methods + ConditionVariable(); + ~ConditionVariable(); + void Lock(); + void Unlock(); + void Wait(); + void Signal(); +private: + // ConditionVariable Private Data +#if !defined(PBRT_IS_WINDOWS) + pthread_mutex_t mutex; + pthread_cond_t cond; +#else + // Count of the number of waiters. + uint32_t waitersCount; + // Serialize access to . + CRITICAL_SECTION waitersCountMutex, conditionMutex; + // Signal and broadcast event HANDLEs. + enum { SIGNAL = 0, BROADCAST=1, NUM_EVENTS=2 }; + HANDLE events[NUM_EVENTS]; +#endif +}; + + +void TasksInit(); +void TasksCleanup(); +class Task { +public: + virtual ~Task(); + virtual void Run() = 0; +}; + + +void EnqueueTasks(const vector &tasks); +void WaitForAllTasks(); +int NumSystemCores(); + +#endif // PBRT_CORE_PARALLEL_H diff --git a/core/paramset.cpp b/core/paramset.cpp new file mode 100644 index 0000000..1027496 --- /dev/null +++ b/core/paramset.cpp @@ -0,0 +1,624 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/paramset.cpp* +#include "stdafx.h" +#include "paramset.h" +#include "floatfile.h" +#include "textures/constant.h" + +// ParamSet Macros +#define ADD_PARAM_TYPE(T, vec) \ + (vec).push_back(new ParamSetItem(name, (T *)data, nItems)) +#define LOOKUP_PTR(vec) \ + for (uint32_t i = 0; i < (vec).size(); ++i) \ + if ((vec)[i]->name == name) { \ + *nItems = (vec)[i]->nItems; \ + (vec)[i]->lookedUp = true; \ + return (vec)[i]->data; \ + } \ + return NULL +#define LOOKUP_ONE(vec) \ + for (uint32_t i = 0; i < (vec).size(); ++i) { \ + if ((vec)[i]->name == name && \ + (vec)[i]->nItems == 1) { \ + (vec)[i]->lookedUp = true; \ + return *((vec)[i]->data); \ +} } \ + return d + +// ParamSet Methods +void ParamSet::AddFloat(const string &name, const float *data, + int nItems) { + EraseFloat(name); + floats.push_back(new ParamSetItem(name, data, nItems)); +} + + +void ParamSet::AddInt(const string &name, const int *data, int nItems) { + EraseInt(name); + ADD_PARAM_TYPE(int, ints); +} + + +void ParamSet::AddBool(const string &name, const bool *data, int nItems) { + EraseBool(name); + ADD_PARAM_TYPE(bool, bools); +} + + +void ParamSet::AddPoint(const string &name, const Point *data, int nItems) { + ErasePoint(name); + ADD_PARAM_TYPE(Point, points); +} + + +void ParamSet::AddVector(const string &name, const Vector *data, int nItems) { + EraseVector(name); + ADD_PARAM_TYPE(Vector, vectors); +} + + +void ParamSet::AddNormal(const string &name, const Normal *data, int nItems) { + EraseNormal(name); + ADD_PARAM_TYPE(Normal, normals); +} + + +void ParamSet::AddRGBSpectrum(const string &name, const float *data, int nItems) { + EraseSpectrum(name); + Assert(nItems % 3 == 0); + nItems /= 3; + Spectrum *s = new Spectrum[nItems]; + for (int i = 0; i < nItems; ++i) + s[i] = Spectrum::FromRGB(&data[3*i]); + spectra.push_back(new ParamSetItem(name, s, nItems)); + delete[] s; +} + + +void ParamSet::AddXYZSpectrum(const string &name, const float *data, int nItems) { + EraseSpectrum(name); + Assert(nItems % 3 == 0); + nItems /= 3; + Spectrum *s = new Spectrum[nItems]; + for (int i = 0; i < nItems; ++i) + s[i] = Spectrum::FromXYZ(&data[3*i]); + spectra.push_back(new ParamSetItem(name, s, nItems)); + delete[] s; +} + + +void ParamSet::AddBlackbodySpectrum(const string &name, const float *data, + int nItems) { + EraseSpectrum(name); + Assert(nItems % 2 == 0); // temperature (K), scale, ... + nItems /= 2; + Spectrum *s = new Spectrum[nItems]; + float *v = new float[nCIESamples]; + for (int i = 0; i < nItems; ++i) { + Blackbody(CIE_lambda, nCIESamples, data[2*i], v); + s[i] = data[2*i+1] * Spectrum::FromSampled(CIE_lambda, v, nCIESamples); + } + spectra.push_back(new ParamSetItem(name, s, nItems)); + delete[] s; + delete[] v; +} + + +void ParamSet::AddSampledSpectrum(const string &name, const float *data, + int nItems) { + EraseSpectrum(name); + Assert(nItems % 2 == 0); + nItems /= 2; + float *wl = new float[nItems], *v = new float[nItems]; + for (int i = 0; i < nItems; ++i) { + wl[i] = data[2*i]; + v[i] = data[2*i+1]; + } + Spectrum s = Spectrum::FromSampled(wl, v, nItems); + spectra.push_back(new ParamSetItem(name, &s, 1)); +} + + +void ParamSet::AddSampledSpectrumFiles(const string &name, const char **names, + int nItems) { + EraseSpectrum(name); + Spectrum *s = new Spectrum[nItems]; + for (int i = 0; i < nItems; ++i) { + string fn = AbsolutePath(ResolveFilename(names[i])); + if (cachedSpectra.find(fn) != cachedSpectra.end()) { + s[i] = cachedSpectra[fn]; + continue; + } + + vector vals; + if (!ReadFloatFile(fn.c_str(), &vals)) { + Warning("Unable to read SPD file \"%s\". Using black distribution.", + fn.c_str()); + s[i] = Spectrum(0.); + } + else { + if (vals.size() % 2) { + Warning("Extra value found in spectrum file \"%s\". " + "Ignoring it.", fn.c_str()); + } + vector wls, v; + for (uint32_t j = 0; j < vals.size() / 2; ++j) { + wls.push_back(vals[2*j]); + v.push_back(vals[2*j+1]); + } + s[i] = Spectrum::FromSampled(&wls[0], &v[0], wls.size()); + } + cachedSpectra[fn] = s[i]; + } + + spectra.push_back(new ParamSetItem(name, s, nItems)); + delete[] s; +} + + +map ParamSet::cachedSpectra; +void ParamSet::AddString(const string &name, const string *data, int nItems) { + EraseString(name); + ADD_PARAM_TYPE(string, strings); +} + + +void ParamSet::AddTexture(const string &name, const string &value) { + EraseTexture(name); + textures.push_back(new ParamSetItem(name, (string *)&value, 1)); +} + + +bool ParamSet::EraseInt(const string &n) { + for (uint32_t i = 0; i < ints.size(); ++i) + if (ints[i]->name == n) { + ints.erase(ints.begin() + i); + return true; + } + return false; +} + + +bool ParamSet::EraseBool(const string &n) { + for (uint32_t i = 0; i < bools.size(); ++i) + if (bools[i]->name == n) { + bools.erase(bools.begin() + i); + return true; + } + return false; +} + + +bool ParamSet::EraseFloat(const string &n) { + for (uint32_t i = 0; i < floats.size(); ++i) + if (floats[i]->name == n) { + floats.erase(floats.begin() + i); + return true; + } + return false; +} + + +bool ParamSet::ErasePoint(const string &n) { + for (uint32_t i = 0; i < points.size(); ++i) + if (points[i]->name == n) { + points.erase(points.begin() + i); + return true; + } + return false; +} + + +bool ParamSet::EraseVector(const string &n) { + for (uint32_t i = 0; i < vectors.size(); ++i) + if (vectors[i]->name == n) { + vectors.erase(vectors.begin() + i); + return true; + } + return false; +} + + +bool ParamSet::EraseNormal(const string &n) { + for (uint32_t i = 0; i < normals.size(); ++i) + if (normals[i]->name == n) { + normals.erase(normals.begin() + i); + return true; + } + return false; +} + + +bool ParamSet::EraseSpectrum(const string &n) { + for (uint32_t i = 0; i < spectra.size(); ++i) + if (spectra[i]->name == n) { + spectra.erase(spectra.begin() + i); + return true; + } + return false; +} + + +bool ParamSet::EraseString(const string &n) { + for (uint32_t i = 0; i < strings.size(); ++i) + if (strings[i]->name == n) { + strings.erase(strings.begin() + i); + return true; + } + return false; +} + + +bool ParamSet::EraseTexture(const string &n) { + for (uint32_t i = 0; i < textures.size(); ++i) + if (textures[i]->name == n) { + textures.erase(textures.begin() + i); + return true; + } + return false; +} + + +float ParamSet::FindOneFloat(const string &name, float d) const { + for (uint32_t i = 0; i < floats.size(); ++i) + if (floats[i]->name == name && floats[i]->nItems == 1) { + floats[i]->lookedUp = true; + return *(floats[i]->data); + } + return d; +} + + +const float *ParamSet::FindFloat(const string &name, int *n) const { + for (uint32_t i = 0; i < floats.size(); ++i) + if (floats[i]->name == name) { + *n = floats[i]->nItems; + floats[i]->lookedUp = true; + return floats[i]->data; + } + return NULL; +} + + +const int *ParamSet::FindInt(const string &name, int *nItems) const { + LOOKUP_PTR(ints); +} + + +const bool *ParamSet::FindBool(const string &name, int *nItems) const { + LOOKUP_PTR(bools); +} + + +int ParamSet::FindOneInt(const string &name, int d) const { + LOOKUP_ONE(ints); +} + + +bool ParamSet::FindOneBool(const string &name, bool d) const { + LOOKUP_ONE(bools); +} + + +const Point *ParamSet::FindPoint(const string &name, int *nItems) const { + LOOKUP_PTR(points); +} + + +Point ParamSet::FindOnePoint(const string &name, const Point &d) const { + LOOKUP_ONE(points); +} + + +const Vector *ParamSet::FindVector(const string &name, int *nItems) const { + LOOKUP_PTR(vectors); +} + + +Vector ParamSet::FindOneVector(const string &name, const Vector &d) const { + LOOKUP_ONE(vectors); +} + + +const Normal *ParamSet::FindNormal(const string &name, int *nItems) const { + LOOKUP_PTR(normals); +} + + +Normal ParamSet::FindOneNormal(const string &name, const Normal &d) const { + LOOKUP_ONE(normals); +} + + +const Spectrum *ParamSet::FindSpectrum(const string &name, int *nItems) const { + LOOKUP_PTR(spectra); +} + + +Spectrum ParamSet::FindOneSpectrum(const string &name, const Spectrum &d) const { + LOOKUP_ONE(spectra); +} + + +const string *ParamSet::FindString(const string &name, int *nItems) const { + LOOKUP_PTR(strings); +} + + +string ParamSet::FindOneString(const string &name, const string &d) const { + LOOKUP_ONE(strings); +} + + +string ParamSet::FindOneFilename(const string &name, const string &d) const { + string filename = FindOneString(name, ""); + if (filename == "") + return d; + filename = AbsolutePath(ResolveFilename(filename)); + return filename; +} + + +string ParamSet::FindTexture(const string &name) const { + string d = ""; + LOOKUP_ONE(textures); +} + + +void ParamSet::ReportUnused() const { +#define CHECK_UNUSED(v) \ + for (i = 0; i < (v).size(); ++i) \ + if (!(v)[i]->lookedUp) \ + Warning("Parameter \"%s\" not used", \ + (v)[i]->name.c_str()) + uint32_t i; + CHECK_UNUSED(ints); CHECK_UNUSED(bools); + CHECK_UNUSED(floats); CHECK_UNUSED(points); + CHECK_UNUSED(vectors); CHECK_UNUSED(normals); + CHECK_UNUSED(spectra); CHECK_UNUSED(strings); + CHECK_UNUSED(textures); +} + + +void ParamSet::Clear() { +#define DEL_PARAMS(name) \ + (name).erase((name).begin(), (name).end()) + DEL_PARAMS(ints); DEL_PARAMS(bools); + DEL_PARAMS(floats); DEL_PARAMS(points); + DEL_PARAMS(vectors); DEL_PARAMS(normals); + DEL_PARAMS(spectra); DEL_PARAMS(strings); + DEL_PARAMS(textures); +#undef DEL_PARAMS +} + + +string ParamSet::ToString() const { + string ret; + uint32_t i; + int j; + string typeString; + const int bufLen = 48*1024*1024; + static char *buf = new char[bufLen]; + char *bufEnd = buf + bufLen; + for (i = 0; i < ints.size(); ++i) { + char *bufp = buf; + *bufp = '\0'; + const Reference > &item = ints[i]; + typeString = "integer "; + // Print _ParamSetItem_ declaration, determine how many to print + int nPrint = item->nItems; + ret += string("\""); + ret += typeString; + ret += item->name; + ret += string("\""); + ret += string(" ["); + for (j = 0; j < nPrint; ++j) + bufp += snprintf(bufp, bufEnd - bufp, "%d ", item->data[j]); + ret += buf; + ret += string("] "); + } + for (i = 0; i < bools.size(); ++i) { + char *bufp = buf; + *bufp = '\0'; + const Reference > &item = bools[i]; + typeString = "bool "; + // Print _ParamSetItem_ declaration, determine how many to print + int nPrint = item->nItems; + ret += string("\""); + ret += typeString; + ret += item->name; + ret += string("\""); + ret += string(" ["); + for (j = 0; j < nPrint; ++j) + bufp += snprintf(bufp, bufEnd - bufp, "\"%s\" ", item->data[j] ? "true" : "false"); + ret += buf; + ret += string("] "); + } + for (i = 0; i < floats.size(); ++i) { + char *bufp = buf; + *bufp = '\0'; + const Reference > &item = floats[i]; + typeString = "float "; + // Print _ParamSetItem_ declaration, determine how many to print + int nPrint = item->nItems; + ret += string("\""); + ret += typeString; + ret += item->name; + ret += string("\""); + ret += string(" ["); + for (j = 0; j < nPrint; ++j) + bufp += snprintf(bufp, bufEnd - bufp, "%.8g ", item->data[j]); + ret += buf; + ret += string("] "); + } + for (i = 0; i < points.size(); ++i) { + char *bufp = buf; + *bufp = '\0'; + const Reference > &item = points[i]; + typeString = "point "; + // Print _ParamSetItem_ declaration, determine how many to print + int nPrint = item->nItems; + ret += string("\""); + ret += typeString; + ret += item->name; + ret += string("\""); + ret += string(" ["); + for (j = 0; j < nPrint; ++j) + bufp += snprintf(bufp, bufEnd - bufp, "%.8g %.8g %.8g ", item->data[j].x, + item->data[j].y, item->data[j].z); + ret += buf; + ret += string("] "); + } + for (i = 0; i < vectors.size(); ++i) { + char *bufp = buf; + *bufp = '\0'; + const Reference > &item = vectors[i]; + typeString = "vector "; + // Print _ParamSetItem_ declaration, determine how many to print + int nPrint = item->nItems; + ret += string("\""); + ret += typeString; + ret += item->name; + ret += string("\""); + ret += string(" ["); + for (j = 0; j < nPrint; ++j) + bufp += snprintf(bufp, bufEnd - bufp, "%.8g %.8g %.8g ", item->data[j].x, + item->data[j].y, item->data[j].z); + ret += buf; + ret += string("] "); + } + for (i = 0; i < normals.size(); ++i) { + char *bufp = buf; + *bufp = '\0'; + const Reference > &item = normals[i]; + typeString = "normal "; + // Print _ParamSetItem_ declaration, determine how many to print + int nPrint = item->nItems; + ret += string("\""); + ret += typeString; + ret += item->name; + ret += string("\""); + ret += string(" ["); + for (j = 0; j < nPrint; ++j) + bufp += snprintf(bufp, bufEnd - bufp, "%.8g %.8g %.8g ", item->data[j].x, + item->data[j].y, item->data[j].z); + ret += buf; + ret += string("] "); + } + for (i = 0; i < strings.size(); ++i) { + char *bufp = buf; + *bufp = '\0'; + const Reference > &item = strings[i]; + typeString = "string "; + // Print _ParamSetItem_ declaration, determine how many to print + int nPrint = item->nItems; + ret += string("\""); + ret += typeString; + ret += item->name; + ret += string("\""); + ret += string(" ["); + for (j = 0; j < nPrint; ++j) + bufp += snprintf(bufp, bufEnd - bufp, "\"%s\" ", item->data[j].c_str()); + ret += buf; + ret += string("] "); + } + for (i = 0; i < textures.size(); ++i) { + char *bufp = buf; + *bufp = '\0'; + const Reference > &item = textures[i]; + typeString = "texture "; + // Print _ParamSetItem_ declaration, determine how many to print + int nPrint = item->nItems; + ret += string("\""); + ret += typeString; + ret += item->name; + ret += string("\""); + ret += string(" ["); + for (j = 0; j < nPrint; ++j) + bufp += snprintf(bufp, bufEnd - bufp, "\"%s\" ", item->data[j].c_str()); + ret += buf; + ret += string("] "); + } + for (i = 0; i < spectra.size(); ++i) { + char *bufp = buf; + *bufp = '\0'; + const Reference > &item = spectra[i]; + typeString = "color "; + // Print _ParamSetItem_ declaration, determine how many to print + int nPrint = item->nItems; + ret += string("\""); + ret += typeString; + ret += item->name; + ret += string("\""); + ret += string(" ["); + for (j = 0; j < nPrint; ++j) { + float rgb[3]; + item->data[j].ToRGB(rgb); + bufp += snprintf(bufp, bufEnd - bufp, "%.8g %.8g %.8g ", rgb[0], rgb[1], rgb[2]); + } + ret += buf; + ret += string("] "); + } + return ret; +} + + +// TextureParams Method Definitions +Reference > +TextureParams::GetSpectrumTexture(const string &n, + const Spectrum &def) const { + string name = geomParams.FindTexture(n); + if (name == "") name = materialParams.FindTexture(n); + if (name != "") { + if (spectrumTextures.find(name) != spectrumTextures.end()) + return spectrumTextures[name]; + else + Error("Couldn't find spectrum texture named \"%s\" " + "for parameter \"%s\"", name.c_str(), n.c_str()); + } + Spectrum val = geomParams.FindOneSpectrum(n, + materialParams.FindOneSpectrum(n, def)); + return new ConstantTexture(val); +} + + +Reference > TextureParams::GetFloatTexture(const string &n, + float def) const { + string name = geomParams.FindTexture(n); + if (name == "") name = materialParams.FindTexture(n); + if (name != "") { + if (floatTextures.find(name) != floatTextures.end()) + return floatTextures[name]; + else + Error("Couldn't find float texture named \"%s\" for parameter \"%s\"", + name.c_str(), n.c_str()); + } + float val = geomParams.FindOneFloat(n, + materialParams.FindOneFloat(n, def)); + return new ConstantTexture(val); +} + + diff --git a/core/paramset.h b/core/paramset.h new file mode 100644 index 0000000..76623ce --- /dev/null +++ b/core/paramset.h @@ -0,0 +1,193 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_PARAMSET_H +#define PBRT_CORE_PARAMSET_H + +// core/paramset.h* +#include "pbrt.h" +#include "fileutil.h" +#include "geometry.h" +#include "texture.h" +#include "spectrum.h" + #if (_MSC_VER >= 1400) + #include + #define snprintf _snprintf + #endif +#include +using std::map; + +// ParamSet Declarations +class ParamSet { +public: + // ParamSet Public Methods + ParamSet() { } + void AddFloat(const string &, const float *, int nItems = 1); + void AddInt(const string &, const int *, int nItems); + void AddBool(const string &, const bool *, int nItems); + void AddPoint(const string &, const Point *, int nItems); + void AddVector(const string &, const Vector *, int nItems); + void AddNormal(const string &, const Normal *, int nItems); + void AddString(const string &, const string *, int nItems); + void AddTexture(const string &, const string &); + void AddRGBSpectrum(const string &, const float *, int nItems); + void AddXYZSpectrum(const string &, const float *, int nItems); + void AddBlackbodySpectrum(const string &, const float *, int nItems); + void AddSampledSpectrumFiles(const string &, const char **, int nItems); + void AddSampledSpectrum(const string &, const float *, int nItems); + bool EraseInt(const string &); + bool EraseBool(const string &); + bool EraseFloat(const string &); + bool ErasePoint(const string &); + bool EraseVector(const string &); + bool EraseNormal(const string &); + bool EraseSpectrum(const string &); + bool EraseString(const string &); + bool EraseTexture(const string &); + float FindOneFloat(const string &, float d) const; + int FindOneInt(const string &, int d) const; + bool FindOneBool(const string &, bool d) const; + Point FindOnePoint(const string &, const Point &d) const; + Vector FindOneVector(const string &, const Vector &d) const; + Normal FindOneNormal(const string &, const Normal &d) const; + Spectrum FindOneSpectrum(const string &, + const Spectrum &d) const; + string FindOneString(const string &, const string &d) const; + string FindOneFilename(const string &, const string &d) const; + string FindTexture(const string &) const; + const float *FindFloat(const string &, int *nItems) const; + const int *FindInt(const string &, int *nItems) const; + const bool *FindBool(const string &, int *nItems) const; + const Point *FindPoint(const string &, int *nItems) const; + const Vector *FindVector(const string &, int *nItems) const; + const Normal *FindNormal(const string &, int *nItems) const; + const Spectrum *FindSpectrum(const string &, int *nItems) const; + const string *FindString(const string &, int *nItems) const; + void ReportUnused() const; + void Clear(); + string ToString() const; + +private: + // ParamSet Private Data + vector > > bools; + vector > > ints; + vector > > floats; + vector > > points; + vector > > vectors; + vector > > normals; + vector > > spectra; + vector > > strings; + vector > > textures; + static map cachedSpectra; +}; + + +template struct ParamSetItem : public ReferenceCounted { + // ParamSetItem Public Methods + ParamSetItem(const string &name, const T *val, int nItems = 1); + ~ParamSetItem() { + delete[] data; + } + + // ParamSetItem Data + string name; + int nItems; + T *data; + mutable bool lookedUp; +}; + + + +// ParamSetItem Methods +template +ParamSetItem::ParamSetItem(const string &n, const T *v, int ni) { + name = n; + nItems = ni; + data = new T[nItems]; + for (int i = 0; i < nItems; ++i) data[i] = v[i]; + lookedUp = false; +} + + + +// TextureParams Declarations +class TextureParams { +public: + // TextureParams Public Methods + TextureParams(const ParamSet &geomp, const ParamSet &matp, + map > > &ft, + map > > &st) + : floatTextures(ft), spectrumTextures(st), + geomParams(geomp), materialParams(matp) { + } + Reference > GetSpectrumTexture(const string &name, + const Spectrum &def) const; + Reference > GetFloatTexture(const string &name, + float def) const; + float FindFloat(const string &n, float d) const { + return geomParams.FindOneFloat(n, materialParams.FindOneFloat(n, d)); + } + string FindString(const string &n, const string &d = "") const { + return geomParams.FindOneString(n, materialParams.FindOneString(n, d)); + } + string FindFilename(const string &n, const string &d = "") const { + return geomParams.FindOneFilename(n, materialParams.FindOneFilename(n, d)); + } + int FindInt(const string &n, int d) const { + return geomParams.FindOneInt(n, materialParams.FindOneInt(n, d)); + } + bool FindBool(const string &n, bool d) const { + return geomParams.FindOneBool(n, materialParams.FindOneBool(n, d)); + } + Point FindPoint(const string &n, const Point &d) const { + return geomParams.FindOnePoint(n, materialParams.FindOnePoint(n, d)); + } + Vector FindVector(const string &n, const Vector &d) const { + return geomParams.FindOneVector(n, materialParams.FindOneVector(n, d)); + } + Normal FindNormal(const string &n, const Normal &d) const { + return geomParams.FindOneNormal(n, materialParams.FindOneNormal(n, d)); + } + Spectrum FindSpectrum(const string &n, const Spectrum &d) const { + return geomParams.FindOneSpectrum(n, materialParams.FindOneSpectrum(n, d)); + } + void ReportUnused() const { + geomParams.ReportUnused(); + materialParams.ReportUnused(); + } + const ParamSet &GetGeomParams() const { return geomParams; } + const ParamSet &GetMaterialParams() const { return materialParams; } +private: + // TextureParams Private Data + map > > &floatTextures; + map > > &spectrumTextures; + const ParamSet &geomParams, &materialParams; +}; + + + +#endif // PBRT_CORE_PARAMSET_H diff --git a/core/parser.cpp b/core/parser.cpp new file mode 100644 index 0000000..b2b4111 --- /dev/null +++ b/core/parser.cpp @@ -0,0 +1,60 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/parser.cpp* +#include "stdafx.h" +#include "parser.h" +#include "fileutil.h" + +// Parsing Global Interface +bool ParseFile(const string &filename) { + extern FILE *yyin; + extern int yyparse(void); + extern string current_file; + extern int line_num; + extern int yydebug; + + if (getenv("PBRT_YYDEBUG") != NULL) + yydebug = 1; + + if (filename == "-") + yyin = stdin; + else { + yyin = fopen(filename.c_str(), "r"); + SetSearchDirectory(DirectoryContaining(filename)); + } + + if (yyin != NULL) { + current_file = filename; + if (yyin == stdin) current_file = ""; + line_num = 1; + yyparse(); + if (yyin != stdin) fclose(yyin); + } + current_file = ""; + line_num = 0; + return (yyin != NULL); +} + + diff --git a/core/parser.h b/core/parser.h new file mode 100644 index 0000000..5f25e16 --- /dev/null +++ b/core/parser.h @@ -0,0 +1,35 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_PARSER_H +#define PBRT_CORE_PARSER_H + +// core/parser.h* +#include "pbrt.h" +bool ParseFile(const string &filename); + +#endif // PBRT_CORE_PARSER_H diff --git a/core/pbrt.h b/core/pbrt.h new file mode 100644 index 0000000..653daa1 --- /dev/null +++ b/core/pbrt.h @@ -0,0 +1,315 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#define NOMINMAX +#pragma once +#endif + +#ifndef PBRT_CORE_PBRT_H +#define PBRT_CORE_PBRT_H + +// core/pbrt.h* + +#if defined(_WIN32) || defined(_WIN64) +#define PBRT_IS_WINDOWS +#elif defined(__linux__) +#define PBRT_IS_LINUX +#elif defined(__APPLE__) + #define PBRT_IS_APPLE + #if !(defined(__i386__) || defined(__amd64__)) + #define PBRT_IS_APPLE_PPC + #else + #define PBRT_IS_APPLE_X86 + #endif +#elif defined(__OpenBSD__) +#define PBRT_IS_OPENBSD +#endif + +// Global Include Files +#include +#include +#define _GNU_SOURCE 1 +#include +#include +#include +using std::string; +#include +using std::vector; +#include "error.h" +#if !defined(PBRT_IS_APPLE) && !defined(PBRT_IS_OPENBSD) +#include // for _alloca, memalign +#endif +#if !defined(PBRT_IS_WINDOWS) && !defined(PBRT_IS_APPLE) && !defined(PBRT_IS_OPENBSD) +#include +#endif +#include +#include +using std::min; +using std::max; +using std::swap; +using std::sort; + +// Platform-specific definitions +#if defined(PBRT_IS_WINDOWS) +#include +#define isnan _isnan +#define isinf(f) (!_finite((f))) +#define int8_t __int8 +#define uint8_t unsigned __int8 +#define int16_t __int16 +#define uint16_t unsigned __int16 +#define int32_t __int32 +#define uint32_t unsigned __int32 +#define int64_t __int64 +#define uint64_t unsigned __int64 +#pragma warning (disable : 4305) // double constant assigned to float +#pragma warning (disable : 4244) // int -> float conversion +#pragma warning (disable : 4267) // size_t -> unsigned int conversion +#endif + +#ifdef PBRT_IS_LINUX +#include +#endif // PBRT_IS_LINUX +#if defined(PBRT_IS_WINDOWS) +#define isnan _isnan +#define isinf(f) (!_finite((f))) +#endif + +// Global Macros +#define ALLOCA(TYPE, COUNT) (TYPE *)alloca((COUNT) * sizeof(TYPE)) + +// Global Forward Declarations +class RNG; +class Timer; +class ProgressReporter; +class MemoryArena; +template class BlockedArray; +struct Matrix4x4; +class Mutex; +class RWMutex; +class Shape; +class ParamSet; +template struct ParamSetItem; +struct Options { + Options() { nCores = 0; + quickRender = quiet = openWindow = verbose = false; + imageFile = ""; } + int nCores; + bool quickRender; + bool quiet, verbose; + bool openWindow; + string imageFile; +}; + + +extern Options PbrtOptions; +class TextureParams; +class Scene; +class Renderer; +class Vector; +class Point; +class Normal; +class Ray; +class RayDifferential; +class BBox; +class Transform; +struct DifferentialGeometry; +class Primitive; +struct Intersection; +class GeometricPrimitive; +template class CoefficientSpectrum; +class RGBSpectrum; +class SampledSpectrum; +typedef RGBSpectrum Spectrum; +// typedef SampledSpectrum Spectrum; +class Camera; +class ProjectiveCamera; +class Sampler; +struct CameraSample; +struct Sample; +class Filter; +class Film; +class BxDF; +class BRDF; +class BTDF; +class BSDF; +class Material; +template class Texture; +class VolumeRegion; +class BSSRDF; +class Light; +struct VisibilityTester; +class AreaLight; +struct Distribution1D; +struct Distribution2D; +struct BSDFSample; +struct BSDFSampleOffsets; +struct LightSample; +struct LightSampleOffsets; +class SurfaceIntegrator; +class Integrator; +class VolumeIntegrator; + +// Global Constants +#define PBRT_VERSION "2.0.0" +#ifdef M_PI +#undef M_PI +#endif +#define M_PI 3.14159265358979323846f +#define INV_PI 0.31830988618379067154f +#define INV_TWOPI 0.15915494309189533577f +#define INV_FOURPI 0.07957747154594766788f +#ifndef INFINITY +#define INFINITY FLT_MAX +#endif +#if defined(PBRT_IS_WINDOWS) +#define alloca _alloca +#endif +#ifndef PBRT_L1_CACHE_LINE_SIZE +#define PBRT_L1_CACHE_LINE_SIZE 64 +#endif +#ifndef PBRT_POINTER_SIZE +#if defined(__amd64__) || defined(_M_X64) +#define PBRT_POINTER_SIZE 8 +#elif defined(__i386__) || defined(_M_IX86) +#define PBRT_POINTER_SIZE 4 +#endif +#endif +#ifndef PBRT_HAS_64_BIT_ATOMICS +#if (PBRT_POINTER_SIZE == 8) +#define PBRT_HAS_64_BIT_ATOMICS +#endif +#endif // PBRT_HAS_64_BIT_ATOMICS + +// Global Inline Functions +inline float Lerp(float t, float v1, float v2) { + return (1.f - t) * v1 + t * v2; +} + + +inline float Clamp(float val, float low, float high) { + if (val < low) return low; + else if (val > high) return high; + else return val; +} + + +inline int Clamp(int val, int low, int high) { + if (val < low) return low; + else if (val > high) return high; + else return val; +} + + +inline int Mod(int a, int b) { + int n = int(a/b); + a -= n*b; + if (a < 0) a += b; + return a; +} + + +inline float Radians(float deg) { + return ((float)M_PI/180.f) * deg; +} + + +inline float Degrees(float rad) { + return (180.f/(float)M_PI) * rad; +} + + +inline float Log2(float x) { + static float invLog2 = 1.f / logf(2.f); + return logf(x) * invLog2; +} + + +inline int Floor2Int(float val); +inline int Log2Int(float v) { + return Floor2Int(Log2(v)); +} + + +inline bool IsPowerOf2(int v) { + return (v & (v - 1)) == 0; +} + + +inline uint32_t RoundUpPow2(uint32_t v) { + v--; + v |= v >> 1; v |= v >> 2; + v |= v >> 4; v |= v >> 8; + v |= v >> 16; + return v+1; +} + + +inline int Floor2Int(float val) { + return (int)floorf(val); +} + + +inline int Round2Int(float val) { + return Floor2Int(val + 0.5f); +} + + +inline int Float2Int(float val) { + return (int)val; +} + + +inline int Ceil2Int(float val) { + return (int)ceilf(val); +} + + +#ifdef NDEBUG +#define Assert(expr) ((void)0) +#else +#define Assert(expr) \ + ((expr) ? (void)0 : \ + Severe("Assertion \"%s\" failed in %s, line %d", \ + #expr, __FILE__, __LINE__)) +#endif // NDEBUG +inline bool Quadratic(float A, float B, float C, float *t0, float *t1) { + // Find quadratic discriminant + float discrim = B * B - 4.f * A * C; + if (discrim <= 0.) return false; + float rootDiscrim = sqrtf(discrim); + + // Compute quadratic _t_ values + float q; + if (B < 0) q = -.5f * (B - rootDiscrim); + else q = -.5f * (B + rootDiscrim); + *t0 = q / A; + *t1 = C / q; + if (*t0 > *t1) swap(*t0, *t1); + return true; +} + + + +#endif // PBRT_CORE_PBRT_H diff --git a/core/pbrtlex.cpp b/core/pbrtlex.cpp new file mode 100644 index 0000000..3a45b4a --- /dev/null +++ b/core/pbrtlex.cpp @@ -0,0 +1,2370 @@ +#line 2 "core/pbrtlex.cpp" + +#line 4 "core/pbrtlex.cpp" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart(yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +extern yy_size_t yyleng; + +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + yy_size_t yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; +static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */ +yy_size_t yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart (FILE *input_file ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); +void yy_delete_buffer (YY_BUFFER_STATE b ); +void yy_flush_buffer (YY_BUFFER_STATE b ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state (void ); + +static void yyensure_buffer_stack (void ); +static void yy_load_buffer_state (void ); +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); + +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ); + +void *yyalloc (yy_size_t ); +void *yyrealloc (void *,yy_size_t ); +void yyfree (void * ); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +typedef unsigned char YY_CHAR; + +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; + +typedef int yy_state_type; + +extern int yylineno; + +int yylineno = 1; + +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[] ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; + +#define YY_NUM_RULES 66 +#define YY_END_OF_BUFFER 67 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[394] = + { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 67, 65, 45, 46, 51, 1, 65, 65, 47, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 49, 50, 63, 64, 62, + 63, 2, 3, 66, 45, 0, 47, 47, 47, 0, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 61, 60, + 57, 61, 58, 55, 56, 52, 54, 53, 47, 0, + 47, 48, 48, 6, 48, 48, 48, 48, 48, 48, + + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, + 48, 15, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 59, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 31, 32, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 10, 48, 48, + 48, 48, 48, 48, 48, 19, 48, 48, 48, 48, + + 48, 48, 48, 29, 48, 48, 48, 48, 48, 48, + 41, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 14, 48, 17, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 30, 48, 48, 35, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 16, + 48, 48, 21, 48, 48, 48, 48, 48, 27, 48, + 48, 48, 48, 48, 48, 48, 44, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 24, 48, + 48, 48, 33, 48, 39, 40, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + + 48, 48, 48, 48, 48, 48, 48, 48, 43, 4, + 48, 48, 48, 48, 48, 48, 48, 18, 48, 48, + 23, 48, 26, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 9, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 37, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 22, 48, 48, 48, 48, 48, 48, 48, + 48, 8, 48, 48, 48, 48, 25, 48, 48, 36, + 38, 48, 5, 7, 11, 48, 48, 48, 48, 48, + 48, 48, 12, 48, 48, 48, 42, 13, 20, 48, + 34, 28, 0 + + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 4, 5, 1, 1, 1, 1, 1, + 1, 1, 6, 1, 6, 7, 1, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, + 1, 1, 1, 1, 9, 10, 11, 12, 13, 14, + 12, 12, 15, 12, 12, 16, 17, 18, 19, 20, + 12, 21, 22, 23, 12, 24, 25, 12, 12, 12, + 26, 27, 28, 1, 12, 1, 29, 30, 31, 32, + + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 12, 45, 46, 47, 48, 49, 12, 50, + 51, 12, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[52] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2 + } ; + +static yyconst flex_int16_t yy_base[399] = + { 0, + 0, 0, 49, 51, 430, 429, 0, 0, 0, 0, + 431, 434, 428, 434, 434, 434, 49, 421, 51, 30, + 0, 31, 386, 390, 30, 26, 397, 396, 394, 386, + 38, 51, 34, 379, 378, 434, 434, 434, 434, 434, + 97, 434, 434, 434, 418, 411, 78, 60, 75, 84, + 0, 63, 378, 384, 369, 374, 23, 382, 373, 379, + 380, 375, 366, 50, 367, 369, 356, 53, 358, 363, + 374, 373, 372, 355, 349, 369, 357, 351, 434, 434, + 434, 387, 434, 434, 434, 434, 434, 434, 96, 386, + 385, 359, 354, 0, 361, 344, 355, 356, 341, 362, + + 343, 341, 342, 345, 341, 346, 345, 344, 343, 342, + 342, 340, 343, 327, 330, 325, 323, 333, 319, 323, + 316, 323, 354, 321, 311, 343, 321, 312, 327, 323, + 317, 0, 306, 304, 304, 341, 331, 303, 315, 315, + 305, 311, 298, 295, 301, 307, 306, 291, 308, 288, + 289, 293, 301, 434, 299, 298, 293, 299, 299, 280, + 81, 285, 288, 292, 301, 275, 292, 283, 302, 271, + 303, 271, 269, 281, 280, 0, 0, 289, 280, 265, + 72, 276, 103, 263, 284, 271, 257, 0, 281, 252, + 260, 268, 253, 266, 255, 0, 256, 267, 266, 104, + + 257, 260, 259, 0, 246, 253, 256, 255, 244, 257, + 270, 251, 241, 253, 236, 244, 232, 233, 231, 247, + 0, 224, 0, 226, 240, 232, 224, 237, 227, 226, + 227, 221, 246, 0, 223, 248, 0, 217, 214, 218, + 224, 226, 210, 227, 208, 221, 224, 229, 204, 0, + 205, 217, 0, 215, 212, 214, 199, 197, 0, 198, + 209, 199, 199, 206, 191, 200, 0, 193, 193, 212, + 110, 191, 187, 198, 199, 212, 183, 190, 0, 179, + 192, 187, 0, 176, 112, 0, 189, 179, 175, 173, + 175, 184, 174, 169, 185, 191, 179, 182, 173, 167, + + 179, 162, 173, 172, 171, 161, 165, 166, 0, 0, + 166, 151, 163, 165, 162, 153, 143, 0, 146, 163, + 0, 149, 0, 148, 154, 153, 155, 145, 140, 141, + 138, 145, 0, 138, 134, 133, 145, 137, 145, 128, + 129, 136, 0, 139, 142, 125, 138, 126, 122, 132, + 118, 119, 0, 130, 133, 132, 118, 113, 111, 116, + 123, 0, 114, 111, 120, 106, 0, 94, 93, 0, + 0, 95, 0, 0, 0, 92, 95, 105, 96, 89, + 85, 87, 0, 86, 78, 70, 0, 0, 0, 65, + 0, 0, 434, 144, 146, 148, 94, 150 + + } ; + +static yyconst flex_int16_t yy_def[399] = + { 0, + 393, 1, 394, 394, 395, 395, 396, 396, 396, 396, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 393, 393, 393, 393, 393, + 398, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 397, 397, 397, 397, 397, 397, 397, 397, 397, + + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 393, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 393, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 0, 393, 393, 393, 393, 393 + + } ; + +static yyconst flex_int16_t yy_nxt[486] = + { 0, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 21, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 12, 37, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 39, 40, 39, 40, 46, 47, 49, 47, 56, + 52, 60, 62, 50, 98, 99, 75, 48, 63, 53, + 68, 61, 50, 57, 54, 41, 55, 41, 76, 70, + 69, 71, 89, 50, 49, 47, 72, 50, 106, 90, + 50, 91, 50, 92, 111, 51, 107, 73, 74, 80, + + 81, 112, 190, 89, 82, 209, 392, 50, 50, 93, + 50, 210, 212, 228, 391, 213, 229, 191, 230, 292, + 390, 305, 293, 83, 306, 389, 84, 388, 50, 387, + 85, 386, 385, 384, 307, 383, 382, 381, 86, 380, + 379, 87, 378, 88, 38, 38, 42, 42, 44, 44, + 79, 79, 377, 376, 375, 374, 373, 372, 371, 370, + 369, 368, 367, 366, 365, 364, 363, 362, 361, 360, + 359, 358, 357, 356, 355, 354, 353, 352, 351, 350, + 349, 348, 347, 346, 345, 344, 343, 342, 341, 340, + 339, 338, 337, 336, 335, 334, 333, 332, 331, 330, + + 329, 328, 327, 326, 325, 324, 323, 322, 321, 320, + 319, 318, 317, 316, 315, 314, 313, 312, 311, 310, + 309, 308, 304, 303, 302, 301, 300, 299, 298, 297, + 296, 295, 294, 291, 290, 289, 288, 287, 286, 285, + 284, 283, 282, 281, 280, 279, 278, 277, 276, 275, + 274, 273, 272, 271, 270, 269, 268, 267, 266, 265, + 264, 263, 262, 261, 260, 259, 258, 257, 256, 255, + 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, + 244, 243, 242, 241, 240, 239, 238, 237, 236, 235, + 234, 233, 232, 231, 227, 226, 225, 224, 223, 222, + + 221, 220, 219, 218, 217, 216, 215, 214, 211, 208, + 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, + 197, 196, 195, 194, 193, 192, 189, 188, 187, 186, + 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, + 175, 174, 173, 172, 171, 170, 169, 168, 167, 166, + 165, 164, 163, 162, 161, 160, 159, 158, 157, 156, + 155, 154, 153, 152, 151, 150, 149, 148, 147, 146, + 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, + 135, 134, 133, 132, 131, 130, 129, 128, 127, 126, + 125, 124, 91, 91, 123, 122, 121, 120, 119, 118, + + 117, 116, 115, 114, 113, 110, 109, 108, 105, 104, + 103, 102, 101, 100, 97, 96, 95, 94, 48, 45, + 78, 77, 67, 66, 65, 64, 59, 58, 48, 45, + 393, 43, 43, 11, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393 + } ; + +static yyconst flex_int16_t yy_chk[486] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 3, 4, 4, 17, 17, 19, 19, 22, + 20, 25, 26, 19, 57, 57, 33, 48, 26, 20, + 31, 25, 48, 22, 20, 3, 20, 4, 33, 32, + 31, 32, 49, 19, 47, 47, 32, 49, 64, 50, + 47, 50, 48, 52, 68, 397, 64, 32, 32, 41, + + 41, 68, 161, 89, 41, 181, 390, 49, 89, 52, + 47, 181, 183, 200, 386, 183, 200, 161, 200, 271, + 385, 285, 271, 41, 285, 384, 41, 382, 89, 381, + 41, 380, 379, 378, 285, 377, 376, 372, 41, 369, + 368, 41, 366, 41, 394, 394, 395, 395, 396, 396, + 398, 398, 365, 364, 363, 361, 360, 359, 358, 357, + 356, 355, 354, 352, 351, 350, 349, 348, 347, 346, + 345, 344, 342, 341, 340, 339, 338, 337, 336, 335, + 334, 332, 331, 330, 329, 328, 327, 326, 325, 324, + 322, 320, 319, 317, 316, 315, 314, 313, 312, 311, + + 308, 307, 306, 305, 304, 303, 302, 301, 300, 299, + 298, 297, 296, 295, 294, 293, 292, 291, 290, 289, + 288, 287, 284, 282, 281, 280, 278, 277, 276, 275, + 274, 273, 272, 270, 269, 268, 266, 265, 264, 263, + 262, 261, 260, 258, 257, 256, 255, 254, 252, 251, + 249, 248, 247, 246, 245, 244, 243, 242, 241, 240, + 239, 238, 236, 235, 233, 232, 231, 230, 229, 228, + 227, 226, 225, 224, 222, 220, 219, 218, 217, 216, + 215, 214, 213, 212, 211, 210, 209, 208, 207, 206, + 205, 203, 202, 201, 199, 198, 197, 195, 194, 193, + + 192, 191, 190, 189, 187, 186, 185, 184, 182, 180, + 179, 178, 175, 174, 173, 172, 171, 170, 169, 168, + 167, 166, 165, 164, 163, 162, 160, 159, 158, 157, + 156, 155, 153, 152, 151, 150, 149, 148, 147, 146, + 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, + 135, 134, 133, 131, 130, 129, 128, 127, 126, 125, + 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, + 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, + 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, + 93, 92, 91, 90, 82, 78, 77, 76, 75, 74, + + 73, 72, 71, 70, 69, 67, 66, 65, 63, 62, + 61, 60, 59, 58, 56, 55, 54, 53, 46, 45, + 35, 34, 30, 29, 28, 27, 24, 23, 18, 13, + 11, 6, 5, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int yy_flex_debug; +int yy_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "core/pbrtlex.ll" +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ +/* state used for include file stuff */ +#line 26 "core/pbrtlex.ll" + +#define YY_MAIN 0 +#define YY_NEVER_INTERACTIVE 1 + +#include "pbrt.h" +#include "api.h" +#include "fileutil.h" + +struct ParamArray; + +#if defined(PBRT_IS_WINDOWS) +#pragma warning(disable:4244) +#pragma warning(disable:4065) +#pragma warning(disable:4018) +#pragma warning(disable:4996) +#endif +#include "pbrtparse.hpp" + +struct IncludeInfo { + string filename; + YY_BUFFER_STATE bufState; + int lineNum; +}; + + +vector includeStack; + +extern int line_num; +int str_pos; + +void add_string_char(char c) { + yylval.string[str_pos++] = c; + yylval.string[str_pos] = '\0'; +} + + +void include_push(char *filename) { + if (includeStack.size() > 32) + Severe("Only 32 levels of nested Include allowed in scene files."); + IncludeInfo ii; + extern string current_file; + ii.filename = current_file; + ii.bufState = YY_CURRENT_BUFFER; + ii.lineNum = line_num; + includeStack.push_back(ii); + + current_file = AbsolutePath(ResolveFilename(filename)); + line_num = 1; + + yyin = fopen(current_file.c_str(), "r"); + if (!yyin) + Severe("Unable to open included scene file \"%s\"", current_file.c_str()); + yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE)); +} + + + +void include_pop() { + extern int line_num; + extern string current_file; + fclose(yyin); + yy_delete_buffer(YY_CURRENT_BUFFER); + yy_switch_to_buffer(includeStack.back().bufState); + current_file = includeStack.back().filename; + line_num = includeStack.back().lineNum; + includeStack.pop_back(); +} + + + +#line 781 "core/pbrtlex.cpp" + +#define INITIAL 0 +#define STR 1 +#define COMMENT 2 +#define INCL 3 +#define INCL_FILE 4 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals (void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy (void ); + +int yyget_debug (void ); + +void yyset_debug (int debug_flag ); + +YY_EXTRA_TYPE yyget_extra (void ); + +void yyset_extra (YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in (void ); + +void yyset_in (FILE * in_str ); + +FILE *yyget_out (void ); + +void yyset_out (FILE * out_str ); + +yy_size_t yyget_leng (void ); + +char *yyget_text (void ); + +int yyget_lineno (void ); + +void yyset_lineno (int line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap (void ); +#else +extern int yywrap (void ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (void ); +#else +static int input (void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + yy_size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 101 "core/pbrtlex.ll" + + +#line 968 "core/pbrtlex.cpp" + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 394 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 434 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 103 "core/pbrtlex.ll" +{ BEGIN COMMENT; } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 104 "core/pbrtlex.ll" +/* eat it up */ + YY_BREAK +case 3: +/* rule 3 can match eol */ +YY_RULE_SETUP +#line 105 "core/pbrtlex.ll" +{ line_num++; BEGIN INITIAL; } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 106 "core/pbrtlex.ll" +{ return ACCELERATOR; } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 107 "core/pbrtlex.ll" +{ return ACTIVETRANSFORM; } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 108 "core/pbrtlex.ll" +{ return ALL; } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 109 "core/pbrtlex.ll" +{ return AREALIGHTSOURCE; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 110 "core/pbrtlex.ll" +{ return ATTRIBUTEBEGIN; } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 111 "core/pbrtlex.ll" +{ return ATTRIBUTEEND; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 112 "core/pbrtlex.ll" +{ return CAMERA; } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 113 "core/pbrtlex.ll" +{ return CONCATTRANSFORM; } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 114 "core/pbrtlex.ll" +{ return COORDINATESYSTEM; } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 115 "core/pbrtlex.ll" +{ return COORDSYSTRANSFORM; } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 116 "core/pbrtlex.ll" +{ return ENDTIME; } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 117 "core/pbrtlex.ll" +{ return FILM; } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 118 "core/pbrtlex.ll" +{ return IDENTITY; } + YY_BREAK +case 17: +YY_RULE_SETUP +#line 119 "core/pbrtlex.ll" +{ return INCLUDE; } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 120 "core/pbrtlex.ll" +{ return LIGHTSOURCE; } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 121 "core/pbrtlex.ll" +{ return LOOKAT; } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 122 "core/pbrtlex.ll" +{ return MAKENAMEDMATERIAL; } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 123 "core/pbrtlex.ll" +{ return MATERIAL; } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 124 "core/pbrtlex.ll" +{ return NAMEDMATERIAL; } + YY_BREAK +case 23: +YY_RULE_SETUP +#line 125 "core/pbrtlex.ll" +{ return OBJECTBEGIN; } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 126 "core/pbrtlex.ll" +{ return OBJECTEND; } + YY_BREAK +case 25: +YY_RULE_SETUP +#line 127 "core/pbrtlex.ll" +{ return OBJECTINSTANCE; } + YY_BREAK +case 26: +YY_RULE_SETUP +#line 128 "core/pbrtlex.ll" +{ return PIXELFILTER; } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 129 "core/pbrtlex.ll" +{ return RENDERER; } + YY_BREAK +case 28: +YY_RULE_SETUP +#line 130 "core/pbrtlex.ll" +{ return REVERSEORIENTATION; } + YY_BREAK +case 29: +YY_RULE_SETUP +#line 131 "core/pbrtlex.ll" +{ return ROTATE; } + YY_BREAK +case 30: +YY_RULE_SETUP +#line 132 "core/pbrtlex.ll" +{ return SAMPLER; } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 133 "core/pbrtlex.ll" +{ return SCALE; } + YY_BREAK +case 32: +YY_RULE_SETUP +#line 134 "core/pbrtlex.ll" +{ return SHAPE; } + YY_BREAK +case 33: +YY_RULE_SETUP +#line 135 "core/pbrtlex.ll" +{ return STARTTIME; } + YY_BREAK +case 34: +YY_RULE_SETUP +#line 136 "core/pbrtlex.ll" +{ return SURFACEINTEGRATOR; } + YY_BREAK +case 35: +YY_RULE_SETUP +#line 137 "core/pbrtlex.ll" +{ return TEXTURE; } + YY_BREAK +case 36: +YY_RULE_SETUP +#line 138 "core/pbrtlex.ll" +{ return TRANSFORMBEGIN; } + YY_BREAK +case 37: +YY_RULE_SETUP +#line 139 "core/pbrtlex.ll" +{ return TRANSFORMEND; } + YY_BREAK +case 38: +YY_RULE_SETUP +#line 140 "core/pbrtlex.ll" +{ return TRANSFORMTIMES; } + YY_BREAK +case 39: +YY_RULE_SETUP +#line 141 "core/pbrtlex.ll" +{ return TRANSFORM; } + YY_BREAK +case 40: +YY_RULE_SETUP +#line 142 "core/pbrtlex.ll" +{ return TRANSLATE; } + YY_BREAK +case 41: +YY_RULE_SETUP +#line 143 "core/pbrtlex.ll" +{ return VOLUME; } + YY_BREAK +case 42: +YY_RULE_SETUP +#line 144 "core/pbrtlex.ll" +{ return VOLUMEINTEGRATOR; } + YY_BREAK +case 43: +YY_RULE_SETUP +#line 145 "core/pbrtlex.ll" +{ return WORLDBEGIN; } + YY_BREAK +case 44: +YY_RULE_SETUP +#line 146 "core/pbrtlex.ll" +{ return WORLDEND; } + YY_BREAK +case 45: +YY_RULE_SETUP +#line 147 "core/pbrtlex.ll" +/* do nothing */ + YY_BREAK +case 46: +/* rule 46 can match eol */ +YY_RULE_SETUP +#line 148 "core/pbrtlex.ll" +{ line_num++; } + YY_BREAK +case 47: +YY_RULE_SETUP +#line 149 "core/pbrtlex.ll" +{ + yylval.num = (float) atof(yytext); + return NUM; +} + YY_BREAK +case 48: +YY_RULE_SETUP +#line 155 "core/pbrtlex.ll" +{ + strcpy(yylval.string, yytext); + return ID; +} + YY_BREAK +case 49: +YY_RULE_SETUP +#line 161 "core/pbrtlex.ll" +{ return LBRACK; } + YY_BREAK +case 50: +YY_RULE_SETUP +#line 162 "core/pbrtlex.ll" +{ return RBRACK; } + YY_BREAK +case 51: +YY_RULE_SETUP +#line 163 "core/pbrtlex.ll" +{ BEGIN STR; str_pos = 0; } + YY_BREAK +case 52: +YY_RULE_SETUP +#line 164 "core/pbrtlex.ll" +{add_string_char('\n');} + YY_BREAK +case 53: +YY_RULE_SETUP +#line 165 "core/pbrtlex.ll" +{add_string_char('\t');} + YY_BREAK +case 54: +YY_RULE_SETUP +#line 166 "core/pbrtlex.ll" +{add_string_char('\r');} + YY_BREAK +case 55: +YY_RULE_SETUP +#line 167 "core/pbrtlex.ll" +{add_string_char('\b');} + YY_BREAK +case 56: +YY_RULE_SETUP +#line 168 "core/pbrtlex.ll" +{add_string_char('\f');} + YY_BREAK +case 57: +YY_RULE_SETUP +#line 169 "core/pbrtlex.ll" +{add_string_char('\"');} + YY_BREAK +case 58: +YY_RULE_SETUP +#line 170 "core/pbrtlex.ll" +{add_string_char('\\');} + YY_BREAK +case 59: +YY_RULE_SETUP +#line 171 "core/pbrtlex.ll" +{ + int val = atoi(yytext+1); + while (val > 256) + val -= 256; + add_string_char(val); +} + YY_BREAK +case 60: +/* rule 60 can match eol */ +YY_RULE_SETUP +#line 179 "core/pbrtlex.ll" +{line_num++;} + YY_BREAK +case 61: +YY_RULE_SETUP +#line 180 "core/pbrtlex.ll" +{ add_string_char(yytext[1]);} + YY_BREAK +case 62: +YY_RULE_SETUP +#line 181 "core/pbrtlex.ll" +{BEGIN INITIAL; return STRING;} + YY_BREAK +case 63: +YY_RULE_SETUP +#line 182 "core/pbrtlex.ll" +{add_string_char(yytext[0]);} + YY_BREAK +case 64: +/* rule 64 can match eol */ +YY_RULE_SETUP +#line 183 "core/pbrtlex.ll" +{Error("Unterminated string!");} + YY_BREAK +case 65: +YY_RULE_SETUP +#line 185 "core/pbrtlex.ll" +{ Error( "Illegal character: %c (0x%x)", yytext[0], int(yytext[0])); } + YY_BREAK +case 66: +YY_RULE_SETUP +#line 186 "core/pbrtlex.ll" +ECHO; + YY_BREAK +#line 1396 "core/pbrtlex.cpp" +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(STR): +case YY_STATE_EOF(COMMENT): +case YY_STATE_EOF(INCL): +case YY_STATE_EOF(INCL_FILE): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_c_buf_p); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( yywrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); + register int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + yy_size_t num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + yy_size_t new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart(yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 394 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + register int yy_is_jam; + register char *yy_cp = (yy_c_buf_p); + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 394 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 393); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + yy_size_t offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart(yyin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( ) ) + return 0; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_init_buffer(YY_CURRENT_BUFFER,input_file ); + yy_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void yy_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer(b,file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree((void *) b->yy_ch_buf ); + + yyfree((void *) b ); +} + +#ifndef __cplusplus +extern int isatty (int ); +#endif /* __cplusplus */ + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + yy_flush_buffer(b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (void) +{ + yy_size_t num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer(b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) +{ + + return yy_scan_bytes(yystr,strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n, i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) yyalloc(n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer(buf,n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg ) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} + +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} + +/** Get the length of the current token. + * + */ +yy_size_t yyget_leng (void) +{ + return yyleng; +} + +/** Get the current token. + * + */ + +char *yyget_text (void) +{ + return yytext; +} + +/** Set the current line number. + * @param line_number + * + */ +void yyset_lineno (int line_number ) +{ + + yylineno = line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * in_str ) +{ + yyin = in_str ; +} + +void yyset_out (FILE * out_str ) +{ + yyout = out_str ; +} + +int yyget_debug (void) +{ + return yy_flex_debug; +} + +void yyset_debug (int bdebug ) +{ + yy_flex_debug = bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = 0; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = (char *) 0; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } + + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s ) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size ) +{ + return (void *) malloc( size ); +} + +void *yyrealloc (void * ptr, yy_size_t size ) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void yyfree (void * ptr ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 186 "core/pbrtlex.ll" + + +int yywrap() { + if (includeStack.size() == 0) return 1; + include_pop(); + return 0; +} + + + + diff --git a/core/pbrtlex.ll b/core/pbrtlex.ll new file mode 100644 index 0000000..d193e96 --- /dev/null +++ b/core/pbrtlex.ll @@ -0,0 +1,194 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +/* state used for include file stuff */ +%{ + +#define YY_MAIN 0 +#define YY_NEVER_INTERACTIVE 1 + +#include "pbrt.h" +#include "api.h" +#include "fileutil.h" + +struct ParamArray; + +#if defined(PBRT_IS_WINDOWS) +#pragma warning(disable:4244) +#pragma warning(disable:4065) +#pragma warning(disable:4018) +#pragma warning(disable:4996) +#endif +#include "pbrtparse.hpp" + +struct IncludeInfo { + string filename; + YY_BUFFER_STATE bufState; + int lineNum; +}; + + +vector includeStack; + +extern int line_num; +int str_pos; + +void add_string_char(char c) { + yylval.string[str_pos++] = c; + yylval.string[str_pos] = '\0'; +} + + +void include_push(char *filename) { + if (includeStack.size() > 32) + Severe("Only 32 levels of nested Include allowed in scene files."); + IncludeInfo ii; + extern string current_file; + ii.filename = current_file; + ii.bufState = YY_CURRENT_BUFFER; + ii.lineNum = line_num; + includeStack.push_back(ii); + + current_file = AbsolutePath(ResolveFilename(filename)); + line_num = 1; + + yyin = fopen(current_file.c_str(), "r"); + if (!yyin) + Severe("Unable to open included scene file \"%s\"", current_file.c_str()); + yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); +} + + + +void include_pop() { + extern int line_num; + extern string current_file; + fclose(yyin); + yy_delete_buffer(YY_CURRENT_BUFFER); + yy_switch_to_buffer(includeStack.back().bufState); + current_file = includeStack.back().filename; + line_num = includeStack.back().lineNum; + includeStack.pop_back(); +} + + +%} +%option nounput +WHITESPACE [ \t\r]+ +NUMBER [-+]?([0-9]+|(([0-9]+\.[0-9]*)|(\.[0-9]+)))([eE][-+]?[0-9]+)? +IDENT [a-zA-Z_][a-zA-Z_0-9]* +%x STR COMMENT INCL INCL_FILE +%% + +"#" { BEGIN COMMENT; } +. /* eat it up */ +\n { line_num++; BEGIN INITIAL; } +Accelerator { return ACCELERATOR; } +ActiveTransform { return ACTIVETRANSFORM; } +All { return ALL; } +AreaLightSource { return AREALIGHTSOURCE; } +AttributeBegin { return ATTRIBUTEBEGIN; } +AttributeEnd { return ATTRIBUTEEND; } +Camera { return CAMERA; } +ConcatTransform { return CONCATTRANSFORM; } +CoordinateSystem { return COORDINATESYSTEM; } +CoordSysTransform { return COORDSYSTRANSFORM; } +EndTime { return ENDTIME; } +Film { return FILM; } +Identity { return IDENTITY; } +Include { return INCLUDE; } +LightSource { return LIGHTSOURCE; } +LookAt { return LOOKAT; } +MakeNamedMaterial { return MAKENAMEDMATERIAL; } +Material { return MATERIAL; } +NamedMaterial { return NAMEDMATERIAL; } +ObjectBegin { return OBJECTBEGIN; } +ObjectEnd { return OBJECTEND; } +ObjectInstance { return OBJECTINSTANCE; } +PixelFilter { return PIXELFILTER; } +Renderer { return RENDERER; } +ReverseOrientation { return REVERSEORIENTATION; } +Rotate { return ROTATE; } +Sampler { return SAMPLER; } +Scale { return SCALE; } +Shape { return SHAPE; } +StartTime { return STARTTIME; } +SurfaceIntegrator { return SURFACEINTEGRATOR; } +Texture { return TEXTURE; } +TransformBegin { return TRANSFORMBEGIN; } +TransformEnd { return TRANSFORMEND; } +TransformTimes { return TRANSFORMTIMES; } +Transform { return TRANSFORM; } +Translate { return TRANSLATE; } +Volume { return VOLUME; } +VolumeIntegrator { return VOLUMEINTEGRATOR; } +WorldBegin { return WORLDBEGIN; } +WorldEnd { return WORLDEND; } +{WHITESPACE} /* do nothing */ +\n { line_num++; } +{NUMBER} { + yylval.num = (float) atof(yytext); + return NUM; +} + + +{IDENT} { + strcpy(yylval.string, yytext); + return ID; +} + + +"[" { return LBRACK; } +"]" { return RBRACK; } +\" { BEGIN STR; str_pos = 0; } +\\n {add_string_char('\n');} +\\t {add_string_char('\t');} +\\r {add_string_char('\r');} +\\b {add_string_char('\b');} +\\f {add_string_char('\f');} +\\\" {add_string_char('\"');} +\\\\ {add_string_char('\\');} +\\[0-9]{3} { + int val = atoi(yytext+1); + while (val > 256) + val -= 256; + add_string_char(val); +} + + +\\\n {line_num++;} +\\. { add_string_char(yytext[1]);} +\" {BEGIN INITIAL; return STRING;} +. {add_string_char(yytext[0]);} +\n {Error("Unterminated string!");} + +. { Error( "Illegal character: %c (0x%x)", yytext[0], int(yytext[0])); } +%% +int yywrap() { + if (includeStack.size() == 0) return 1; + include_pop(); + return 0; +} + + + diff --git a/core/pbrtparse.cpp b/core/pbrtparse.cpp new file mode 100644 index 0000000..d48fa7a --- /dev/null +++ b/core/pbrtparse.cpp @@ -0,0 +1,2542 @@ +/* A Bison parser, made by GNU Bison 2.3. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.3" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + STRING = 258, + ID = 259, + NUM = 260, + LBRACK = 261, + RBRACK = 262, + ACCELERATOR = 263, + ACTIVETRANSFORM = 264, + ALL = 265, + AREALIGHTSOURCE = 266, + ATTRIBUTEBEGIN = 267, + ATTRIBUTEEND = 268, + CAMERA = 269, + CONCATTRANSFORM = 270, + COORDINATESYSTEM = 271, + COORDSYSTRANSFORM = 272, + ENDTIME = 273, + FILM = 274, + IDENTITY = 275, + INCLUDE = 276, + LIGHTSOURCE = 277, + LOOKAT = 278, + MAKENAMEDMATERIAL = 279, + MATERIAL = 280, + NAMEDMATERIAL = 281, + OBJECTBEGIN = 282, + OBJECTEND = 283, + OBJECTINSTANCE = 284, + PIXELFILTER = 285, + RENDERER = 286, + REVERSEORIENTATION = 287, + ROTATE = 288, + SAMPLER = 289, + SCALE = 290, + SHAPE = 291, + STARTTIME = 292, + SURFACEINTEGRATOR = 293, + TEXTURE = 294, + TRANSFORMBEGIN = 295, + TRANSFORMEND = 296, + TRANSFORMTIMES = 297, + TRANSFORM = 298, + TRANSLATE = 299, + VOLUME = 300, + VOLUMEINTEGRATOR = 301, + WORLDBEGIN = 302, + WORLDEND = 303, + HIGH_PRECEDENCE = 304 + }; +#endif +/* Tokens. */ +#define STRING 258 +#define ID 259 +#define NUM 260 +#define LBRACK 261 +#define RBRACK 262 +#define ACCELERATOR 263 +#define ACTIVETRANSFORM 264 +#define ALL 265 +#define AREALIGHTSOURCE 266 +#define ATTRIBUTEBEGIN 267 +#define ATTRIBUTEEND 268 +#define CAMERA 269 +#define CONCATTRANSFORM 270 +#define COORDINATESYSTEM 271 +#define COORDSYSTRANSFORM 272 +#define ENDTIME 273 +#define FILM 274 +#define IDENTITY 275 +#define INCLUDE 276 +#define LIGHTSOURCE 277 +#define LOOKAT 278 +#define MAKENAMEDMATERIAL 279 +#define MATERIAL 280 +#define NAMEDMATERIAL 281 +#define OBJECTBEGIN 282 +#define OBJECTEND 283 +#define OBJECTINSTANCE 284 +#define PIXELFILTER 285 +#define RENDERER 286 +#define REVERSEORIENTATION 287 +#define ROTATE 288 +#define SAMPLER 289 +#define SCALE 290 +#define SHAPE 291 +#define STARTTIME 292 +#define SURFACEINTEGRATOR 293 +#define TEXTURE 294 +#define TRANSFORMBEGIN 295 +#define TRANSFORMEND 296 +#define TRANSFORMTIMES 297 +#define TRANSFORM 298 +#define TRANSLATE 299 +#define VOLUME 300 +#define VOLUMEINTEGRATOR 301 +#define WORLDBEGIN 302 +#define WORLDEND 303 +#define HIGH_PRECEDENCE 304 + + + + +/* Copy the first part of user declarations. */ +#line 24 "core/pbrtparse.yy" + +#include "api.h" +#include "pbrt.h" +#include "paramset.h" +#include + +#ifdef PBRT_IS_WINDOWS +#pragma warning(disable:4065) +#pragma warning(disable:4996) +#pragma warning(disable:4018) +#endif // PBRT_IS_WINDOWS + +extern int yylex(); +extern void include_push(char *filename); +int line_num = 0; +string current_file; + +#define YYMAXDEPTH 100000000 + +void yyerror(const char *str) { + Severe("Parsing error: %s", str); +} + + + +struct ParamArray { + ParamArray() { + isString = false; + element_size = allocated = nelems = 0; + array = NULL; + } + bool isString; + int element_size; + int allocated; + int nelems; + void *array; +}; + + + +struct ParamListItem { + ParamListItem(const char *t, ParamArray *array) { + arg = array->array; + name = t; + size = array->nelems; + isString = array->isString; + array->allocated = 0; + array->nelems = 0; + array->array = NULL; + } + const char *name; + void *arg; + int size; + bool isString; +}; + + + +static vector cur_paramlist; + +static ParamArray *cur_array = NULL; + +static void AddArrayElement(void *elem) { + if (cur_array->nelems >= cur_array->allocated) { + cur_array->allocated = 2*cur_array->allocated + 1; + cur_array->array = realloc(cur_array->array, + cur_array->allocated*cur_array->element_size); + } + char *next = ((char *)cur_array->array) + cur_array->nelems * cur_array->element_size; + Assert(cur_array->element_size == 4 || cur_array->element_size == 8); + if (cur_array->element_size == 4) + *((uint32_t *)next) = *((uint32_t *)elem); + else + *((uint64_t *)next) = *((uint64_t *)elem); + cur_array->nelems++; +} + + + +static void ArrayFree(ParamArray *ra) { + if (ra->isString && ra->array) + for (int i = 0; i < ra->nelems; ++i) free(((char **)ra->array)[i]); + free(ra->array); + delete ra; +} + + + +static void FreeArgs() { + for (uint32_t i = 0; i < cur_paramlist.size(); ++i) + free((char *)cur_paramlist[i].arg); + cur_paramlist.erase(cur_paramlist.begin(), cur_paramlist.end()); +} + + + +static bool VerifyArrayLength(ParamArray *arr, int required, + const char *command) { + if (arr->nelems != required) { + Error("\"%s\" requires a %d element array! (%d found)", + command, required, arr->nelems); + return false; + } + return true; +} + + +enum { PARAM_TYPE_INT, PARAM_TYPE_BOOL, PARAM_TYPE_FLOAT, PARAM_TYPE_POINT, + PARAM_TYPE_VECTOR, PARAM_TYPE_NORMAL, PARAM_TYPE_RGB, PARAM_TYPE_XYZ, + PARAM_TYPE_BLACKBODY, PARAM_TYPE_SPECTRUM, + PARAM_TYPE_STRING, PARAM_TYPE_TEXTURE }; +static const char *paramTypeToName(int type); +static void InitParamSet(ParamSet &ps, SpectrumType); +static bool lookupType(const char *name, int *type, string &sname); +#define YYPRINT(file, type, value) { \ + if ((type) == ID || (type) == STRING) \ + fprintf ((file), " %s", (value).string); \ + else if ((type) == NUM) \ + fprintf ((file), " %f", (value).num); \ +} + + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 1 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 148 "core/pbrtparse.yy" +{ +char string[1024]; +float num; +ParamArray *ribarray; +} +/* Line 193 of yacc.c. */ +#line 324 "core/pbrtparse.cpp" + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +/* Copy the second part of user declarations. */ + + +/* Line 216 of yacc.c. */ +#line 337 "core/pbrtparse.cpp" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int i) +#else +static int +YYID (i) + int i; +#endif +{ + return i; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 75 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 118 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 50 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 20 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 66 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 136 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 304 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint8 yyprhs[] = +{ + 0, 0, 3, 5, 6, 7, 8, 10, 12, 17, + 19, 22, 25, 27, 30, 35, 37, 40, 43, 45, + 48, 51, 52, 55, 56, 59, 62, 64, 68, 71, + 74, 77, 81, 83, 85, 89, 92, 95, 98, 102, + 104, 107, 111, 122, 126, 130, 133, 136, 138, 141, + 145, 149, 151, 157, 161, 166, 170, 174, 180, 182, + 184, 188, 191, 196, 200, 204, 206 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 51, 0, -1, 68, -1, -1, -1, -1, 56, -1, + 60, -1, 52, 6, 58, 7, -1, 57, -1, 52, + 59, -1, 58, 59, -1, 59, -1, 53, 3, -1, + 52, 6, 62, 7, -1, 61, -1, 52, 63, -1, + 62, 63, -1, 63, -1, 54, 5, -1, 65, 66, + -1, -1, 67, 66, -1, -1, 3, 55, -1, 68, + 69, -1, 69, -1, 8, 3, 64, -1, 9, 10, + -1, 9, 18, -1, 9, 37, -1, 11, 3, 64, + -1, 12, -1, 13, -1, 14, 3, 64, -1, 15, + 60, -1, 16, 3, -1, 17, 3, -1, 19, 3, + 64, -1, 20, -1, 21, 3, -1, 22, 3, 64, + -1, 23, 5, 5, 5, 5, 5, 5, 5, 5, + 5, -1, 24, 3, 64, -1, 25, 3, 64, -1, + 26, 3, -1, 27, 3, -1, 28, -1, 29, 3, + -1, 30, 3, 64, -1, 31, 3, 64, -1, 32, + -1, 33, 5, 5, 5, 5, -1, 34, 3, 64, + -1, 35, 5, 5, 5, -1, 36, 3, 64, -1, + 38, 3, 64, -1, 39, 3, 3, 3, 64, -1, + 40, -1, 41, -1, 42, 5, 5, -1, 43, 60, + -1, 44, 5, 5, 5, -1, 46, 3, 64, -1, + 45, 3, 64, -1, 47, -1, 48, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 171, 171, 177, 185, 193, 201, 207, 214, 221, + 229, 235, 240, 246, 254, 261, 269, 275, 280, 286, + 294, 300, 313, 319, 324, 332, 337, 343, 352, 358, + 364, 370, 379, 385, 391, 400, 408, 414, 420, 429, + 435, 441, 450, 456, 465, 474, 480, 486, 492, 498, + 507, 516, 522, 528, 537, 543, 552, 561, 570, 576, + 582, 588, 596, 602, 611, 620, 626 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "STRING", "ID", "NUM", "LBRACK", + "RBRACK", "ACCELERATOR", "ACTIVETRANSFORM", "ALL", "AREALIGHTSOURCE", + "ATTRIBUTEBEGIN", "ATTRIBUTEEND", "CAMERA", "CONCATTRANSFORM", + "COORDINATESYSTEM", "COORDSYSTRANSFORM", "ENDTIME", "FILM", "IDENTITY", + "INCLUDE", "LIGHTSOURCE", "LOOKAT", "MAKENAMEDMATERIAL", "MATERIAL", + "NAMEDMATERIAL", "OBJECTBEGIN", "OBJECTEND", "OBJECTINSTANCE", + "PIXELFILTER", "RENDERER", "REVERSEORIENTATION", "ROTATE", "SAMPLER", + "SCALE", "SHAPE", "STARTTIME", "SURFACEINTEGRATOR", "TEXTURE", + "TRANSFORMBEGIN", "TRANSFORMEND", "TRANSFORMTIMES", "TRANSFORM", + "TRANSLATE", "VOLUME", "VOLUMEINTEGRATOR", "WORLDBEGIN", "WORLDEND", + "HIGH_PRECEDENCE", "$accept", "start", "array_init", "string_array_init", + "num_array_init", "array", "string_array", "single_element_string_array", + "string_list", "string_list_entry", "num_array", + "single_element_num_array", "num_list", "num_list_entry", "paramlist", + "paramlist_init", "paramlist_contents", "paramlist_entry", + "pbrt_stmt_list", "pbrt_stmt", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 50, 51, 52, 53, 54, 55, 55, 56, 56, + 57, 58, 58, 59, 60, 60, 61, 62, 62, 63, + 64, 65, 66, 66, 67, 68, 68, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 0, 0, 0, 1, 1, 4, 1, + 2, 2, 1, 2, 4, 1, 2, 2, 1, 2, + 2, 0, 2, 0, 2, 2, 1, 3, 2, 2, + 2, 3, 1, 1, 3, 2, 2, 2, 3, 1, + 2, 3, 10, 3, 3, 2, 2, 1, 2, 3, + 3, 1, 5, 3, 4, 3, 3, 5, 1, 1, + 3, 2, 4, 3, 3, 1, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 0, 0, 0, 0, 32, 33, 0, 3, 0, 0, + 0, 39, 0, 0, 0, 0, 0, 0, 0, 47, + 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, + 58, 59, 0, 3, 0, 0, 0, 65, 66, 0, + 2, 26, 21, 28, 29, 30, 21, 21, 5, 35, + 15, 36, 37, 21, 40, 21, 0, 21, 21, 45, + 46, 48, 21, 21, 0, 21, 0, 21, 21, 0, + 0, 61, 0, 21, 21, 1, 25, 27, 23, 31, + 34, 5, 0, 16, 38, 41, 0, 43, 44, 49, + 50, 0, 53, 0, 55, 56, 0, 60, 0, 64, + 63, 3, 20, 23, 5, 18, 19, 0, 0, 54, + 21, 62, 4, 24, 6, 9, 7, 22, 14, 17, + 0, 52, 57, 4, 0, 10, 0, 4, 12, 13, + 0, 8, 11, 0, 0, 42 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 39, 48, 124, 82, 113, 114, 115, 127, 125, + 49, 50, 104, 83, 77, 78, 102, 103, 40, 41 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -119 +static const yytype_int8 yypact[] = +{ + 58, 1, -4, 4, -119, -119, 8, -119, 16, 18, + 21, -119, 22, 24, 25, 28, 29, 31, 32, -119, + 33, 34, 35, -119, 36, 37, 38, 39, 41, 43, + -119, -119, 42, -119, 44, 45, 47, -119, -119, 51, + 58, -119, -119, -119, -119, -119, -119, -119, 46, -119, + -119, -119, -119, -119, -119, -119, 48, -119, -119, -119, + -119, -119, -119, -119, 49, -119, 50, -119, -119, 53, + 52, -119, 54, -119, -119, -119, -119, -119, 55, -119, + -119, -119, 56, -119, -119, -119, 57, -119, -119, -119, + -119, 59, -119, 71, -119, -119, 60, -119, 90, -119, + -119, -119, -119, 55, 100, -119, -119, 103, 104, -119, + -119, -119, 10, -119, -119, -119, -119, -119, -119, -119, + 105, -119, -119, 106, 109, -119, 108, 107, -119, -119, + 110, -119, -119, 111, 112, -119 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -119, -119, -62, -119, -119, -119, -119, -119, -119, -118, + -33, -119, -119, -78, -45, -119, -43, -119, -119, 78 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -6 +static const yytype_int16 yytable[] = +{ + 71, 79, 80, 105, 42, 128, 43, 46, 84, 132, + 85, 47, 87, 88, 44, -5, 123, 89, 90, 51, + 92, 52, 94, 95, 53, 54, 119, 55, 99, 100, + 56, 57, 58, 45, 59, 60, 61, 62, 63, 112, + 65, 64, 67, 66, 68, 105, 69, 70, 73, 72, + 74, 75, 81, 86, 91, 93, 96, 97, 101, 98, + 117, 106, 107, 110, 108, 122, 1, 2, 116, 3, + 4, 5, 6, 7, 8, 9, 109, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 111, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 118, 120, 121, + 126, -5, 129, 130, 131, 133, 134, 135, 76 +}; + +static const yytype_uint8 yycheck[] = +{ + 33, 46, 47, 81, 3, 123, 10, 3, 53, 127, + 55, 3, 57, 58, 18, 5, 6, 62, 63, 3, + 65, 3, 67, 68, 3, 3, 104, 3, 73, 74, + 5, 3, 3, 37, 3, 3, 3, 3, 3, 101, + 3, 5, 3, 5, 3, 123, 3, 5, 3, 5, + 3, 0, 6, 5, 5, 5, 3, 5, 3, 5, + 103, 5, 5, 3, 5, 110, 8, 9, 101, 11, + 12, 13, 14, 15, 16, 17, 5, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 5, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 7, 5, 5, + 5, 5, 3, 5, 7, 5, 5, 5, 40 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 8, 9, 11, 12, 13, 14, 15, 16, 17, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 51, + 68, 69, 3, 10, 18, 37, 3, 3, 52, 60, + 61, 3, 3, 3, 3, 3, 5, 3, 3, 3, + 3, 3, 3, 3, 5, 3, 5, 3, 3, 3, + 5, 60, 5, 3, 3, 0, 69, 64, 65, 64, + 64, 6, 54, 63, 64, 64, 5, 64, 64, 64, + 64, 5, 64, 5, 64, 64, 3, 5, 5, 64, + 64, 3, 66, 67, 62, 63, 5, 5, 5, 5, + 3, 5, 52, 55, 56, 57, 60, 66, 7, 63, + 5, 5, 64, 6, 53, 59, 5, 58, 59, 3, + 5, 7, 59, 5, 5, 5 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) +#else +static void +yy_stack_print (bottom, top) + yytype_int16 *bottom; + yytype_int16 *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + fprintf (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + fprintf (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + +/* The look-ahead symbol. */ +int yychar; + +/* The semantic value of the look-ahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + int yystate; + int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ + int yytoken = 0; +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss = yyssa; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; + + + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + look-ahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to look-ahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a look-ahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the look-ahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: +#line 172 "core/pbrtparse.yy" + { +;} + break; + + case 3: +#line 178 "core/pbrtparse.yy" + { + if (cur_array) Severe("MUH"); + cur_array = new ParamArray; +;} + break; + + case 4: +#line 186 "core/pbrtparse.yy" + { + cur_array->element_size = sizeof(const char *); + cur_array->isString = true; +;} + break; + + case 5: +#line 194 "core/pbrtparse.yy" + { + cur_array->element_size = sizeof(float); + cur_array->isString = false; +;} + break; + + case 6: +#line 202 "core/pbrtparse.yy" + { + (yyval.ribarray) = (yyvsp[(1) - (1)].ribarray); +;} + break; + + case 7: +#line 208 "core/pbrtparse.yy" + { + (yyval.ribarray) = (yyvsp[(1) - (1)].ribarray); +;} + break; + + case 8: +#line 215 "core/pbrtparse.yy" + { + (yyval.ribarray) = cur_array; + cur_array = NULL; +;} + break; + + case 9: +#line 222 "core/pbrtparse.yy" + { + (yyval.ribarray) = cur_array; + cur_array = NULL; +;} + break; + + case 10: +#line 230 "core/pbrtparse.yy" + { +;} + break; + + case 11: +#line 236 "core/pbrtparse.yy" + { +;} + break; + + case 12: +#line 241 "core/pbrtparse.yy" + { +;} + break; + + case 13: +#line 247 "core/pbrtparse.yy" + { + char *to_add = strdup((yyvsp[(2) - (2)].string)); + AddArrayElement(&to_add); +;} + break; + + case 14: +#line 255 "core/pbrtparse.yy" + { + (yyval.ribarray) = cur_array; + cur_array = NULL; +;} + break; + + case 15: +#line 262 "core/pbrtparse.yy" + { + (yyval.ribarray) = cur_array; + cur_array = NULL; +;} + break; + + case 16: +#line 270 "core/pbrtparse.yy" + { +;} + break; + + case 17: +#line 276 "core/pbrtparse.yy" + { +;} + break; + + case 18: +#line 281 "core/pbrtparse.yy" + { +;} + break; + + case 19: +#line 287 "core/pbrtparse.yy" + { + float to_add = (yyvsp[(2) - (2)].num); + AddArrayElement(&to_add); +;} + break; + + case 20: +#line 295 "core/pbrtparse.yy" + { +;} + break; + + case 21: +#line 301 "core/pbrtparse.yy" + { + for (uint32_t i = 0; i < cur_paramlist.size(); ++i) { + if (cur_paramlist[i].isString) { + for (uint32_t j = 0; j < cur_paramlist[i].size; ++j) + free(((char **)cur_paramlist[i].arg)[j]); + } + } + cur_paramlist.erase(cur_paramlist.begin(), cur_paramlist.end()); +;} + break; + + case 22: +#line 314 "core/pbrtparse.yy" + { +;} + break; + + case 23: +#line 319 "core/pbrtparse.yy" + { +;} + break; + + case 24: +#line 325 "core/pbrtparse.yy" + { + cur_paramlist.push_back(ParamListItem((yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].ribarray))); + ArrayFree((yyvsp[(2) - (2)].ribarray)); +;} + break; + + case 25: +#line 333 "core/pbrtparse.yy" + { +;} + break; + + case 26: +#line 338 "core/pbrtparse.yy" + { +;} + break; + + case 27: +#line 344 "core/pbrtparse.yy" + { + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtAccelerator((yyvsp[(2) - (3)].string), params); + FreeArgs(); +;} + break; + + case 28: +#line 353 "core/pbrtparse.yy" + { + pbrtActiveTransformAll(); +;} + break; + + case 29: +#line 359 "core/pbrtparse.yy" + { + pbrtActiveTransformEndTime(); +;} + break; + + case 30: +#line 365 "core/pbrtparse.yy" + { + pbrtActiveTransformStartTime(); +;} + break; + + case 31: +#line 371 "core/pbrtparse.yy" + { + ParamSet params; + InitParamSet(params, SPECTRUM_ILLUMINANT); + pbrtAreaLightSource((yyvsp[(2) - (3)].string), params); + FreeArgs(); +;} + break; + + case 32: +#line 380 "core/pbrtparse.yy" + { + pbrtAttributeBegin(); +;} + break; + + case 33: +#line 386 "core/pbrtparse.yy" + { + pbrtAttributeEnd(); +;} + break; + + case 34: +#line 392 "core/pbrtparse.yy" + { + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtCamera((yyvsp[(2) - (3)].string), params); + FreeArgs(); +;} + break; + + case 35: +#line 401 "core/pbrtparse.yy" + { + if (VerifyArrayLength((yyvsp[(2) - (2)].ribarray), 16, "ConcatTransform")) + pbrtConcatTransform((float *) (yyvsp[(2) - (2)].ribarray)->array); + ArrayFree((yyvsp[(2) - (2)].ribarray)); +;} + break; + + case 36: +#line 409 "core/pbrtparse.yy" + { + pbrtCoordinateSystem((yyvsp[(2) - (2)].string)); +;} + break; + + case 37: +#line 415 "core/pbrtparse.yy" + { + pbrtCoordSysTransform((yyvsp[(2) - (2)].string)); +;} + break; + + case 38: +#line 421 "core/pbrtparse.yy" + { + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtFilm((yyvsp[(2) - (3)].string), params); + FreeArgs(); +;} + break; + + case 39: +#line 430 "core/pbrtparse.yy" + { + pbrtIdentity(); +;} + break; + + case 40: +#line 436 "core/pbrtparse.yy" + { + include_push((yyvsp[(2) - (2)].string)); +;} + break; + + case 41: +#line 442 "core/pbrtparse.yy" + { + ParamSet params; + InitParamSet(params, SPECTRUM_ILLUMINANT); + pbrtLightSource((yyvsp[(2) - (3)].string), params); + FreeArgs(); +;} + break; + + case 42: +#line 451 "core/pbrtparse.yy" + { + pbrtLookAt((yyvsp[(2) - (10)].num), (yyvsp[(3) - (10)].num), (yyvsp[(4) - (10)].num), (yyvsp[(5) - (10)].num), (yyvsp[(6) - (10)].num), (yyvsp[(7) - (10)].num), (yyvsp[(8) - (10)].num), (yyvsp[(9) - (10)].num), (yyvsp[(10) - (10)].num)); +;} + break; + + case 43: +#line 457 "core/pbrtparse.yy" + { + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtMakeNamedMaterial((yyvsp[(2) - (3)].string), params); + FreeArgs(); +;} + break; + + case 44: +#line 466 "core/pbrtparse.yy" + { + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtMaterial((yyvsp[(2) - (3)].string), params); + FreeArgs(); +;} + break; + + case 45: +#line 475 "core/pbrtparse.yy" + { + pbrtNamedMaterial((yyvsp[(2) - (2)].string)); +;} + break; + + case 46: +#line 481 "core/pbrtparse.yy" + { + pbrtObjectBegin((yyvsp[(2) - (2)].string)); +;} + break; + + case 47: +#line 487 "core/pbrtparse.yy" + { + pbrtObjectEnd(); +;} + break; + + case 48: +#line 493 "core/pbrtparse.yy" + { + pbrtObjectInstance((yyvsp[(2) - (2)].string)); +;} + break; + + case 49: +#line 499 "core/pbrtparse.yy" + { + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtPixelFilter((yyvsp[(2) - (3)].string), params); + FreeArgs(); +;} + break; + + case 50: +#line 508 "core/pbrtparse.yy" + { + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtRenderer((yyvsp[(2) - (3)].string), params); + FreeArgs(); +;} + break; + + case 51: +#line 517 "core/pbrtparse.yy" + { + pbrtReverseOrientation(); +;} + break; + + case 52: +#line 523 "core/pbrtparse.yy" + { + pbrtRotate((yyvsp[(2) - (5)].num), (yyvsp[(3) - (5)].num), (yyvsp[(4) - (5)].num), (yyvsp[(5) - (5)].num)); +;} + break; + + case 53: +#line 529 "core/pbrtparse.yy" + { + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtSampler((yyvsp[(2) - (3)].string), params); + FreeArgs(); +;} + break; + + case 54: +#line 538 "core/pbrtparse.yy" + { + pbrtScale((yyvsp[(2) - (4)].num), (yyvsp[(3) - (4)].num), (yyvsp[(4) - (4)].num)); +;} + break; + + case 55: +#line 544 "core/pbrtparse.yy" + { + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtShape((yyvsp[(2) - (3)].string), params); + FreeArgs(); +;} + break; + + case 56: +#line 553 "core/pbrtparse.yy" + { + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtSurfaceIntegrator((yyvsp[(2) - (3)].string), params); + FreeArgs(); +;} + break; + + case 57: +#line 562 "core/pbrtparse.yy" + { + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtTexture((yyvsp[(2) - (5)].string), (yyvsp[(3) - (5)].string), (yyvsp[(4) - (5)].string), params); + FreeArgs(); +;} + break; + + case 58: +#line 571 "core/pbrtparse.yy" + { + pbrtTransformBegin(); +;} + break; + + case 59: +#line 577 "core/pbrtparse.yy" + { + pbrtTransformEnd(); +;} + break; + + case 60: +#line 583 "core/pbrtparse.yy" + { + pbrtTransformTimes((yyvsp[(2) - (3)].num), (yyvsp[(3) - (3)].num)); +;} + break; + + case 61: +#line 589 "core/pbrtparse.yy" + { + if (VerifyArrayLength( (yyvsp[(2) - (2)].ribarray), 16, "Transform" )) + pbrtTransform( (float *) (yyvsp[(2) - (2)].ribarray)->array ); + ArrayFree((yyvsp[(2) - (2)].ribarray)); +;} + break; + + case 62: +#line 597 "core/pbrtparse.yy" + { + pbrtTranslate((yyvsp[(2) - (4)].num), (yyvsp[(3) - (4)].num), (yyvsp[(4) - (4)].num)); +;} + break; + + case 63: +#line 603 "core/pbrtparse.yy" + { + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtVolumeIntegrator((yyvsp[(2) - (3)].string), params); + FreeArgs(); +;} + break; + + case 64: +#line 612 "core/pbrtparse.yy" + { + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtVolume((yyvsp[(2) - (3)].string), params); + FreeArgs(); +;} + break; + + case 65: +#line 621 "core/pbrtparse.yy" + { + pbrtWorldBegin(); +;} + break; + + case 66: +#line 627 "core/pbrtparse.yy" + { + pbrtWorldEnd(); +;} + break; + + +/* Line 1267 of yacc.c. */ +#line 2154 "core/pbrtparse.cpp" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse look-ahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse look-ahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + +#line 632 "core/pbrtparse.yy" + +static const char *paramTypeToName(int type) { + switch (type) { + case PARAM_TYPE_INT: return "int"; + case PARAM_TYPE_BOOL: return "bool"; + case PARAM_TYPE_FLOAT: return "float"; + case PARAM_TYPE_POINT: return "point"; + case PARAM_TYPE_VECTOR: return "vector"; + case PARAM_TYPE_NORMAL: return "normal"; + case PARAM_TYPE_RGB: return "rgb/color"; + case PARAM_TYPE_XYZ: return "xyz"; + case PARAM_TYPE_BLACKBODY: return "blackbody"; + case PARAM_TYPE_SPECTRUM: return "spectrum"; + case PARAM_TYPE_STRING: return "string"; + case PARAM_TYPE_TEXTURE: return "texture"; + default: Severe("Error in paramTypeToName"); return NULL; + } +} + + +static void InitParamSet(ParamSet &ps, SpectrumType type) { + ps.Clear(); + for (uint32_t i = 0; i < cur_paramlist.size(); ++i) { + int type; + string name; + if (lookupType(cur_paramlist[i].name, &type, name)) { + if (type == PARAM_TYPE_TEXTURE || type == PARAM_TYPE_STRING || + type == PARAM_TYPE_BOOL) { + if (!cur_paramlist[i].isString) { + Error("Expected string parameter value for parameter \"%s\" with type \"%s\". Ignoring.", + name.c_str(), paramTypeToName(type)); + continue; + } + } + else if (type != PARAM_TYPE_SPECTRUM) { /* spectrum can be either... */ + if (cur_paramlist[i].isString) { + Error("Expected numeric parameter value for parameter \"%s\" with type \"%s\". Ignoring.", + name.c_str(), paramTypeToName(type)); + continue; + } + } + void *data = cur_paramlist[i].arg; + int nItems = cur_paramlist[i].size; + if (type == PARAM_TYPE_INT) { + // parser doesn't handle ints, so convert from floats here.... + int nAlloc = nItems; + int *idata = new int[nAlloc]; + float *fdata = (float *)cur_paramlist[i].arg; + for (int j = 0; j < nAlloc; ++j) + idata[j] = int(fdata[j]); + ps.AddInt(name, idata, nItems); + delete[] idata; + } + else if (type == PARAM_TYPE_BOOL) { + // strings -> bools + int nAlloc = cur_paramlist[i].size; + bool *bdata = new bool[nAlloc]; + for (int j = 0; j < nAlloc; ++j) { + string s(((const char **)data)[j]); + if (s == "true") bdata[j] = true; + else if (s == "false") bdata[j] = false; + else { + Warning("Value \"%s\" unknown for boolean parameter \"%s\"." + "Using \"false\".", s.c_str(), cur_paramlist[i].name); + bdata[j] = false; + } + } + ps.AddBool(name, bdata, nItems); + delete[] bdata; + } + else if (type == PARAM_TYPE_FLOAT) { + ps.AddFloat(name, (float *)data, nItems); + } else if (type == PARAM_TYPE_POINT) { + if ((nItems % 3) != 0) + Warning("Excess values given with point parameter \"%s\". " + "Ignoring last %d of them", cur_paramlist[i].name, nItems % 3); + ps.AddPoint(name, (Point *)data, nItems / 3); + } else if (type == PARAM_TYPE_VECTOR) { + if ((nItems % 3) != 0) + Warning("Excess values given with vector parameter \"%s\". " + "Ignoring last %d of them", cur_paramlist[i].name, nItems % 3); + ps.AddVector(name, (Vector *)data, nItems / 3); + } else if (type == PARAM_TYPE_NORMAL) { + if ((nItems % 3) != 0) + Warning("Excess values given with normal parameter \"%s\". " + "Ignoring last %d of them", cur_paramlist[i].name, nItems % 3); + ps.AddNormal(name, (Normal *)data, nItems / 3); + } else if (type == PARAM_TYPE_RGB) { + if ((nItems % 3) != 0) + Warning("Excess RGB values given with parameter \"%s\". " + "Ignoring last %d of them", cur_paramlist[i].name, nItems % 3); + ps.AddRGBSpectrum(name, (float *)data, nItems); + } else if (type == PARAM_TYPE_XYZ) { + if ((nItems % 3) != 0) + Warning("Excess XYZ values given with parameter \"%s\". " + "Ignoring last %d of them", cur_paramlist[i].name, nItems % 3); + ps.AddXYZSpectrum(name, (float *)data, nItems); + } else if (type == PARAM_TYPE_BLACKBODY) { + if ((nItems % 2) != 0) + Warning("Excess value given with blackbody parameter \"%s\". " + "Ignoring extra one.", cur_paramlist[i].name); + ps.AddBlackbodySpectrum(name, (float *)data, nItems); + } else if (type == PARAM_TYPE_SPECTRUM) { + if (cur_paramlist[i].isString) { + ps.AddSampledSpectrumFiles(name, (const char **)data, nItems); + } + else { + if ((nItems % 2) != 0) + Warning("Non-even number of values given with sampled spectrum " + "parameter \"%s\". Ignoring extra.", cur_paramlist[i].name); + ps.AddSampledSpectrum(name, (float *)data, nItems); + } + } else if (type == PARAM_TYPE_STRING) { + string *strings = new string[nItems]; + for (int j = 0; j < nItems; ++j) + strings[j] = string(((const char **)data)[j]); + ps.AddString(name, strings, nItems); + delete[] strings; + } + else if (type == PARAM_TYPE_TEXTURE) { + if (nItems == 1) { + string val(*((const char **)data)); + ps.AddTexture(name, val); + } + else + Error("Only one string allowed for \"texture\" parameter \"%s\"", + name.c_str()); + } + } + else + Warning("Type of parameter \"%s\" is unknown", + cur_paramlist[i].name); + } +} + + +static bool lookupType(const char *name, int *type, string &sname) { + Assert(name != NULL); + *type = 0; + const char *strp = name; + while (*strp && isspace(*strp)) + ++strp; + if (!*strp) { + Error("Parameter \"%s\" doesn't have a type declaration?!", name); + return false; + } +#define TRY_DECODING_TYPE(name, mask) \ + if (strncmp(name, strp, strlen(name)) == 0) { \ + *type = mask; strp += strlen(name); \ + } + TRY_DECODING_TYPE("float", PARAM_TYPE_FLOAT) + else TRY_DECODING_TYPE("integer", PARAM_TYPE_INT) + else TRY_DECODING_TYPE("bool", PARAM_TYPE_BOOL) + else TRY_DECODING_TYPE("point", PARAM_TYPE_POINT) + else TRY_DECODING_TYPE("vector", PARAM_TYPE_VECTOR) + else TRY_DECODING_TYPE("normal", PARAM_TYPE_NORMAL) + else TRY_DECODING_TYPE("string", PARAM_TYPE_STRING) + else TRY_DECODING_TYPE("texture", PARAM_TYPE_TEXTURE) + else TRY_DECODING_TYPE("color", PARAM_TYPE_RGB) + else TRY_DECODING_TYPE("rgb", PARAM_TYPE_RGB) + else TRY_DECODING_TYPE("xyz", PARAM_TYPE_XYZ) + else TRY_DECODING_TYPE("blackbody", PARAM_TYPE_BLACKBODY) + else TRY_DECODING_TYPE("spectrum", PARAM_TYPE_SPECTRUM) + else { + Error("Unable to decode type for name \"%s\"", name); + return false; + } + while (*strp && isspace(*strp)) + ++strp; + sname = string(strp); + return true; +} + + + diff --git a/core/pbrtparse.hpp b/core/pbrtparse.hpp new file mode 100644 index 0000000..984ad05 --- /dev/null +++ b/core/pbrtparse.hpp @@ -0,0 +1,160 @@ +/* A Bison parser, made by GNU Bison 2.3. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + STRING = 258, + ID = 259, + NUM = 260, + LBRACK = 261, + RBRACK = 262, + ACCELERATOR = 263, + ACTIVETRANSFORM = 264, + ALL = 265, + AREALIGHTSOURCE = 266, + ATTRIBUTEBEGIN = 267, + ATTRIBUTEEND = 268, + CAMERA = 269, + CONCATTRANSFORM = 270, + COORDINATESYSTEM = 271, + COORDSYSTRANSFORM = 272, + ENDTIME = 273, + FILM = 274, + IDENTITY = 275, + INCLUDE = 276, + LIGHTSOURCE = 277, + LOOKAT = 278, + MAKENAMEDMATERIAL = 279, + MATERIAL = 280, + NAMEDMATERIAL = 281, + OBJECTBEGIN = 282, + OBJECTEND = 283, + OBJECTINSTANCE = 284, + PIXELFILTER = 285, + RENDERER = 286, + REVERSEORIENTATION = 287, + ROTATE = 288, + SAMPLER = 289, + SCALE = 290, + SHAPE = 291, + STARTTIME = 292, + SURFACEINTEGRATOR = 293, + TEXTURE = 294, + TRANSFORMBEGIN = 295, + TRANSFORMEND = 296, + TRANSFORMTIMES = 297, + TRANSFORM = 298, + TRANSLATE = 299, + VOLUME = 300, + VOLUMEINTEGRATOR = 301, + WORLDBEGIN = 302, + WORLDEND = 303, + HIGH_PRECEDENCE = 304 + }; +#endif +/* Tokens. */ +#define STRING 258 +#define ID 259 +#define NUM 260 +#define LBRACK 261 +#define RBRACK 262 +#define ACCELERATOR 263 +#define ACTIVETRANSFORM 264 +#define ALL 265 +#define AREALIGHTSOURCE 266 +#define ATTRIBUTEBEGIN 267 +#define ATTRIBUTEEND 268 +#define CAMERA 269 +#define CONCATTRANSFORM 270 +#define COORDINATESYSTEM 271 +#define COORDSYSTRANSFORM 272 +#define ENDTIME 273 +#define FILM 274 +#define IDENTITY 275 +#define INCLUDE 276 +#define LIGHTSOURCE 277 +#define LOOKAT 278 +#define MAKENAMEDMATERIAL 279 +#define MATERIAL 280 +#define NAMEDMATERIAL 281 +#define OBJECTBEGIN 282 +#define OBJECTEND 283 +#define OBJECTINSTANCE 284 +#define PIXELFILTER 285 +#define RENDERER 286 +#define REVERSEORIENTATION 287 +#define ROTATE 288 +#define SAMPLER 289 +#define SCALE 290 +#define SHAPE 291 +#define STARTTIME 292 +#define SURFACEINTEGRATOR 293 +#define TEXTURE 294 +#define TRANSFORMBEGIN 295 +#define TRANSFORMEND 296 +#define TRANSFORMTIMES 297 +#define TRANSFORM 298 +#define TRANSLATE 299 +#define VOLUME 300 +#define VOLUMEINTEGRATOR 301 +#define WORLDBEGIN 302 +#define WORLDEND 303 +#define HIGH_PRECEDENCE 304 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 148 "core/pbrtparse.yy" +{ +char string[1024]; +float num; +ParamArray *ribarray; +} +/* Line 1529 of yacc.c. */ +#line 153 "core/pbrtparse.hpp" + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + +extern YYSTYPE yylval; + diff --git a/core/pbrtparse.output b/core/pbrtparse.output new file mode 100644 index 0000000..7e4d978 --- /dev/null +++ b/core/pbrtparse.output @@ -0,0 +1,1344 @@ +Terminals which are not used + + ID + + +Grammar + + 0 $accept: start $end + + 1 start: pbrt_stmt_list + + 2 array_init: /* empty */ + + 3 string_array_init: /* empty */ + + 4 num_array_init: /* empty */ + + 5 array: string_array + 6 | num_array + + 7 string_array: array_init LBRACK string_list RBRACK + 8 | single_element_string_array + + 9 single_element_string_array: array_init string_list_entry + + 10 string_list: string_list string_list_entry + 11 | string_list_entry + + 12 string_list_entry: string_array_init STRING + + 13 num_array: array_init LBRACK num_list RBRACK + 14 | single_element_num_array + + 15 single_element_num_array: array_init num_list_entry + + 16 num_list: num_list num_list_entry + 17 | num_list_entry + + 18 num_list_entry: num_array_init NUM + + 19 paramlist: paramlist_init paramlist_contents + + 20 paramlist_init: /* empty */ + + 21 paramlist_contents: paramlist_entry paramlist_contents + 22 | /* empty */ + + 23 paramlist_entry: STRING array + + 24 pbrt_stmt_list: pbrt_stmt_list pbrt_stmt + 25 | pbrt_stmt + + 26 pbrt_stmt: ACCELERATOR STRING paramlist + 27 | ACTIVETRANSFORM ALL + 28 | ACTIVETRANSFORM ENDTIME + 29 | ACTIVETRANSFORM STARTTIME + 30 | AREALIGHTSOURCE STRING paramlist + 31 | ATTRIBUTEBEGIN + 32 | ATTRIBUTEEND + 33 | CAMERA STRING paramlist + 34 | CONCATTRANSFORM num_array + 35 | COORDINATESYSTEM STRING + 36 | COORDSYSTRANSFORM STRING + 37 | FILM STRING paramlist + 38 | IDENTITY + 39 | INCLUDE STRING + 40 | LIGHTSOURCE STRING paramlist + 41 | LOOKAT NUM NUM NUM NUM NUM NUM NUM NUM NUM + 42 | MAKENAMEDMATERIAL STRING paramlist + 43 | MATERIAL STRING paramlist + 44 | NAMEDMATERIAL STRING + 45 | OBJECTBEGIN STRING + 46 | OBJECTEND + 47 | OBJECTINSTANCE STRING + 48 | PIXELFILTER STRING paramlist + 49 | RENDERER STRING paramlist + 50 | REVERSEORIENTATION + 51 | ROTATE NUM NUM NUM NUM + 52 | SAMPLER STRING paramlist + 53 | SCALE NUM NUM NUM + 54 | SHAPE STRING paramlist + 55 | SURFACEINTEGRATOR STRING paramlist + 56 | TEXTURE STRING STRING STRING paramlist + 57 | TRANSFORMBEGIN + 58 | TRANSFORMEND + 59 | TRANSFORMTIMES NUM NUM + 60 | TRANSFORM num_array + 61 | TRANSLATE NUM NUM NUM + 62 | VOLUMEINTEGRATOR STRING paramlist + 63 | VOLUME STRING paramlist + 64 | WORLDBEGIN + 65 | WORLDEND + + +Terminals, with rules where they appear + +$end (0) 0 +error (256) +STRING (258) 12 23 26 30 33 35 36 37 39 40 42 43 44 45 47 48 49 52 + 54 55 56 62 63 +ID (259) +NUM (260) 18 41 51 53 59 61 +LBRACK (261) 7 13 +RBRACK (262) 7 13 +ACCELERATOR (263) 26 +ACTIVETRANSFORM (264) 27 28 29 +ALL (265) 27 +AREALIGHTSOURCE (266) 30 +ATTRIBUTEBEGIN (267) 31 +ATTRIBUTEEND (268) 32 +CAMERA (269) 33 +CONCATTRANSFORM (270) 34 +COORDINATESYSTEM (271) 35 +COORDSYSTRANSFORM (272) 36 +ENDTIME (273) 28 +FILM (274) 37 +IDENTITY (275) 38 +INCLUDE (276) 39 +LIGHTSOURCE (277) 40 +LOOKAT (278) 41 +MAKENAMEDMATERIAL (279) 42 +MATERIAL (280) 43 +NAMEDMATERIAL (281) 44 +OBJECTBEGIN (282) 45 +OBJECTEND (283) 46 +OBJECTINSTANCE (284) 47 +PIXELFILTER (285) 48 +RENDERER (286) 49 +REVERSEORIENTATION (287) 50 +ROTATE (288) 51 +SAMPLER (289) 52 +SCALE (290) 53 +SHAPE (291) 54 +STARTTIME (292) 29 +SURFACEINTEGRATOR (293) 55 +TEXTURE (294) 56 +TRANSFORMBEGIN (295) 57 +TRANSFORMEND (296) 58 +TRANSFORMTIMES (297) 59 +TRANSFORM (298) 60 +TRANSLATE (299) 61 +VOLUME (300) 63 +VOLUMEINTEGRATOR (301) 62 +WORLDBEGIN (302) 64 +WORLDEND (303) 65 +HIGH_PRECEDENCE (304) + + +Nonterminals, with rules where they appear + +$accept (50) + on left: 0 +start (51) + on left: 1, on right: 0 +array_init (52) + on left: 2, on right: 7 9 13 15 +string_array_init (53) + on left: 3, on right: 12 +num_array_init (54) + on left: 4, on right: 18 +array (55) + on left: 5 6, on right: 23 +string_array (56) + on left: 7 8, on right: 5 +single_element_string_array (57) + on left: 9, on right: 8 +string_list (58) + on left: 10 11, on right: 7 10 +string_list_entry (59) + on left: 12, on right: 9 10 11 +num_array (60) + on left: 13 14, on right: 6 34 60 +single_element_num_array (61) + on left: 15, on right: 14 +num_list (62) + on left: 16 17, on right: 13 16 +num_list_entry (63) + on left: 18, on right: 15 16 17 +paramlist (64) + on left: 19, on right: 26 30 33 37 40 42 43 48 49 52 54 55 56 62 + 63 +paramlist_init (65) + on left: 20, on right: 19 +paramlist_contents (66) + on left: 21 22, on right: 19 21 +paramlist_entry (67) + on left: 23, on right: 21 +pbrt_stmt_list (68) + on left: 24 25, on right: 1 24 +pbrt_stmt (69) + on left: 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 + 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 + 65, on right: 24 25 + + +state 0 + + 0 $accept: . start $end + + ACCELERATOR shift, and go to state 1 + ACTIVETRANSFORM shift, and go to state 2 + AREALIGHTSOURCE shift, and go to state 3 + ATTRIBUTEBEGIN shift, and go to state 4 + ATTRIBUTEEND shift, and go to state 5 + CAMERA shift, and go to state 6 + CONCATTRANSFORM shift, and go to state 7 + COORDINATESYSTEM shift, and go to state 8 + COORDSYSTRANSFORM shift, and go to state 9 + FILM shift, and go to state 10 + IDENTITY shift, and go to state 11 + INCLUDE shift, and go to state 12 + LIGHTSOURCE shift, and go to state 13 + LOOKAT shift, and go to state 14 + MAKENAMEDMATERIAL shift, and go to state 15 + MATERIAL shift, and go to state 16 + NAMEDMATERIAL shift, and go to state 17 + OBJECTBEGIN shift, and go to state 18 + OBJECTEND shift, and go to state 19 + OBJECTINSTANCE shift, and go to state 20 + PIXELFILTER shift, and go to state 21 + RENDERER shift, and go to state 22 + REVERSEORIENTATION shift, and go to state 23 + ROTATE shift, and go to state 24 + SAMPLER shift, and go to state 25 + SCALE shift, and go to state 26 + SHAPE shift, and go to state 27 + SURFACEINTEGRATOR shift, and go to state 28 + TEXTURE shift, and go to state 29 + TRANSFORMBEGIN shift, and go to state 30 + TRANSFORMEND shift, and go to state 31 + TRANSFORMTIMES shift, and go to state 32 + TRANSFORM shift, and go to state 33 + TRANSLATE shift, and go to state 34 + VOLUME shift, and go to state 35 + VOLUMEINTEGRATOR shift, and go to state 36 + WORLDBEGIN shift, and go to state 37 + WORLDEND shift, and go to state 38 + + start go to state 39 + pbrt_stmt_list go to state 40 + pbrt_stmt go to state 41 + + +state 1 + + 26 pbrt_stmt: ACCELERATOR . STRING paramlist + + STRING shift, and go to state 42 + + +state 2 + + 27 pbrt_stmt: ACTIVETRANSFORM . ALL + 28 | ACTIVETRANSFORM . ENDTIME + 29 | ACTIVETRANSFORM . STARTTIME + + ALL shift, and go to state 43 + ENDTIME shift, and go to state 44 + STARTTIME shift, and go to state 45 + + +state 3 + + 30 pbrt_stmt: AREALIGHTSOURCE . STRING paramlist + + STRING shift, and go to state 46 + + +state 4 + + 31 pbrt_stmt: ATTRIBUTEBEGIN . + + $default reduce using rule 31 (pbrt_stmt) + + +state 5 + + 32 pbrt_stmt: ATTRIBUTEEND . + + $default reduce using rule 32 (pbrt_stmt) + + +state 6 + + 33 pbrt_stmt: CAMERA . STRING paramlist + + STRING shift, and go to state 47 + + +state 7 + + 34 pbrt_stmt: CONCATTRANSFORM . num_array + + $default reduce using rule 2 (array_init) + + array_init go to state 48 + num_array go to state 49 + single_element_num_array go to state 50 + + +state 8 + + 35 pbrt_stmt: COORDINATESYSTEM . STRING + + STRING shift, and go to state 51 + + +state 9 + + 36 pbrt_stmt: COORDSYSTRANSFORM . STRING + + STRING shift, and go to state 52 + + +state 10 + + 37 pbrt_stmt: FILM . STRING paramlist + + STRING shift, and go to state 53 + + +state 11 + + 38 pbrt_stmt: IDENTITY . + + $default reduce using rule 38 (pbrt_stmt) + + +state 12 + + 39 pbrt_stmt: INCLUDE . STRING + + STRING shift, and go to state 54 + + +state 13 + + 40 pbrt_stmt: LIGHTSOURCE . STRING paramlist + + STRING shift, and go to state 55 + + +state 14 + + 41 pbrt_stmt: LOOKAT . NUM NUM NUM NUM NUM NUM NUM NUM NUM + + NUM shift, and go to state 56 + + +state 15 + + 42 pbrt_stmt: MAKENAMEDMATERIAL . STRING paramlist + + STRING shift, and go to state 57 + + +state 16 + + 43 pbrt_stmt: MATERIAL . STRING paramlist + + STRING shift, and go to state 58 + + +state 17 + + 44 pbrt_stmt: NAMEDMATERIAL . STRING + + STRING shift, and go to state 59 + + +state 18 + + 45 pbrt_stmt: OBJECTBEGIN . STRING + + STRING shift, and go to state 60 + + +state 19 + + 46 pbrt_stmt: OBJECTEND . + + $default reduce using rule 46 (pbrt_stmt) + + +state 20 + + 47 pbrt_stmt: OBJECTINSTANCE . STRING + + STRING shift, and go to state 61 + + +state 21 + + 48 pbrt_stmt: PIXELFILTER . STRING paramlist + + STRING shift, and go to state 62 + + +state 22 + + 49 pbrt_stmt: RENDERER . STRING paramlist + + STRING shift, and go to state 63 + + +state 23 + + 50 pbrt_stmt: REVERSEORIENTATION . + + $default reduce using rule 50 (pbrt_stmt) + + +state 24 + + 51 pbrt_stmt: ROTATE . NUM NUM NUM NUM + + NUM shift, and go to state 64 + + +state 25 + + 52 pbrt_stmt: SAMPLER . STRING paramlist + + STRING shift, and go to state 65 + + +state 26 + + 53 pbrt_stmt: SCALE . NUM NUM NUM + + NUM shift, and go to state 66 + + +state 27 + + 54 pbrt_stmt: SHAPE . STRING paramlist + + STRING shift, and go to state 67 + + +state 28 + + 55 pbrt_stmt: SURFACEINTEGRATOR . STRING paramlist + + STRING shift, and go to state 68 + + +state 29 + + 56 pbrt_stmt: TEXTURE . STRING STRING STRING paramlist + + STRING shift, and go to state 69 + + +state 30 + + 57 pbrt_stmt: TRANSFORMBEGIN . + + $default reduce using rule 57 (pbrt_stmt) + + +state 31 + + 58 pbrt_stmt: TRANSFORMEND . + + $default reduce using rule 58 (pbrt_stmt) + + +state 32 + + 59 pbrt_stmt: TRANSFORMTIMES . NUM NUM + + NUM shift, and go to state 70 + + +state 33 + + 60 pbrt_stmt: TRANSFORM . num_array + + $default reduce using rule 2 (array_init) + + array_init go to state 48 + num_array go to state 71 + single_element_num_array go to state 50 + + +state 34 + + 61 pbrt_stmt: TRANSLATE . NUM NUM NUM + + NUM shift, and go to state 72 + + +state 35 + + 63 pbrt_stmt: VOLUME . STRING paramlist + + STRING shift, and go to state 73 + + +state 36 + + 62 pbrt_stmt: VOLUMEINTEGRATOR . STRING paramlist + + STRING shift, and go to state 74 + + +state 37 + + 64 pbrt_stmt: WORLDBEGIN . + + $default reduce using rule 64 (pbrt_stmt) + + +state 38 + + 65 pbrt_stmt: WORLDEND . + + $default reduce using rule 65 (pbrt_stmt) + + +state 39 + + 0 $accept: start . $end + + $end shift, and go to state 75 + + +state 40 + + 1 start: pbrt_stmt_list . + 24 pbrt_stmt_list: pbrt_stmt_list . pbrt_stmt + + ACCELERATOR shift, and go to state 1 + ACTIVETRANSFORM shift, and go to state 2 + AREALIGHTSOURCE shift, and go to state 3 + ATTRIBUTEBEGIN shift, and go to state 4 + ATTRIBUTEEND shift, and go to state 5 + CAMERA shift, and go to state 6 + CONCATTRANSFORM shift, and go to state 7 + COORDINATESYSTEM shift, and go to state 8 + COORDSYSTRANSFORM shift, and go to state 9 + FILM shift, and go to state 10 + IDENTITY shift, and go to state 11 + INCLUDE shift, and go to state 12 + LIGHTSOURCE shift, and go to state 13 + LOOKAT shift, and go to state 14 + MAKENAMEDMATERIAL shift, and go to state 15 + MATERIAL shift, and go to state 16 + NAMEDMATERIAL shift, and go to state 17 + OBJECTBEGIN shift, and go to state 18 + OBJECTEND shift, and go to state 19 + OBJECTINSTANCE shift, and go to state 20 + PIXELFILTER shift, and go to state 21 + RENDERER shift, and go to state 22 + REVERSEORIENTATION shift, and go to state 23 + ROTATE shift, and go to state 24 + SAMPLER shift, and go to state 25 + SCALE shift, and go to state 26 + SHAPE shift, and go to state 27 + SURFACEINTEGRATOR shift, and go to state 28 + TEXTURE shift, and go to state 29 + TRANSFORMBEGIN shift, and go to state 30 + TRANSFORMEND shift, and go to state 31 + TRANSFORMTIMES shift, and go to state 32 + TRANSFORM shift, and go to state 33 + TRANSLATE shift, and go to state 34 + VOLUME shift, and go to state 35 + VOLUMEINTEGRATOR shift, and go to state 36 + WORLDBEGIN shift, and go to state 37 + WORLDEND shift, and go to state 38 + + $default reduce using rule 1 (start) + + pbrt_stmt go to state 76 + + +state 41 + + 25 pbrt_stmt_list: pbrt_stmt . + + $default reduce using rule 25 (pbrt_stmt_list) + + +state 42 + + 26 pbrt_stmt: ACCELERATOR STRING . paramlist + + $default reduce using rule 20 (paramlist_init) + + paramlist go to state 77 + paramlist_init go to state 78 + + +state 43 + + 27 pbrt_stmt: ACTIVETRANSFORM ALL . + + $default reduce using rule 27 (pbrt_stmt) + + +state 44 + + 28 pbrt_stmt: ACTIVETRANSFORM ENDTIME . + + $default reduce using rule 28 (pbrt_stmt) + + +state 45 + + 29 pbrt_stmt: ACTIVETRANSFORM STARTTIME . + + $default reduce using rule 29 (pbrt_stmt) + + +state 46 + + 30 pbrt_stmt: AREALIGHTSOURCE STRING . paramlist + + $default reduce using rule 20 (paramlist_init) + + paramlist go to state 79 + paramlist_init go to state 78 + + +state 47 + + 33 pbrt_stmt: CAMERA STRING . paramlist + + $default reduce using rule 20 (paramlist_init) + + paramlist go to state 80 + paramlist_init go to state 78 + + +state 48 + + 13 num_array: array_init . LBRACK num_list RBRACK + 15 single_element_num_array: array_init . num_list_entry + + LBRACK shift, and go to state 81 + + $default reduce using rule 4 (num_array_init) + + num_array_init go to state 82 + num_list_entry go to state 83 + + +state 49 + + 34 pbrt_stmt: CONCATTRANSFORM num_array . + + $default reduce using rule 34 (pbrt_stmt) + + +state 50 + + 14 num_array: single_element_num_array . + + $default reduce using rule 14 (num_array) + + +state 51 + + 35 pbrt_stmt: COORDINATESYSTEM STRING . + + $default reduce using rule 35 (pbrt_stmt) + + +state 52 + + 36 pbrt_stmt: COORDSYSTRANSFORM STRING . + + $default reduce using rule 36 (pbrt_stmt) + + +state 53 + + 37 pbrt_stmt: FILM STRING . paramlist + + $default reduce using rule 20 (paramlist_init) + + paramlist go to state 84 + paramlist_init go to state 78 + + +state 54 + + 39 pbrt_stmt: INCLUDE STRING . + + $default reduce using rule 39 (pbrt_stmt) + + +state 55 + + 40 pbrt_stmt: LIGHTSOURCE STRING . paramlist + + $default reduce using rule 20 (paramlist_init) + + paramlist go to state 85 + paramlist_init go to state 78 + + +state 56 + + 41 pbrt_stmt: LOOKAT NUM . NUM NUM NUM NUM NUM NUM NUM NUM + + NUM shift, and go to state 86 + + +state 57 + + 42 pbrt_stmt: MAKENAMEDMATERIAL STRING . paramlist + + $default reduce using rule 20 (paramlist_init) + + paramlist go to state 87 + paramlist_init go to state 78 + + +state 58 + + 43 pbrt_stmt: MATERIAL STRING . paramlist + + $default reduce using rule 20 (paramlist_init) + + paramlist go to state 88 + paramlist_init go to state 78 + + +state 59 + + 44 pbrt_stmt: NAMEDMATERIAL STRING . + + $default reduce using rule 44 (pbrt_stmt) + + +state 60 + + 45 pbrt_stmt: OBJECTBEGIN STRING . + + $default reduce using rule 45 (pbrt_stmt) + + +state 61 + + 47 pbrt_stmt: OBJECTINSTANCE STRING . + + $default reduce using rule 47 (pbrt_stmt) + + +state 62 + + 48 pbrt_stmt: PIXELFILTER STRING . paramlist + + $default reduce using rule 20 (paramlist_init) + + paramlist go to state 89 + paramlist_init go to state 78 + + +state 63 + + 49 pbrt_stmt: RENDERER STRING . paramlist + + $default reduce using rule 20 (paramlist_init) + + paramlist go to state 90 + paramlist_init go to state 78 + + +state 64 + + 51 pbrt_stmt: ROTATE NUM . NUM NUM NUM + + NUM shift, and go to state 91 + + +state 65 + + 52 pbrt_stmt: SAMPLER STRING . paramlist + + $default reduce using rule 20 (paramlist_init) + + paramlist go to state 92 + paramlist_init go to state 78 + + +state 66 + + 53 pbrt_stmt: SCALE NUM . NUM NUM + + NUM shift, and go to state 93 + + +state 67 + + 54 pbrt_stmt: SHAPE STRING . paramlist + + $default reduce using rule 20 (paramlist_init) + + paramlist go to state 94 + paramlist_init go to state 78 + + +state 68 + + 55 pbrt_stmt: SURFACEINTEGRATOR STRING . paramlist + + $default reduce using rule 20 (paramlist_init) + + paramlist go to state 95 + paramlist_init go to state 78 + + +state 69 + + 56 pbrt_stmt: TEXTURE STRING . STRING STRING paramlist + + STRING shift, and go to state 96 + + +state 70 + + 59 pbrt_stmt: TRANSFORMTIMES NUM . NUM + + NUM shift, and go to state 97 + + +state 71 + + 60 pbrt_stmt: TRANSFORM num_array . + + $default reduce using rule 60 (pbrt_stmt) + + +state 72 + + 61 pbrt_stmt: TRANSLATE NUM . NUM NUM + + NUM shift, and go to state 98 + + +state 73 + + 63 pbrt_stmt: VOLUME STRING . paramlist + + $default reduce using rule 20 (paramlist_init) + + paramlist go to state 99 + paramlist_init go to state 78 + + +state 74 + + 62 pbrt_stmt: VOLUMEINTEGRATOR STRING . paramlist + + $default reduce using rule 20 (paramlist_init) + + paramlist go to state 100 + paramlist_init go to state 78 + + +state 75 + + 0 $accept: start $end . + + $default accept + + +state 76 + + 24 pbrt_stmt_list: pbrt_stmt_list pbrt_stmt . + + $default reduce using rule 24 (pbrt_stmt_list) + + +state 77 + + 26 pbrt_stmt: ACCELERATOR STRING paramlist . + + $default reduce using rule 26 (pbrt_stmt) + + +state 78 + + 19 paramlist: paramlist_init . paramlist_contents + + STRING shift, and go to state 101 + + $default reduce using rule 22 (paramlist_contents) + + paramlist_contents go to state 102 + paramlist_entry go to state 103 + + +state 79 + + 30 pbrt_stmt: AREALIGHTSOURCE STRING paramlist . + + $default reduce using rule 30 (pbrt_stmt) + + +state 80 + + 33 pbrt_stmt: CAMERA STRING paramlist . + + $default reduce using rule 33 (pbrt_stmt) + + +state 81 + + 13 num_array: array_init LBRACK . num_list RBRACK + + $default reduce using rule 4 (num_array_init) + + num_array_init go to state 82 + num_list go to state 104 + num_list_entry go to state 105 + + +state 82 + + 18 num_list_entry: num_array_init . NUM + + NUM shift, and go to state 106 + + +state 83 + + 15 single_element_num_array: array_init num_list_entry . + + $default reduce using rule 15 (single_element_num_array) + + +state 84 + + 37 pbrt_stmt: FILM STRING paramlist . + + $default reduce using rule 37 (pbrt_stmt) + + +state 85 + + 40 pbrt_stmt: LIGHTSOURCE STRING paramlist . + + $default reduce using rule 40 (pbrt_stmt) + + +state 86 + + 41 pbrt_stmt: LOOKAT NUM NUM . NUM NUM NUM NUM NUM NUM NUM + + NUM shift, and go to state 107 + + +state 87 + + 42 pbrt_stmt: MAKENAMEDMATERIAL STRING paramlist . + + $default reduce using rule 42 (pbrt_stmt) + + +state 88 + + 43 pbrt_stmt: MATERIAL STRING paramlist . + + $default reduce using rule 43 (pbrt_stmt) + + +state 89 + + 48 pbrt_stmt: PIXELFILTER STRING paramlist . + + $default reduce using rule 48 (pbrt_stmt) + + +state 90 + + 49 pbrt_stmt: RENDERER STRING paramlist . + + $default reduce using rule 49 (pbrt_stmt) + + +state 91 + + 51 pbrt_stmt: ROTATE NUM NUM . NUM NUM + + NUM shift, and go to state 108 + + +state 92 + + 52 pbrt_stmt: SAMPLER STRING paramlist . + + $default reduce using rule 52 (pbrt_stmt) + + +state 93 + + 53 pbrt_stmt: SCALE NUM NUM . NUM + + NUM shift, and go to state 109 + + +state 94 + + 54 pbrt_stmt: SHAPE STRING paramlist . + + $default reduce using rule 54 (pbrt_stmt) + + +state 95 + + 55 pbrt_stmt: SURFACEINTEGRATOR STRING paramlist . + + $default reduce using rule 55 (pbrt_stmt) + + +state 96 + + 56 pbrt_stmt: TEXTURE STRING STRING . STRING paramlist + + STRING shift, and go to state 110 + + +state 97 + + 59 pbrt_stmt: TRANSFORMTIMES NUM NUM . + + $default reduce using rule 59 (pbrt_stmt) + + +state 98 + + 61 pbrt_stmt: TRANSLATE NUM NUM . NUM + + NUM shift, and go to state 111 + + +state 99 + + 63 pbrt_stmt: VOLUME STRING paramlist . + + $default reduce using rule 63 (pbrt_stmt) + + +state 100 + + 62 pbrt_stmt: VOLUMEINTEGRATOR STRING paramlist . + + $default reduce using rule 62 (pbrt_stmt) + + +state 101 + + 23 paramlist_entry: STRING . array + + $default reduce using rule 2 (array_init) + + array_init go to state 112 + array go to state 113 + string_array go to state 114 + single_element_string_array go to state 115 + num_array go to state 116 + single_element_num_array go to state 50 + + +state 102 + + 19 paramlist: paramlist_init paramlist_contents . + + $default reduce using rule 19 (paramlist) + + +state 103 + + 21 paramlist_contents: paramlist_entry . paramlist_contents + + STRING shift, and go to state 101 + + $default reduce using rule 22 (paramlist_contents) + + paramlist_contents go to state 117 + paramlist_entry go to state 103 + + +state 104 + + 13 num_array: array_init LBRACK num_list . RBRACK + 16 num_list: num_list . num_list_entry + + RBRACK shift, and go to state 118 + + $default reduce using rule 4 (num_array_init) + + num_array_init go to state 82 + num_list_entry go to state 119 + + +state 105 + + 17 num_list: num_list_entry . + + $default reduce using rule 17 (num_list) + + +state 106 + + 18 num_list_entry: num_array_init NUM . + + $default reduce using rule 18 (num_list_entry) + + +state 107 + + 41 pbrt_stmt: LOOKAT NUM NUM NUM . NUM NUM NUM NUM NUM NUM + + NUM shift, and go to state 120 + + +state 108 + + 51 pbrt_stmt: ROTATE NUM NUM NUM . NUM + + NUM shift, and go to state 121 + + +state 109 + + 53 pbrt_stmt: SCALE NUM NUM NUM . + + $default reduce using rule 53 (pbrt_stmt) + + +state 110 + + 56 pbrt_stmt: TEXTURE STRING STRING STRING . paramlist + + $default reduce using rule 20 (paramlist_init) + + paramlist go to state 122 + paramlist_init go to state 78 + + +state 111 + + 61 pbrt_stmt: TRANSLATE NUM NUM NUM . + + $default reduce using rule 61 (pbrt_stmt) + + +state 112 + + 7 string_array: array_init . LBRACK string_list RBRACK + 9 single_element_string_array: array_init . string_list_entry + 13 num_array: array_init . LBRACK num_list RBRACK + 15 single_element_num_array: array_init . num_list_entry + + LBRACK shift, and go to state 123 + + NUM reduce using rule 4 (num_array_init) + $default reduce using rule 3 (string_array_init) + + string_array_init go to state 124 + num_array_init go to state 82 + string_list_entry go to state 125 + num_list_entry go to state 83 + + +state 113 + + 23 paramlist_entry: STRING array . + + $default reduce using rule 23 (paramlist_entry) + + +state 114 + + 5 array: string_array . + + $default reduce using rule 5 (array) + + +state 115 + + 8 string_array: single_element_string_array . + + $default reduce using rule 8 (string_array) + + +state 116 + + 6 array: num_array . + + $default reduce using rule 6 (array) + + +state 117 + + 21 paramlist_contents: paramlist_entry paramlist_contents . + + $default reduce using rule 21 (paramlist_contents) + + +state 118 + + 13 num_array: array_init LBRACK num_list RBRACK . + + $default reduce using rule 13 (num_array) + + +state 119 + + 16 num_list: num_list num_list_entry . + + $default reduce using rule 16 (num_list) + + +state 120 + + 41 pbrt_stmt: LOOKAT NUM NUM NUM NUM . NUM NUM NUM NUM NUM + + NUM shift, and go to state 126 + + +state 121 + + 51 pbrt_stmt: ROTATE NUM NUM NUM NUM . + + $default reduce using rule 51 (pbrt_stmt) + + +state 122 + + 56 pbrt_stmt: TEXTURE STRING STRING STRING paramlist . + + $default reduce using rule 56 (pbrt_stmt) + + +state 123 + + 7 string_array: array_init LBRACK . string_list RBRACK + 13 num_array: array_init LBRACK . num_list RBRACK + + NUM reduce using rule 4 (num_array_init) + $default reduce using rule 3 (string_array_init) + + string_array_init go to state 124 + num_array_init go to state 82 + string_list go to state 127 + string_list_entry go to state 128 + num_list go to state 104 + num_list_entry go to state 105 + + +state 124 + + 12 string_list_entry: string_array_init . STRING + + STRING shift, and go to state 129 + + +state 125 + + 9 single_element_string_array: array_init string_list_entry . + + $default reduce using rule 9 (single_element_string_array) + + +state 126 + + 41 pbrt_stmt: LOOKAT NUM NUM NUM NUM NUM . NUM NUM NUM NUM + + NUM shift, and go to state 130 + + +state 127 + + 7 string_array: array_init LBRACK string_list . RBRACK + 10 string_list: string_list . string_list_entry + + RBRACK shift, and go to state 131 + + $default reduce using rule 3 (string_array_init) + + string_array_init go to state 124 + string_list_entry go to state 132 + + +state 128 + + 11 string_list: string_list_entry . + + $default reduce using rule 11 (string_list) + + +state 129 + + 12 string_list_entry: string_array_init STRING . + + $default reduce using rule 12 (string_list_entry) + + +state 130 + + 41 pbrt_stmt: LOOKAT NUM NUM NUM NUM NUM NUM . NUM NUM NUM + + NUM shift, and go to state 133 + + +state 131 + + 7 string_array: array_init LBRACK string_list RBRACK . + + $default reduce using rule 7 (string_array) + + +state 132 + + 10 string_list: string_list string_list_entry . + + $default reduce using rule 10 (string_list) + + +state 133 + + 41 pbrt_stmt: LOOKAT NUM NUM NUM NUM NUM NUM NUM . NUM NUM + + NUM shift, and go to state 134 + + +state 134 + + 41 pbrt_stmt: LOOKAT NUM NUM NUM NUM NUM NUM NUM NUM . NUM + + NUM shift, and go to state 135 + + +state 135 + + 41 pbrt_stmt: LOOKAT NUM NUM NUM NUM NUM NUM NUM NUM NUM . + + $default reduce using rule 41 (pbrt_stmt) diff --git a/core/pbrtparse.yy b/core/pbrtparse.yy new file mode 100644 index 0000000..a78ede2 --- /dev/null +++ b/core/pbrtparse.yy @@ -0,0 +1,805 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +%{ +#include "api.h" +#include "pbrt.h" +#include "paramset.h" +#include + +#ifdef PBRT_IS_WINDOWS +#pragma warning(disable:4065) +#pragma warning(disable:4996) +#pragma warning(disable:4018) +#endif // PBRT_IS_WINDOWS + +extern int yylex(); +extern void include_push(char *filename); +int line_num = 0; +string current_file; + +#define YYMAXDEPTH 100000000 + +void yyerror(const char *str) { + Severe("Parsing error: %s", str); +} + + + +struct ParamArray { + ParamArray() { + isString = false; + element_size = allocated = nelems = 0; + array = NULL; + } + bool isString; + int element_size; + int allocated; + int nelems; + void *array; +}; + + + +struct ParamListItem { + ParamListItem(const char *t, ParamArray *array) { + arg = array->array; + name = t; + size = array->nelems; + isString = array->isString; + array->allocated = 0; + array->nelems = 0; + array->array = NULL; + } + const char *name; + void *arg; + int size; + bool isString; +}; + + + +static vector cur_paramlist; + +static ParamArray *cur_array = NULL; + +static void AddArrayElement(void *elem) { + if (cur_array->nelems >= cur_array->allocated) { + cur_array->allocated = 2*cur_array->allocated + 1; + cur_array->array = realloc(cur_array->array, + cur_array->allocated*cur_array->element_size); + } + char *next = ((char *)cur_array->array) + cur_array->nelems * cur_array->element_size; + Assert(cur_array->element_size == 4 || cur_array->element_size == 8); + if (cur_array->element_size == 4) + *((uint32_t *)next) = *((uint32_t *)elem); + else + *((uint64_t *)next) = *((uint64_t *)elem); + cur_array->nelems++; +} + + + +static void ArrayFree(ParamArray *ra) { + if (ra->isString && ra->array) + for (int i = 0; i < ra->nelems; ++i) free(((char **)ra->array)[i]); + free(ra->array); + delete ra; +} + + + +static void FreeArgs() { + for (uint32_t i = 0; i < cur_paramlist.size(); ++i) + free((char *)cur_paramlist[i].arg); + cur_paramlist.erase(cur_paramlist.begin(), cur_paramlist.end()); +} + + + +static bool VerifyArrayLength(ParamArray *arr, int required, + const char *command) { + if (arr->nelems != required) { + Error("\"%s\" requires a %d element array! (%d found)", + command, required, arr->nelems); + return false; + } + return true; +} + + +enum { PARAM_TYPE_INT, PARAM_TYPE_BOOL, PARAM_TYPE_FLOAT, PARAM_TYPE_POINT, + PARAM_TYPE_VECTOR, PARAM_TYPE_NORMAL, PARAM_TYPE_RGB, PARAM_TYPE_XYZ, + PARAM_TYPE_BLACKBODY, PARAM_TYPE_SPECTRUM, + PARAM_TYPE_STRING, PARAM_TYPE_TEXTURE }; +static const char *paramTypeToName(int type); +static void InitParamSet(ParamSet &ps, SpectrumType); +static bool lookupType(const char *name, int *type, string &sname); +#define YYPRINT(file, type, value) { \ + if ((type) == ID || (type) == STRING) \ + fprintf ((file), " %s", (value).string); \ + else if ((type) == NUM) \ + fprintf ((file), " %f", (value).num); \ +} + + +%} + +%union { +char string[1024]; +float num; +ParamArray *ribarray; +} + + +%token STRING ID +%token NUM +%token LBRACK RBRACK + +%token ACCELERATOR ACTIVETRANSFORM ALL AREALIGHTSOURCE ATTRIBUTEBEGIN +%token ATTRIBUTEEND CAMERA CONCATTRANSFORM COORDINATESYSTEM COORDSYSTRANSFORM +%token ENDTIME FILM IDENTITY INCLUDE LIGHTSOURCE LOOKAT MAKENAMEDMATERIAL +%token MATERIAL NAMEDMATERIAL OBJECTBEGIN OBJECTEND OBJECTINSTANCE PIXELFILTER +%token RENDERER REVERSEORIENTATION ROTATE SAMPLER SCALE SHAPE STARTTIME +%token SURFACEINTEGRATOR TEXTURE TRANSFORMBEGIN TRANSFORMEND TRANSFORMTIMES +%token TRANSFORM TRANSLATE VOLUME VOLUMEINTEGRATOR WORLDBEGIN WORLDEND + +%token HIGH_PRECEDENCE + +%type array num_array string_array +%% +start: pbrt_stmt_list +{ +}; + + + +array_init: %prec HIGH_PRECEDENCE +{ + if (cur_array) Severe("MUH"); + cur_array = new ParamArray; +}; + + + +string_array_init: %prec HIGH_PRECEDENCE +{ + cur_array->element_size = sizeof(const char *); + cur_array->isString = true; +}; + + + +num_array_init: %prec HIGH_PRECEDENCE +{ + cur_array->element_size = sizeof(float); + cur_array->isString = false; +}; + + + +array: string_array +{ + $$ = $1; +} + + +| num_array +{ + $$ = $1; +}; + + + +string_array: array_init LBRACK string_list RBRACK +{ + $$ = cur_array; + cur_array = NULL; +} + + +| single_element_string_array +{ + $$ = cur_array; + cur_array = NULL; +}; + + + +single_element_string_array: array_init string_list_entry +{ +}; + + + +string_list: string_list string_list_entry +{ +} + + +| string_list_entry +{ +}; + + + +string_list_entry: string_array_init STRING +{ + char *to_add = strdup($2); + AddArrayElement(&to_add); +}; + + + +num_array: array_init LBRACK num_list RBRACK +{ + $$ = cur_array; + cur_array = NULL; +} + + +| single_element_num_array +{ + $$ = cur_array; + cur_array = NULL; +}; + + + +single_element_num_array: array_init num_list_entry +{ +}; + + + +num_list: num_list num_list_entry +{ +} + + +| num_list_entry +{ +}; + + + +num_list_entry: num_array_init NUM +{ + float to_add = $2; + AddArrayElement(&to_add); +}; + + + +paramlist: paramlist_init paramlist_contents +{ +}; + + + +paramlist_init: %prec HIGH_PRECEDENCE +{ + for (uint32_t i = 0; i < cur_paramlist.size(); ++i) { + if (cur_paramlist[i].isString) { + for (uint32_t j = 0; j < cur_paramlist[i].size; ++j) + free(((char **)cur_paramlist[i].arg)[j]); + } + } + cur_paramlist.erase(cur_paramlist.begin(), cur_paramlist.end()); +}; + + + +paramlist_contents: paramlist_entry paramlist_contents +{ +} + + +| +{ +}; + + + +paramlist_entry: STRING array +{ + cur_paramlist.push_back(ParamListItem($1, $2)); + ArrayFree($2); +}; + + + +pbrt_stmt_list: pbrt_stmt_list pbrt_stmt +{ +} + + +| pbrt_stmt +{ +}; + + + +pbrt_stmt: ACCELERATOR STRING paramlist +{ + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtAccelerator($2, params); + FreeArgs(); +} + + +| ACTIVETRANSFORM ALL +{ + pbrtActiveTransformAll(); +} + + +| ACTIVETRANSFORM ENDTIME +{ + pbrtActiveTransformEndTime(); +} + + +| ACTIVETRANSFORM STARTTIME +{ + pbrtActiveTransformStartTime(); +} + + +| AREALIGHTSOURCE STRING paramlist +{ + ParamSet params; + InitParamSet(params, SPECTRUM_ILLUMINANT); + pbrtAreaLightSource($2, params); + FreeArgs(); +} + + +| ATTRIBUTEBEGIN +{ + pbrtAttributeBegin(); +} + + +| ATTRIBUTEEND +{ + pbrtAttributeEnd(); +} + + +| CAMERA STRING paramlist +{ + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtCamera($2, params); + FreeArgs(); +} + + +| CONCATTRANSFORM num_array +{ + if (VerifyArrayLength($2, 16, "ConcatTransform")) + pbrtConcatTransform((float *) $2->array); + ArrayFree($2); +} + + +| COORDINATESYSTEM STRING +{ + pbrtCoordinateSystem($2); +} + + +| COORDSYSTRANSFORM STRING +{ + pbrtCoordSysTransform($2); +} + + +| FILM STRING paramlist +{ + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtFilm($2, params); + FreeArgs(); +} + + +| IDENTITY +{ + pbrtIdentity(); +} + + +| INCLUDE STRING +{ + include_push($2); +} + + +| LIGHTSOURCE STRING paramlist +{ + ParamSet params; + InitParamSet(params, SPECTRUM_ILLUMINANT); + pbrtLightSource($2, params); + FreeArgs(); +} + + +| LOOKAT NUM NUM NUM NUM NUM NUM NUM NUM NUM +{ + pbrtLookAt($2, $3, $4, $5, $6, $7, $8, $9, $10); +} + + +| MAKENAMEDMATERIAL STRING paramlist +{ + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtMakeNamedMaterial($2, params); + FreeArgs(); +} + + +| MATERIAL STRING paramlist +{ + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtMaterial($2, params); + FreeArgs(); +} + + +| NAMEDMATERIAL STRING +{ + pbrtNamedMaterial($2); +} + + +| OBJECTBEGIN STRING +{ + pbrtObjectBegin($2); +} + + +| OBJECTEND +{ + pbrtObjectEnd(); +} + + +| OBJECTINSTANCE STRING +{ + pbrtObjectInstance($2); +} + + +| PIXELFILTER STRING paramlist +{ + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtPixelFilter($2, params); + FreeArgs(); +} + + +| RENDERER STRING paramlist +{ + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtRenderer($2, params); + FreeArgs(); +} + + +| REVERSEORIENTATION +{ + pbrtReverseOrientation(); +} + + +| ROTATE NUM NUM NUM NUM +{ + pbrtRotate($2, $3, $4, $5); +} + + +| SAMPLER STRING paramlist +{ + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtSampler($2, params); + FreeArgs(); +} + + +| SCALE NUM NUM NUM +{ + pbrtScale($2, $3, $4); +} + + +| SHAPE STRING paramlist +{ + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtShape($2, params); + FreeArgs(); +} + + +| SURFACEINTEGRATOR STRING paramlist +{ + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtSurfaceIntegrator($2, params); + FreeArgs(); +} + + +| TEXTURE STRING STRING STRING paramlist +{ + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtTexture($2, $3, $4, params); + FreeArgs(); +} + + +| TRANSFORMBEGIN +{ + pbrtTransformBegin(); +} + + +| TRANSFORMEND +{ + pbrtTransformEnd(); +} + + +| TRANSFORMTIMES NUM NUM +{ + pbrtTransformTimes($2, $3); +} + + +| TRANSFORM num_array +{ + if (VerifyArrayLength( $2, 16, "Transform" )) + pbrtTransform( (float *) $2->array ); + ArrayFree($2); +} + + +| TRANSLATE NUM NUM NUM +{ + pbrtTranslate($2, $3, $4); +} + + +| VOLUMEINTEGRATOR STRING paramlist +{ + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtVolumeIntegrator($2, params); + FreeArgs(); +} + + +| VOLUME STRING paramlist +{ + ParamSet params; + InitParamSet(params, SPECTRUM_REFLECTANCE); + pbrtVolume($2, params); + FreeArgs(); +} + + +| WORLDBEGIN +{ + pbrtWorldBegin(); +} + + +| WORLDEND +{ + pbrtWorldEnd(); +}; + + +%% +static const char *paramTypeToName(int type) { + switch (type) { + case PARAM_TYPE_INT: return "int"; + case PARAM_TYPE_BOOL: return "bool"; + case PARAM_TYPE_FLOAT: return "float"; + case PARAM_TYPE_POINT: return "point"; + case PARAM_TYPE_VECTOR: return "vector"; + case PARAM_TYPE_NORMAL: return "normal"; + case PARAM_TYPE_RGB: return "rgb/color"; + case PARAM_TYPE_XYZ: return "xyz"; + case PARAM_TYPE_BLACKBODY: return "blackbody"; + case PARAM_TYPE_SPECTRUM: return "spectrum"; + case PARAM_TYPE_STRING: return "string"; + case PARAM_TYPE_TEXTURE: return "texture"; + default: Severe("Error in paramTypeToName"); return NULL; + } +} + + +static void InitParamSet(ParamSet &ps, SpectrumType type) { + ps.Clear(); + for (uint32_t i = 0; i < cur_paramlist.size(); ++i) { + int type; + string name; + if (lookupType(cur_paramlist[i].name, &type, name)) { + if (type == PARAM_TYPE_TEXTURE || type == PARAM_TYPE_STRING || + type == PARAM_TYPE_BOOL) { + if (!cur_paramlist[i].isString) { + Error("Expected string parameter value for parameter \"%s\" with type \"%s\". Ignoring.", + name.c_str(), paramTypeToName(type)); + continue; + } + } + else if (type != PARAM_TYPE_SPECTRUM) { /* spectrum can be either... */ + if (cur_paramlist[i].isString) { + Error("Expected numeric parameter value for parameter \"%s\" with type \"%s\". Ignoring.", + name.c_str(), paramTypeToName(type)); + continue; + } + } + void *data = cur_paramlist[i].arg; + int nItems = cur_paramlist[i].size; + if (type == PARAM_TYPE_INT) { + // parser doesn't handle ints, so convert from floats here.... + int nAlloc = nItems; + int *idata = new int[nAlloc]; + float *fdata = (float *)cur_paramlist[i].arg; + for (int j = 0; j < nAlloc; ++j) + idata[j] = int(fdata[j]); + ps.AddInt(name, idata, nItems); + delete[] idata; + } + else if (type == PARAM_TYPE_BOOL) { + // strings -> bools + int nAlloc = cur_paramlist[i].size; + bool *bdata = new bool[nAlloc]; + for (int j = 0; j < nAlloc; ++j) { + string s(((const char **)data)[j]); + if (s == "true") bdata[j] = true; + else if (s == "false") bdata[j] = false; + else { + Warning("Value \"%s\" unknown for boolean parameter \"%s\"." + "Using \"false\".", s.c_str(), cur_paramlist[i].name); + bdata[j] = false; + } + } + ps.AddBool(name, bdata, nItems); + delete[] bdata; + } + else if (type == PARAM_TYPE_FLOAT) { + ps.AddFloat(name, (float *)data, nItems); + } else if (type == PARAM_TYPE_POINT) { + if ((nItems % 3) != 0) + Warning("Excess values given with point parameter \"%s\". " + "Ignoring last %d of them", cur_paramlist[i].name, nItems % 3); + ps.AddPoint(name, (Point *)data, nItems / 3); + } else if (type == PARAM_TYPE_VECTOR) { + if ((nItems % 3) != 0) + Warning("Excess values given with vector parameter \"%s\". " + "Ignoring last %d of them", cur_paramlist[i].name, nItems % 3); + ps.AddVector(name, (Vector *)data, nItems / 3); + } else if (type == PARAM_TYPE_NORMAL) { + if ((nItems % 3) != 0) + Warning("Excess values given with normal parameter \"%s\". " + "Ignoring last %d of them", cur_paramlist[i].name, nItems % 3); + ps.AddNormal(name, (Normal *)data, nItems / 3); + } else if (type == PARAM_TYPE_RGB) { + if ((nItems % 3) != 0) + Warning("Excess RGB values given with parameter \"%s\". " + "Ignoring last %d of them", cur_paramlist[i].name, nItems % 3); + ps.AddRGBSpectrum(name, (float *)data, nItems); + } else if (type == PARAM_TYPE_XYZ) { + if ((nItems % 3) != 0) + Warning("Excess XYZ values given with parameter \"%s\". " + "Ignoring last %d of them", cur_paramlist[i].name, nItems % 3); + ps.AddXYZSpectrum(name, (float *)data, nItems); + } else if (type == PARAM_TYPE_BLACKBODY) { + if ((nItems % 2) != 0) + Warning("Excess value given with blackbody parameter \"%s\". " + "Ignoring extra one.", cur_paramlist[i].name); + ps.AddBlackbodySpectrum(name, (float *)data, nItems); + } else if (type == PARAM_TYPE_SPECTRUM) { + if (cur_paramlist[i].isString) { + ps.AddSampledSpectrumFiles(name, (const char **)data, nItems); + } + else { + if ((nItems % 2) != 0) + Warning("Non-even number of values given with sampled spectrum " + "parameter \"%s\". Ignoring extra.", cur_paramlist[i].name); + ps.AddSampledSpectrum(name, (float *)data, nItems); + } + } else if (type == PARAM_TYPE_STRING) { + string *strings = new string[nItems]; + for (int j = 0; j < nItems; ++j) + strings[j] = string(((const char **)data)[j]); + ps.AddString(name, strings, nItems); + delete[] strings; + } + else if (type == PARAM_TYPE_TEXTURE) { + if (nItems == 1) { + string val(*((const char **)data)); + ps.AddTexture(name, val); + } + else + Error("Only one string allowed for \"texture\" parameter \"%s\"", + name.c_str()); + } + } + else + Warning("Type of parameter \"%s\" is unknown", + cur_paramlist[i].name); + } +} + + +static bool lookupType(const char *name, int *type, string &sname) { + Assert(name != NULL); + *type = 0; + const char *strp = name; + while (*strp && isspace(*strp)) + ++strp; + if (!*strp) { + Error("Parameter \"%s\" doesn't have a type declaration?!", name); + return false; + } +#define TRY_DECODING_TYPE(name, mask) \ + if (strncmp(name, strp, strlen(name)) == 0) { \ + *type = mask; strp += strlen(name); \ + } + TRY_DECODING_TYPE("float", PARAM_TYPE_FLOAT) + else TRY_DECODING_TYPE("integer", PARAM_TYPE_INT) + else TRY_DECODING_TYPE("bool", PARAM_TYPE_BOOL) + else TRY_DECODING_TYPE("point", PARAM_TYPE_POINT) + else TRY_DECODING_TYPE("vector", PARAM_TYPE_VECTOR) + else TRY_DECODING_TYPE("normal", PARAM_TYPE_NORMAL) + else TRY_DECODING_TYPE("string", PARAM_TYPE_STRING) + else TRY_DECODING_TYPE("texture", PARAM_TYPE_TEXTURE) + else TRY_DECODING_TYPE("color", PARAM_TYPE_RGB) + else TRY_DECODING_TYPE("rgb", PARAM_TYPE_RGB) + else TRY_DECODING_TYPE("xyz", PARAM_TYPE_XYZ) + else TRY_DECODING_TYPE("blackbody", PARAM_TYPE_BLACKBODY) + else TRY_DECODING_TYPE("spectrum", PARAM_TYPE_SPECTRUM) + else { + Error("Unable to decode type for name \"%s\"", name); + return false; + } + while (*strp && isspace(*strp)) + ++strp; + sname = string(strp); + return true; +} + + diff --git a/core/primitive.cpp b/core/primitive.cpp new file mode 100644 index 0000000..62d8d0e --- /dev/null +++ b/core/primitive.cpp @@ -0,0 +1,193 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/primitive.cpp* +#include "stdafx.h" +#include "primitive.h" +#include "light.h" +#include "intersection.h" + +// Primitive Method Definitions +uint32_t Primitive::nextprimitiveId = 1; +Primitive::~Primitive() { } + +bool Primitive::CanIntersect() const { + return true; +} + + + +void Primitive::Refine(vector > &refined) const { + Severe("Unimplemented Primitive::Refine() method called!"); +} + + +void +Primitive::FullyRefine(vector > &refined) const { + vector > todo; + todo.push_back(const_cast(this)); + while (todo.size()) { + // Refine last primitive in todo list + Reference prim = todo.back(); + todo.pop_back(); + if (prim->CanIntersect()) + refined.push_back(prim); + else + prim->Refine(todo); + } +} + + +const AreaLight *Aggregate::GetAreaLight() const { + Severe("Aggregate::GetAreaLight() method" + "called; should have gone to GeometricPrimitive"); + return NULL; +} + + +BSDF *Aggregate::GetBSDF(const DifferentialGeometry &, + const Transform &, MemoryArena &) const { + Severe("Aggregate::GetBSDF() method" + "called; should have gone to GeometricPrimitive"); + return NULL; +} + + +BSSRDF *Aggregate::GetBSSRDF(const DifferentialGeometry &, + const Transform &, MemoryArena &) const { + Severe("Aggregate::GetBSSRDF() method" + "called; should have gone to GeometricPrimitive"); + return NULL; +} + + + +// TransformedPrimitive Method Definitions +bool TransformedPrimitive::Intersect(const Ray &r, + Intersection *isect) const { + Transform w2p; + WorldToPrimitive.Interpolate(r.time, &w2p); + Ray ray = w2p(r); + if (!primitive->Intersect(ray, isect)) + return false; + r.maxt = ray.maxt; + isect->primitiveId = primitiveId; + if (!w2p.IsIdentity()) { + // Compute world-to-object transformation for instance + isect->WorldToObject = isect->WorldToObject * w2p; + isect->ObjectToWorld = Inverse(isect->WorldToObject); + + // Transform instance's differential geometry to world space + Transform PrimitiveToWorld = Inverse(w2p); + isect->dg.p = PrimitiveToWorld(isect->dg.p); + isect->dg.nn = Normalize(PrimitiveToWorld(isect->dg.nn)); + isect->dg.dpdu = PrimitiveToWorld(isect->dg.dpdu); + isect->dg.dpdv = PrimitiveToWorld(isect->dg.dpdv); + isect->dg.dndu = PrimitiveToWorld(isect->dg.dndu); + isect->dg.dndv = PrimitiveToWorld(isect->dg.dndv); + } + return true; +} + + +bool TransformedPrimitive::IntersectP(const Ray &r) const { + return primitive->IntersectP(WorldToPrimitive(r)); +} + + + +// GeometricPrimitive Method Definitions +BBox GeometricPrimitive::WorldBound() const { + return shape->WorldBound(); +} + + +bool GeometricPrimitive::IntersectP(const Ray &r) const { + return shape->IntersectP(r); +} + + +bool GeometricPrimitive::CanIntersect() const { + return shape->CanIntersect(); +} + + +void GeometricPrimitive:: + Refine(vector > &refined) + const { + vector > r; + shape->Refine(r); + for (uint32_t i = 0; i < r.size(); ++i) { + GeometricPrimitive *gp = new GeometricPrimitive(r[i], + material, areaLight); + refined.push_back(gp); + } +} + + +GeometricPrimitive::GeometricPrimitive(const Reference &s, + const Reference &m, AreaLight *a) + : shape(s), material(m), areaLight(a) { +} + + +bool GeometricPrimitive::Intersect(const Ray &r, + Intersection *isect) const { + float thit, rayEpsilon; + if (!shape->Intersect(r, &thit, &rayEpsilon, &isect->dg)) + return false; + isect->primitive = this; + isect->WorldToObject = *shape->WorldToObject; + isect->ObjectToWorld = *shape->ObjectToWorld; + isect->shapeId = shape->shapeId; + isect->primitiveId = primitiveId; + isect->rayEpsilon = rayEpsilon; + r.maxt = thit; + return true; +} + + +const AreaLight *GeometricPrimitive::GetAreaLight() const { + return areaLight; +} + + +BSDF *GeometricPrimitive::GetBSDF(const DifferentialGeometry &dg, + const Transform &ObjectToWorld, + MemoryArena &arena) const { + DifferentialGeometry dgs; + shape->GetShadingGeometry(ObjectToWorld, dg, &dgs); + return material->GetBSDF(dg, dgs, arena); +} + + +BSSRDF *GeometricPrimitive::GetBSSRDF(const DifferentialGeometry &dg, + const Transform &ObjectToWorld, + MemoryArena &arena) const { + DifferentialGeometry dgs; + shape->GetShadingGeometry(ObjectToWorld, dg, &dgs); + return material->GetBSSRDF(dg, dgs, arena); +} + + diff --git a/core/primitive.h b/core/primitive.h new file mode 100644 index 0000000..9aa42fb --- /dev/null +++ b/core/primitive.h @@ -0,0 +1,130 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_PRIMITIVE_H +#define PBRT_CORE_PRIMITIVE_H + +// core/primitive.h* +#include "pbrt.h" +#include "shape.h" +#include "material.h" + +// Primitive Declarations +class Primitive : public ReferenceCounted { +public: + // Primitive Interface + Primitive() : primitiveId(nextprimitiveId++) { } + virtual ~Primitive(); + virtual BBox WorldBound() const = 0; + virtual bool CanIntersect() const; + virtual bool Intersect(const Ray &r, Intersection *in) const = 0; + virtual bool IntersectP(const Ray &r) const = 0; + virtual void Refine(vector > &refined) const; + void FullyRefine(vector > &refined) const; + virtual const AreaLight *GetAreaLight() const = 0; + virtual BSDF *GetBSDF(const DifferentialGeometry &dg, + const Transform &ObjectToWorld, MemoryArena &arena) const = 0; + virtual BSSRDF *GetBSSRDF(const DifferentialGeometry &dg, + const Transform &ObjectToWorld, MemoryArena &arena) const = 0; + + // Primitive Public Data + const uint32_t primitiveId; +protected: + // Primitive Protected Data + static uint32_t nextprimitiveId; +}; + + + +// GeometricPrimitive Declarations +class GeometricPrimitive : public Primitive { +public: + // GeometricPrimitive Public Methods + bool CanIntersect() const; + void Refine(vector > &refined) const; + virtual BBox WorldBound() const; + virtual bool Intersect(const Ray &r, Intersection *isect) const; + virtual bool IntersectP(const Ray &r) const; + GeometricPrimitive(const Reference &s, + const Reference &m, AreaLight *a); + const AreaLight *GetAreaLight() const; + BSDF *GetBSDF(const DifferentialGeometry &dg, + const Transform &ObjectToWorld, MemoryArena &arena) const; + BSSRDF *GetBSSRDF(const DifferentialGeometry &dg, + const Transform &ObjectToWorld, MemoryArena &arena) const; +private: + // GeometricPrimitive Private Data + Reference shape; + Reference material; + AreaLight *areaLight; +}; + + + +// TransformedPrimitive Declarations +class TransformedPrimitive : public Primitive { +public: + // TransformedPrimitive Public Methods + TransformedPrimitive(Reference &prim, + const AnimatedTransform &w2p) + : primitive(prim), WorldToPrimitive(w2p) { } + bool Intersect(const Ray &r, Intersection *in) const; + bool IntersectP(const Ray &r) const; + const AreaLight *GetAreaLight() const { return NULL; } + BSDF *GetBSDF(const DifferentialGeometry &dg, + const Transform &ObjectToWorld, MemoryArena &arena) const { + return NULL; + } + BSSRDF *GetBSSRDF(const DifferentialGeometry &dg, + const Transform &ObjectToWorld, MemoryArena &arena) const { + return NULL; + } + BBox WorldBound() const { + return WorldToPrimitive.MotionBounds(primitive->WorldBound(), true); + } +private: + // TransformedPrimitive Private Data + Reference primitive; + const AnimatedTransform WorldToPrimitive; +}; + + + +// Aggregate Declarations +class Aggregate : public Primitive { +public: + // Aggregate Public Methods + const AreaLight *GetAreaLight() const; + BSDF *GetBSDF(const DifferentialGeometry &dg, + const Transform &, MemoryArena &) const; + BSSRDF *GetBSSRDF(const DifferentialGeometry &dg, + const Transform &, MemoryArena &) const; +}; + + + +#endif // PBRT_CORE_PRIMITIVE_H diff --git a/core/probes.cpp b/core/probes.cpp new file mode 100644 index 0000000..6443f2c --- /dev/null +++ b/core/probes.cpp @@ -0,0 +1,358 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/probes.cpp* +#include "stdafx.h" +#include "probes.h" +#ifdef PBRT_PROBES_COUNTERS +#include "parallel.h" +#include +using std::map; + +// Statistics Counters Local Declarations +#ifdef PBRT_HAS_64_BIT_ATOMICS +typedef AtomicInt64 StatsCounterType; +#else +typedef AtomicInt32 StatsCounterType; +#endif +class StatsCounter { +public: + // StatsCounter Public Methods + StatsCounter(const string &category, const string &name); + void operator++() { + AtomicAdd(&num, 1); + } + void operator++(int) { + AtomicAdd(&num, 1); + } +#ifdef PBRT_HAS_64_BIT_ATOMICS + void Max(int64_t newval) { + int64_t oldval; + do { + oldval = num; + newval = max(oldval, newval); + if (newval == oldval) return; + } while(AtomicCompareAndSwap(&num, newval, oldval) != oldval); + } + void Min(int64_t newval) { + int64_t oldval; + do { + oldval = (uint32_t)num; + newval = min(oldval, newval); + if (newval == oldval) return; + } while(AtomicCompareAndSwap(&num, newval, oldval) != oldval); + } +#else + void Max(int32_t newval) { + int32_t oldval; + do { + oldval = num; + newval = max(oldval, newval); + if (newval == oldval) return; + } while(AtomicCompareAndSwap(&num, newval, oldval) != oldval); + } + void Min(int32_t newval) { + int32_t oldval; + do { + oldval = (uint32_t)num; + newval = min(oldval, newval); + if (newval == oldval) return; + } while(AtomicCompareAndSwap(&num, newval, oldval) != oldval); + } +#endif +#ifdef PBRT_HAS_64_BIT_ATOMICS + operator int64_t() volatile { return (int64_t)num; } +#else + operator int32_t() volatile { return (int32_t)num; } +#endif +private: + // StatsCounter Private Data + StatsCounterType num; +}; + + +class StatsRatio { +public: + // StatsRatio Public Methods + StatsRatio(const string &category, const string &name); + void Add(int a, int b) { + AtomicAdd(&na, a); + AtomicAdd(&nb, b); + } +private: + // StatsRatio Private Data + StatsCounterType na, nb; +}; + + +class StatsPercentage { +public: + // StatsPercentage Public Methods + void Add(int a, int b) { + AtomicAdd(&na, a); + AtomicAdd(&nb, b); + } + StatsPercentage(const string &category, const string &name); +private: + // StatsPercentage Private Data + StatsCounterType na, nb; +}; + + + +// Statistics Counters Definitions +static void ProbesPrintVal(FILE *f, const StatsCounterType &v); +static void ProbesPrintVal(FILE *f, const StatsCounterType &v1, + const StatsCounterType &v2); +struct StatTracker { + StatTracker(const string &cat, const string &n, + StatsCounterType *pa, StatsCounterType *pb = NULL, + bool percentage = true); + string category, name; + StatsCounterType *ptra, *ptrb; + bool percentage; +}; + + +typedef map, StatTracker *> TrackerMap; +static TrackerMap trackers; +static void addTracker(StatTracker *newTracker) { + static Mutex *mutex = Mutex::Create(); + MutexLock lock(*mutex); + std::pair s = std::make_pair(newTracker->category, newTracker->name); + if (trackers.find(s) != trackers.end()) { + newTracker->ptra = trackers[s]->ptra; + newTracker->ptrb = trackers[s]->ptrb; + return; + } + trackers[s] = newTracker; +} + + + +// Statistics Counters Function Definitions +void ProbesPrint(FILE *dest) { + fprintf(dest, "Statistics:\n"); + TrackerMap::iterator iter = trackers.begin(); + string lastCategory; + while (iter != trackers.end()) { + // Print statistic + StatTracker *tr = iter->second; + if (tr->category != lastCategory) { + fprintf(dest, "%s\n", tr->category.c_str()); + lastCategory = tr->category; + } + fprintf(dest, " %s", tr->name.c_str()); + + // Pad out to results column + int resultsColumn = 56; + int paddingSpaces = resultsColumn - (int) tr->name.size(); + while (paddingSpaces-- > 0) + putc(' ', dest); + if (tr->ptrb == NULL) + ProbesPrintVal(dest, *tr->ptra); + else { + if ((int64_t)(*tr->ptrb) > 0) { + float ratio = double((int64_t)*tr->ptra) / double((int64_t)*tr->ptrb); + ProbesPrintVal(dest, *tr->ptra, *tr->ptrb); + if (tr->percentage) + fprintf(dest, " (%3.2f%%)", 100. * ratio); + else + fprintf(dest, " (%.2fx)", ratio); + } + else + ProbesPrintVal(dest, *tr->ptra, *tr->ptrb); + } + fprintf(dest, "\n"); + ++iter; + } +} + + +static void ProbesPrintVal(FILE *f, const StatsCounterType &v) { +#if defined(PBRT_IS_WINDOWS) + LONG vv = v; + fprintf(f, "%d", vv); +#else +#ifdef PBRT_HAS_64_BIT_ATOMICS + int64_t vv = v; + fprintf(f, "%lld", vv); +#else + int32_t vv = v; + fprintf(f, "%d", vv); +#endif +#endif +} + + +static void ProbesPrintVal(FILE *f, const StatsCounterType &v1, + const StatsCounterType &v2) { +#if defined(PBRT_IS_WINDOWS) + LONG vv1 = v1, vv2 = v2; + fprintf(f, "%d:%d", vv1, vv2); +#else +#ifdef PBRT_HAS_64_BIT_ATOMICS + int64_t vv1 = v1, vv2 = v2; + fprintf(f, "%lld:%lld", vv1, vv2); +#else + int32_t vv1 = v1, vv2 = v2; + fprintf(f, "%d:%d", vv1, vv2); +#endif +#endif +} + + +void ProbesCleanup() { + TrackerMap::iterator iter = trackers.begin(); + string lastCategory; + while (iter != trackers.end()) { + delete iter->second; + ++iter; + } + trackers.erase(trackers.begin(), trackers.end()); +} + + +StatTracker::StatTracker(const string &cat, const string &n, + StatsCounterType *pa, StatsCounterType *pb, bool p) { + category = cat; + name = n; + ptra = pa; + ptrb = pb; + percentage = p; +} + + +StatsCounter::StatsCounter(const string &category, const string &name) { + num = 0; + addTracker(new StatTracker(category, name, &num)); +} + + +StatsRatio::StatsRatio(const string &category, const string &name) { + na = nb = 0; + addTracker(new StatTracker(category, name, &na, &nb, false)); +} + + +StatsPercentage::StatsPercentage(const string &category, const string &name) { + addTracker(new StatTracker(category, name, &na, &nb, true)); +} + + + +// Statistics Counters Probe Declarations +static StatsCounter shapesMade("Shapes", "Total Shapes Created"); +static StatsCounter trianglesMade("Shapes", "Total Triangles Created"); +static StatsCounter cameraRays("Rays", "Camera Rays Traced"); +static StatsCounter specularReflectionRays("Rays", "Specular Reflection Rays Traced"); +static StatsCounter specularRefractionRays("Rays", "Specular Refraction Rays Traced"); +static StatsCounter shadowRays("Rays", "Shadow Rays Traced"); +static StatsCounter nonShadowRays("Rays", "Total Non-Shadow Rays Traced"); +static StatsCounter kdTreeInteriorNodes("Kd-Tree", "Interior Nodes Created"); +static StatsCounter kdTreeLeafNodes("Kd-Tree", "Interior Nodes Created"); +static StatsCounter kdTreeMaxPrims("Kd-Tree", "Maximum Primitives in Leaf"); +static StatsCounter kdTreeMaxDepth("Kd-Tree", "Maximum Depth of Leaf Nodes"); +static StatsPercentage rayTriIntersections("Intersections", "Ray/Triangle Intersection Hits"); +static StatsPercentage rayTriIntersectionPs("Intersections", "Ray/Triangle IntersectionP Hits"); + +// Statistics Counters Probe Definitions +void PBRT_CREATED_SHAPE(Shape *) { + ++shapesMade; +} + + +void PBRT_CREATED_TRIANGLE(Triangle *) { + ++trianglesMade; +} + + +void PBRT_STARTED_GENERATING_CAMERA_RAY(const CameraSample *) { + ++cameraRays; +} + + + +void PBRT_KDTREE_CREATED_INTERIOR_NODE(int axis, float split) { + ++kdTreeInteriorNodes; +} + + + +void PBRT_KDTREE_CREATED_LEAF(int nprims, int depth) { + ++kdTreeLeafNodes; + kdTreeMaxPrims.Max(nprims); + kdTreeMaxDepth.Max(depth); +} + + + +void PBRT_RAY_TRIANGLE_INTERSECTION_TEST(const Ray *, const Triangle *) { + rayTriIntersections.Add(0, 1); +} + + + +void PBRT_RAY_TRIANGLE_INTERSECTIONP_TEST(const Ray *, const Triangle *) { + rayTriIntersectionPs.Add(0, 1); +} + + + +void PBRT_RAY_TRIANGLE_INTERSECTION_HIT(const Ray *, float t) { + rayTriIntersections.Add(1, 0); +} + + + +void PBRT_RAY_TRIANGLE_INTERSECTIONP_HIT(const Ray *, float t) { + rayTriIntersectionPs.Add(1, 0); +} + + + +void PBRT_FINISHED_RAY_INTERSECTION(const Ray *, const Intersection *, int hit) { + ++nonShadowRays; +} + + + +void PBRT_FINISHED_RAY_INTERSECTIONP(const Ray *, int hit) { + ++shadowRays; +} + + + +void PBRT_STARTED_SPECULAR_REFLECTION_RAY(const RayDifferential *) { + ++specularReflectionRays; +} + + + +void PBRT_STARTED_SPECULAR_REFRACTION_RAY(const RayDifferential *) { + ++specularRefractionRays; +} + + +#endif // PBRT_PROBES_COUNTERS diff --git a/core/probes.h b/core/probes.h new file mode 100644 index 0000000..6751ffd --- /dev/null +++ b/core/probes.h @@ -0,0 +1,389 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_PROBES_H +#define PBRT_CORE_PROBES_H + +// core/probes.h* +#include "pbrt.h" +#ifdef PBRT_PROBES_DTRACE +#include "core/dtrace.h" +inline void ProbesCleanup() { } +inline void ProbesPrint(FILE *) { } +#endif // PBRT_PROBES_DTRACE + +#ifdef PBRT_PROBES_NONE +inline void ProbesCleanup() { } +inline void ProbesPrint(FILE *) { } + +// Statistics Disabled Declarations +#define PBRT_STARTED_RAY_INTERSECTION(ray) +#define PBRT_FINISHED_RAY_INTERSECTION(ray, isect, hit) +#define PBRT_STARTED_RAY_INTERSECTIONP(ray) +#define PBRT_FINISHED_RAY_INTERSECTIONP(ray, hit) + +// Remainder of disabled probes declarations +#define PBRT_ACCESSED_TEXEL(arg0, arg1, arg2, arg3) +#define PBRT_ALLOCATED_CACHED_TRANSFORM() +#define PBRT_FOUND_CACHED_TRANSFORM() +#define PBRT_ATOMIC_MEMORY_OP() +#define PBRT_BVH_STARTED_CONSTRUCTION(arg0, arg1) +#define PBRT_BVH_FINISHED_CONSTRUCTION(arg0) +#define PBRT_BVH_INTERSECTION_STARTED(arg0, arg1) +#define PBRT_BVH_INTERSECTION_TRAVERSED_INTERIOR_NODE(arg0) +#define PBRT_BVH_INTERSECTION_TRAVERSED_LEAF_NODE(arg0) +#define PBRT_BVH_INTERSECTION_PRIMITIVE_TEST(arg0) +#define PBRT_BVH_INTERSECTION_PRIMITIVE_HIT(arg0) +#define PBRT_BVH_INTERSECTION_PRIMITIVE_MISSED(arg0) +#define PBRT_BVH_INTERSECTION_FINISHED() +#define PBRT_BVH_INTERSECTIONP_STARTED(arg0, arg1) +#define PBRT_BVH_INTERSECTIONP_TRAVERSED_INTERIOR_NODE(arg0) +#define PBRT_BVH_INTERSECTIONP_TRAVERSED_LEAF_NODE(arg0) +#define PBRT_BVH_INTERSECTIONP_PRIMITIVE_TEST(arg0) +#define PBRT_BVH_INTERSECTIONP_PRIMITIVE_HIT(arg0) +#define PBRT_BVH_INTERSECTIONP_PRIMITIVE_MISSED(arg0) +#define PBRT_BVH_INTERSECTIONP_FINISHED() +#define PBRT_CREATED_SHAPE(shape) +#define PBRT_CREATED_TRIANGLE(tri) +#define PBRT_FINISHED_GENERATING_CAMERA_RAY(arg0, arg1, arg2) +#define PBRT_FINISHED_PARSING() +#define PBRT_FINISHED_PREPROCESSING() +#define PBRT_FINISHED_RENDERING() +#define PBRT_FINISHED_RENDERTASK(arg0) +#define PBRT_FINISHED_TASK(arg0) +#define PBRT_FINISHED_ADDING_IMAGE_SAMPLE() +#define PBRT_FINISHED_CAMERA_RAY_INTEGRATION(arg0, arg1, arg2) +#define PBRT_FINISHED_EWA_TEXTURE_LOOKUP() +#define PBRT_FINISHED_BSDF_SHADING(arg0, arg1) +#define PBRT_FINISHED_BSSRDF_SHADING(arg0, arg1) +#define PBRT_FINISHED_SPECULAR_REFLECTION_RAY(arg0) +#define PBRT_FINISHED_SPECULAR_REFRACTION_RAY(arg0) +#define PBRT_FINISHED_TRILINEAR_TEXTURE_LOOKUP() +#define PBRT_GRID_BOUNDS_AND_RESOLUTION(arg0, arg1) +#define PBRT_GRID_FINISHED_CONSTRUCTION(arg0) +#define PBRT_GRID_INTERSECTIONP_TEST(arg0, arg1) +#define PBRT_GRID_INTERSECTION_TEST(arg0, arg1) +#define PBRT_GRID_RAY_MISSED_BOUNDS() +#define PBRT_GRID_RAY_PRIMITIVE_HIT(arg0) +#define PBRT_GRID_RAY_PRIMITIVE_INTERSECTIONP_TEST(arg0) +#define PBRT_GRID_RAY_PRIMITIVE_INTERSECTION_TEST(arg0) +#define PBRT_GRID_RAY_TRAVERSED_VOXEL(arg0, arg1) +#define PBRT_GRID_STARTED_CONSTRUCTION(arg0, arg1) +#define PBRT_GRID_VOXELIZED_PRIMITIVE(arg0, arg1) +#define PBRT_IRRADIANCE_CACHE_ADDED_NEW_SAMPLE(arg0, arg1, arg2, arg3, arg4, arg5) +#define PBRT_IRRADIANCE_CACHE_CHECKED_SAMPLE(arg0, arg1, arg2) +#define PBRT_IRRADIANCE_CACHE_FINISHED_COMPUTING_IRRADIANCE(arg0, arg1) +#define PBRT_IRRADIANCE_CACHE_FINISHED_INTERPOLATION(arg0, arg1, arg2, arg3) +#define PBRT_IRRADIANCE_CACHE_FINISHED_RAY(arg0, arg1, arg2) +#define PBRT_IRRADIANCE_CACHE_STARTED_COMPUTING_IRRADIANCE(arg0, arg1) +#define PBRT_IRRADIANCE_CACHE_STARTED_INTERPOLATION(arg0, arg1) +#define PBRT_IRRADIANCE_CACHE_STARTED_RAY(arg0) +#define PBRT_KDTREE_CREATED_INTERIOR_NODE(arg0, arg1) +#define PBRT_KDTREE_CREATED_LEAF(arg0, arg1) +#define PBRT_KDTREE_FINISHED_CONSTRUCTION(arg0) +#define PBRT_KDTREE_INTERSECTIONP_PRIMITIVE_TEST(arg0) +#define PBRT_KDTREE_INTERSECTION_PRIMITIVE_TEST(arg0) +#define PBRT_KDTREE_INTERSECTIONP_HIT(arg0) +#define PBRT_KDTREE_INTERSECTIONP_MISSED() +#define PBRT_KDTREE_INTERSECTIONP_TEST(arg0, arg1) +#define PBRT_KDTREE_INTERSECTION_FINISHED() +#define PBRT_KDTREE_INTERSECTION_HIT(arg0) +#define PBRT_KDTREE_INTERSECTION_TEST(arg0, arg1) +#define PBRT_KDTREE_RAY_MISSED_BOUNDS() +#define PBRT_KDTREE_STARTED_CONSTRUCTION(arg0, arg1) +#define PBRT_KDTREE_INTERSECTION_TRAVERSED_INTERIOR_NODE(arg0) +#define PBRT_KDTREE_INTERSECTION_TRAVERSED_LEAF_NODE(arg0, arg1) +#define PBRT_KDTREE_INTERSECTIONP_TRAVERSED_INTERIOR_NODE(arg0) +#define PBRT_KDTREE_INTERSECTIONP_TRAVERSED_LEAF_NODE(arg0, arg1) +#define PBRT_LOADED_IMAGE_MAP(arg0, arg1, arg2, arg3, arg4) +#define PBRT_MIPMAP_EWA_FILTER(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) +#define PBRT_MIPMAP_TRILINEAR_FILTER(arg0, arg1, arg2, arg3, arg4, arg5) +#define PBRT_MLT_ACCEPTED_MUTATION(arg0, arg1, arg2) +#define PBRT_MLT_REJECTED_MUTATION(arg0, arg1, arg2) +#define PBRT_MLT_STARTED_MLT_TASK(arg0) +#define PBRT_MLT_FINISHED_MLT_TASK(arg0) +#define PBRT_MLT_STARTED_RENDERING() +#define PBRT_MLT_FINISHED_RENDERING() +#define PBRT_MLT_STARTED_DIRECTLIGHTING() +#define PBRT_MLT_FINISHED_DIRECTLIGHTING() +#define PBRT_MLT_STARTED_BOOTSTRAPPING(count) +#define PBRT_MLT_FINISHED_BOOTSTRAPPING(b) +#define PBRT_MLT_STARTED_MUTATION() +#define PBRT_MLT_FINISHED_MUTATION() +#define PBRT_MLT_STARTED_SAMPLE_SPLAT() +#define PBRT_MLT_FINISHED_SAMPLE_SPLAT() +#define PBRT_MLT_STARTED_GENERATE_PATH() +#define PBRT_MLT_FINISHED_GENERATE_PATH() +#define PBRT_MLT_STARTED_LPATH() +#define PBRT_MLT_FINISHED_LPATH() +#define PBRT_MLT_STARTED_LBIDIR() +#define PBRT_MLT_FINISHED_LBIDIR() +#define PBRT_MLT_STARTED_TASK_INIT() +#define PBRT_MLT_FINISHED_TASK_INIT() +#define PBRT_MLT_STARTED_SAMPLE_LIGHT_FOR_BIDIR() +#define PBRT_MLT_FINISHED_SAMPLE_LIGHT_FOR_BIDIR() +#define PBRT_MLT_STARTED_DISPLAY_UPDATE() +#define PBRT_MLT_FINISHED_DISPLAY_UPDATE() +#define PBRT_MLT_STARTED_ESTIMATE_DIRECT() +#define PBRT_MLT_FINISHED_ESTIMATE_DIRECT() +#define PBRT_PHOTON_MAP_DEPOSITED_CAUSTIC_PHOTON(arg0, arg1, arg2) +#define PBRT_PHOTON_MAP_DEPOSITED_DIRECT_PHOTON(arg0, arg1, arg2) +#define PBRT_PHOTON_MAP_DEPOSITED_INDIRECT_PHOTON(arg0, arg1, arg2) +#define PBRT_PHOTON_MAP_FINISHED_GATHER_RAY(arg0) +#define PBRT_PHOTON_MAP_FINISHED_LOOKUP(arg0, arg1, arg2, arg3) +#define PBRT_PHOTON_MAP_FINISHED_RAY_PATH(arg0, arg1) +#define PBRT_PHOTON_MAP_STARTED_GATHER_RAY(arg0) +#define PBRT_PHOTON_MAP_STARTED_LOOKUP(arg0) +#define PBRT_PHOTON_MAP_STARTED_RAY_PATH(arg0, arg1) +#define PBRT_RAY_TRIANGLE_INTERSECTIONP_HIT(arg0, arg1) +#define PBRT_RAY_TRIANGLE_INTERSECTIONP_TEST(arg0, arg1) +#define PBRT_RAY_TRIANGLE_INTERSECTION_HIT(arg0, arg1) +#define PBRT_RAY_TRIANGLE_INTERSECTION_TEST(arg0, arg1) +#define PBRT_SAMPLE_OUTSIDE_IMAGE_EXTENT(arg0) +#define PBRT_STARTED_ADDING_IMAGE_SAMPLE(arg0, arg1, arg2, arg3) +#define PBRT_STARTED_CAMERA_RAY_INTEGRATION(arg0, arg1) +#define PBRT_STARTED_EWA_TEXTURE_LOOKUP(arg0, arg1) +#define PBRT_STARTED_GENERATING_CAMERA_RAY(arg0) +#define PBRT_STARTED_PARSING() +#define PBRT_STARTED_PREPROCESSING() +#define PBRT_STARTED_RENDERING() +#define PBRT_STARTED_RENDERTASK(arg0) +#define PBRT_STARTED_BSDF_SHADING(arg0) +#define PBRT_STARTED_BSSRDF_SHADING(arg0) +#define PBRT_STARTED_SPECULAR_REFLECTION_RAY(arg0) +#define PBRT_STARTED_SPECULAR_REFRACTION_RAY(arg0) +#define PBRT_STARTED_TASK(arg0) +#define PBRT_STARTED_TRILINEAR_TEXTURE_LOOKUP(arg0, arg1) +#define PBRT_SUBSURFACE_ADDED_INTERIOR_CONTRIBUTION(arg0) +#define PBRT_SUBSURFACE_ADDED_POINT_CONTRIBUTION(arg0) +#define PBRT_SUBSURFACE_ADDED_POINT_TO_OCTREE(arg0, arg1) +#define PBRT_SUBSURFACE_COMPUTED_IRRADIANCE_AT_POINT(arg0, arg1) +#define PBRT_SUBSURFACE_FINISHED_COMPUTING_IRRADIANCE_VALUES() +#define PBRT_SUBSURFACE_FINISHED_OCTREE_LOOKUP() +#define PBRT_SUBSURFACE_FINISHED_RAYS_FOR_POINTS(arg0, arg1) +#define PBRT_SUBSURFACE_STARTED_COMPUTING_IRRADIANCE_VALUES() +#define PBRT_SUBSURFACE_STARTED_OCTREE_LOOKUP(arg0) +#define PBRT_SUBSURFACE_STARTED_RAYS_FOR_POINTS() +#define PBRT_SUPERSAMPLE_PIXEL_NO(arg0, arg1) +#define PBRT_SUPERSAMPLE_PIXEL_YES(arg0, arg1) +#define PBRT_RNG_STARTED_RANDOM_FLOAT() +#define PBRT_RNG_FINISHED_RANDOM_FLOAT() +#define PBRT_RNG_FINISHED_TABLEGEN() +#define PBRT_RNG_STARTED_TABLEGEN() +#define PBRT_STARTED_BSDF_EVAL() +#define PBRT_FINISHED_BSDF_EVAL() +#define PBRT_STARTED_BSDF_SAMPLE() +#define PBRT_FINISHED_BSDF_SAMPLE() +#define PBRT_STARTED_BSDF_PDF() +#define PBRT_FINISHED_BSDF_PDF() +#define PBRT_AREA_LIGHT_STARTED_SAMPLE() +#define PBRT_AREA_LIGHT_FINISHED_SAMPLE() +#define PBRT_INFINITE_LIGHT_STARTED_SAMPLE() +#define PBRT_INFINITE_LIGHT_FINISHED_SAMPLE() +#define PBRT_INFINITE_LIGHT_STARTED_PDF() +#define PBRT_INFINITE_LIGHT_FINISHED_PDF() +#endif // PBRT_PROBES_NONE + +#ifdef PBRT_PROBES_COUNTERS + +// Statistics Counters Declarations +void ProbesPrint(FILE *dest); +void ProbesCleanup(); +class Triangle; +extern void PBRT_CREATED_SHAPE(Shape *); +extern void PBRT_CREATED_TRIANGLE(Triangle *); +extern void PBRT_STARTED_GENERATING_CAMERA_RAY(const struct CameraSample *); +extern void PBRT_KDTREE_CREATED_INTERIOR_NODE(int axis, float split); +extern void PBRT_KDTREE_CREATED_LEAF(int nprims, int depth); +#if 1 +extern void PBRT_RAY_TRIANGLE_INTERSECTION_TEST(const Ray *, const Triangle *); +extern void PBRT_RAY_TRIANGLE_INTERSECTIONP_TEST(const Ray *, const Triangle *); +extern void PBRT_RAY_TRIANGLE_INTERSECTION_HIT(const Ray *, float t); +extern void PBRT_RAY_TRIANGLE_INTERSECTIONP_HIT(const Ray *, float t); +#else +#define PBRT_RAY_TRIANGLE_INTERSECTION_HIT(arg0, arg1) +#define PBRT_RAY_TRIANGLE_INTERSECTION_TEST(arg0, arg1) +#define PBRT_RAY_TRIANGLE_INTERSECTIONP_HIT(arg0, arg1) +#define PBRT_RAY_TRIANGLE_INTERSECTIONP_TEST(arg0, arg1) +#endif +extern void PBRT_FINISHED_RAY_INTERSECTION(const Ray *, const Intersection *, int hit); +extern void PBRT_FINISHED_RAY_INTERSECTIONP(const Ray *, int hit); +extern void PBRT_STARTED_SPECULAR_REFLECTION_RAY(const RayDifferential *); +extern void PBRT_STARTED_SPECULAR_REFRACTION_RAY(const RayDifferential *); +#define PBRT_ACCESSED_TEXEL(arg0, arg1, arg2, arg3) +#define PBRT_ALLOCATED_CACHED_TRANSFORM() +#define PBRT_FOUND_CACHED_TRANSFORM() +#define PBRT_ATOMIC_MEMORY_OP() +#define PBRT_BVH_STARTED_CONSTRUCTION(arg0, arg1) +#define PBRT_BVH_FINISHED_CONSTRUCTION(arg0) +#define PBRT_BVH_INTERSECTION_STARTED(arg0, arg1) +#define PBRT_BVH_INTERSECTION_TRAVERSED_INTERIOR_NODE(arg0) +#define PBRT_BVH_INTERSECTION_TRAVERSED_LEAF_NODE(arg0) +#define PBRT_BVH_INTERSECTION_PRIMITIVE_TEST(arg0) +#define PBRT_BVH_INTERSECTION_PRIMITIVE_HIT(arg0) +#define PBRT_BVH_INTERSECTION_PRIMITIVE_MISSED(arg0) +#define PBRT_BVH_INTERSECTION_FINISHED() +#define PBRT_BVH_INTERSECTIONP_STARTED(arg0, arg1) +#define PBRT_BVH_INTERSECTIONP_TRAVERSED_INTERIOR_NODE(arg0) +#define PBRT_BVH_INTERSECTIONP_TRAVERSED_LEAF_NODE(arg0) +#define PBRT_BVH_INTERSECTIONP_PRIMITIVE_TEST(arg0) +#define PBRT_BVH_INTERSECTIONP_PRIMITIVE_HIT(arg0) +#define PBRT_BVH_INTERSECTIONP_PRIMITIVE_MISSED(arg0) +#define PBRT_BVH_INTERSECTIONP_FINISHED() +#define PBRT_FINISHED_PARSING() +#define PBRT_FINISHED_PREPROCESSING() +#define PBRT_FINISHED_RENDERING() +#define PBRT_FINISHED_RENDERTASK(arg0) +#define PBRT_FINISHED_TASK(arg0) +#define PBRT_FINISHED_ADDING_IMAGE_SAMPLE() +#define PBRT_FINISHED_CAMERA_RAY_INTEGRATION(arg0, arg1, arg2) +#define PBRT_FINISHED_EWA_TEXTURE_LOOKUP() +#define PBRT_FINISHED_GENERATING_CAMERA_RAY(arg0, arg1, arg2) +#define PBRT_FINISHED_BSDF_SHADING(arg0, arg1) +#define PBRT_FINISHED_BSSRDF_SHADING(arg0, arg1) +#define PBRT_FINISHED_SPECULAR_REFLECTION_RAY(arg0) +#define PBRT_FINISHED_SPECULAR_REFRACTION_RAY(arg0) +#define PBRT_FINISHED_TRILINEAR_TEXTURE_LOOKUP() +#define PBRT_GRID_BOUNDS_AND_RESOLUTION(arg0, arg1) +#define PBRT_GRID_FINISHED_CONSTRUCTION(arg0) +#define PBRT_GRID_INTERSECTIONP_TEST(arg0, arg1) +#define PBRT_GRID_INTERSECTION_TEST(arg0, arg1) +#define PBRT_GRID_RAY_MISSED_BOUNDS() +#define PBRT_GRID_RAY_PRIMITIVE_HIT(arg0) +#define PBRT_GRID_RAY_PRIMITIVE_INTERSECTIONP_TEST(arg0) +#define PBRT_GRID_RAY_PRIMITIVE_INTERSECTION_TEST(arg0) +#define PBRT_GRID_RAY_TRAVERSED_VOXEL(arg0, arg1) +#define PBRT_GRID_STARTED_CONSTRUCTION(arg0, arg1) +#define PBRT_GRID_VOXELIZED_PRIMITIVE(arg0, arg1) +#define PBRT_IRRADIANCE_CACHE_ADDED_NEW_SAMPLE(arg0, arg1, arg2, arg3, arg4, arg5) +#define PBRT_IRRADIANCE_CACHE_CHECKED_SAMPLE(arg0, arg1, arg2) +#define PBRT_IRRADIANCE_CACHE_FINISHED_COMPUTING_IRRADIANCE(arg0, arg1) +#define PBRT_IRRADIANCE_CACHE_FINISHED_INTERPOLATION(arg0, arg1, arg2, arg3) +#define PBRT_IRRADIANCE_CACHE_FINISHED_RAY(arg0, arg1, arg2) +#define PBRT_IRRADIANCE_CACHE_STARTED_COMPUTING_IRRADIANCE(arg0, arg1) +#define PBRT_IRRADIANCE_CACHE_STARTED_INTERPOLATION(arg0, arg1) +#define PBRT_IRRADIANCE_CACHE_STARTED_RAY(arg0) +#define PBRT_KDTREE_FINISHED_CONSTRUCTION(arg0) +#define PBRT_KDTREE_INTERSECTIONP_PRIMITIVE_TEST(arg0) +#define PBRT_KDTREE_INTERSECTION_PRIMITIVE_TEST(arg0) +#define PBRT_KDTREE_INTERSECTIONP_HIT(arg0) +#define PBRT_KDTREE_INTERSECTIONP_MISSED() +#define PBRT_KDTREE_INTERSECTIONP_TEST(arg0, arg1) +#define PBRT_KDTREE_INTERSECTION_FINISHED() +#define PBRT_KDTREE_INTERSECTION_HIT(arg0) +#define PBRT_KDTREE_INTERSECTION_TEST(arg0, arg1) +#define PBRT_KDTREE_RAY_MISSED_BOUNDS() +#define PBRT_KDTREE_STARTED_CONSTRUCTION(arg0, arg1) +#define PBRT_KDTREE_INTERSECTION_TRAVERSED_INTERIOR_NODE(arg0) +#define PBRT_KDTREE_INTERSECTION_TRAVERSED_LEAF_NODE(arg0, arg1) +#define PBRT_KDTREE_INTERSECTIONP_TRAVERSED_INTERIOR_NODE(arg0) +#define PBRT_KDTREE_INTERSECTIONP_TRAVERSED_LEAF_NODE(arg0, arg1) +#define PBRT_LOADED_IMAGE_MAP(arg0, arg1, arg2, arg3, arg4) +#define PBRT_MIPMAP_EWA_FILTER(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) +#define PBRT_MIPMAP_TRILINEAR_FILTER(arg0, arg1, arg2, arg3, arg4, arg5) +#define PBRT_MLT_ACCEPTED_MUTATION(arg0, arg1, arg2) +#define PBRT_MLT_REJECTED_MUTATION(arg0, arg1, arg2) +#define PBRT_MLT_STARTED_MLT_TASK(arg0) +#define PBRT_MLT_FINISHED_MLT_TASK(arg0) +#define PBRT_MLT_STARTED_RENDERING() +#define PBRT_MLT_FINISHED_RENDERING() +#define PBRT_MLT_STARTED_DIRECTLIGHTING() +#define PBRT_MLT_FINISHED_DIRECTLIGHTING() +#define PBRT_MLT_STARTED_BOOTSTRAPPING(count) +#define PBRT_MLT_FINISHED_BOOTSTRAPPING(b) +#define PBRT_MLT_STARTED_MUTATION() +#define PBRT_MLT_FINISHED_MUTATION() +#define PBRT_MLT_STARTED_SAMPLE_SPLAT() +#define PBRT_MLT_FINISHED_SAMPLE_SPLAT() +#define PBRT_MLT_STARTED_GENERATE_PATH() +#define PBRT_MLT_FINISHED_GENERATE_PATH() +#define PBRT_MLT_STARTED_LPATH() +#define PBRT_MLT_FINISHED_LPATH() +#define PBRT_MLT_STARTED_LBIDIR() +#define PBRT_MLT_FINISHED_LBIDIR() +#define PBRT_MLT_STARTED_TASK_INIT() +#define PBRT_MLT_FINISHED_TASK_INIT() +#define PBRT_MLT_STARTED_SAMPLE_LIGHT_FOR_BIDIR() +#define PBRT_MLT_FINISHED_SAMPLE_LIGHT_FOR_BIDIR() +#define PBRT_MLT_STARTED_DISPLAY_UPDATE() +#define PBRT_MLT_FINISHED_DISPLAY_UPDATE() +#define PBRT_MLT_STARTED_ESTIMATE_DIRECT() +#define PBRT_MLT_FINISHED_ESTIMATE_DIRECT() +#define PBRT_PHOTON_MAP_DEPOSITED_CAUSTIC_PHOTON(arg0, arg1, arg2) +#define PBRT_PHOTON_MAP_DEPOSITED_DIRECT_PHOTON(arg0, arg1, arg2) +#define PBRT_PHOTON_MAP_DEPOSITED_INDIRECT_PHOTON(arg0, arg1, arg2) +#define PBRT_PHOTON_MAP_FINISHED_GATHER_RAY(arg0) +#define PBRT_PHOTON_MAP_FINISHED_LOOKUP(arg0, arg1, arg2, arg3) +#define PBRT_PHOTON_MAP_FINISHED_RAY_PATH(arg0, arg1) +#define PBRT_PHOTON_MAP_STARTED_GATHER_RAY(arg0) +#define PBRT_PHOTON_MAP_STARTED_LOOKUP(arg0) +#define PBRT_PHOTON_MAP_STARTED_RAY_PATH(arg0, arg1) +#define PBRT_SAMPLE_OUTSIDE_IMAGE_EXTENT(arg0) +#define PBRT_STARTED_ADDING_IMAGE_SAMPLE(arg0, arg1, arg2, arg3) +#define PBRT_STARTED_CAMERA_RAY_INTEGRATION(arg0, arg1) +#define PBRT_STARTED_EWA_TEXTURE_LOOKUP(arg0, arg1) +#define PBRT_STARTED_PARSING() +#define PBRT_STARTED_PREPROCESSING() +#define PBRT_STARTED_RAY_INTERSECTION(arg0) +#define PBRT_STARTED_RAY_INTERSECTIONP(arg0) +#define PBRT_STARTED_RENDERING() +#define PBRT_STARTED_RENDERTASK(arg0) +#define PBRT_STARTED_BSDF_SHADING(arg0) +#define PBRT_STARTED_BSSRDF_SHADING(arg0) +#define PBRT_STARTED_TASK(arg0) +#define PBRT_STARTED_TRILINEAR_TEXTURE_LOOKUP(arg0, arg1) +#define PBRT_SUBSURFACE_ADDED_INTERIOR_CONTRIBUTION(arg0) +#define PBRT_SUBSURFACE_ADDED_POINT_CONTRIBUTION(arg0) +#define PBRT_SUBSURFACE_ADDED_POINT_TO_OCTREE(arg0, arg1) +#define PBRT_SUBSURFACE_COMPUTED_IRRADIANCE_AT_POINT(arg0, arg1) +#define PBRT_SUBSURFACE_FINISHED_COMPUTING_IRRADIANCE_VALUES() +#define PBRT_SUBSURFACE_FINISHED_OCTREE_LOOKUP() +#define PBRT_SUBSURFACE_FINISHED_RAYS_FOR_POINTS(arg0, arg1) +#define PBRT_SUBSURFACE_STARTED_COMPUTING_IRRADIANCE_VALUES() +#define PBRT_SUBSURFACE_STARTED_OCTREE_LOOKUP(arg0) +#define PBRT_SUBSURFACE_STARTED_RAYS_FOR_POINTS() +#define PBRT_SUPERSAMPLE_PIXEL_NO(arg0, arg1) +#define PBRT_SUPERSAMPLE_PIXEL_YES(arg0, arg1) +#define PBRT_RNG_STARTED_RANDOM_FLOAT() +#define PBRT_RNG_FINISHED_RANDOM_FLOAT() +#define PBRT_RNG_FINISHED_TABLEGEN() +#define PBRT_RNG_STARTED_TABLEGEN() +#define PBRT_STARTED_BSDF_EVAL() +#define PBRT_FINISHED_BSDF_EVAL() +#define PBRT_STARTED_BSDF_SAMPLE() +#define PBRT_FINISHED_BSDF_SAMPLE() +#define PBRT_STARTED_BSDF_PDF() +#define PBRT_FINISHED_BSDF_PDF() +#define PBRT_AREA_LIGHT_STARTED_SAMPLE() +#define PBRT_AREA_LIGHT_FINISHED_SAMPLE() +#define PBRT_INFINITE_LIGHT_STARTED_SAMPLE() +#define PBRT_INFINITE_LIGHT_FINISHED_SAMPLE() +#define PBRT_INFINITE_LIGHT_STARTED_PDF() +#define PBRT_INFINITE_LIGHT_FINISHED_PDF() +#endif // PBRT_PROBES_COUNTERS + +#endif // PBRT_CORE_PROBES_H diff --git a/core/progressreporter.cpp b/core/progressreporter.cpp new file mode 100644 index 0000000..73d0382 --- /dev/null +++ b/core/progressreporter.cpp @@ -0,0 +1,131 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/progressreporter.cpp* +#include "stdafx.h" +#include "progressreporter.h" +#include "timer.h" +#include "parallel.h" +#if defined(PBRT_IS_WINDOWS) +#include +#else +#include +#include +#include +#endif // !PBRT_IS_WINDOWS + +// ProgressReporter Method Definitions +ProgressReporter::ProgressReporter(int tw, const string &title, int barLength) + : totalWork(tw) { + if (barLength <= 0) + barLength = TerminalWidth() - 28; + totalPlusses = max(2, barLength - (int)title.size()); + mutex = Mutex::Create(); + plussesPrinted = 0; + workDone = 0; + timer = new Timer; + timer->Start(); + outFile = stdout; + // Initialize progress string + const int bufLen = title.size() + totalPlusses + 64; + buf = new char[bufLen]; + snprintf(buf, bufLen, "\r%s: [", title.c_str()); + curSpace = buf + strlen(buf); + char *s = curSpace; + for (int i = 0; i < totalPlusses; ++i) + *s++ = ' '; + *s++ = ']'; + *s++ = ' '; + *s++ = '\0'; + if (!PbrtOptions.quiet) { + fputs(buf, outFile); + fflush(outFile); + } +} + + +ProgressReporter::~ProgressReporter() { + delete[] buf; + delete timer; + Mutex::Destroy(mutex); +} + + +void ProgressReporter::Update(int num) { + if (num == 0 || PbrtOptions.quiet) return; + MutexLock lock(*mutex); + workDone += num; + float percentDone = float(workDone) / float(totalWork); + int plussesNeeded = Round2Int(totalPlusses * percentDone); + if (plussesNeeded > totalPlusses) plussesNeeded = totalPlusses; + while (plussesPrinted < plussesNeeded) { + *curSpace++ = '+'; + ++plussesPrinted; + } + fputs(buf, outFile); + // Update elapsed time and estimated time to completion + float seconds = (float)timer->Time(); + float estRemaining = seconds / percentDone - seconds; + if (percentDone == 1.f) + fprintf(outFile, " (%.1fs) ", seconds); + else + fprintf(outFile, " (%.1fs|%.1fs) ", seconds, max(0.f, estRemaining)); + fflush(outFile); +} + + +void ProgressReporter::Done() { + if (PbrtOptions.quiet) return; + MutexLock lock(*mutex); + while (plussesPrinted++ < totalPlusses) + *curSpace++ = '+'; + fputs(buf, outFile); + float seconds = (float)timer->Time(); + fprintf(outFile, " (%.1fs) \n", seconds); + fflush(outFile); +} + + +int TerminalWidth() { +#if defined(PBRT_IS_WINDOWS) + HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); + if (h == INVALID_HANDLE_VALUE || h == NULL) { + fprintf(stderr, "GetStdHandle() call failed"); + return 80; + } + CONSOLE_SCREEN_BUFFER_INFO bufferInfo = { 0 }; + GetConsoleScreenBufferInfo(h, &bufferInfo); + return bufferInfo.dwSize.X; +#else + struct winsize w; + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) < 0) { + fprintf(stderr, "Error in ioctl() in TerminalWidth(): %d", errno); + return 80; + } + return w.ws_col; +#endif // PBRT_IS_WINDOWS +} + + + diff --git a/core/progressreporter.h b/core/progressreporter.h new file mode 100644 index 0000000..2770e4f --- /dev/null +++ b/core/progressreporter.h @@ -0,0 +1,56 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_PROGRESSREPORTER_H +#define PBRT_CORE_PROGRESSREPORTER_H + +// core/progressreporter.h* +#include "pbrt.h" + +// ProgressReporter Declarations +class ProgressReporter { +public: + // ProgressReporter Public Methods + ProgressReporter(int totalWork, const string &title, + int barLength = -1); + ~ProgressReporter(); + void Update(int num = 1); + void Done(); +private: + // ProgressReporter Private Data + const int totalWork; + int workDone, plussesPrinted, totalPlusses; + Timer *timer; + FILE *outFile; + char *buf, *curSpace; + Mutex *mutex; +}; + + +extern int TerminalWidth(); + +#endif // PBRT_CORE_PROGRESSREPORTER_H diff --git a/core/quaternion.cpp b/core/quaternion.cpp new file mode 100644 index 0000000..61a9dac --- /dev/null +++ b/core/quaternion.cpp @@ -0,0 +1,100 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/quaternion.cpp* +#include "stdafx.h" +#include "quaternion.h" +#include "transform.h" + +// Quaternion Method Definitions +Transform Quaternion::ToTransform() const { + float xx = v.x * v.x, yy = v.y * v.y, zz = v.z * v.z; + float xy = v.x * v.y, xz = v.x * v.z, yz = v.y * v.z; + float wx = v.x * w, wy = v.y * w, wz = v.z * w; + + Matrix4x4 m; + m.m[0][0] = 1.f - 2.f * (yy + zz); + m.m[0][1] = 2.f * (xy + wz); + m.m[0][2] = 2.f * (xz - wy); + m.m[1][0] = 2.f * (xy - wz); + m.m[1][1] = 1.f - 2.f * (xx + zz); + m.m[1][2] = 2.f * (yz + wx); + m.m[2][0] = 2.f * (xz + wy); + m.m[2][1] = 2.f * (yz - wx); + m.m[2][2] = 1.f - 2.f * (xx + yy); + + // Transpose since we are left-handed. Ugh. + return Transform(Transpose(m), m); +} + + +Quaternion::Quaternion(const Transform &t) { + const Matrix4x4 &m = t.m; + float trace = m.m[0][0] + m.m[1][1] + m.m[2][2]; + if (trace > 0.f) { + // Compute w from matrix trace, then xyz + // 4w^2 = m[0][0] + m[1][1] + m[2][2] + m[3][3] (but m[3][3] == 1) + float s = sqrtf(trace + 1.0); + w = s / 2.0f; + s = 0.5f / s; + v.x = (m.m[2][1] - m.m[1][2]) * s; + v.y = (m.m[0][2] - m.m[2][0]) * s; + v.z = (m.m[1][0] - m.m[0][1]) * s; + } + else { + // Compute largest of $x$, $y$, or $z$, then remaining components + const int nxt[3] = {1, 2, 0}; + float q[3]; + int i = 0; + if (m.m[1][1] > m.m[0][0]) i = 1; + if (m.m[2][2] > m.m[i][i]) i = 2; + int j = nxt[i]; + int k = nxt[j]; + float s = sqrtf((m.m[i][i] - (m.m[j][j] + m.m[k][k])) + 1.0); + q[i] = s * 0.5f; + if (s != 0.f) s = 0.5f / s; + w = (m.m[k][j] - m.m[j][k]) * s; + q[j] = (m.m[j][i] + m.m[i][j]) * s; + q[k] = (m.m[k][i] + m.m[i][k]) * s; + v.x = q[0]; + v.y = q[1]; + v.z = q[2]; + } +} + + +Quaternion Slerp(float t, const Quaternion &q1, + const Quaternion &q2) { + float cosTheta = Dot(q1, q2); + if (cosTheta > .9995f) + return Normalize((1.f - t) * q1 + t * q2); + else { + float theta = acosf(Clamp(cosTheta, -1.f, 1.f)); + float thetap = theta * t; + Quaternion qperp = Normalize(q2 - q1 * cosTheta); + return q1 * cosf(thetap) + qperp * sinf(thetap); + } +} + + diff --git a/core/quaternion.h b/core/quaternion.h new file mode 100644 index 0000000..989f337 --- /dev/null +++ b/core/quaternion.h @@ -0,0 +1,107 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_QUATERNION_H +#define PBRT_CORE_QUATERNION_H + +// core/quaternion.h* +#include "pbrt.h" +#include "geometry.h" + +// Quaternion Declarations +struct Quaternion { + // Quaternion Public Methods + Quaternion() { v = Vector(0., 0., 0.); w = 1.f; } + Quaternion &operator+=(const Quaternion &q) { + v += q.v; + w += q.w; + return *this; + } + friend Quaternion operator+(const Quaternion &q1, const Quaternion &q2) { + Quaternion ret = q1; + return ret += q2; + } + Quaternion &operator-=(const Quaternion &q) { + v -= q.v; + w -= q.w; + return *this; + } + friend Quaternion operator-(const Quaternion &q1, const Quaternion &q2) { + Quaternion ret = q1; + return ret -= q2; + } + Quaternion &operator*=(float f) { + v *= f; + w *= f; + return *this; + } + Quaternion operator*(float f) const { + Quaternion ret = *this; + ret.v *= f; + ret.w *= f; + return ret; + } + Quaternion &operator/=(float f) { + v /= f; + w /= f; + return *this; + } + Quaternion operator/(float f) const { + Quaternion ret = *this; + ret.v /= f; + ret.w /= f; + return ret; + } + Transform ToTransform() const; + Quaternion(const Transform &t); + + // Quaternion Public Data + Vector v; + float w; +}; + + +Quaternion Slerp(float t, const Quaternion &q1, const Quaternion &q2); + +// Quaternion Inline Functions +inline Quaternion operator*(float f, const Quaternion &q) { + return q * f; +} + + +inline float Dot(const Quaternion &q1, const Quaternion &q2) { + return Dot(q1.v, q2.v) + q1.w * q2.w; +} + + +inline Quaternion Normalize(const Quaternion &q) { + return q / sqrtf(Dot(q, q)); +} + + + +#endif // PBRT_CORE_QUATERNION_H diff --git a/core/reflection.cpp b/core/reflection.cpp new file mode 100644 index 0000000..f29a80c --- /dev/null +++ b/core/reflection.cpp @@ -0,0 +1,648 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/reflection.cpp* +#include "stdafx.h" +#include "reflection.h" +#include "spectrum.h" +#include "sampler.h" +#include "montecarlo.h" +#include + +// BxDF Local Definitions +struct IrregIsoProc { + // IrregIsoProc Public Methods + IrregIsoProc() { sumWeights = 0.f; nFound = 0; } + void operator()(const Point &p, const IrregIsotropicBRDFSample &sample, + float d2, float &maxDist2) { + float weight = expf(-100.f * d2); + v += weight * sample.v; + sumWeights += weight; + ++nFound; + } + Spectrum v; + float sumWeights; + int nFound; +}; + + + +// BxDF Utility Functions +Spectrum FrDiel(float cosi, float cost, const Spectrum &etai, + const Spectrum &etat) { + Spectrum Rparl = ((etat * cosi) - (etai * cost)) / + ((etat * cosi) + (etai * cost)); + Spectrum Rperp = ((etai * cosi) - (etat * cost)) / + ((etai * cosi) + (etat * cost)); + return (Rparl*Rparl + Rperp*Rperp) / 2.f; +} + + +Spectrum FrCond(float cosi, const Spectrum &eta, const Spectrum &k) { + Spectrum tmp = (eta*eta + k*k) * cosi*cosi; + Spectrum Rparl2 = (tmp - (2.f * eta * cosi) + 1) / + (tmp + (2.f * eta * cosi) + 1); + Spectrum tmp_f = eta*eta + k*k; + Spectrum Rperp2 = + (tmp_f - (2.f * eta * cosi) + cosi*cosi) / + (tmp_f + (2.f * eta * cosi) + cosi*cosi); + return (Rparl2 + Rperp2) / 2.f; +} + + + +// BxDF Method Definitions +Spectrum BRDFToBTDF::f(const Vector &wo, const Vector &wi) const { + return brdf->f(wo, otherHemisphere(wi)); +} + + +Spectrum BRDFToBTDF::Sample_f(const Vector &wo, Vector *wi, + float u1, float u2, float *pdf) const { + Spectrum f = brdf->Sample_f(wo, wi, u1, u2, pdf); + *wi = otherHemisphere(*wi); + return f; +} + + +Spectrum ScaledBxDF::f(const Vector &wo, const Vector &wi) const { + return s * bxdf->f(wo, wi); +} + + +Spectrum ScaledBxDF::Sample_f(const Vector &wo, Vector *wi, + float u1, float u2, float *pdf) const { + Spectrum f = bxdf->Sample_f(wo, wi, u1, u2, pdf); + return s * f; +} + + +Fresnel::~Fresnel() { } +Spectrum FresnelConductor::Evaluate(float cosi) const { + return FrCond(fabsf(cosi), eta, k); +} + + +Spectrum FresnelDielectric::Evaluate(float cosi) const { + // Compute Fresnel reflectance for dielectric + cosi = Clamp(cosi, -1.f, 1.f); + + // Compute indices of refraction for dielectric + bool entering = cosi > 0.; + float ei = eta_i, et = eta_t; + if (!entering) + swap(ei, et); + + // Compute _sint_ using Snell's law + float sint = ei/et * sqrtf(max(0.f, 1.f - cosi*cosi)); + if (sint >= 1.) { + // Handle total internal reflection + return 1.; + } + else { + float cost = sqrtf(max(0.f, 1.f - sint*sint)); + return FrDiel(fabsf(cosi), cost, ei, et); + } +} + + +Spectrum SpecularReflection::Sample_f(const Vector &wo, + Vector *wi, float u1, float u2, float *pdf) const { + // Compute perfect specular reflection direction + *wi = Vector(-wo.x, -wo.y, wo.z); + *pdf = 1.f; + return fresnel->Evaluate(CosTheta(wo)) * R / AbsCosTheta(*wi); +} + + +Spectrum SpecularTransmission::Sample_f(const Vector &wo, + Vector *wi, float u1, float u2, float *pdf) const { + // Figure out which $\eta$ is incident and which is transmitted + bool entering = CosTheta(wo) > 0.; + float ei = etai, et = etat; + if (!entering) + swap(ei, et); + + // Compute transmitted ray direction + float sini2 = SinTheta2(wo); + float eta = ei / et; + float sint2 = eta * eta * sini2; + + // Handle total internal reflection for transmission + if (sint2 >= 1.) return 0.; + float cost = sqrtf(max(0.f, 1.f - sint2)); + if (entering) cost = -cost; + float sintOverSini = eta; + *wi = Vector(sintOverSini * -wo.x, sintOverSini * -wo.y, cost); + *pdf = 1.f; + Spectrum F = fresnel.Evaluate(CosTheta(wo)); + return /*(ei*ei)/(et*et) * */ (Spectrum(1.)-F) * T / + AbsCosTheta(*wi); +} + + +Spectrum Lambertian::f(const Vector &wo, const Vector &wi) const { + return R * INV_PI; +} + + +Spectrum OrenNayar::f(const Vector &wo, const Vector &wi) const { + float sinthetai = SinTheta(wi); + float sinthetao = SinTheta(wo); + // Compute cosine term of Oren-Nayar model + float maxcos = 0.f; + if (sinthetai > 1e-4 && sinthetao > 1e-4) { + float sinphii = SinPhi(wi), cosphii = CosPhi(wi); + float sinphio = SinPhi(wo), cosphio = CosPhi(wo); + float dcos = cosphii * cosphio + sinphii * sinphio; + maxcos = max(0.f, dcos); + } + + // Compute sine and tangent terms of Oren-Nayar model + float sinalpha, tanbeta; + if (AbsCosTheta(wi) > AbsCosTheta(wo)) { + sinalpha = sinthetao; + tanbeta = sinthetai / AbsCosTheta(wi); + } + else { + sinalpha = sinthetai; + tanbeta = sinthetao / AbsCosTheta(wo); + } + return R * INV_PI * (A + B * maxcos * sinalpha * tanbeta); +} + + +Microfacet::Microfacet(const Spectrum &reflectance, Fresnel *f, + MicrofacetDistribution *d) + : BxDF(BxDFType(BSDF_REFLECTION | BSDF_GLOSSY)), + R(reflectance), distribution(d), fresnel(f) { +} + + +Spectrum Microfacet::f(const Vector &wo, const Vector &wi) const { + float cosThetaO = AbsCosTheta(wo); + float cosThetaI = AbsCosTheta(wi); + if (cosThetaI == 0.f || cosThetaO == 0.f) return Spectrum(0.f); + Vector wh = wi + wo; + if (wh.x == 0. && wh.y == 0. && wh.z == 0.) return Spectrum(0.f); + wh = Normalize(wh); + float cosThetaH = Dot(wi, wh); + Spectrum F = fresnel->Evaluate(cosThetaH); + return R * distribution->D(wh) * G(wo, wi, wh) * F / + (4.f * cosThetaI * cosThetaO); +} + + +FresnelBlend::FresnelBlend(const Spectrum &d, const Spectrum &s, + MicrofacetDistribution *dist) + : BxDF(BxDFType(BSDF_REFLECTION | BSDF_GLOSSY)), Rd(d), Rs(s) { + distribution = dist; +} + + +Spectrum FresnelBlend::f(const Vector &wo, const Vector &wi) const { + Spectrum diffuse = (28.f/(23.f*M_PI)) * Rd * + (Spectrum(1.f) - Rs) * + (1.f - powf(1.f - .5f * AbsCosTheta(wi), 5)) * + (1.f - powf(1.f - .5f * AbsCosTheta(wo), 5)); + Vector wh = wi + wo; + if (wh.x == 0. && wh.y == 0. && wh.z == 0.) return Spectrum(0.f); + wh = Normalize(wh); + Spectrum specular = distribution->D(wh) / + (4.f * AbsDot(wi, wh) * max(AbsCosTheta(wi), AbsCosTheta(wo))) * + SchlickFresnel(Dot(wi, wh)); + return diffuse + specular; +} + + +Point BRDFRemap(const Vector &wo, const Vector &wi) { + float cosi = CosTheta(wi), coso = CosTheta(wo); + float sini = SinTheta(wi), sino = SinTheta(wo); + float phii = SphericalPhi(wi), phio = SphericalPhi(wo); + float dphi = phii - phio; + if (dphi < 0.) dphi += 2.f * M_PI; + if (dphi > 2.f * M_PI) dphi -= 2.f * M_PI; + if (dphi > M_PI) dphi = 2.f * M_PI - dphi; + return Point(sini * sino, dphi / M_PI, cosi * coso); +} + + +Spectrum IrregIsotropicBRDF::f(const Vector &wo, + const Vector &wi) const { + Point m = BRDFRemap(wo, wi); + float lastMaxDist2 = .001f; + while (true) { + // Try to find enough BRDF samples around _m_ within search radius + IrregIsoProc proc; + float maxDist2 = lastMaxDist2; + isoBRDFData->Lookup(m, proc, maxDist2); + if (proc.nFound > 2 || lastMaxDist2 > 1.5f) + return proc.v.Clamp() / proc.sumWeights; + lastMaxDist2 *= 2.f; + } +} + + +Spectrum RegularHalfangleBRDF::f(const Vector &WO, + const Vector &WI) const { + // Compute $\wh$ and transform $\wi$ to halfangle coordinate system + Vector wo = WO, wi = WI; + Vector wh = wo + wi; + if (wh.z < 0.f) { + wo = -wo; + wi = -wi; + wh = -wh; + } + if (wh.x == 0.f && wh.y == 0.f && wh.z == 0.f) return Spectrum (0.f); + wh = Normalize(wh); + float whTheta = SphericalTheta(wh); + float whCosPhi = CosPhi(wh), whSinPhi = SinPhi(wh); + float whCosTheta = CosTheta(wh), whSinTheta = SinTheta(wh); + Vector whx(whCosPhi * whCosTheta, whSinPhi * whCosTheta, -whSinTheta); + Vector why(-whSinPhi, whCosPhi, 0); + Vector wd(Dot(wi, whx), Dot(wi, why), Dot(wi, wh)); + + // Compute _index_ into measured BRDF tables + float wdTheta = SphericalTheta(wd), wdPhi = SphericalPhi(wd); + if (wdPhi > M_PI) wdPhi -= M_PI; + + // Compute indices _whThetaIndex_, _wdThetaIndex_, _wdPhiIndex_ +#define REMAP(V, MAX, COUNT) \ + Clamp(int((V) / (MAX) * (COUNT)), 0, (COUNT)-1) + int whThetaIndex = REMAP(sqrtf(max(0.f, whTheta / (M_PI / 2.f))), + 1.f, nThetaH); + int wdThetaIndex = REMAP(wdTheta, M_PI / 2.f, nThetaD); + int wdPhiIndex = REMAP(wdPhi, M_PI, nPhiD); +#undef REMAP + int index = wdPhiIndex + nPhiD * (wdThetaIndex + whThetaIndex * nThetaD); + return Spectrum::FromRGB(&brdf[3*index]); +} + + +Spectrum BxDF::Sample_f(const Vector &wo, Vector *wi, + float u1, float u2, float *pdf) const { + // Cosine-sample the hemisphere, flipping the direction if necessary + *wi = CosineSampleHemisphere(u1, u2); + if (wo.z < 0.) wi->z *= -1.f; + *pdf = Pdf(wo, *wi); + return f(wo, *wi); +} + + +float BxDF::Pdf(const Vector &wo, const Vector &wi) const { + return SameHemisphere(wo, wi) ? AbsCosTheta(wi) * INV_PI : 0.f; +} + + +float BRDFToBTDF::Pdf(const Vector &wo, + const Vector &wi) const { + return brdf->Pdf(wo, otherHemisphere(wi)); +} + + +Spectrum Microfacet::Sample_f(const Vector &wo, Vector *wi, + float u1, float u2, float *pdf) const { + distribution->Sample_f(wo, wi, u1, u2, pdf); + if (!SameHemisphere(wo, *wi)) return Spectrum(0.f); + return f(wo, *wi); +} + + +float Microfacet::Pdf(const Vector &wo, const Vector &wi) const { + if (!SameHemisphere(wo, wi)) return 0.f; + return distribution->Pdf(wo, wi); +} + + +void Blinn::Sample_f(const Vector &wo, Vector *wi, float u1, float u2, + float *pdf) const { + // Compute sampled half-angle vector $\wh$ for Blinn distribution + float costheta = powf(u1, 1.f / (exponent+1)); + float sintheta = sqrtf(max(0.f, 1.f - costheta*costheta)); + float phi = u2 * 2.f * M_PI; + Vector wh = SphericalDirection(sintheta, costheta, phi); + if (!SameHemisphere(wo, wh)) wh = -wh; + + // Compute incident direction by reflecting about $\wh$ + *wi = -wo + 2.f * Dot(wo, wh) * wh; + + // Compute PDF for $\wi$ from Blinn distribution + float blinn_pdf = ((exponent + 1.f) * powf(costheta, exponent)) / + (2.f * M_PI * 4.f * Dot(wo, wh)); + if (Dot(wo, wh) <= 0.f) blinn_pdf = 0.f; + *pdf = blinn_pdf; +} + + +float Blinn::Pdf(const Vector &wo, const Vector &wi) const { + Vector wh = Normalize(wo + wi); + float costheta = AbsCosTheta(wh); + // Compute PDF for $\wi$ from Blinn distribution + float blinn_pdf = ((exponent + 1.f) * powf(costheta, exponent)) / + (2.f * M_PI * 4.f * Dot(wo, wh)); + if (Dot(wo, wh) <= 0.f) blinn_pdf = 0.f; + return blinn_pdf; +} + + +void Anisotropic::Sample_f(const Vector &wo, Vector *wi, + float u1, float u2, float *pdf) const { + // Sample from first quadrant and remap to hemisphere to sample $\wh$ + float phi, costheta; + if (u1 < .25f) { + sampleFirstQuadrant(4.f * u1, u2, &phi, &costheta); + } else if (u1 < .5f) { + u1 = 4.f * (.5f - u1); + sampleFirstQuadrant(u1, u2, &phi, &costheta); + phi = M_PI - phi; + } else if (u1 < .75f) { + u1 = 4.f * (u1 - .5f); + sampleFirstQuadrant(u1, u2, &phi, &costheta); + phi += M_PI; + } else { + u1 = 4.f * (1.f - u1); + sampleFirstQuadrant(u1, u2, &phi, &costheta); + phi = 2.f * M_PI - phi; + } + float sintheta = sqrtf(max(0.f, 1.f - costheta*costheta)); + Vector wh = SphericalDirection(sintheta, costheta, phi); + if (!SameHemisphere(wo, wh)) wh = -wh; + + // Compute incident direction by reflecting about $\wh$ + *wi = -wo + 2.f * Dot(wo, wh) * wh; + + // Compute PDF for $\wi$ from anisotropic distribution + float costhetah = AbsCosTheta(wh); + float ds = 1.f - costhetah * costhetah; + float anisotropic_pdf = 0.f; + if (ds > 0.f && Dot(wo, wh) > 0.f) { + float e = (ex * wh.x * wh.x + ey * wh.y * wh.y) / ds; + float d = sqrtf((ex+1.f) * (ey+1.f)) * INV_TWOPI * + powf(costhetah, e); + anisotropic_pdf = d / (4.f * Dot(wo, wh)); + } + *pdf = anisotropic_pdf; +} + + +void Anisotropic::sampleFirstQuadrant(float u1, float u2, + float *phi, float *costheta) const { + if (ex == ey) + *phi = M_PI * u1 * 0.5f; + else + *phi = atanf(sqrtf((ex+1.f) / (ey+1.f)) * + tanf(M_PI * u1 * 0.5f)); + float cosphi = cosf(*phi), sinphi = sinf(*phi); + *costheta = powf(u2, 1.f/(ex * cosphi * cosphi + + ey * sinphi * sinphi + 1)); +} + + +float Anisotropic::Pdf(const Vector &wo, const Vector &wi) const { + Vector wh = Normalize(wo + wi); + // Compute PDF for $\wi$ from anisotropic distribution + float costhetah = AbsCosTheta(wh); + float ds = 1.f - costhetah * costhetah; + float anisotropic_pdf = 0.f; + if (ds > 0.f && Dot(wo, wh) > 0.f) { + float e = (ex * wh.x * wh.x + ey * wh.y * wh.y) / ds; + float d = sqrtf((ex+1.f) * (ey+1.f)) * INV_TWOPI * + powf(costhetah, e); + anisotropic_pdf = d / (4.f * Dot(wo, wh)); + } + return anisotropic_pdf; +} + + +Spectrum FresnelBlend::Sample_f(const Vector &wo, Vector *wi, + float u1, float u2, float *pdf) const { + if (u1 < .5) { + u1 = 2.f * u1; + // Cosine-sample the hemisphere, flipping the direction if necessary + *wi = CosineSampleHemisphere(u1, u2); + if (wo.z < 0.) wi->z *= -1.f; + } + else { + u1 = 2.f * (u1 - .5f); + distribution->Sample_f(wo, wi, u1, u2, pdf); + if (!SameHemisphere(wo, *wi)) return Spectrum(0.f); + } + *pdf = Pdf(wo, *wi); + return f(wo, *wi); +} + + +float FresnelBlend::Pdf(const Vector &wo, const Vector &wi) const { + if (!SameHemisphere(wo, wi)) return 0.f; + return .5f * (AbsCosTheta(wi) * INV_PI + distribution->Pdf(wo, wi)); +} + + +Spectrum BxDF::rho(const Vector &w, int nSamples, + const float *samples) const { + Spectrum r = 0.; + for (int i = 0; i < nSamples; ++i) { + // Estimate one term of $\rho_\roman{hd}$ + Vector wi; + float pdf = 0.f; + Spectrum f = Sample_f(w, &wi, samples[2*i], samples[2*i+1], &pdf); + if (pdf > 0.) r += f * AbsCosTheta(wi) / pdf; + } + return r / float(nSamples); +} + + +Spectrum BxDF::rho(int nSamples, const float *samples1, + const float *samples2) const { + Spectrum r = 0.; + for (int i = 0; i < nSamples; ++i) { + // Estimate one term of $\rho_\roman{hh}$ + Vector wo, wi; + wo = UniformSampleHemisphere(samples1[2*i], samples1[2*i+1]); + float pdf_o = INV_TWOPI, pdf_i = 0.f; + Spectrum f = Sample_f(wo, &wi, samples2[2*i], samples2[2*i+1], &pdf_i); + if (pdf_i > 0.) + r += f * AbsCosTheta(wi) * AbsCosTheta(wo) / (pdf_o * pdf_i); + } + return r / (M_PI*nSamples); +} + + + +// BSDF Method Definitions +BSDFSampleOffsets::BSDFSampleOffsets(int count, Sample *sample) { + nSamples = count; + componentOffset = sample->Add1D(nSamples); + dirOffset = sample->Add2D(nSamples); +} + + +BSDFSample::BSDFSample(const Sample *sample, + const BSDFSampleOffsets &offsets, uint32_t n) { + Assert(n < sample->n2D[offsets.dirOffset]); + Assert(n < sample->n1D[offsets.componentOffset]); + uDir[0] = sample->twoD[offsets.dirOffset][2*n]; + uDir[1] = sample->twoD[offsets.dirOffset][2*n+1]; + uComponent = sample->oneD[offsets.componentOffset][n]; + Assert(uDir[0] >= 0.f && uDir[0] < 1.f); + Assert(uDir[1] >= 0.f && uDir[1] < 1.f); + Assert(uComponent >= 0.f && uComponent < 1.f); +} + + +Spectrum BSDF::Sample_f(const Vector &woW, Vector *wiW, + const BSDFSample &bsdfSample, float *pdf, + BxDFType flags, BxDFType *sampledType) const { + PBRT_STARTED_BSDF_SAMPLE(); + // Choose which _BxDF_ to sample + int matchingComps = NumComponents(flags); + if (matchingComps == 0) { + *pdf = 0.f; + if (sampledType) *sampledType = BxDFType(0); + PBRT_FINISHED_BSDF_SAMPLE(); + return Spectrum(0.f); + } + int which = min(Floor2Int(bsdfSample.uComponent * matchingComps), + matchingComps-1); + BxDF *bxdf = NULL; + int count = which; + for (int i = 0; i < nBxDFs; ++i) + if (bxdfs[i]->MatchesFlags(flags) && count-- == 0) { + bxdf = bxdfs[i]; + break; + } + Assert(bxdf); + + // Sample chosen _BxDF_ + Vector wo = WorldToLocal(woW); + Vector wi; + *pdf = 0.f; + Spectrum f = bxdf->Sample_f(wo, &wi, bsdfSample.uDir[0], + bsdfSample.uDir[1], pdf); + if (*pdf == 0.f) + { + if (sampledType) *sampledType = BxDFType(0); + PBRT_FINISHED_BSDF_SAMPLE(); + return 0.f; + } + if (sampledType) *sampledType = bxdf->type; + *wiW = LocalToWorld(wi); + + // Compute overall PDF with all matching _BxDF_s + if (!(bxdf->type & BSDF_SPECULAR) && matchingComps > 1) + for (int i = 0; i < nBxDFs; ++i) + if (bxdfs[i] != bxdf && bxdfs[i]->MatchesFlags(flags)) + *pdf += bxdfs[i]->Pdf(wo, wi); + if (matchingComps > 1) *pdf /= matchingComps; + + // Compute value of BSDF for sampled direction + if (!(bxdf->type & BSDF_SPECULAR)) { + f = 0.; + if (Dot(*wiW, ng) * Dot(woW, ng) > 0) // ignore BTDFs + flags = BxDFType(flags & ~BSDF_TRANSMISSION); + else // ignore BRDFs + flags = BxDFType(flags & ~BSDF_REFLECTION); + for (int i = 0; i < nBxDFs; ++i) + if (bxdfs[i]->MatchesFlags(flags)) + f += bxdfs[i]->f(wo, wi); + } + PBRT_FINISHED_BSDF_SAMPLE(); + return f; +} + + +float BSDF::Pdf(const Vector &woW, const Vector &wiW, + BxDFType flags) const { + if (nBxDFs == 0.) return 0.; + PBRT_STARTED_BSDF_PDF(); + Vector wo = WorldToLocal(woW), wi = WorldToLocal(wiW); + float pdf = 0.f; + int matchingComps = 0; + for (int i = 0; i < nBxDFs; ++i) + if (bxdfs[i]->MatchesFlags(flags)) { + ++matchingComps; + pdf += bxdfs[i]->Pdf(wo, wi); + } + float v = matchingComps > 0 ? pdf / matchingComps : 0.f; + PBRT_FINISHED_BSDF_PDF(); + return v; +} + + +BSDF::BSDF(const DifferentialGeometry &dg, const Normal &ngeom, + float e) + : dgShading(dg), eta(e) { + ng = ngeom; + nn = dgShading.nn; + sn = Normalize(dgShading.dpdu); + tn = Cross(nn, sn); + nBxDFs = 0; +} + + +Spectrum BSDF::f(const Vector &woW, const Vector &wiW, + BxDFType flags) const { + PBRT_STARTED_BSDF_EVAL(); + Vector wi = WorldToLocal(wiW), wo = WorldToLocal(woW); + if (Dot(wiW, ng) * Dot(woW, ng) > 0) // ignore BTDFs + flags = BxDFType(flags & ~BSDF_TRANSMISSION); + else // ignore BRDFs + flags = BxDFType(flags & ~BSDF_REFLECTION); + Spectrum f = 0.; + for (int i = 0; i < nBxDFs; ++i) + if (bxdfs[i]->MatchesFlags(flags)) + f += bxdfs[i]->f(wo, wi); + PBRT_FINISHED_BSDF_EVAL(); + return f; +} + + +Spectrum BSDF::rho(RNG &rng, BxDFType flags, int sqrtSamples) const { + int nSamples = sqrtSamples * sqrtSamples; + float *s1 = ALLOCA(float, 2 * nSamples); + StratifiedSample2D(s1, sqrtSamples, sqrtSamples, rng); + float *s2 = ALLOCA(float, 2 * nSamples); + StratifiedSample2D(s2, sqrtSamples, sqrtSamples, rng); + + Spectrum ret(0.); + for (int i = 0; i < nBxDFs; ++i) + if (bxdfs[i]->MatchesFlags(flags)) + ret += bxdfs[i]->rho(nSamples, s1, s2); + return ret; +} + + +Spectrum BSDF::rho(const Vector &wo, RNG &rng, BxDFType flags, + int sqrtSamples) const { + int nSamples = sqrtSamples * sqrtSamples; + float *s1 = ALLOCA(float, 2 * nSamples); + StratifiedSample2D(s1, sqrtSamples, sqrtSamples, rng); + Spectrum ret(0.); + for (int i = 0; i < nBxDFs; ++i) + if (bxdfs[i]->MatchesFlags(flags)) + ret += bxdfs[i]->rho(wo, nSamples, s1); + return ret; +} + + diff --git a/core/reflection.h b/core/reflection.h new file mode 100644 index 0000000..f04cee2 --- /dev/null +++ b/core/reflection.h @@ -0,0 +1,533 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_REFLECTION_H +#define PBRT_CORE_REFLECTION_H + +// core/reflection.h* +#include "pbrt.h" +#include "geometry.h" +#include "shape.h" +#include "rng.h" +#include "spectrum.h" +#include "kdtree.h" + +// Reflection Declarations +Spectrum FrDiel(float cosi, float cost, const Spectrum &etai, + const Spectrum &etat); +Spectrum FrCond(float cosi, const Spectrum &n, const Spectrum &k); + +Point BRDFRemap(const Vector &wo, const Vector &wi); +struct IrregIsotropicBRDFSample { + IrregIsotropicBRDFSample(const Point &pp, const Spectrum &vv) + : p(pp), v(vv) { } + IrregIsotropicBRDFSample() { } + Point p; + Spectrum v; +}; + + +inline float Fdr(float eta) { + if (eta >= 1) + return -1.4399f / (eta*eta) + 0.7099f / eta + 0.6681f + + 0.0636f * eta; + else + return -0.4399f + .7099f / eta - .3319f / (eta * eta) + + .0636f / (eta*eta*eta); +} + + + +// BSDF Inline Functions +inline float CosTheta(const Vector &w) { return w.z; } +inline float AbsCosTheta(const Vector &w) { return fabsf(w.z); } +inline float SinTheta2(const Vector &w) { + return max(0.f, 1.f - CosTheta(w)*CosTheta(w)); +} + + +inline float SinTheta(const Vector &w) { + return sqrtf(SinTheta2(w)); +} + + +inline float CosPhi(const Vector &w) { + float sintheta = SinTheta(w); + if (sintheta == 0.f) return 1.f; + return Clamp(w.x / sintheta, -1.f, 1.f); +} + + +inline float SinPhi(const Vector &w) { + float sintheta = SinTheta(w); + if (sintheta == 0.f) return 0.f; + return Clamp(w.y / sintheta, -1.f, 1.f); +} + + +inline bool SameHemisphere(const Vector &w, const Vector &wp) { + return w.z * wp.z > 0.f; +} + + + +// BSDF Declarations +enum BxDFType { + BSDF_REFLECTION = 1<<0, + BSDF_TRANSMISSION = 1<<1, + BSDF_DIFFUSE = 1<<2, + BSDF_GLOSSY = 1<<3, + BSDF_SPECULAR = 1<<4, + BSDF_ALL_TYPES = BSDF_DIFFUSE | + BSDF_GLOSSY | + BSDF_SPECULAR, + BSDF_ALL_REFLECTION = BSDF_REFLECTION | + BSDF_ALL_TYPES, + BSDF_ALL_TRANSMISSION = BSDF_TRANSMISSION | + BSDF_ALL_TYPES, + BSDF_ALL = BSDF_ALL_REFLECTION | + BSDF_ALL_TRANSMISSION +}; + + +struct BSDFSample { + // BSDFSample Public Methods + BSDFSample(float up0, float up1, float ucomp) { + Assert(up0 >= 0.f && up0 < 1.f); + Assert(up1 >= 0.f && up1 < 1.f); + Assert(ucomp >= 0.f && ucomp < 1.f); + uDir[0] = up0; + uDir[1] = up1; + uComponent = ucomp; + } + BSDFSample(RNG &rng) { + uDir[0] = rng.RandomFloat(); + uDir[1] = rng.RandomFloat(); + uComponent = rng.RandomFloat(); + } + BSDFSample(const Sample *sample, const BSDFSampleOffsets &offsets, uint32_t num); + BSDFSample() { } + float uDir[2], uComponent; +}; + + +struct BSDFSampleOffsets { + BSDFSampleOffsets() { } + BSDFSampleOffsets(int count, Sample *sample); + int nSamples, componentOffset, dirOffset; +}; + + +class BSDF { +public: + // BSDF Public Methods + Spectrum Sample_f(const Vector &wo, Vector *wi, const BSDFSample &bsdfSample, + float *pdf, BxDFType flags = BSDF_ALL, + BxDFType *sampledType = NULL) const; + float Pdf(const Vector &wo, const Vector &wi, + BxDFType flags = BSDF_ALL) const; + BSDF(const DifferentialGeometry &dgs, const Normal &ngeom, + float eta = 1.f); + inline void Add(BxDF *bxdf); + int NumComponents() const { return nBxDFs; } + int NumComponents(BxDFType flags) const; + Vector WorldToLocal(const Vector &v) const { + return Vector(Dot(v, sn), Dot(v, tn), Dot(v, nn)); + } + Vector LocalToWorld(const Vector &v) const { + return Vector(sn.x * v.x + tn.x * v.y + nn.x * v.z, + sn.y * v.x + tn.y * v.y + nn.y * v.z, + sn.z * v.x + tn.z * v.y + nn.z * v.z); + } + Spectrum f(const Vector &woW, const Vector &wiW, BxDFType flags = BSDF_ALL) const; + Spectrum rho(RNG &rng, BxDFType flags = BSDF_ALL, + int sqrtSamples = 6) const; + Spectrum rho(const Vector &wo, RNG &rng, BxDFType flags = BSDF_ALL, + int sqrtSamples = 6) const; + + // BSDF Public Data + const DifferentialGeometry dgShading; + const float eta; +private: + // BSDF Private Methods + ~BSDF() { } + + // BSDF Private Data + Normal nn, ng; + Vector sn, tn; + int nBxDFs; +#define MAX_BxDFS 8 + BxDF *bxdfs[MAX_BxDFS]; + friend class MixMaterial; +}; + + +#define BSDF_ALLOC(arena, Type) new (arena.Alloc(sizeof(Type))) Type + +// BxDF Declarations +class BxDF { +public: + // BxDF Interface + virtual ~BxDF() { } + BxDF(BxDFType t) : type(t) { } + bool MatchesFlags(BxDFType flags) const { + return (type & flags) == type; + } + virtual Spectrum f(const Vector &wo, const Vector &wi) const = 0; + virtual Spectrum Sample_f(const Vector &wo, Vector *wi, + float u1, float u2, float *pdf) const; + virtual Spectrum rho(const Vector &wo, int nSamples, + const float *samples) const; + virtual Spectrum rho(int nSamples, const float *samples1, + const float *samples2) const; + virtual float Pdf(const Vector &wi, const Vector &wo) const; + + // BxDF Public Data + const BxDFType type; +}; + + +class BRDFToBTDF : public BxDF { +public: + // BRDFToBTDF Public Methods + BRDFToBTDF(BxDF *b) + : BxDF(BxDFType(b->type ^ (BSDF_REFLECTION | BSDF_TRANSMISSION))) { + brdf = b; + } + static Vector otherHemisphere(const Vector &w) { + return Vector(w.x, w.y, -w.z); + } + Spectrum f(const Vector &wo, const Vector &wi) const; + Spectrum Sample_f(const Vector &wo, Vector *wi, float u1, float u2, + float *pdf) const; + Spectrum rho(const Vector &w, int nSamples, const float *samples) const { + return brdf->rho(otherHemisphere(w), nSamples, samples); + } + Spectrum rho(int nSamples, const float *samples1, const float *samples2) const { + return brdf->rho(nSamples, samples1, samples2); + } + float Pdf(const Vector &wo, const Vector &wi) const; +private: + BxDF *brdf; +}; + + +class ScaledBxDF : public BxDF { +public: + // ScaledBxDF Public Methods + ScaledBxDF(BxDF *b, const Spectrum &sc) + : BxDF(BxDFType(b->type)), bxdf(b), s(sc) { + } + Spectrum rho(const Vector &w, int nSamples, const float *samples) const { + return s * bxdf->rho(w, nSamples, samples); + } + Spectrum rho(int nSamples, const float *samples1, + const float *samples2) const { + return s * bxdf->rho(nSamples, samples1, samples2); + } + Spectrum f(const Vector &wo, const Vector &wi) const; + Spectrum Sample_f(const Vector &wo, Vector *wi, + float u1, float u2, float *pdf) const; +private: + BxDF *bxdf; + Spectrum s; +}; + + +class Fresnel { +public: + // Fresnel Interface + virtual ~Fresnel(); + virtual Spectrum Evaluate(float cosi) const = 0; +}; + + +class FresnelConductor : public Fresnel { +public: + // FresnelConductor Public Methods + Spectrum Evaluate(float cosi) const; + FresnelConductor(const Spectrum &e, const Spectrum &kk) + : eta(e), k(kk) { + } + +private: + Spectrum eta, k; +}; + + +class FresnelDielectric : public Fresnel { +public: + // FresnelDielectric Public Methods + Spectrum Evaluate(float cosi) const; + FresnelDielectric(float ei, float et) : eta_i(ei), eta_t(et) { } +private: + float eta_i, eta_t; +}; + + +class FresnelNoOp : public Fresnel { +public: + Spectrum Evaluate(float) const { return Spectrum(1.); } +}; + + +class SpecularReflection : public BxDF { +public: + // SpecularReflection Public Methods + SpecularReflection(const Spectrum &r, Fresnel *f) + : BxDF(BxDFType(BSDF_REFLECTION | BSDF_SPECULAR)), + R(r), fresnel(f) { + } + Spectrum f(const Vector &, const Vector &) const { + return Spectrum(0.); + } + Spectrum Sample_f(const Vector &wo, Vector *wi, + float u1, float u2, float *pdf) const; + float Pdf(const Vector &wo, const Vector &wi) const { + return 0.; + } +private: + // SpecularReflection Private Data + Spectrum R; + Fresnel *fresnel; +}; + + +class SpecularTransmission : public BxDF { +public: + // SpecularTransmission Public Methods + SpecularTransmission(const Spectrum &t, float ei, float et) + : BxDF(BxDFType(BSDF_TRANSMISSION | BSDF_SPECULAR)), + fresnel(ei, et) { + T = t; + etai = ei; + etat = et; + } + Spectrum f(const Vector &, const Vector &) const { + return Spectrum(0.); + } + Spectrum Sample_f(const Vector &wo, Vector *wi, float u1, float u2, float *pdf) const; + float Pdf(const Vector &wo, const Vector &wi) const { + return 0.; + } +private: + // SpecularTransmission Private Data + Spectrum T; + float etai, etat; + FresnelDielectric fresnel; +}; + + +class Lambertian : public BxDF { +public: + // Lambertian Public Methods + Lambertian(const Spectrum &reflectance) + : BxDF(BxDFType(BSDF_REFLECTION | BSDF_DIFFUSE)), R(reflectance) { } + Spectrum f(const Vector &wo, const Vector &wi) const; + Spectrum rho(const Vector &, int, const float *) const { return R; } + Spectrum rho(int, const float *, const float *) const { return R; } +private: + // Lambertian Private Data + Spectrum R; +}; + + +class OrenNayar : public BxDF { +public: + // OrenNayar Public Methods + Spectrum f(const Vector &wo, const Vector &wi) const; + OrenNayar(const Spectrum &reflectance, float sig) + : BxDF(BxDFType(BSDF_REFLECTION | BSDF_DIFFUSE)), + R(reflectance) { + float sigma = Radians(sig); + float sigma2 = sigma*sigma; + A = 1.f - (sigma2 / (2.f * (sigma2 + 0.33f))); + B = 0.45f * sigma2 / (sigma2 + 0.09f); + } +private: + // OrenNayar Private Data + Spectrum R; + float A, B; +}; + + +class MicrofacetDistribution { +public: + // MicrofacetDistribution Interface + virtual ~MicrofacetDistribution() { } + virtual float D(const Vector &wh) const = 0; + virtual void Sample_f(const Vector &wo, Vector *wi, + float u1, float u2, float *pdf) const = 0; + virtual float Pdf(const Vector &wo, const Vector &wi) const = 0; +}; + + +class Microfacet : public BxDF { +public: + // Microfacet Public Methods + Microfacet(const Spectrum &reflectance, Fresnel *f, + MicrofacetDistribution *d); + Spectrum f(const Vector &wo, const Vector &wi) const; + float G(const Vector &wo, const Vector &wi, const Vector &wh) const { + float NdotWh = AbsCosTheta(wh); + float NdotWo = AbsCosTheta(wo); + float NdotWi = AbsCosTheta(wi); + float WOdotWh = AbsDot(wo, wh); + return min(1.f, min((2.f * NdotWh * NdotWo / WOdotWh), + (2.f * NdotWh * NdotWi / WOdotWh))); + } + Spectrum Sample_f(const Vector &wo, Vector *wi, + float u1, float u2, float *pdf) const; + float Pdf(const Vector &wo, const Vector &wi) const; +private: + // Microfacet Private Data + Spectrum R; + MicrofacetDistribution *distribution; + Fresnel *fresnel; +}; + + +class Blinn : public MicrofacetDistribution { +public: + Blinn(float e) { if (e > 10000.f || isnan(e)) e = 10000.f; + exponent = e; } + // Blinn Public Methods + float D(const Vector &wh) const { + float costhetah = AbsCosTheta(wh); + return (exponent+2) * INV_TWOPI * powf(costhetah, exponent); + } + virtual void Sample_f(const Vector &wi, Vector *sampled_f, float u1, float u2, float *pdf) const; + virtual float Pdf(const Vector &wi, const Vector &wo) const; +private: + float exponent; +}; + + +class Anisotropic : public MicrofacetDistribution { +public: + // Anisotropic Public Methods + Anisotropic(float x, float y) { + ex = x; ey = y; + if (ex > 10000.f || isnan(ex)) ex = 10000.f; + if (ey > 10000.f || isnan(ey)) ey = 10000.f; + } + float D(const Vector &wh) const { + float costhetah = AbsCosTheta(wh); + float d = 1.f - costhetah * costhetah; + if (d == 0.f) return 0.f; + float e = (ex * wh.x * wh.x + ey * wh.y * wh.y) / d; + return sqrtf((ex+2.f) * (ey+2.f)) * INV_TWOPI * powf(costhetah, e); + } + void Sample_f(const Vector &wo, Vector *wi, float u1, float u2, float *pdf) const; + float Pdf(const Vector &wo, const Vector &wi) const; + void sampleFirstQuadrant(float u1, float u2, float *phi, float *costheta) const; +private: + float ex, ey; +}; + + +class FresnelBlend : public BxDF { +public: + // FresnelBlend Public Methods + FresnelBlend(const Spectrum &Rd, + const Spectrum &Rs, + MicrofacetDistribution *dist); + Spectrum f(const Vector &wo, const Vector &wi) const; + Spectrum SchlickFresnel(float costheta) const { + return Rs + powf(1 - costheta, 5.f) * (Spectrum(1.) - Rs); + } + Spectrum Sample_f(const Vector &wi, Vector *sampled_f, float u1, float u2, float *pdf) const; + float Pdf(const Vector &wi, const Vector &wo) const; +private: + // FresnelBlend Private Data + Spectrum Rd, Rs; + MicrofacetDistribution *distribution; +}; + + +class IrregIsotropicBRDF : public BxDF { +public: + // IrregIsotropicBRDF Public Methods + IrregIsotropicBRDF(const KdTree *d) + : BxDF(BxDFType(BSDF_REFLECTION | BSDF_GLOSSY)), isoBRDFData(d) { } + Spectrum f(const Vector &wo, const Vector &wi) const; +private: + // IrregIsotropicBRDF Private Data + const KdTree *isoBRDFData; +}; + + +class RegularHalfangleBRDF : public BxDF { +public: + // RegularHalfangleBRDF Public Methods + RegularHalfangleBRDF(const float *d, uint32_t nth, uint32_t ntd, + uint32_t npd) + : BxDF(BxDFType(BSDF_REFLECTION | BSDF_GLOSSY)), brdf(d), + nThetaH(nth), nThetaD(ntd), nPhiD(npd) { } + Spectrum f(const Vector &wo, const Vector &wi) const; +private: + // RegularHalfangleBRDF Private Data + const float *brdf; + const uint32_t nThetaH, nThetaD, nPhiD; +}; + + + +// BSSRDF Declarations +class BSSRDF { +public: + // BSSRDF Public Methods + BSSRDF(const Spectrum &sa, const Spectrum &sps, float et) + : e(et), sig_a(sa), sigp_s(sps) { } + float eta() const { return e; } + Spectrum sigma_a() const { return sig_a; } + Spectrum sigma_prime_s() const { return sigp_s; } +private: + // BSSRDF Private Data + float e; + Spectrum sig_a, sigp_s; +}; + + + +// BSDF Inline Method Definitions +inline void BSDF::Add(BxDF *b) { + Assert(nBxDFs < MAX_BxDFS); + bxdfs[nBxDFs++] = b; +} + + +inline int BSDF::NumComponents(BxDFType flags) const { + int num = 0; + for (int i = 0; i < nBxDFs; ++i) + if (bxdfs[i]->MatchesFlags(flags)) ++num; + return num; +} + + + +#endif // PBRT_CORE_REFLECTION_H diff --git a/core/renderer.cpp b/core/renderer.cpp new file mode 100644 index 0000000..6a973be --- /dev/null +++ b/core/renderer.cpp @@ -0,0 +1,33 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/renderer.cpp* +#include "stdafx.h" +#include "renderer.h" + +// Renderer Method Definitions +Renderer::~Renderer() { +} + + diff --git a/core/renderer.h b/core/renderer.h new file mode 100644 index 0000000..08b4597 --- /dev/null +++ b/core/renderer.h @@ -0,0 +1,50 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_RENDERER_H +#define PBRT_CORE_RENDERER_H + +// core/renderer.h* +#include "pbrt.h" + +// Renderer Declarations +class Renderer { +public: + // Renderer Interface + virtual ~Renderer(); + virtual void Render(const Scene *scene) = 0; + virtual Spectrum Li(const Scene *scene, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena, + Intersection *isect = NULL, Spectrum *T = NULL) const = 0; + virtual Spectrum Transmittance(const Scene *scene, + const RayDifferential &ray, const Sample *sample, + RNG &rng, MemoryArena &arena) const = 0; +}; + + + +#endif // PBRT_CORE_RENDERER_H diff --git a/core/rng.cpp b/core/rng.cpp new file mode 100644 index 0000000..95fb9f1 --- /dev/null +++ b/core/rng.cpp @@ -0,0 +1,101 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/rng.cpp* +#include "stdafx.h" +#include "rng.h" + +// Random Number Method Definitions +#define M 397 +#define MATRIX_A 0x9908b0dfUL /* constant vector a */ +#define UPPER_MASK 0x80000000UL /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffffUL /* least significant r bits */ + +void RNG::Seed(uint32_t seed) const { + mt[0]= seed & 0xffffffffUL; + for (mti=1; mti> 30)) + mti); + /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ + /* In the previous versions, MSBs of the seed affect */ + /* only MSBs of the array mt[]. */ + /* 2002/01/09 modified by Makoto Matsumoto */ + mt[mti] &= 0xffffffffUL; + /* for >32 bit machines */ + } +} + + +/* generates a random number on [0,1)-real-interval */ +float RNG::RandomFloat() const +{ + PBRT_RNG_STARTED_RANDOM_FLOAT(); + float v = (RandomUInt() & 0xffffff) / float(1 << 24); + PBRT_RNG_FINISHED_RANDOM_FLOAT(); + return v; +} + + + +// Random Number Functions +unsigned long RNG::RandomUInt() const +{ + unsigned long y; + static unsigned long mag01[2]={0x0UL, MATRIX_A}; + /* mag01[x] = x * MATRIX_A for x=0,1 */ + + if (mti >= N) { /* generate N words at one time */ + PBRT_RNG_STARTED_TABLEGEN(); + int kk; + + if (mti == N+1) /* if Seed() has not been called, */ + Seed(5489UL); /* default initial seed */ + + for (kk=0;kk> 1) ^ mag01[y & 0x1UL]; + } + for (;kk> 1) ^ mag01[y & 0x1UL]; + } + y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); + mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; + + mti = 0; + PBRT_RNG_FINISHED_TABLEGEN(); + } + + y = mt[mti++]; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + + return y; +} + + diff --git a/core/rng.h b/core/rng.h new file mode 100644 index 0000000..69d8948 --- /dev/null +++ b/core/rng.h @@ -0,0 +1,55 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_RNG_H +#define PBRT_CORE_RNG_H + +// core/rng.h* +#include "pbrt.h" +#include "probes.h" + +// Random Number Declarations +class RNG { +public: + RNG(uint32_t seed = 5489UL) { + mti = N+1; /* mti==N+1 means mt[N] is not initialized */ + Seed(seed); + } + + void Seed(uint32_t seed) const; + float RandomFloat() const; + unsigned long RandomUInt() const; + +private: + static const int N = 624; + mutable unsigned long mt[N]; /* the array for the state vector */ + mutable int mti; +}; + + + +#endif // PBRT_CORE_RNG_H diff --git a/core/sampler.cpp b/core/sampler.cpp new file mode 100644 index 0000000..cbe28a2 --- /dev/null +++ b/core/sampler.cpp @@ -0,0 +1,119 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/sampler.cpp* +#include "stdafx.h" +#include "sampler.h" +#include "integrator.h" +#include "volume.h" + +// Sampler Method Definitions +Sampler::~Sampler() { +} + + +Sampler::Sampler(int xstart, int xend, int ystart, int yend, int spp, + float sopen, float sclose) + : xPixelStart(xstart), xPixelEnd(xend), yPixelStart(ystart), + yPixelEnd(yend), samplesPerPixel(spp), shutterOpen(sopen), + shutterClose(sclose) { } +bool Sampler::ReportResults(Sample *samples, const RayDifferential *rays, + const Spectrum *Ls, const Intersection *isects, int count) { + return true; +} + + +void Sampler::ComputeSubWindow(int num, int count, int *newXStart, + int *newXEnd, int *newYStart, int *newYEnd) const { + // Determine how many tiles to use in each dimension, _nx_ and _ny_ + int dx = xPixelEnd - xPixelStart, dy = yPixelEnd - yPixelStart; + int nx = count, ny = 1; + while ((nx & 0x1) == 0 && 2 * dx * ny < dy * nx) { + nx >>= 1; + ny <<= 1; + } + Assert(nx * ny == count); + + // Compute $x$ and $y$ pixel sample range for sub-window + int xo = num % nx, yo = num / nx; + float tx0 = float(xo) / float(nx), tx1 = float(xo+1) / float(nx); + float ty0 = float(yo) / float(ny), ty1 = float(yo+1) / float(ny); + *newXStart = Floor2Int(Lerp(tx0, xPixelStart, xPixelEnd)); + *newXEnd = Floor2Int(Lerp(tx1, xPixelStart, xPixelEnd)); + *newYStart = Floor2Int(Lerp(ty0, yPixelStart, yPixelEnd)); + *newYEnd = Floor2Int(Lerp(ty1, yPixelStart, yPixelEnd)); +} + + + +// Sample Method Definitions +Sample::Sample(Sampler *sampler, SurfaceIntegrator *surf, + VolumeIntegrator *vol, const Scene *scene) { + if (surf) surf->RequestSamples(sampler, this, scene); + if (vol) vol->RequestSamples(sampler, this, scene); + AllocateSampleMemory(); +} + + +void Sample::AllocateSampleMemory() { + // Allocate storage for sample pointers + int nPtrs = n1D.size() + n2D.size(); + if (!nPtrs) { + oneD = twoD = NULL; + return; + } + oneD = AllocAligned(nPtrs); + twoD = oneD + n1D.size(); + + // Compute total number of sample values needed + int totSamples = 0; + for (uint32_t i = 0; i < n1D.size(); ++i) + totSamples += n1D[i]; + for (uint32_t i = 0; i < n2D.size(); ++i) + totSamples += 2 * n2D[i]; + + // Allocate storage for sample values + float *mem = AllocAligned(totSamples); + for (uint32_t i = 0; i < n1D.size(); ++i) { + oneD[i] = mem; + mem += n1D[i]; + } + for (uint32_t i = 0; i < n2D.size(); ++i) { + twoD[i] = mem; + mem += 2 * n2D[i]; + } +} + + +Sample *Sample::Duplicate(int count) const { + Sample *ret = new Sample[count]; + for (int i = 0; i < count; ++i) { + ret[i].n1D = n1D; + ret[i].n2D = n2D; + ret[i].AllocateSampleMemory(); + } + return ret; +} + + diff --git a/core/sampler.h b/core/sampler.h new file mode 100644 index 0000000..0226aa8 --- /dev/null +++ b/core/sampler.h @@ -0,0 +1,99 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_SAMPLER_H +#define PBRT_CORE_SAMPLER_H + +// core/sampler.h* +#include "pbrt.h" +#include "geometry.h" +#include "rng.h" +#include "memory.h" + +// Sampling Declarations +class Sampler { +public: + // Sampler Interface + virtual ~Sampler(); + Sampler(int xstart, int xend, int ystart, int yend, + int spp, float sopen, float sclose); + virtual int GetMoreSamples(Sample *sample, RNG &rng) = 0; + virtual int MaximumSampleCount() = 0; + virtual bool ReportResults(Sample *samples, const RayDifferential *rays, + const Spectrum *Ls, const Intersection *isects, int count); + virtual Sampler *GetSubSampler(int num, int count) = 0; + virtual int RoundSize(int size) const = 0; + + // Sampler Public Data + const int xPixelStart, xPixelEnd, yPixelStart, yPixelEnd; + const int samplesPerPixel; + const float shutterOpen, shutterClose; +protected: + // Sampler Protected Methods + void ComputeSubWindow(int num, int count, int *xstart, int *xend, int *ystart, int *yend) const; +}; + + +struct CameraSample { + float imageX, imageY; + float lensU, lensV; + float time; +}; + + +struct Sample : public CameraSample { + // Sample Public Methods + Sample(Sampler *sampler, SurfaceIntegrator *surf, VolumeIntegrator *vol, + const Scene *scene); + uint32_t Add1D(uint32_t num) { + n1D.push_back(num); + return n1D.size()-1; + } + uint32_t Add2D(uint32_t num) { + n2D.push_back(num); + return n2D.size()-1; + } + ~Sample() { + if (oneD != NULL) { + FreeAligned(oneD[0]); + FreeAligned(oneD); + } + } + Sample *Duplicate(int count) const; + + // Sample Public Data + vector n1D, n2D; + float **oneD, **twoD; +private: + // Sample Private Methods + void AllocateSampleMemory(); + Sample() { oneD = twoD = NULL; } +}; + + + +#endif // PBRT_CORE_SAMPLER_H diff --git a/core/scene.cpp b/core/scene.cpp new file mode 100644 index 0000000..49a341e --- /dev/null +++ b/core/scene.cpp @@ -0,0 +1,60 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/scene.cpp* +#include "stdafx.h" +#include "scene.h" +#include "camera.h" +#include "film.h" +#include "sampler.h" +#include "volume.h" +#include "parallel.h" +#include "progressreporter.h" +#include "renderer.h" + +// Scene Method Definitions +Scene::~Scene() { + delete aggregate; + delete volumeRegion; + for (uint32_t i = 0; i < lights.size(); ++i) + delete lights[i]; +} + + +Scene::Scene(Primitive *accel, const vector <s, + VolumeRegion *vr) { + lights = lts; + aggregate = accel; + volumeRegion = vr; + // Scene Constructor Implementation + bound = aggregate->WorldBound(); + if (volumeRegion) bound = Union(bound, volumeRegion->WorldBound()); +} + + +const BBox &Scene::WorldBound() const { + return bound; +} + + diff --git a/core/scene.h b/core/scene.h new file mode 100644 index 0000000..2f29405 --- /dev/null +++ b/core/scene.h @@ -0,0 +1,65 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_SCENE_H +#define PBRT_CORE_SCENE_H + +// core/scene.h* +#include "pbrt.h" +#include "primitive.h" +#include "integrator.h" + +// Scene Declarations +class Scene { +public: + // Scene Public Methods + Scene(Primitive *accel, const vector <s, VolumeRegion *vr); + ~Scene(); + bool Intersect(const Ray &ray, Intersection *isect) const { + PBRT_STARTED_RAY_INTERSECTION(const_cast(&ray)); + bool hit = aggregate->Intersect(ray, isect); + PBRT_FINISHED_RAY_INTERSECTION(const_cast(&ray), isect, int(hit)); + return hit; + } + bool IntersectP(const Ray &ray) const { + PBRT_STARTED_RAY_INTERSECTIONP(const_cast(&ray)); + bool hit = aggregate->IntersectP(ray); + PBRT_FINISHED_RAY_INTERSECTIONP(const_cast(&ray), int(hit)); + return hit; + } + const BBox &WorldBound() const; + + // Scene Public Data + Primitive *aggregate; + vector lights; + VolumeRegion *volumeRegion; + BBox bound; +}; + + + +#endif // PBRT_CORE_SCENE_H diff --git a/core/sh.cpp b/core/sh.cpp new file mode 100644 index 0000000..4c8633a --- /dev/null +++ b/core/sh.cpp @@ -0,0 +1,495 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/sh.cpp* +#include "stdafx.h" +#include "sh.h" +#include "scene.h" +#include "integrator.h" +#include "intersection.h" +#include "montecarlo.h" +#include "imageio.h" +#include + +// Spherical Harmonics Local Definitions +static void legendrep(float x, int lmax, float *out) { +#define P(l,m) out[SHIndex(l,m)] + // Compute $m=0$ Legendre values using recurrence + P(0,0) = 1.f; + P(1,0) = x; + for (int l = 2; l <= lmax; ++l) + { + P(l, 0) = ((2*l-1)*x*P(l-1,0) - (l-1)*P(l-2,0)) / l; + Assert(!isnan(P(l, 0))); + Assert(!isinf(P(l, 0))); + } + + // Compute $m=l$ edge using Legendre recurrence + float neg = -1.f; + float dfact = 1.f; + float xroot = sqrtf(max(0.f, 1.f - x*x)); + float xpow = xroot; + for (int l = 1; l <= lmax; ++l) { + P(l, l) = neg * dfact * xpow; + Assert(!isnan(P(l, l))); + Assert(!isinf(P(l, l))); + neg *= -1.f; // neg = (-1)^l + dfact *= 2*l + 1; // dfact = (2*l-1)!! + xpow *= xroot; // xpow = powf(1.f - x*x, float(l) * 0.5f); + } + + // Compute $m=l-1$ edge using Legendre recurrence + for (int l = 2; l <= lmax; ++l) + { + P(l, l-1) = x * (2*l-1) * P(l-1, l-1); + Assert(!isnan(P(l, l-1))); + Assert(!isinf(P(l, l-1))); + } + + // Compute $m=1, \ldots, l-2$ values using Legendre recurrence + for (int l = 3; l <= lmax; ++l) + for (int m = 1; m <= l-2; ++m) + { + P(l, m) = ((2 * (l-1) + 1) * x * P(l-1,m) - + (l-1+m) * P(l-2,m)) / (l - m); + Assert(!isnan(P(l, m))); + Assert(!isinf(P(l, m))); + } + #if 0 + // wrap up with the negative m ones now + // P(l,-m)(x) = -1^m (l-m)!/(l+m)! P(l,m)(x) + for (int l = 1; l <= lmax; ++l) { + float fa = 1.f, fb = fact(2*l); + // fa = fact(l+m), fb = fact(l-m) + for (int m = -l; m < 0; ++m) { + float neg = ((-m) & 0x1) ? -1.f : 1.f; + P(l,m) = neg * fa/fb * P(l,-m); + fb /= l-m; + fa *= (l+m+1) > 1 ? (l+m+1) : 1.; + } + } + #endif +#undef P +} + + +static inline float fact(float v); +static inline float divfact(int a, int b); +static inline float K(int l, int m) { + return sqrtf((2.f * l + 1.f) * INV_FOURPI * divfact(l, m)); +} + + +static inline float divfact(int a, int b) { + if (b == 0) return 1.f; + float fa = a, fb = fabsf(b); + float v = 1.f; + for (float x = fa-fb+1.f; x <= fa+fb; x += 1.f) + v *= x; + return 1.f / v; +} + + +// n!! = 1 if n==0 or 1, otherwise n * (n-2)!! +static float dfact(float v) { + if (v <= 1.f) return 1.f; + return v * dfact(v - 2.f); +} + + +static inline float fact(float v) { + if (v <= 1.f) return 1.f; + return v * fact(v - 1.f); +} + + +static void sinCosIndexed(float s, float c, int n, + float *sout, float *cout) { + float si = 0, ci = 1; + for (int i = 0; i < n; ++i) { + // Compute $\sin{}i\phi$ and $\cos{}i\phi$ using recurrence + *sout++ = si; + *cout++ = ci; + float oldsi = si; + si = si * c + ci * s; + ci = ci * c - oldsi * s; + } +} + + +static void toZYZ(const Matrix4x4 &m, float *alpha, float *beta, float *gamma) { +#define M(a, b) (m.m[a][b]) + + float sy = sqrtf(M(2,1)*M(2,1) + M(2,0)*M(2,0)); + if (sy > 16*FLT_EPSILON) { + *gamma = -atan2f(M(1,2), -M(0,2)); + *beta = -atan2f(sy, M(2,2)); + *alpha = -atan2f(M(2,1), M(2,0)); + } else { + *gamma = 0; + *beta = -atan2f(sy, M(2,2)); + *alpha = -atan2f(-M(1,0), M(1,1)); + } +#undef M +} + + +static inline float lambda(float l) { + return sqrtf((4.f * M_PI) / (2.f * l + 1.)); +} + + + +// Spherical Harmonics Definitions +void SHEvaluate(const Vector &w, int lmax, float *out) { + if (lmax > 28) + Severe("SHEvaluate() runs out of numerical precision for lmax > 28. " + "If you need more bands, try recompiling using doubles."); + // Compute Legendre polynomial values for $\cos\theta$ + Assert(w.Length() > .995f && w.Length() < 1.005f); + legendrep(w.z, lmax, out); + + // Compute $K_l^m$ coefficients + float *Klm = ALLOCA(float, SHTerms(lmax)); + for (int l = 0; l <= lmax; ++l) + for (int m = -l; m <= l; ++m) + Klm[SHIndex(l, m)] = K(l, m); + + // Compute $\sin\phi$ and $\cos\phi$ values + float *sins = ALLOCA(float, lmax+1), *coss = ALLOCA(float, lmax+1); + float xyLen = sqrtf(max(0.f, 1.f - w.z*w.z)); + if (xyLen == 0.f) { + for (int i = 0; i <= lmax; ++i) sins[i] = 0.f; + for (int i = 0; i <= lmax; ++i) coss[i] = 1.f; + } + else + sinCosIndexed(w.y / xyLen, w.x / xyLen, lmax+1, sins, coss); + + // Apply SH definitions to compute final $(l,m)$ values + static const float sqrt2 = sqrtf(2.f); + for (int l = 0; l <= lmax; ++l) { + for (int m = -l; m < 0; ++m) + { + out[SHIndex(l, m)] = sqrt2 * Klm[SHIndex(l, m)] * + out[SHIndex(l, -m)] * sins[-m]; + Assert(!isnan(out[SHIndex(l,m)])); + Assert(!isinf(out[SHIndex(l,m)])); + } + out[SHIndex(l, 0)] *= Klm[SHIndex(l, 0)]; + for (int m = 1; m <= l; ++m) + { + out[SHIndex(l, m)] *= sqrt2 * Klm[SHIndex(l, m)] * coss[m]; + Assert(!isnan(out[SHIndex(l,m)])); + Assert(!isinf(out[SHIndex(l,m)])); + } + } +} + + +#if 0 +// Believe this is correct, but not well tested +void SHEvaluate(float costheta, float cosphi, float sinphi, int lmax, float *out) { + legendrep(costheta, lmax, out); + + float *Klm = ALLOCA(float, SHTerms(lmax)); + klm(lmax, Klm); + + float sqrt2 = sqrtf(2.f); + float sins[(lmax+1)], coss[(lmax+1)]; + sinCosIndexed(sinphi, cosphi, lmax+1, sins, coss); + + for (int l = 0; l <= lmax; ++l) { + for (int m = -l; m < 0; ++m) + // sin(-x) = -sin(x) + out[SHIndex(l, m)] = sqrt2 * Klm[SHIndex(l, m)] * + out[SHIndex(l, -m)] * sins[-m]; + + out[SHIndex(l, 0)] *= Klm[SHIndex(l, 0)]; + + for (int m = 1; m <= l; ++m) + out[SHIndex(l, m)] *= sqrt2 * Klm[SHIndex(l, m)] * coss[m]; + } +} + + +#endif +void SHWriteImage(const char *filename, const Spectrum *c, int lmax, int yres) { + int xres = 2 * yres; + float *rgb = new float[xres * yres * 3]; + float *Ylm = ALLOCA(float, SHTerms(lmax)); + for (int y = 0; y < yres; ++y) { + float theta = (float(y) + 0.5f) / float(yres) * M_PI; + for (int x = 0; x < xres; ++x) { + float phi = (float(x) + 0.5f) / float(xres) * 2.f * M_PI; + // Compute RGB color for direction $(\theta,\phi)$ from SH coefficients + Vector w = SphericalDirection(sinf(theta), cosf(theta), phi); + SHEvaluate(w, lmax, Ylm); + Spectrum val = 0.f; + for (int i = 0; i < SHTerms(lmax); ++i) + val += Ylm[i] * c[i]; + int offset = xres * y + x; + val.ToRGB(&rgb[3*offset]); + } + } + + WriteImage(filename, rgb, NULL, xres, yres, xres, yres, 0, 0); + delete[] rgb; +} + + +void SHProjectIncidentDirectRadiance(const Point &p, float pEpsilon, + float time, MemoryArena &arena, const Scene *scene, + bool computeLightVis, int lmax, RNG &rng, Spectrum *c_d) { + // Loop over light sources and sum their SH coefficients + Spectrum *c = arena.Alloc(SHTerms(lmax)); + for (uint32_t i = 0; i < scene->lights.size(); ++i) { + Light *light = scene->lights[i]; + light->SHProject(p, pEpsilon, lmax, scene, computeLightVis, time, + rng, c); + for (int j = 0; j < SHTerms(lmax); ++j) + c_d[j] += c[j]; + } + SHReduceRinging(c_d, lmax); +} + + +void SHProjectIncidentIndirectRadiance(const Point &p, float pEpsilon, + float time, const Renderer *renderer, Sample *origSample, + const Scene *scene, int lmax, RNG &rng, int ns, Spectrum *c_i) { + Sample *sample = origSample->Duplicate(1); + MemoryArena arena; + uint32_t scramble[2] = { rng.RandomUInt(), rng.RandomUInt() }; + int nSamples = RoundUpPow2(ns); + float *Ylm = ALLOCA(float, SHTerms(lmax)); + for (int i = 0; i < nSamples; ++i) { + // Sample incident direction for radiance probe + float u[2]; + Sample02(i, scramble, u); + Vector wi = UniformSampleSphere(u[0], u[1]); + float pdf = UniformSpherePdf(); + + // Compute incident radiance along direction for probe + Spectrum Li = 0.f; + RayDifferential ray(p, wi, pEpsilon, INFINITY, time); + + // Fill in values in _sample_ for radiance probe ray + sample->time = time; + for (uint32_t j = 0; j < sample->n1D.size(); ++j) + for (uint32_t k = 0; k < sample->n1D[j]; ++k) + sample->oneD[j][k] = rng.RandomFloat(); + for (uint32_t j = 0; j < sample->n2D.size(); ++j) + for (uint32_t k = 0; k < 2 * sample->n2D[j]; ++k) + sample->twoD[j][k] = rng.RandomFloat(); + Li = renderer->Li(scene, ray, sample, rng, arena); + + // Update SH coefficients for probe sample point + SHEvaluate(wi, lmax, Ylm); + for (int j = 0; j < SHTerms(lmax); ++j) + c_i[j] += Ylm[j] * Li / (pdf * nSamples); + arena.FreeAll(); + } + delete[] sample; +} + + +void SHReduceRinging(Spectrum *c, int lmax, float lambda) { + for (int l = 0; l <= lmax; ++l) { + float scale = 1.f / (1.f + lambda * l * l * (l + 1) * (l + 1)); + for (int m = -l; m <= l; ++m) + c[SHIndex(l, m)] *= scale; + } +} + + +void SHRotate(const Spectrum *c_in, Spectrum *c_out, const Matrix4x4 &m, + int lmax, MemoryArena &arena) { + float alpha, beta, gamma; + toZYZ(m, &alpha, &beta, &gamma); + Spectrum *work = arena.Alloc(SHTerms(lmax)); + SHRotateZ(c_in, c_out, gamma, lmax); + SHRotateXPlus(c_out, work, lmax); + SHRotateZ(work, c_out, beta, lmax); + SHRotateXMinus(c_out, work, lmax); + SHRotateZ(work, c_out, alpha, lmax); +} + + +void SHRotateZ(const Spectrum *c_in, Spectrum *c_out, float alpha, + int lmax) { + Assert(c_in != c_out); + c_out[0] = c_in[0]; + if (lmax == 0) return; + // Precompute sine and cosine terms for $z$-axis SH rotation + float *ct = ALLOCA(float, lmax+1); + float *st = ALLOCA(float, lmax+1); + sinCosIndexed(sinf(alpha), cosf(alpha), lmax+1, st, ct); + for (int l = 1; l <= lmax; ++l) { + // Rotate coefficients for band _l_ about $z$ + for (int m = -l; m < 0; ++m) + c_out[SHIndex(l, m)] = + ( ct[-m] * c_in[SHIndex(l, m)] + + -st[-m] * c_in[SHIndex(l, -m)]); + c_out[SHIndex(l, 0)] = c_in[SHIndex(l, 0)]; + for (int m = 1; m <= l; ++m) + c_out[SHIndex(l, m)] = + (ct[m] * c_in[SHIndex(l, m)] + + st[m] * c_in[SHIndex(l, -m)]); + } +} + + +void SHConvolveCosTheta(int lmax, const Spectrum *c_in, + Spectrum *c_out) { + static const float c_costheta[18] = { 0.8862268925, 1.0233267546, + 0.4954159260, 0.0000000000, -0.1107783690, 0.0000000000, + 0.0499271341, 0.0000000000, -0.0285469331, 0.0000000000, + 0.0185080823, 0.0000000000, -0.0129818395, 0.0000000000, + 0.0096125342, 0.0000000000, -0.0074057109, 0.0000000000 }; + for (int l = 0; l <= lmax; ++l) + for (int m = -l; m <= l; ++m) { + int o = SHIndex(l, m); + if (l < 18) c_out[o] = lambda(l) * c_in[o] * c_costheta[l]; + else c_out[o] = 0.f; + } +} + + +void SHConvolvePhong(int lmax, float n, const Spectrum *c_in, + Spectrum *c_out) { + for (int l = 0; l <= lmax; ++l) { + float c_phong = expf(-(l*l) / (2.f * n)); + for (int m = -l; m <= l; ++m) { + int o = SHIndex(l, m); + c_out[o] = lambda(l) * c_in[o] * c_phong; + } + } +} + + +void SHComputeDiffuseTransfer(const Point &p, const Normal &n, + float rayEpsilon, const Scene *scene, RNG &rng, int nSamples, + int lmax, Spectrum *c_transfer) { + for (int i = 0; i < SHTerms(lmax); ++i) + c_transfer[i] = 0.f; + uint32_t scramble[2] = { rng.RandomUInt(), rng.RandomUInt() }; + float *Ylm = ALLOCA(float, SHTerms(lmax)); + for (int i = 0; i < nSamples; ++i) { + // Sample _i_th direction and compute estimate for transfer coefficients + float u[2]; + Sample02(i, scramble, u); + Vector w = UniformSampleSphere(u[0], u[1]); + float pdf = UniformSpherePdf(); + if (Dot(w, n) > 0.f && !scene->IntersectP(Ray(p, w, rayEpsilon))) { + // Accumulate contribution of direction $\w{}$ to transfer coefficients + SHEvaluate(w, lmax, Ylm); + for (int j = 0; j < SHTerms(lmax); ++j) + c_transfer[j] += (Ylm[j] * AbsDot(w, n)) / (pdf * nSamples); + } + } +} + + +void SHComputeTransferMatrix(const Point &p, float rayEpsilon, + const Scene *scene, RNG &rng, int nSamples, int lmax, + Spectrum *T) { + for (int i = 0; i < SHTerms(lmax)*SHTerms(lmax); ++i) + T[i] = 0.f; + uint32_t scramble[2] = { rng.RandomUInt(), rng.RandomUInt() }; + float *Ylm = ALLOCA(float, SHTerms(lmax)); + for (int i = 0; i < nSamples; ++i) { + // Compute Monte Carlo estimate of $i$th sample for transfer matrix + float u[2]; + Sample02(i, scramble, u); + Vector w = UniformSampleSphere(u[0], u[1]); + float pdf = UniformSpherePdf(); + if (!scene->IntersectP(Ray(p, w, rayEpsilon))) { + // Update transfer matrix for unoccluded direction + SHEvaluate(w, lmax, Ylm); + for (int j = 0; j < SHTerms(lmax); ++j) + for (int k = 0; k < SHTerms(lmax); ++k) + T[j*SHTerms(lmax)+k] += (Ylm[j] * Ylm[k]) / (pdf * nSamples); + } + } +} + + +void SHComputeBSDFMatrix(const Spectrum &Kd, const Spectrum &Ks, + float roughness, RNG &rng, int nSamples, int lmax, Spectrum *B) { + for (int i = 0; i < SHTerms(lmax)*SHTerms(lmax); ++i) + B[i] = 0.f; + // Create _BSDF_ for computing BSDF transfer matrix + MemoryArena arena; + DifferentialGeometry dg(Point(0,0,0), Vector(1,0,0), Vector(0,1,0), + Normal(0,0,0), Normal(0,0,0), 0, 0, NULL); + BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dg, Normal(0,0,1)); + bsdf->Add(BSDF_ALLOC(arena, Lambertian)(Spectrum(Kd))); + Fresnel *fresnel = BSDF_ALLOC(arena, FresnelDielectric)(1.5f, 1.f); + bsdf->Add(BSDF_ALLOC(arena, Microfacet)(Ks, fresnel, + BSDF_ALLOC(arena, Blinn)(1.f / roughness))); + + // Precompute directions $\w{}$ and SH values for directions + float *Ylm = new float[SHTerms(lmax) * nSamples]; + Vector *w = new Vector[nSamples]; + uint32_t scramble[2] = { rng.RandomUInt(), rng.RandomUInt() }; + for (int i = 0; i < nSamples; ++i) { + float u[2]; + Sample02(i, scramble, u); + w[i] = UniformSampleSphere(u[0], u[1]); + SHEvaluate(w[i], lmax, &Ylm[SHTerms(lmax)*i]); + } + + // Compute double spherical integral for BSDF matrix + for (int osamp = 0; osamp < nSamples; ++osamp) { + const Vector &wo = w[osamp]; + for (int isamp = 0; isamp < nSamples; ++isamp) { + const Vector &wi = w[isamp]; + // Update BSDF matrix elements for sampled directions + Spectrum f = bsdf->f(wo, wi); + if (!f.IsBlack()) { + float pdf = UniformSpherePdf() * UniformSpherePdf(); + f *= fabsf(CosTheta(wi)) / (pdf * nSamples * nSamples); + for (int i = 0; i < SHTerms(lmax); ++i) + for (int j = 0; j < SHTerms(lmax); ++j) + B[i*SHTerms(lmax)+j] += f * Ylm[isamp*SHTerms(lmax)+j] * + Ylm[osamp*SHTerms(lmax)+i]; + } + } + } + + // Free memory allocated for SH matrix computation + delete[] w; + delete[] Ylm; +} + + +void SHMatrixVectorMultiply(const Spectrum *M, const Spectrum *v, + Spectrum *vout, int lmax) { + for (int i = 0; i < SHTerms(lmax); ++i) { + vout[i] = 0.f; + for (int j = 0; j < SHTerms(lmax); ++j) + vout[i] += M[SHTerms(lmax) * i + j] * v[j]; + } +} + + diff --git a/core/sh.h b/core/sh.h new file mode 100644 index 0000000..359648c --- /dev/null +++ b/core/sh.h @@ -0,0 +1,120 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_SH_H +#define PBRT_CORE_SH_H + +// core/sh.h* +#include "pbrt.h" +#include "geometry.h" +#include "spectrum.h" + +// Spherical Harmonics Declarations +inline int SHTerms(int lmax) { + return (lmax + 1) * (lmax + 1); +} + + +inline int SHIndex(int l, int m) { + return l*l + l + m; +} + + +void SHEvaluate(const Vector &v, int lmax, float *out); +void SHWriteImage(const char *filename, const Spectrum *c, int lmax, int yres); +template +void SHProjectCube(Func func, const Point &p, int res, int lmax, + Spectrum *coeffs) { + float *Ylm = ALLOCA(float, SHTerms(lmax)); + for (int u = 0; u < res; ++u) { + float fu = -1.f + 2.f * (float(u) + 0.5f) / float(res); + for (int v = 0; v < res; ++v) { + float fv = -1.f + 2.f * (float(v) + 0.5f) / float(res); + // Incorporate results from $+z$ face to coefficients + Vector w(fu, fv, 1); + SHEvaluate(Normalize(w), lmax, Ylm); + Spectrum f = func(u, v, p, w); + float dA = 1.f / powf(Dot(w, w), 3.f/2.f); + for (int k = 0; k < SHTerms(lmax); ++k) + coeffs[k] += f * Ylm[k] * dA * (4.f / (res * res)); + + // Incorporate results from other faces to coefficients + w = Vector(fu, fv, -1); + SHEvaluate(Normalize(w), lmax, Ylm); + f = func(u, v, p, w); + for (int k = 0; k < SHTerms(lmax); ++k) + coeffs[k] += f * Ylm[k] * dA * (4.f / (res * res)); + w = Vector(fu, 1, fv); + SHEvaluate(Normalize(w), lmax, Ylm); + f = func(u, v, p, w); + for (int k = 0; k < SHTerms(lmax); ++k) + coeffs[k] += f * Ylm[k] * dA * (4.f / (res * res)); + w = Vector(fu, -1, fv); + SHEvaluate(Normalize(w), lmax, Ylm); + f = func(u, v, p, w); + for (int k = 0; k < SHTerms(lmax); ++k) + coeffs[k] += f * Ylm[k] * dA * (4.f / (res * res)); + w = Vector(1, fu, fv); + SHEvaluate(Normalize(w), lmax, Ylm); + f = func(u, v, p, w); + for (int k = 0; k < SHTerms(lmax); ++k) + coeffs[k] += f * Ylm[k] * dA * (4.f / (res * res)); + w = Vector(-1, fu, fv); + SHEvaluate(Normalize(w), lmax, Ylm); + f = func(u, v, p, w); + for (int k = 0; k < SHTerms(lmax); ++k) + coeffs[k] += f * Ylm[k] * dA * (4.f / (res * res)); + } + } +} + + +void SHProjectIncidentDirectRadiance(const Point &p, float pEpsilon, float time, + MemoryArena &arena, const Scene *scene, bool computeLightVisibility, + int lmax, RNG &rng, Spectrum *c_d); +void SHProjectIncidentIndirectRadiance(const Point &p, float pEpsilon, + float time, const Renderer *renderer, Sample *origSample, + const Scene *scene, int lmax, RNG &rng, int nSamples, Spectrum *c_i); +void SHReduceRinging(Spectrum *c, int lmax, float lambda = .005f); +void SHRotate(const Spectrum *c_in, Spectrum *c_out, const Matrix4x4 &m, + int lmax, MemoryArena &arena); +void SHRotateZ(const Spectrum *c_in, Spectrum *c_out, float alpha, int lmax); +void SHRotateXMinus(const Spectrum *c_in, Spectrum *c_out, int lmax); +void SHRotateXPlus(const Spectrum *c_in, Spectrum *c_out, int lmax); +//void SHSwapYZ(const Spectrum *c_in, Spectrum *c_out, int lmax); +void SHConvolveCosTheta(int lmax, const Spectrum *c_in, Spectrum *c_out); +void SHConvolvePhong(int lmax, float n, const Spectrum *c_in, Spectrum *c_out); +void SHComputeDiffuseTransfer(const Point &p, const Normal &n, float rayEpsilon, + const Scene *scene, RNG &rng, int nSamples, int lmax, Spectrum *c_transfer); +void SHComputeTransferMatrix(const Point &p, float rayEpsilon, + const Scene *scene, RNG &rng, int nSamples, int lmax, Spectrum *T); +void SHComputeBSDFMatrix(const Spectrum &Kd, const Spectrum &Ks, + float roughness, RNG &rng, int nSamples, int lmax, Spectrum *B); +void SHMatrixVectorMultiply(const Spectrum *M, const Spectrum *v, + Spectrum *vout, int lmax); + +#endif // PBRT_CORE_SH_H diff --git a/core/shape.cpp b/core/shape.cpp new file mode 100644 index 0000000..0860b6b --- /dev/null +++ b/core/shape.cpp @@ -0,0 +1,93 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/shape.cpp* +#include "stdafx.h" +#include "shape.h" + +// Shape Method Definitions +Shape::~Shape() { +} + + +Shape::Shape(const Transform *o2w, const Transform *w2o, bool ro) + : ObjectToWorld(o2w), WorldToObject(w2o), ReverseOrientation(ro), + TransformSwapsHandedness(o2w->SwapsHandedness()), + shapeId(nextshapeId++) { + // Update shape creation statistics + PBRT_CREATED_SHAPE(this); +} + + +uint32_t Shape::nextshapeId = 1; +BBox Shape::WorldBound() const { + return (*ObjectToWorld)(ObjectBound()); +} + + +bool Shape::CanIntersect() const { + return true; +} + + +void Shape::Refine(vector > &refined) const { + Severe("Unimplemented Shape::Refine() method called"); +} + + +bool Shape::Intersect(const Ray &ray, float *tHit, float *rayEpsilon, + DifferentialGeometry *dg) const { + Severe("Unimplemented Shape::Intersect() method called"); + return false; +} + + +bool Shape::IntersectP(const Ray &ray) const { + Severe("Unimplemented Shape::IntersectP() method called"); + return false; +} + + +float Shape::Area() const { + Severe("Unimplemented Shape::Area() method called"); + return 0.; +} + + +float Shape::Pdf(const Point &p, const Vector &wi) const { + // Intersect sample ray with area light geometry + DifferentialGeometry dgLight; + Ray ray(p, wi, 1e-3f); + ray.depth = -1; // temporary hack to ignore alpha mask + float thit, rayEpsilon; + if (!Intersect(ray, &thit, &rayEpsilon, &dgLight)) return 0.; + + // Convert light sample weight to solid angle measure + float pdf = DistanceSquared(p, ray(thit)) / + (AbsDot(dgLight.nn, -wi) * Area()); + if (isinf(pdf)) pdf = 0.f; + return pdf; +} + + diff --git a/core/shape.h b/core/shape.h new file mode 100644 index 0000000..e3ce2eb --- /dev/null +++ b/core/shape.h @@ -0,0 +1,79 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_SHAPE_H +#define PBRT_CORE_SHAPE_H + +// core/shape.h* +#include "pbrt.h" +#include "geometry.h" +#include "transform.h" +#include "diffgeom.h" +#include "memory.h" + +// Shape Declarations +class Shape : public ReferenceCounted { +public: + // Shape Interface + Shape(const Transform *o2w, const Transform *w2o, bool ro); + virtual ~Shape(); + virtual BBox ObjectBound() const = 0; + virtual BBox WorldBound() const; + virtual bool CanIntersect() const; + virtual void Refine(vector > &refined) const; + virtual bool Intersect(const Ray &ray, float *tHit, + float *rayEpsilon, DifferentialGeometry *dg) const; + virtual bool IntersectP(const Ray &ray) const; + virtual void GetShadingGeometry(const Transform &obj2world, + const DifferentialGeometry &dg, + DifferentialGeometry *dgShading) const { + *dgShading = dg; + } + virtual float Area() const; + virtual Point Sample(float u1, float u2, Normal *Ns) const { + Severe("Unimplemented Shape::Sample() method called"); + return Point(); + } + virtual float Pdf(const Point &Pshape) const { + return 1.f / Area(); + } + virtual Point Sample(const Point &P, float u1, float u2, + Normal *Ns) const { + return Sample(u1, u2, Ns); + } + virtual float Pdf(const Point &p, const Vector &wi) const; + + // Shape Public Data + const Transform *ObjectToWorld, *WorldToObject; + const bool ReverseOrientation, TransformSwapsHandedness; + const uint32_t shapeId; + static uint32_t nextshapeId; +}; + + + +#endif // PBRT_CORE_SHAPE_H diff --git a/core/shrots.cpp b/core/shrots.cpp new file mode 100644 index 0000000..46ab952 --- /dev/null +++ b/core/shrots.cpp @@ -0,0 +1,1463 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/shrots.cpp* +#include "stdafx.h" +#include "sh.h" + +// Spherical Harmonics Rotations Definitions +void SHRotateXMinus(const Spectrum *c_in, Spectrum *c_out, int lmax) { + // -x rotations are the same as +x rotations, just with a negation + // factor thrown in for some of the terms. + SHRotateXPlus(c_in, c_out, lmax); + + // l = 0 band is a no op... + for (int l = 1; l <= lmax; ++l) { + float s = (l & 0x1) ? -1.f : 1.f; + c_out[SHIndex(l, 0)] *= s; + for (int m = 1; m <= l; ++m) { + s = -s; + c_out[SHIndex(l, m)] *= s; + c_out[SHIndex(l, -m)] *= -s; + } + } +} + + +void SHRotateXPlus(const Spectrum *c_in, Spectrum *c_out, int lmax) { +#define O(l, m) c_in[SHIndex(l, m)] + + // first band is a no-op + *c_out++ = c_in[0]; + + if (lmax < 1) return; + *c_out++ = (O(1,0)); + *c_out++ = (-1.*O(1,-1)); + *c_out++ = (O(1,1)); + + if (lmax < 2) return; + *c_out++ = (O(2,1)); + *c_out++ = (-1.*O(2,-1)); + *c_out++ = (-0.5*O(2,0) - 0.8660254037844386*O(2,2)); + *c_out++ = (-1.*O(2,-2)); + *c_out++ = (-0.8660254037844386*O(2,0) + 0.5*O(2,2)); + + // Remainder of SH $x+$ rotation definition + if (lmax < 3) return; + *c_out++ = (-0.7905694150420949*O(3,0) + 0.6123724356957945*O(3,2)); + *c_out++ = (-1.*O(3,-2)); + *c_out++ = (-0.6123724356957945*O(3,0) - 0.7905694150420949*O(3,2)); + *c_out++ = (0.7905694150420949*O(3,-3) + 0.6123724356957945*O(3,-1)); + *c_out++ = (-0.25*O(3,1) - 0.9682458365518543*O(3,3)); + *c_out++ = (-0.6123724356957945*O(3,-3) + 0.7905694150420949*O(3,-1)); + *c_out++ = (-0.9682458365518543*O(3,1) + 0.25*O(3,3)); + + if (lmax < 4) return; + *c_out++ = (-0.9354143466934853*O(4,1) + 0.35355339059327373*O(4,3)); + *c_out++ = (-0.75*O(4,-3) + 0.6614378277661477*O(4,-1)); + *c_out++ = (-0.35355339059327373*O(4,1) - 0.9354143466934853*O(4,3)); + *c_out++ = (0.6614378277661477*O(4,-3) + 0.75*O(4,-1)); + *c_out++ = (0.375*O(4,0) + 0.5590169943749475*O(4,2) + 0.739509972887452*O(4,4)); + *c_out++ = (0.9354143466934853*O(4,-4) + 0.35355339059327373*O(4,-2)); + *c_out++ = (0.5590169943749475*O(4,0) + 0.5*O(4,2) - 0.6614378277661477*O(4,4)); + *c_out++ = (-0.35355339059327373*O(4,-4) + 0.9354143466934853*O(4,-2)); + *c_out++ = (0.739509972887452*O(4,0) - 0.6614378277661477*O(4,2) + 0.125*O(4,4)); + + if (lmax < 5) return; + *c_out++ = (0.701560760020114*O(5,0) - 0.6846531968814576*O(5,2) + + 0.19764235376052372*O(5,4)); + *c_out++ = (-0.5*O(5,-4) + 0.8660254037844386*O(5,-2)); + *c_out++ = (0.5229125165837972*O(5,0) + 0.30618621784789724*O(5,2) - + 0.795495128834866*O(5,4)); + *c_out++ = (0.8660254037844386*O(5,-4) + 0.5*O(5,-2)); + *c_out++ = (0.4841229182759271*O(5,0) + 0.6614378277661477*O(5,2) + + 0.57282196186948*O(5,4)); + *c_out++ = (-0.701560760020114*O(5,-5) - 0.5229125165837972*O(5,-3) - + 0.4841229182759271*O(5,-1)); + *c_out++ = (0.125*O(5,1) + 0.4050462936504913*O(5,3) + 0.9057110466368399*O(5,5)); + *c_out++ = (0.6846531968814576*O(5,-5) - 0.30618621784789724*O(5,-3) - + 0.6614378277661477*O(5,-1)); + *c_out++ = (0.4050462936504913*O(5,1) + 0.8125*O(5,3) - 0.4192627457812106*O(5,5)); + *c_out++ = (-0.19764235376052372*O(5,-5) + 0.795495128834866*O(5,-3) - + 0.57282196186948*O(5,-1)); + *c_out++ = (0.9057110466368399*O(5,1) - 0.4192627457812106*O(5,3) + 0.0625*O(5,5)); + + if (lmax < 6) return; + *c_out++ = (0.879452954966893*O(6,1) - 0.46351240544347894*O(6,3) + + 0.10825317547305482*O(6,5)); + *c_out++ = (-0.3125*O(6,-5) + 0.8028270361665706*O(6,-3) - 0.5077524002897476*O(6,-1)); + *c_out++ = (0.4330127018922193*O(6,1) + 0.6846531968814576*O(6,3) - + 0.5863019699779287*O(6,5)); + *c_out++ = (0.8028270361665706*O(6,-5) - 0.0625*O(6,-3) - 0.5929270612815711*O(6,-1)); + *c_out++ = (0.19764235376052372*O(6,1) + 0.5625*O(6,3) + 0.8028270361665706*O(6,5)); + *c_out++ = (-0.5077524002897476*O(6,-5) - 0.5929270612815711*O(6,-3) - + 0.625*O(6,-1)); + *c_out++ = (-0.3125*O(6,0) - 0.45285552331841994*O(6,2) - 0.49607837082461076*O(6,4) - + 0.6716932893813962*O(6,6)); + *c_out++ = (-0.879452954966893*O(6,-6) - 0.4330127018922193*O(6,-4) - + 0.19764235376052372*O(6,-2)); + *c_out++ = (-0.45285552331841994*O(6,0) - 0.53125*O(6,2) - 0.1711632992203644*O(6,4) + + 0.6952686081652184*O(6,6)); + *c_out++ = (0.46351240544347894*O(6,-6) - 0.6846531968814576*O(6,-4) - + 0.5625*O(6,-2)); + *c_out++ = (-0.49607837082461076*O(6,0) - 0.1711632992203644*O(6,2) + + 0.8125*O(6,4) - 0.2538762001448738*O(6,6)); + *c_out++ = (-0.10825317547305482*O(6,-6) + 0.5863019699779287*O(6,-4) - + 0.8028270361665706*O(6,-2)); + *c_out++ = (-0.6716932893813962*O(6,0) + 0.6952686081652184*O(6,2) - + 0.2538762001448738*O(6,4) + 0.03125*O(6,6)); + + if (lmax < 7) return; + *c_out++ = (-0.6472598492877494*O(7,0) + 0.6991205412874092*O(7,2) - + 0.2981060004427955*O(7,4) + 0.05846339666834283*O(7,6)); + *c_out++ = (-0.1875*O(7,-6) + 0.6373774391990981*O(7,-4) - 0.7473912964438374*O(7,-2)); + *c_out++ = (-0.47495887979908324*O(7,0) - 0.07328774624724109*O(7,2) + + 0.78125*O(7,4) - 0.3983608994994363*O(7,6)); + *c_out++ = (0.6373774391990981*O(7,-6) - 0.5*O(7,-4) - 0.5863019699779287*O(7,-2)); + *c_out++ = (-0.42961647140211*O(7,0) - 0.41984465132951254*O(7,2) + + 0.10364452469860624*O(7,4) + 0.7927281808728639*O(7,6)); + *c_out++ = (-0.7473912964438374*O(7,-6) - 0.5863019699779287*O(7,-4) - + 0.3125*O(7,-2)); + *c_out++ = (-0.41339864235384227*O(7,0) - 0.5740991584648073*O(7,2) - + 0.5385527481129402*O(7,4) - 0.4576818286211503*O(7,6)); + *c_out++ = (0.6472598492877494*O(7,-7) + 0.47495887979908324*O(7,-5) + + 0.42961647140211*O(7,-3) + 0.41339864235384227*O(7,-1)); + *c_out++ = (-0.078125*O(7,1) - 0.24356964481437335*O(7,3) - 0.4487939567607835*O(7,5) - + 0.8562442974262661*O(7,7)); + *c_out++ = (-0.6991205412874092*O(7,-7) + 0.07328774624724109*O(7,-5) + + 0.41984465132951254*O(7,-3) + 0.5740991584648073*O(7,-1)); + *c_out++ = (-0.24356964481437335*O(7,1) - 0.609375*O(7,3) - 0.5700448858423344*O(7,5) + + 0.4943528756111367*O(7,7)); + *c_out++ = (0.2981060004427955*O(7,-7) - 0.78125*O(7,-5) - 0.10364452469860624*O(7,-3) + + 0.5385527481129402*O(7,-1)); + *c_out++ = (-0.4487939567607835*O(7,1) - 0.5700448858423344*O(7,3) + 0.671875*O(7,5) - + 0.14905300022139775*O(7,7)); + *c_out++ = (-0.05846339666834283*O(7,-7) + 0.3983608994994363*O(7,-5) - + 0.7927281808728639*O(7,-3) + 0.4576818286211503*O(7,-1)); + *c_out++ = (-0.8562442974262661*O(7,1) + 0.4943528756111367*O(7,3) - + 0.14905300022139775*O(7,5) + 0.015625*O(7,7)); + + if (lmax < 8) return; + *c_out++ = (-0.8356088723200586*O(8,1) + 0.516334738808072*O(8,3) - + 0.184877493221863*O(8,5) + 0.03125*O(8,7)); + *c_out++ = (-0.109375*O(8,-7) + 0.4621937330546575*O(8,-5) - 0.774502108212108*O(8,-3) + + 0.4178044361600293*O(8,-1)); + *c_out++ = (-0.4576818286211503*O(8,1) - 0.47134697278119864*O(8,3) + + 0.7088310138883598*O(8,5) - 0.2567449488305466*O(8,7)); + *c_out++ = (0.4621937330546575*O(8,-7) - 0.703125*O(8,-5) - 0.2181912506838897*O(8,-3) + + 0.4943528756111367*O(8,-1)); + *c_out++ = (-0.27421763710600383*O(8,1) - 0.6051536478449089*O(8,3) - + 0.33802043207474897*O(8,5) + 0.6665852814906732*O(8,7)); + *c_out++ = (-0.774502108212108*O(8,-7) - 0.2181912506838897*O(8,-5) + + 0.265625*O(8,-3) + 0.5310201708739509*O(8,-1)); + *c_out++ = (-0.1307281291459493*O(8,1) - 0.38081430021731066*O(8,3) - + 0.5908647000371574*O(8,5) - 0.6991205412874092*O(8,7)); + *c_out++ = (0.4178044361600293*O(8,-7) + 0.4943528756111367*O(8,-5) + + 0.5310201708739509*O(8,-3) + 0.546875*O(8,-1)); + *c_out++ = (0.2734375*O(8,0) + 0.3921843874378479*O(8,2) + 0.4113264556590057*O(8,4) + + 0.4576818286211503*O(8,6) + 0.626706654240044*O(8,8)); + *c_out++ = (0.8356088723200586*O(8,-8) + 0.4576818286211503*O(8,-6) + + 0.27421763710600383*O(8,-4) + 0.1307281291459493*O(8,-2)); + *c_out++ = (0.3921843874378479*O(8,0) + 0.5*O(8,2) + 0.32775276505317236*O(8,4) - + 0.6991205412874092*O(8,8)); + *c_out++ = (-0.516334738808072*O(8,-8) + 0.47134697278119864*O(8,-6) + + 0.6051536478449089*O(8,-4) + 0.38081430021731066*O(8,-2)); + *c_out++ = (0.4113264556590057*O(8,0) + 0.32775276505317236*O(8,2) - + 0.28125*O(8,4) - 0.7302075903467452*O(8,6) + 0.3332926407453366*O(8,8)); + *c_out++ = (0.184877493221863*O(8,-8) - 0.7088310138883598*O(8,-6) + + 0.33802043207474897*O(8,-4) + 0.5908647000371574*O(8,-2)); + *c_out++ = (0.4576818286211503*O(8,0) - 0.7302075903467452*O(8,4) + 0.5*O(8,6) - + 0.0855816496101822*O(8,8)); + *c_out++ = (-0.03125*O(8,-8) + 0.2567449488305466*O(8,-6) - 0.6665852814906732*O(8,-4) + + 0.6991205412874092*O(8,-2)); + *c_out++ = (0.626706654240044*O(8,0) - 0.6991205412874092*O(8,2) + + 0.3332926407453366*O(8,4) - 0.0855816496101822*O(8,6) + 0.0078125*O(8,8)); + + if (lmax < 9) return; + *c_out++ = (0.6090493921755238*O(9,0) - 0.6968469725305549*O(9,2) + + 0.3615761395439417*O(9,4) - 0.11158481919598204*O(9,6) + 0.016572815184059706*O(9,8)); + *c_out++ = (-0.0625*O(9,-8) + 0.3156095293238149*O(9,-6) - 0.6817945071647321*O(9,-4) + + 0.656993626300895*O(9,-2)); + *c_out++ = (0.44314852502786806*O(9,0) - 0.05633673867912483*O(9,2) - 0.6723290616859425*O(9,4) + + 0.5683291712335379*O(9,6) - 0.1594400908746762*O(9,8)); + *c_out++ = (0.3156095293238149*O(9,-8) - 0.71875*O(9,-6) + 0.20252314682524564*O(9,-4) + + 0.5854685623498499*O(9,-2)); + *c_out++ = (0.39636409043643195*O(9,0) + 0.25194555463432966*O(9,2) - 0.3921843874378479*O(9,4) - + 0.6051536478449089*O(9,6) + 0.509312687906457*O(9,8)); + *c_out++ = (-0.6817945071647321*O(9,-8) + 0.20252314682524564*O(9,-6) + 0.5625*O(9,-4) + + 0.4215855488510013*O(9,-2)); + *c_out++ = (0.3754879637718099*O(9,0) + 0.42961647140211*O(9,2) + 0.13799626353637262*O(9,4) - + 0.2981060004427955*O(9,6) - 0.7526807559068452*O(9,8)); + *c_out++ = (0.656993626300895*O(9,-8) + 0.5854685623498499*O(9,-6) + 0.4215855488510013*O(9,-4) + + 0.21875*O(9,-2)); + *c_out++ = (0.36685490255855924*O(9,0) + 0.5130142237306876*O(9,2) + 0.4943528756111367*O(9,4) + + 0.4576818286211503*O(9,6) + 0.38519665736315783*O(9,8)); + *c_out++ = (-0.6090493921755238*O(9,-9) - 0.44314852502786806*O(9,-7) - 0.39636409043643195*O(9,-5) - + 0.3754879637718099*O(9,-3) - 0.36685490255855924*O(9,-1)); + *c_out++ = (0.0546875*O(9,1) + 0.16792332234534904*O(9,3) + 0.2954323500185787*O(9,5) + + 0.4624247721758373*O(9,7) + 0.8171255055356398*O(9,9)); + *c_out++ = (0.6968469725305549*O(9,-9) + 0.05633673867912483*O(9,-7) - 0.25194555463432966*O(9,-5) - + 0.42961647140211*O(9,-3) - 0.5130142237306876*O(9,-1)); + *c_out++ = (0.16792332234534904*O(9,1) + 0.453125*O(9,3) + 0.577279787559724*O(9,5) + + 0.387251054106054*O(9,7) - 0.5322256665703469*O(9,9)); + *c_out++ = (-0.3615761395439417*O(9,-9) + 0.6723290616859425*O(9,-7) + 0.3921843874378479*O(9,-5) - + 0.13799626353637262*O(9,-3) - 0.4943528756111367*O(9,-1)); + *c_out++ = (0.2954323500185787*O(9,1) + 0.577279787559724*O(9,3) + 0.140625*O(9,5) - + 0.7162405240429014*O(9,7) + 0.21608307321780204*O(9,9)); + *c_out++ = (0.11158481919598204*O(9,-9) - 0.5683291712335379*O(9,-7) + 0.6051536478449089*O(9,-5) + + 0.2981060004427955*O(9,-3) - 0.4576818286211503*O(9,-1)); + *c_out++ = (0.4624247721758373*O(9,1) + 0.387251054106054*O(9,3) - 0.7162405240429014*O(9,5) + + 0.34765625*O(9,7) - 0.048317644050206957*O(9,9)); + *c_out++ = (-0.016572815184059706*O(9,-9) + 0.1594400908746762*O(9,-7) - 0.509312687906457*O(9,-5) + + 0.7526807559068452*O(9,-3) - 0.38519665736315783*O(9,-1)); + *c_out++ = (0.8171255055356398*O(9,1) - 0.5322256665703469*O(9,3) + 0.21608307321780204*O(9,5) - + 0.048317644050206957*O(9,7) + 0.00390625*O(9,9)); + Assert(lmax < 10); + +#if 0 + if (lmax < 10) return; + *c_out++ = (0.800447720175637*O(10,1) - 0.5437971423529642*O(10,3) + 0.24319347525427157*O(10,5) - + 0.06594508990677396*O(10,7) + 0.008734640537108554*O(10,9)); + *c_out++ = (-0.03515625*O(10,-9) + 0.20644078533943455*O(10,-7) - 0.5437971423529642*O(10,-5) + + 0.7295804257628147*O(10,-3) - 0.35797110294949086*O(10,-1)); + *c_out++ = (0.4645646483537033*O(10,1) + 0.3156095293238149*O(10,3) - 0.7057243619147634*O(10,5) + + 0.4210060495408587*O(10,7) - 0.09631896879639025*O(10,9)); + *c_out++ = (0.20644078533943455*O(10,-9) - 0.62890625*O(10,-7) + 0.5041938375082048*O(10,-5) + + 0.3543293897015177*O(10,-3) - 0.4267298778757763*O(10,-1)); + *c_out++ = (0.31049159295683837*O(10,1) + 0.5390625*O(10,3) - 0.017469281074217108*O(10,5) - + 0.6925528980529664*O(10,7) + 0.36479021288140734*O(10,9)); + *c_out++ = (-0.5437971423529642*O(10,-9) + 0.5041938375082048*O(10,-7) + 0.484375*O(10,-5) - + 0.034938562148434216*O(10,-3) - 0.46285353886245695*O(10,-1)); + *c_out++ = (0.19515618744994995*O(10,1) + 0.48613591206575135*O(10,3) + 0.4941058844013093*O(10,5) + + 0.09110862335695782*O(10,7) - 0.6878550219704731*O(10,9)); + *c_out++ = (0.7295804257628147*O(10,-9) + 0.3543293897015177*O(10,-7) - 0.034938562148434216*O(10,-5) - + 0.328125*O(10,-3) - 0.4829869223773042*O(10,-1)); + *c_out++ = (0.09472152853892297*O(10,1) + 0.2788526296496054*O(10,3) + 0.44538102542935076*O(10,5) + + 0.5748694230132831*O(10,7) + 0.6200241379499873*O(10,9)); + *c_out++ = (-0.35797110294949086*O(10,-9) - 0.4267298778757763*O(10,-7) - 0.46285353886245695*O(10,-5) - + 0.4829869223773042*O(10,-3) - 0.4921875*O(10,-1)); + *c_out++ = (-0.24609375*O(10,0) - 0.3512368283228746*O(10,2) - 0.3618292555284191*O(10,4) - + 0.3837778803237379*O(10,6) - 0.4306629552848579*O(10,8) - 0.5936279171365733*O(10,10)); + *c_out++ = (-0.800447720175637*O(10,-10) - 0.4645646483537033*O(10,-8) - 0.31049159295683837*O(10,-6) - + 0.19515618744994995*O(10,-4) - 0.09472152853892297*O(10,-2)); + *c_out++ = (-0.3512368283228746*O(10,0) - 0.46484375*O(10,2) - 0.36618880141431137*O(10,4) - + 0.18922142726223223*O(10,6) + 0.10058119679362292*O(10,8) + 0.6932080600734395*O(10,10)); + *c_out++ = (0.5437971423529642*O(10,-10) - 0.3156095293238149*O(10,-8) - 0.5390625*O(10,-6) - + 0.48613591206575135*O(10,-4) - 0.2788526296496054*O(10,-2)); + *c_out++ = (-0.3618292555284191*O(10,0) - 0.36618880141431137*O(10,2) + 0.015625*O(10,4) + + 0.4585145534256519*O(10,6) + 0.6137165055779013*O(10,8) - 0.38452264694764726*O(10,10)); + *c_out++ = (-0.24319347525427157*O(10,-10) + 0.7057243619147634*O(10,-8) + 0.017469281074217108*O(10,-6) - + 0.4941058844013093*O(10,-4) - 0.44538102542935076*O(10,-2)); + *c_out++ = (-0.3837778803237379*O(10,0) - 0.18922142726223223*O(10,2) + 0.4585145534256519*O(10,4) + + 0.462890625*O(10,6) - 0.6114934630648914*O(10,8) + 0.13594928558824104*O(10,10)); + *c_out++ = (0.06594508990677396*O(10,-10) - 0.4210060495408587*O(10,-8) + 0.6925528980529664*O(10,-6) - + 0.09110862335695782*O(10,-4) - 0.5748694230132831*O(10,-2)); + *c_out++ = (-0.4306629552848579*O(10,0) + 0.10058119679362292*O(10,2) + 0.6137165055779013*O(10,4) - + 0.6114934630648914*O(10,6) + 0.23046875*O(10,8) - 0.026921970218926214*O(10,10)); + *c_out++ = (-0.008734640537108554*O(10,-10) + 0.09631896879639025*O(10,-8) - 0.36479021288140734*O(10,-6) + + 0.6878550219704731*O(10,-4) - 0.6200241379499873*O(10,-2)); + *c_out++ = (-0.5936279171365733*O(10,0) + 0.6932080600734395*O(10,2) - 0.38452264694764726*O(10,4) + + 0.13594928558824104*O(10,6) - 0.026921970218926214*O(10,8) + 0.001953125*O(10,10)); +#endif +#undef O +} + + +#if 0 +void SHSwapYZ(const Spectrum *c_in, Spectrum *c_out, int lmax) { + for (int i = 0; i < SHTerms(lmax); ++i) + c_out[i] = 0.f; + c_out[SHIndex(0, 0)] += c_in[SHIndex(0, 0)] * 1.; + if (lmax == 0) return; + + c_out[SHIndex(1, -1)] += c_in[SHIndex(1, 0)] * -1.; + c_out[SHIndex(1, 0)] += c_in[SHIndex(1, -1)] * -1.; + c_out[SHIndex(1, 1)] += c_in[SHIndex(1, 1)] * 1.; + if (lmax == 1) return; + // Remainder of _SHSwapYZ()_ implementation + c_out[SHIndex(2, -2)] += c_in[SHIndex(2, 1)] * -1.; + c_out[SHIndex(2, -1)] += c_in[SHIndex(2, -1)] * 1.; + c_out[SHIndex(2, 0)] += c_in[SHIndex(2, 0)] * -0.5; + c_out[SHIndex(2, 0)] += c_in[SHIndex(2, 2)] * -0.86602540378444; + c_out[SHIndex(2, 1)] += c_in[SHIndex(2, -2)] * -1.; + c_out[SHIndex(2, 2)] += c_in[SHIndex(2, 0)] * -0.86602540378444; + c_out[SHIndex(2, 2)] += c_in[SHIndex(2, 2)] * 0.5; + if (lmax == 2) return; + + c_out[SHIndex(3, -3)] += c_in[SHIndex(3, 0)] * 0.79056941504209; + c_out[SHIndex(3, -3)] += c_in[SHIndex(3, 2)] * -0.61237243569579; + c_out[SHIndex(3, -2)] += c_in[SHIndex(3, -2)] * 1.; + c_out[SHIndex(3, -1)] += c_in[SHIndex(3, 0)] * 0.61237243569579; + c_out[SHIndex(3, -1)] += c_in[SHIndex(3, 2)] * 0.79056941504209; + c_out[SHIndex(3, 0)] += c_in[SHIndex(3, -3)] * 0.79056941504209; + c_out[SHIndex(3, 0)] += c_in[SHIndex(3, -1)] * 0.61237243569579; + c_out[SHIndex(3, 1)] += c_in[SHIndex(3, 1)] * -0.25; + c_out[SHIndex(3, 1)] += c_in[SHIndex(3, 3)] * -0.96824583655185; + c_out[SHIndex(3, 2)] += c_in[SHIndex(3, -3)] * -0.61237243569579; + c_out[SHIndex(3, 2)] += c_in[SHIndex(3, -1)] * 0.79056941504209; + c_out[SHIndex(3, 3)] += c_in[SHIndex(3, 1)] * -0.96824583655185; + c_out[SHIndex(3, 3)] += c_in[SHIndex(3, 3)] * 0.25; + if (lmax == 3) return; + + c_out[SHIndex(4, -4)] += c_in[SHIndex(4, 1)] * 0.93541434669349; + c_out[SHIndex(4, -4)] += c_in[SHIndex(4, 3)] * -0.35355339059327; + c_out[SHIndex(4, -3)] += c_in[SHIndex(4, -3)] * 0.75; + c_out[SHIndex(4, -3)] += c_in[SHIndex(4, -1)] * -0.66143782776615; + c_out[SHIndex(4, -2)] += c_in[SHIndex(4, 1)] * 0.35355339059327; + c_out[SHIndex(4, -2)] += c_in[SHIndex(4, 3)] * 0.93541434669349; + c_out[SHIndex(4, -1)] += c_in[SHIndex(4, -3)] * -0.66143782776615; + c_out[SHIndex(4, -1)] += c_in[SHIndex(4, -1)] * -0.75; + c_out[SHIndex(4, 0)] += c_in[SHIndex(4, 0)] * 0.375; + c_out[SHIndex(4, 0)] += c_in[SHIndex(4, 2)] * 0.55901699437495; + c_out[SHIndex(4, 0)] += c_in[SHIndex(4, 4)] * 0.73950997288745; + c_out[SHIndex(4, 1)] += c_in[SHIndex(4, -4)] * 0.93541434669349; + c_out[SHIndex(4, 1)] += c_in[SHIndex(4, -2)] * 0.35355339059327; + c_out[SHIndex(4, 2)] += c_in[SHIndex(4, 0)] * 0.55901699437495; + c_out[SHIndex(4, 2)] += c_in[SHIndex(4, 2)] * 0.5; + c_out[SHIndex(4, 2)] += c_in[SHIndex(4, 4)] * -0.66143782776615; + c_out[SHIndex(4, 3)] += c_in[SHIndex(4, -4)] * -0.35355339059327; + c_out[SHIndex(4, 3)] += c_in[SHIndex(4, -2)] * 0.93541434669349; + c_out[SHIndex(4, 4)] += c_in[SHIndex(4, 0)] * 0.73950997288745; + c_out[SHIndex(4, 4)] += c_in[SHIndex(4, 2)] * -0.66143782776615; + c_out[SHIndex(4, 4)] += c_in[SHIndex(4, 4)] * 0.125; + if (lmax == 4) return; + + + c_out[SHIndex(5, -5)] += c_in[SHIndex(5, 0)] * -0.70156076002011; + c_out[SHIndex(5, -5)] += c_in[SHIndex(5, 2)] * 0.68465319688146; + c_out[SHIndex(5, -5)] += c_in[SHIndex(5, 4)] * -0.19764235376052; + c_out[SHIndex(5, -4)] += c_in[SHIndex(5, -4)] * 0.5; + c_out[SHIndex(5, -4)] += c_in[SHIndex(5, -2)] * -0.86602540378444; + c_out[SHIndex(5, -3)] += c_in[SHIndex(5, 0)] * -0.5229125165838; + c_out[SHIndex(5, -3)] += c_in[SHIndex(5, 2)] * -0.3061862178479; + c_out[SHIndex(5, -3)] += c_in[SHIndex(5, 4)] * 0.79549512883487; + c_out[SHIndex(5, -2)] += c_in[SHIndex(5, -4)] * -0.86602540378444; + c_out[SHIndex(5, -2)] += c_in[SHIndex(5, -2)] * -0.5; + c_out[SHIndex(5, -1)] += c_in[SHIndex(5, 0)] * -0.48412291827593; + c_out[SHIndex(5, -1)] += c_in[SHIndex(5, 2)] * -0.66143782776615; + c_out[SHIndex(5, -1)] += c_in[SHIndex(5, 4)] * -0.57282196186948; + c_out[SHIndex(5, 0)] += c_in[SHIndex(5, -5)] * -0.70156076002011; + c_out[SHIndex(5, 0)] += c_in[SHIndex(5, -3)] * -0.5229125165838; + c_out[SHIndex(5, 0)] += c_in[SHIndex(5, -1)] * -0.48412291827593; + c_out[SHIndex(5, 1)] += c_in[SHIndex(5, 1)] * 0.125; + c_out[SHIndex(5, 1)] += c_in[SHIndex(5, 3)] * 0.40504629365049; + c_out[SHIndex(5, 1)] += c_in[SHIndex(5, 5)] * 0.90571104663684; + c_out[SHIndex(5, 2)] += c_in[SHIndex(5, -5)] * 0.68465319688146; + c_out[SHIndex(5, 2)] += c_in[SHIndex(5, -3)] * -0.3061862178479; + c_out[SHIndex(5, 2)] += c_in[SHIndex(5, -1)] * -0.66143782776615; + c_out[SHIndex(5, 3)] += c_in[SHIndex(5, 1)] * 0.40504629365049; + c_out[SHIndex(5, 3)] += c_in[SHIndex(5, 3)] * 0.8125; + c_out[SHIndex(5, 3)] += c_in[SHIndex(5, 5)] * -0.41926274578121; + c_out[SHIndex(5, 4)] += c_in[SHIndex(5, -5)] * -0.19764235376052; + c_out[SHIndex(5, 4)] += c_in[SHIndex(5, -3)] * 0.79549512883487; + c_out[SHIndex(5, 4)] += c_in[SHIndex(5, -1)] * -0.57282196186948; + c_out[SHIndex(5, 5)] += c_in[SHIndex(5, 1)] * 0.90571104663684; + c_out[SHIndex(5, 5)] += c_in[SHIndex(5, 3)] * -0.41926274578121; + c_out[SHIndex(5, 5)] += c_in[SHIndex(5, 5)] * 0.0625; + if (lmax == 5) return; + + + c_out[SHIndex(6, -6)] += c_in[SHIndex(6, 1)] * -0.87945295496689; + c_out[SHIndex(6, -6)] += c_in[SHIndex(6, 3)] * 0.46351240544348; + c_out[SHIndex(6, -6)] += c_in[SHIndex(6, 5)] * -0.10825317547305; + c_out[SHIndex(6, -5)] += c_in[SHIndex(6, -5)] * 0.3125; + c_out[SHIndex(6, -5)] += c_in[SHIndex(6, -3)] * -0.80282703616657; + c_out[SHIndex(6, -5)] += c_in[SHIndex(6, -1)] * 0.50775240028975; + c_out[SHIndex(6, -4)] += c_in[SHIndex(6, 1)] * -0.43301270189222; + c_out[SHIndex(6, -4)] += c_in[SHIndex(6, 3)] * -0.68465319688146; + c_out[SHIndex(6, -4)] += c_in[SHIndex(6, 5)] * 0.58630196997793; + c_out[SHIndex(6, -3)] += c_in[SHIndex(6, -5)] * -0.80282703616657; + c_out[SHIndex(6, -3)] += c_in[SHIndex(6, -3)] * 0.0625; + c_out[SHIndex(6, -3)] += c_in[SHIndex(6, -1)] * 0.59292706128157; + c_out[SHIndex(6, -2)] += c_in[SHIndex(6, 1)] * -0.19764235376052; + c_out[SHIndex(6, -2)] += c_in[SHIndex(6, 3)] * -0.5625; + c_out[SHIndex(6, -2)] += c_in[SHIndex(6, 5)] * -0.80282703616657; + c_out[SHIndex(6, -1)] += c_in[SHIndex(6, -5)] * 0.50775240028975; + c_out[SHIndex(6, -1)] += c_in[SHIndex(6, -3)] * 0.59292706128157; + c_out[SHIndex(6, -1)] += c_in[SHIndex(6, -1)] * 0.625; + c_out[SHIndex(6, 0)] += c_in[SHIndex(6, 0)] * -0.3125; + c_out[SHIndex(6, 0)] += c_in[SHIndex(6, 2)] * -0.45285552331842; + c_out[SHIndex(6, 0)] += c_in[SHIndex(6, 4)] * -0.49607837082461; + c_out[SHIndex(6, 0)] += c_in[SHIndex(6, 6)] * -0.6716932893814; + c_out[SHIndex(6, 1)] += c_in[SHIndex(6, -6)] * -0.87945295496689; + c_out[SHIndex(6, 1)] += c_in[SHIndex(6, -4)] * -0.43301270189222; + c_out[SHIndex(6, 1)] += c_in[SHIndex(6, -2)] * -0.19764235376052; + c_out[SHIndex(6, 2)] += c_in[SHIndex(6, 0)] * -0.45285552331842; + c_out[SHIndex(6, 2)] += c_in[SHIndex(6, 2)] * -0.53125; + c_out[SHIndex(6, 2)] += c_in[SHIndex(6, 4)] * -0.17116329922036; + c_out[SHIndex(6, 2)] += c_in[SHIndex(6, 6)] * 0.69526860816522; + c_out[SHIndex(6, 3)] += c_in[SHIndex(6, -6)] * 0.46351240544348; + c_out[SHIndex(6, 3)] += c_in[SHIndex(6, -4)] * -0.68465319688146; + c_out[SHIndex(6, 3)] += c_in[SHIndex(6, -2)] * -0.5625; + c_out[SHIndex(6, 4)] += c_in[SHIndex(6, 0)] * -0.49607837082461; + c_out[SHIndex(6, 4)] += c_in[SHIndex(6, 2)] * -0.17116329922036; + c_out[SHIndex(6, 4)] += c_in[SHIndex(6, 4)] * 0.8125; + c_out[SHIndex(6, 4)] += c_in[SHIndex(6, 6)] * -0.25387620014487; + c_out[SHIndex(6, 5)] += c_in[SHIndex(6, -6)] * -0.10825317547305; + c_out[SHIndex(6, 5)] += c_in[SHIndex(6, -4)] * 0.58630196997793; + c_out[SHIndex(6, 5)] += c_in[SHIndex(6, -2)] * -0.80282703616657; + c_out[SHIndex(6, 6)] += c_in[SHIndex(6, 0)] * -0.6716932893814; + c_out[SHIndex(6, 6)] += c_in[SHIndex(6, 2)] * 0.69526860816522; + c_out[SHIndex(6, 6)] += c_in[SHIndex(6, 4)] * -0.25387620014487; + c_out[SHIndex(6, 6)] += c_in[SHIndex(6, 6)] * 0.03125; + if (lmax == 6) return; + + + c_out[SHIndex(7, -7)] += c_in[SHIndex(7, 0)] * 0.64725984928775; + c_out[SHIndex(7, -7)] += c_in[SHIndex(7, 2)] * -0.69912054128741; + c_out[SHIndex(7, -7)] += c_in[SHIndex(7, 4)] * 0.2981060004428; + c_out[SHIndex(7, -7)] += c_in[SHIndex(7, 6)] * -0.058463396668343; + c_out[SHIndex(7, -6)] += c_in[SHIndex(7, -6)] * 0.1875; + c_out[SHIndex(7, -6)] += c_in[SHIndex(7, -4)] * -0.6373774391991; + c_out[SHIndex(7, -6)] += c_in[SHIndex(7, -2)] * 0.74739129644384; + c_out[SHIndex(7, -5)] += c_in[SHIndex(7, 0)] * 0.47495887979908; + c_out[SHIndex(7, -5)] += c_in[SHIndex(7, 2)] * 0.073287746247241; + c_out[SHIndex(7, -5)] += c_in[SHIndex(7, 4)] * -0.78125; + c_out[SHIndex(7, -5)] += c_in[SHIndex(7, 6)] * 0.39836089949944; + c_out[SHIndex(7, -4)] += c_in[SHIndex(7, -6)] * -0.6373774391991; + c_out[SHIndex(7, -4)] += c_in[SHIndex(7, -4)] * 0.5; + c_out[SHIndex(7, -4)] += c_in[SHIndex(7, -2)] * 0.58630196997793; + c_out[SHIndex(7, -3)] += c_in[SHIndex(7, 0)] * 0.42961647140211; + c_out[SHIndex(7, -3)] += c_in[SHIndex(7, 2)] * 0.41984465132951; + c_out[SHIndex(7, -3)] += c_in[SHIndex(7, 4)] * -0.10364452469861; + c_out[SHIndex(7, -3)] += c_in[SHIndex(7, 6)] * -0.79272818087286; + c_out[SHIndex(7, -2)] += c_in[SHIndex(7, -6)] * 0.74739129644384; + c_out[SHIndex(7, -2)] += c_in[SHIndex(7, -4)] * 0.58630196997793; + c_out[SHIndex(7, -2)] += c_in[SHIndex(7, -2)] * 0.3125; + c_out[SHIndex(7, -1)] += c_in[SHIndex(7, 0)] * 0.41339864235384; + c_out[SHIndex(7, -1)] += c_in[SHIndex(7, 2)] * 0.57409915846481; + c_out[SHIndex(7, -1)] += c_in[SHIndex(7, 4)] * 0.53855274811294; + c_out[SHIndex(7, -1)] += c_in[SHIndex(7, 6)] * 0.45768182862115; + c_out[SHIndex(7, 0)] += c_in[SHIndex(7, -7)] * 0.64725984928775; + c_out[SHIndex(7, 0)] += c_in[SHIndex(7, -5)] * 0.47495887979908; + c_out[SHIndex(7, 0)] += c_in[SHIndex(7, -3)] * 0.42961647140211; + c_out[SHIndex(7, 0)] += c_in[SHIndex(7, -1)] * 0.41339864235384; + c_out[SHIndex(7, 1)] += c_in[SHIndex(7, 1)] * -0.078125; + c_out[SHIndex(7, 1)] += c_in[SHIndex(7, 3)] * -0.24356964481437; + c_out[SHIndex(7, 1)] += c_in[SHIndex(7, 5)] * -0.44879395676078; + c_out[SHIndex(7, 1)] += c_in[SHIndex(7, 7)] * -0.85624429742627; + c_out[SHIndex(7, 2)] += c_in[SHIndex(7, -7)] * -0.69912054128741; + c_out[SHIndex(7, 2)] += c_in[SHIndex(7, -5)] * 0.073287746247241; + c_out[SHIndex(7, 2)] += c_in[SHIndex(7, -3)] * 0.41984465132951; + c_out[SHIndex(7, 2)] += c_in[SHIndex(7, -1)] * 0.57409915846481; + c_out[SHIndex(7, 3)] += c_in[SHIndex(7, 1)] * -0.24356964481437; + c_out[SHIndex(7, 3)] += c_in[SHIndex(7, 3)] * -0.609375; + c_out[SHIndex(7, 3)] += c_in[SHIndex(7, 5)] * -0.57004488584233; + c_out[SHIndex(7, 3)] += c_in[SHIndex(7, 7)] * 0.49435287561114; + c_out[SHIndex(7, 4)] += c_in[SHIndex(7, -7)] * 0.2981060004428; + c_out[SHIndex(7, 4)] += c_in[SHIndex(7, -5)] * -0.78125; + c_out[SHIndex(7, 4)] += c_in[SHIndex(7, -3)] * -0.10364452469861; + c_out[SHIndex(7, 4)] += c_in[SHIndex(7, -1)] * 0.53855274811294; + c_out[SHIndex(7, 5)] += c_in[SHIndex(7, 1)] * -0.44879395676078; + c_out[SHIndex(7, 5)] += c_in[SHIndex(7, 3)] * -0.57004488584233; + c_out[SHIndex(7, 5)] += c_in[SHIndex(7, 5)] * 0.671875; + c_out[SHIndex(7, 5)] += c_in[SHIndex(7, 7)] * -0.1490530002214; + c_out[SHIndex(7, 6)] += c_in[SHIndex(7, -7)] * -0.058463396668343; + c_out[SHIndex(7, 6)] += c_in[SHIndex(7, -5)] * 0.39836089949944; + c_out[SHIndex(7, 6)] += c_in[SHIndex(7, -3)] * -0.79272818087286; + c_out[SHIndex(7, 6)] += c_in[SHIndex(7, -1)] * 0.45768182862115; + c_out[SHIndex(7, 7)] += c_in[SHIndex(7, 1)] * -0.85624429742627; + c_out[SHIndex(7, 7)] += c_in[SHIndex(7, 3)] * 0.49435287561114; + c_out[SHIndex(7, 7)] += c_in[SHIndex(7, 5)] * -0.1490530002214; + c_out[SHIndex(7, 7)] += c_in[SHIndex(7, 7)] * 0.015625; + if (lmax == 7) return; + + + c_out[SHIndex(8, -8)] += c_in[SHIndex(8, 1)] * 0.83560887232006; + c_out[SHIndex(8, -8)] += c_in[SHIndex(8, 3)] * -0.51633473880807; + c_out[SHIndex(8, -8)] += c_in[SHIndex(8, 5)] * 0.18487749322186; + c_out[SHIndex(8, -8)] += c_in[SHIndex(8, 7)] * -0.03125; + c_out[SHIndex(8, -7)] += c_in[SHIndex(8, -7)] * 0.109375; + c_out[SHIndex(8, -7)] += c_in[SHIndex(8, -5)] * -0.46219373305466; + c_out[SHIndex(8, -7)] += c_in[SHIndex(8, -3)] * 0.77450210821211; + c_out[SHIndex(8, -7)] += c_in[SHIndex(8, -1)] * -0.41780443616003; + c_out[SHIndex(8, -6)] += c_in[SHIndex(8, 1)] * 0.45768182862115; + c_out[SHIndex(8, -6)] += c_in[SHIndex(8, 3)] * 0.4713469727812; + c_out[SHIndex(8, -6)] += c_in[SHIndex(8, 5)] * -0.70883101388836; + c_out[SHIndex(8, -6)] += c_in[SHIndex(8, 7)] * 0.25674494883055; + c_out[SHIndex(8, -5)] += c_in[SHIndex(8, -7)] * -0.46219373305466; + c_out[SHIndex(8, -5)] += c_in[SHIndex(8, -5)] * 0.703125; + c_out[SHIndex(8, -5)] += c_in[SHIndex(8, -3)] * 0.21819125068389; + c_out[SHIndex(8, -5)] += c_in[SHIndex(8, -1)] * -0.49435287561114; + c_out[SHIndex(8, -4)] += c_in[SHIndex(8, 1)] * 0.274217637106; + c_out[SHIndex(8, -4)] += c_in[SHIndex(8, 3)] * 0.60515364784491; + c_out[SHIndex(8, -4)] += c_in[SHIndex(8, 5)] * 0.33802043207475; + c_out[SHIndex(8, -4)] += c_in[SHIndex(8, 7)] * -0.66658528149067; + c_out[SHIndex(8, -3)] += c_in[SHIndex(8, -7)] * 0.77450210821211; + c_out[SHIndex(8, -3)] += c_in[SHIndex(8, -5)] * 0.21819125068389; + c_out[SHIndex(8, -3)] += c_in[SHIndex(8, -3)] * -0.265625; + c_out[SHIndex(8, -3)] += c_in[SHIndex(8, -1)] * -0.53102017087395; + c_out[SHIndex(8, -2)] += c_in[SHIndex(8, 1)] * 0.13072812914595; + c_out[SHIndex(8, -2)] += c_in[SHIndex(8, 3)] * 0.38081430021731; + c_out[SHIndex(8, -2)] += c_in[SHIndex(8, 5)] * 0.59086470003716; + c_out[SHIndex(8, -2)] += c_in[SHIndex(8, 7)] * 0.69912054128741; + c_out[SHIndex(8, -1)] += c_in[SHIndex(8, -7)] * -0.41780443616003; + c_out[SHIndex(8, -1)] += c_in[SHIndex(8, -5)] * -0.49435287561114; + c_out[SHIndex(8, -1)] += c_in[SHIndex(8, -3)] * -0.53102017087395; + c_out[SHIndex(8, -1)] += c_in[SHIndex(8, -1)] * -0.546875; + c_out[SHIndex(8, 0)] += c_in[SHIndex(8, 0)] * 0.2734375; + c_out[SHIndex(8, 0)] += c_in[SHIndex(8, 2)] * 0.39218438743785; + c_out[SHIndex(8, 0)] += c_in[SHIndex(8, 4)] * 0.41132645565901; + c_out[SHIndex(8, 0)] += c_in[SHIndex(8, 6)] * 0.45768182862115; + c_out[SHIndex(8, 0)] += c_in[SHIndex(8, 8)] * 0.62670665424004; + c_out[SHIndex(8, 1)] += c_in[SHIndex(8, -8)] * 0.83560887232006; + c_out[SHIndex(8, 1)] += c_in[SHIndex(8, -6)] * 0.45768182862115; + c_out[SHIndex(8, 1)] += c_in[SHIndex(8, -4)] * 0.274217637106; + c_out[SHIndex(8, 1)] += c_in[SHIndex(8, -2)] * 0.13072812914595; + c_out[SHIndex(8, 2)] += c_in[SHIndex(8, 0)] * 0.39218438743785; + c_out[SHIndex(8, 2)] += c_in[SHIndex(8, 2)] * 0.5; + c_out[SHIndex(8, 2)] += c_in[SHIndex(8, 4)] * 0.32775276505317; + c_out[SHIndex(8, 2)] += c_in[SHIndex(8, 8)] * -0.69912054128741; + c_out[SHIndex(8, 3)] += c_in[SHIndex(8, -8)] * -0.51633473880807; + c_out[SHIndex(8, 3)] += c_in[SHIndex(8, -6)] * 0.4713469727812; + c_out[SHIndex(8, 3)] += c_in[SHIndex(8, -4)] * 0.60515364784491; + c_out[SHIndex(8, 3)] += c_in[SHIndex(8, -2)] * 0.38081430021731; + c_out[SHIndex(8, 4)] += c_in[SHIndex(8, 0)] * 0.41132645565901; + c_out[SHIndex(8, 4)] += c_in[SHIndex(8, 2)] * 0.32775276505317; + c_out[SHIndex(8, 4)] += c_in[SHIndex(8, 4)] * -0.28125; + c_out[SHIndex(8, 4)] += c_in[SHIndex(8, 6)] * -0.73020759034675; + c_out[SHIndex(8, 4)] += c_in[SHIndex(8, 8)] * 0.33329264074534; + c_out[SHIndex(8, 5)] += c_in[SHIndex(8, -8)] * 0.18487749322186; + c_out[SHIndex(8, 5)] += c_in[SHIndex(8, -6)] * -0.70883101388836; + c_out[SHIndex(8, 5)] += c_in[SHIndex(8, -4)] * 0.33802043207475; + c_out[SHIndex(8, 5)] += c_in[SHIndex(8, -2)] * 0.59086470003716; + c_out[SHIndex(8, 6)] += c_in[SHIndex(8, 0)] * 0.45768182862115; + c_out[SHIndex(8, 6)] += c_in[SHIndex(8, 4)] * -0.73020759034675; + c_out[SHIndex(8, 6)] += c_in[SHIndex(8, 6)] * 0.5; + c_out[SHIndex(8, 6)] += c_in[SHIndex(8, 8)] * -0.085581649610182; + c_out[SHIndex(8, 7)] += c_in[SHIndex(8, -8)] * -0.03125; + c_out[SHIndex(8, 7)] += c_in[SHIndex(8, -6)] * 0.25674494883055; + c_out[SHIndex(8, 7)] += c_in[SHIndex(8, -4)] * -0.66658528149067; + c_out[SHIndex(8, 7)] += c_in[SHIndex(8, -2)] * 0.69912054128741; + c_out[SHIndex(8, 8)] += c_in[SHIndex(8, 0)] * 0.62670665424004; + c_out[SHIndex(8, 8)] += c_in[SHIndex(8, 2)] * -0.69912054128741; + c_out[SHIndex(8, 8)] += c_in[SHIndex(8, 4)] * 0.33329264074534; + c_out[SHIndex(8, 8)] += c_in[SHIndex(8, 6)] * -0.085581649610182; + c_out[SHIndex(8, 8)] += c_in[SHIndex(8, 8)] * 0.0078125; + if (lmax == 8) return; + + + c_out[SHIndex(9, -9)] += c_in[SHIndex(9, 0)] * -0.60904939217552; + c_out[SHIndex(9, -9)] += c_in[SHIndex(9, 2)] * 0.69684697253055; + c_out[SHIndex(9, -9)] += c_in[SHIndex(9, 4)] * -0.36157613954394; + c_out[SHIndex(9, -9)] += c_in[SHIndex(9, 6)] * 0.11158481919598; + c_out[SHIndex(9, -9)] += c_in[SHIndex(9, 8)] * -0.01657281518406; + c_out[SHIndex(9, -8)] += c_in[SHIndex(9, -8)] * 0.0625; + c_out[SHIndex(9, -8)] += c_in[SHIndex(9, -6)] * -0.31560952932381; + c_out[SHIndex(9, -8)] += c_in[SHIndex(9, -4)] * 0.68179450716473; + c_out[SHIndex(9, -8)] += c_in[SHIndex(9, -2)] * -0.65699362630089; + c_out[SHIndex(9, -7)] += c_in[SHIndex(9, 0)] * -0.44314852502787; + c_out[SHIndex(9, -7)] += c_in[SHIndex(9, 2)] * 0.056336738679125; + c_out[SHIndex(9, -7)] += c_in[SHIndex(9, 4)] * 0.67232906168594; + c_out[SHIndex(9, -7)] += c_in[SHIndex(9, 6)] * -0.56832917123354; + c_out[SHIndex(9, -7)] += c_in[SHIndex(9, 8)] * 0.15944009087468; + c_out[SHIndex(9, -6)] += c_in[SHIndex(9, -8)] * -0.31560952932381; + c_out[SHIndex(9, -6)] += c_in[SHIndex(9, -6)] * 0.71875; + c_out[SHIndex(9, -6)] += c_in[SHIndex(9, -4)] * -0.20252314682525; + c_out[SHIndex(9, -6)] += c_in[SHIndex(9, -2)] * -0.58546856234985; + c_out[SHIndex(9, -5)] += c_in[SHIndex(9, 0)] * -0.39636409043643; + c_out[SHIndex(9, -5)] += c_in[SHIndex(9, 2)] * -0.25194555463433; + c_out[SHIndex(9, -5)] += c_in[SHIndex(9, 4)] * 0.39218438743785; + c_out[SHIndex(9, -5)] += c_in[SHIndex(9, 6)] * 0.60515364784491; + c_out[SHIndex(9, -5)] += c_in[SHIndex(9, 8)] * -0.50931268790646; + c_out[SHIndex(9, -4)] += c_in[SHIndex(9, -8)] * 0.68179450716473; + c_out[SHIndex(9, -4)] += c_in[SHIndex(9, -6)] * -0.20252314682525; + c_out[SHIndex(9, -4)] += c_in[SHIndex(9, -4)] * -0.5625; + c_out[SHIndex(9, -4)] += c_in[SHIndex(9, -2)] * -0.421585548851; + c_out[SHIndex(9, -3)] += c_in[SHIndex(9, 0)] * -0.37548796377181; + c_out[SHIndex(9, -3)] += c_in[SHIndex(9, 2)] * -0.42961647140211; + c_out[SHIndex(9, -3)] += c_in[SHIndex(9, 4)] * -0.13799626353637; + c_out[SHIndex(9, -3)] += c_in[SHIndex(9, 6)] * 0.2981060004428; + c_out[SHIndex(9, -3)] += c_in[SHIndex(9, 8)] * 0.75268075590685; + c_out[SHIndex(9, -2)] += c_in[SHIndex(9, -8)] * -0.65699362630089; + c_out[SHIndex(9, -2)] += c_in[SHIndex(9, -6)] * -0.58546856234985; + c_out[SHIndex(9, -2)] += c_in[SHIndex(9, -4)] * -0.421585548851; + c_out[SHIndex(9, -2)] += c_in[SHIndex(9, -2)] * -0.21875; + c_out[SHIndex(9, -1)] += c_in[SHIndex(9, 0)] * -0.36685490255856; + c_out[SHIndex(9, -1)] += c_in[SHIndex(9, 2)] * -0.51301422373069; + c_out[SHIndex(9, -1)] += c_in[SHIndex(9, 4)] * -0.49435287561114; + c_out[SHIndex(9, -1)] += c_in[SHIndex(9, 6)] * -0.45768182862115; + c_out[SHIndex(9, -1)] += c_in[SHIndex(9, 8)] * -0.38519665736316; + c_out[SHIndex(9, 0)] += c_in[SHIndex(9, -9)] * -0.60904939217552; + c_out[SHIndex(9, 0)] += c_in[SHIndex(9, -7)] * -0.44314852502787; + c_out[SHIndex(9, 0)] += c_in[SHIndex(9, -5)] * -0.39636409043643; + c_out[SHIndex(9, 0)] += c_in[SHIndex(9, -3)] * -0.37548796377181; + c_out[SHIndex(9, 0)] += c_in[SHIndex(9, -1)] * -0.36685490255856; + c_out[SHIndex(9, 1)] += c_in[SHIndex(9, 1)] * 0.0546875; + c_out[SHIndex(9, 1)] += c_in[SHIndex(9, 3)] * 0.16792332234535; + c_out[SHIndex(9, 1)] += c_in[SHIndex(9, 5)] * 0.29543235001858; + c_out[SHIndex(9, 1)] += c_in[SHIndex(9, 7)] * 0.46242477217584; + c_out[SHIndex(9, 1)] += c_in[SHIndex(9, 9)] * 0.81712550553564; + c_out[SHIndex(9, 2)] += c_in[SHIndex(9, -9)] * 0.69684697253055; + c_out[SHIndex(9, 2)] += c_in[SHIndex(9, -7)] * 0.056336738679125; + c_out[SHIndex(9, 2)] += c_in[SHIndex(9, -5)] * -0.25194555463433; + c_out[SHIndex(9, 2)] += c_in[SHIndex(9, -3)] * -0.42961647140211; + c_out[SHIndex(9, 2)] += c_in[SHIndex(9, -1)] * -0.51301422373069; + c_out[SHIndex(9, 3)] += c_in[SHIndex(9, 1)] * 0.16792332234535; + c_out[SHIndex(9, 3)] += c_in[SHIndex(9, 3)] * 0.453125; + c_out[SHIndex(9, 3)] += c_in[SHIndex(9, 5)] * 0.57727978755972; + c_out[SHIndex(9, 3)] += c_in[SHIndex(9, 7)] * 0.38725105410605; + c_out[SHIndex(9, 3)] += c_in[SHIndex(9, 9)] * -0.53222566657035; + c_out[SHIndex(9, 4)] += c_in[SHIndex(9, -9)] * -0.36157613954394; + c_out[SHIndex(9, 4)] += c_in[SHIndex(9, -7)] * 0.67232906168594; + c_out[SHIndex(9, 4)] += c_in[SHIndex(9, -5)] * 0.39218438743785; + c_out[SHIndex(9, 4)] += c_in[SHIndex(9, -3)] * -0.13799626353637; + c_out[SHIndex(9, 4)] += c_in[SHIndex(9, -1)] * -0.49435287561114; + c_out[SHIndex(9, 5)] += c_in[SHIndex(9, 1)] * 0.29543235001858; + c_out[SHIndex(9, 5)] += c_in[SHIndex(9, 3)] * 0.57727978755972; + c_out[SHIndex(9, 5)] += c_in[SHIndex(9, 5)] * 0.140625; + c_out[SHIndex(9, 5)] += c_in[SHIndex(9, 7)] * -0.7162405240429; + c_out[SHIndex(9, 5)] += c_in[SHIndex(9, 9)] * 0.2160830732178; + c_out[SHIndex(9, 6)] += c_in[SHIndex(9, -9)] * 0.11158481919598; + c_out[SHIndex(9, 6)] += c_in[SHIndex(9, -7)] * -0.56832917123354; + c_out[SHIndex(9, 6)] += c_in[SHIndex(9, -5)] * 0.60515364784491; + c_out[SHIndex(9, 6)] += c_in[SHIndex(9, -3)] * 0.2981060004428; + c_out[SHIndex(9, 6)] += c_in[SHIndex(9, -1)] * -0.45768182862115; + c_out[SHIndex(9, 7)] += c_in[SHIndex(9, 1)] * 0.46242477217584; + c_out[SHIndex(9, 7)] += c_in[SHIndex(9, 3)] * 0.38725105410605; + c_out[SHIndex(9, 7)] += c_in[SHIndex(9, 5)] * -0.7162405240429; + c_out[SHIndex(9, 7)] += c_in[SHIndex(9, 7)] * 0.34765625; + c_out[SHIndex(9, 7)] += c_in[SHIndex(9, 9)] * -0.048317644050207; + c_out[SHIndex(9, 8)] += c_in[SHIndex(9, -9)] * -0.01657281518406; + c_out[SHIndex(9, 8)] += c_in[SHIndex(9, -7)] * 0.15944009087468; + c_out[SHIndex(9, 8)] += c_in[SHIndex(9, -5)] * -0.50931268790646; + c_out[SHIndex(9, 8)] += c_in[SHIndex(9, -3)] * 0.75268075590685; + c_out[SHIndex(9, 8)] += c_in[SHIndex(9, -1)] * -0.38519665736316; + c_out[SHIndex(9, 9)] += c_in[SHIndex(9, 1)] * 0.81712550553564; + c_out[SHIndex(9, 9)] += c_in[SHIndex(9, 3)] * -0.53222566657035; + c_out[SHIndex(9, 9)] += c_in[SHIndex(9, 5)] * 0.2160830732178; + c_out[SHIndex(9, 9)] += c_in[SHIndex(9, 7)] * -0.048317644050207; + c_out[SHIndex(9, 9)] += c_in[SHIndex(9, 9)] * 0.00390625; + if (lmax == 9) return; + + + c_out[SHIndex(10, -10)] += c_in[SHIndex(10, 1)] * -0.80044772017564; + c_out[SHIndex(10, -10)] += c_in[SHIndex(10, 3)] * 0.54379714235296; + c_out[SHIndex(10, -10)] += c_in[SHIndex(10, 5)] * -0.24319347525427; + c_out[SHIndex(10, -10)] += c_in[SHIndex(10, 7)] * 0.065945089906774; + c_out[SHIndex(10, -10)] += c_in[SHIndex(10, 9)] * -0.0087346405371086; + c_out[SHIndex(10, -9)] += c_in[SHIndex(10, -9)] * 0.03515625; + c_out[SHIndex(10, -9)] += c_in[SHIndex(10, -7)] * -0.20644078533943; + c_out[SHIndex(10, -9)] += c_in[SHIndex(10, -5)] * 0.54379714235296; + c_out[SHIndex(10, -9)] += c_in[SHIndex(10, -3)] * -0.72958042576281; + c_out[SHIndex(10, -9)] += c_in[SHIndex(10, -1)] * 0.35797110294949; + c_out[SHIndex(10, -8)] += c_in[SHIndex(10, 1)] * -0.4645646483537; + c_out[SHIndex(10, -8)] += c_in[SHIndex(10, 3)] * -0.31560952932381; + c_out[SHIndex(10, -8)] += c_in[SHIndex(10, 5)] * 0.70572436191476; + c_out[SHIndex(10, -8)] += c_in[SHIndex(10, 7)] * -0.42100604954086; + c_out[SHIndex(10, -8)] += c_in[SHIndex(10, 9)] * 0.09631896879639; + c_out[SHIndex(10, -7)] += c_in[SHIndex(10, -9)] * -0.20644078533943; + c_out[SHIndex(10, -7)] += c_in[SHIndex(10, -7)] * 0.62890625; + c_out[SHIndex(10, -7)] += c_in[SHIndex(10, -5)] * -0.5041938375082; + c_out[SHIndex(10, -7)] += c_in[SHIndex(10, -3)] * -0.35432938970152; + c_out[SHIndex(10, -7)] += c_in[SHIndex(10, -1)] * 0.42672987787578; + c_out[SHIndex(10, -6)] += c_in[SHIndex(10, 1)] * -0.31049159295684; + c_out[SHIndex(10, -6)] += c_in[SHIndex(10, 3)] * -0.5390625; + c_out[SHIndex(10, -6)] += c_in[SHIndex(10, 5)] * 0.017469281074217; + c_out[SHIndex(10, -6)] += c_in[SHIndex(10, 7)] * 0.69255289805297; + c_out[SHIndex(10, -6)] += c_in[SHIndex(10, 9)] * -0.36479021288141; + c_out[SHIndex(10, -5)] += c_in[SHIndex(10, -9)] * 0.54379714235296; + c_out[SHIndex(10, -5)] += c_in[SHIndex(10, -7)] * -0.5041938375082; + c_out[SHIndex(10, -5)] += c_in[SHIndex(10, -5)] * -0.484375; + c_out[SHIndex(10, -5)] += c_in[SHIndex(10, -3)] * 0.034938562148434; + c_out[SHIndex(10, -5)] += c_in[SHIndex(10, -1)] * 0.46285353886246; + c_out[SHIndex(10, -4)] += c_in[SHIndex(10, 1)] * -0.19515618744995; + c_out[SHIndex(10, -4)] += c_in[SHIndex(10, 3)] * -0.48613591206575; + c_out[SHIndex(10, -4)] += c_in[SHIndex(10, 5)] * -0.49410588440131; + c_out[SHIndex(10, -4)] += c_in[SHIndex(10, 7)] * -0.091108623356958; + c_out[SHIndex(10, -4)] += c_in[SHIndex(10, 9)] * 0.68785502197047; + c_out[SHIndex(10, -3)] += c_in[SHIndex(10, -9)] * -0.72958042576281; + c_out[SHIndex(10, -3)] += c_in[SHIndex(10, -7)] * -0.35432938970152; + c_out[SHIndex(10, -3)] += c_in[SHIndex(10, -5)] * 0.034938562148434; + c_out[SHIndex(10, -3)] += c_in[SHIndex(10, -3)] * 0.328125; + c_out[SHIndex(10, -3)] += c_in[SHIndex(10, -1)] * 0.4829869223773; + c_out[SHIndex(10, -2)] += c_in[SHIndex(10, 1)] * -0.094721528538923; + c_out[SHIndex(10, -2)] += c_in[SHIndex(10, 3)] * -0.27885262964961; + c_out[SHIndex(10, -2)] += c_in[SHIndex(10, 5)] * -0.44538102542935; + c_out[SHIndex(10, -2)] += c_in[SHIndex(10, 7)] * -0.57486942301328; + c_out[SHIndex(10, -2)] += c_in[SHIndex(10, 9)] * -0.62002413794999; + c_out[SHIndex(10, -1)] += c_in[SHIndex(10, -9)] * 0.35797110294949; + c_out[SHIndex(10, -1)] += c_in[SHIndex(10, -7)] * 0.42672987787578; + c_out[SHIndex(10, -1)] += c_in[SHIndex(10, -5)] * 0.46285353886246; + c_out[SHIndex(10, -1)] += c_in[SHIndex(10, -3)] * 0.4829869223773; + c_out[SHIndex(10, -1)] += c_in[SHIndex(10, -1)] * 0.4921875; + c_out[SHIndex(10, 0)] += c_in[SHIndex(10, 0)] * -0.24609375; + c_out[SHIndex(10, 0)] += c_in[SHIndex(10, 2)] * -0.35123682832287; + c_out[SHIndex(10, 0)] += c_in[SHIndex(10, 4)] * -0.36182925552842; + c_out[SHIndex(10, 0)] += c_in[SHIndex(10, 6)] * -0.38377788032374; + c_out[SHIndex(10, 0)] += c_in[SHIndex(10, 8)] * -0.43066295528486; + c_out[SHIndex(10, 0)] += c_in[SHIndex(10, 10)] * -0.59362791713657; + c_out[SHIndex(10, 1)] += c_in[SHIndex(10, -10)] * -0.80044772017564; + c_out[SHIndex(10, 1)] += c_in[SHIndex(10, -8)] * -0.4645646483537; + c_out[SHIndex(10, 1)] += c_in[SHIndex(10, -6)] * -0.31049159295684; + c_out[SHIndex(10, 1)] += c_in[SHIndex(10, -4)] * -0.19515618744995; + c_out[SHIndex(10, 1)] += c_in[SHIndex(10, -2)] * -0.094721528538923; + c_out[SHIndex(10, 2)] += c_in[SHIndex(10, 0)] * -0.35123682832287; + c_out[SHIndex(10, 2)] += c_in[SHIndex(10, 2)] * -0.46484375; + c_out[SHIndex(10, 2)] += c_in[SHIndex(10, 4)] * -0.36618880141431; + c_out[SHIndex(10, 2)] += c_in[SHIndex(10, 6)] * -0.18922142726223; + c_out[SHIndex(10, 2)] += c_in[SHIndex(10, 8)] * 0.10058119679362; + c_out[SHIndex(10, 2)] += c_in[SHIndex(10, 10)] * 0.69320806007344; + c_out[SHIndex(10, 3)] += c_in[SHIndex(10, -10)] * 0.54379714235296; + c_out[SHIndex(10, 3)] += c_in[SHIndex(10, -8)] * -0.31560952932381; + c_out[SHIndex(10, 3)] += c_in[SHIndex(10, -6)] * -0.5390625; + c_out[SHIndex(10, 3)] += c_in[SHIndex(10, -4)] * -0.48613591206575; + c_out[SHIndex(10, 3)] += c_in[SHIndex(10, -2)] * -0.27885262964961; + c_out[SHIndex(10, 4)] += c_in[SHIndex(10, 0)] * -0.36182925552842; + c_out[SHIndex(10, 4)] += c_in[SHIndex(10, 2)] * -0.36618880141431; + c_out[SHIndex(10, 4)] += c_in[SHIndex(10, 4)] * 0.015625; + c_out[SHIndex(10, 4)] += c_in[SHIndex(10, 6)] * 0.45851455342565; + c_out[SHIndex(10, 4)] += c_in[SHIndex(10, 8)] * 0.6137165055779; + c_out[SHIndex(10, 4)] += c_in[SHIndex(10, 10)] * -0.38452264694765; + c_out[SHIndex(10, 5)] += c_in[SHIndex(10, -10)] * -0.24319347525427; + c_out[SHIndex(10, 5)] += c_in[SHIndex(10, -8)] * 0.70572436191476; + c_out[SHIndex(10, 5)] += c_in[SHIndex(10, -6)] * 0.017469281074217; + c_out[SHIndex(10, 5)] += c_in[SHIndex(10, -4)] * -0.49410588440131; + c_out[SHIndex(10, 5)] += c_in[SHIndex(10, -2)] * -0.44538102542935; + c_out[SHIndex(10, 6)] += c_in[SHIndex(10, 0)] * -0.38377788032374; + c_out[SHIndex(10, 6)] += c_in[SHIndex(10, 2)] * -0.18922142726223; + c_out[SHIndex(10, 6)] += c_in[SHIndex(10, 4)] * 0.45851455342565; + c_out[SHIndex(10, 6)] += c_in[SHIndex(10, 6)] * 0.462890625; + c_out[SHIndex(10, 6)] += c_in[SHIndex(10, 8)] * -0.61149346306489; + c_out[SHIndex(10, 6)] += c_in[SHIndex(10, 10)] * 0.13594928558824; + c_out[SHIndex(10, 7)] += c_in[SHIndex(10, -10)] * 0.065945089906774; + c_out[SHIndex(10, 7)] += c_in[SHIndex(10, -8)] * -0.42100604954086; + c_out[SHIndex(10, 7)] += c_in[SHIndex(10, -6)] * 0.69255289805297; + c_out[SHIndex(10, 7)] += c_in[SHIndex(10, -4)] * -0.091108623356958; + c_out[SHIndex(10, 7)] += c_in[SHIndex(10, -2)] * -0.57486942301328; + c_out[SHIndex(10, 8)] += c_in[SHIndex(10, 0)] * -0.43066295528486; + c_out[SHIndex(10, 8)] += c_in[SHIndex(10, 2)] * 0.10058119679362; + c_out[SHIndex(10, 8)] += c_in[SHIndex(10, 4)] * 0.6137165055779; + c_out[SHIndex(10, 8)] += c_in[SHIndex(10, 6)] * -0.61149346306489; + c_out[SHIndex(10, 8)] += c_in[SHIndex(10, 8)] * 0.23046875; + c_out[SHIndex(10, 8)] += c_in[SHIndex(10, 10)] * -0.026921970218926; + c_out[SHIndex(10, 9)] += c_in[SHIndex(10, -10)] * -0.0087346405371086; + c_out[SHIndex(10, 9)] += c_in[SHIndex(10, -8)] * 0.09631896879639; + c_out[SHIndex(10, 9)] += c_in[SHIndex(10, -6)] * -0.36479021288141; + c_out[SHIndex(10, 9)] += c_in[SHIndex(10, -4)] * 0.68785502197047; + c_out[SHIndex(10, 9)] += c_in[SHIndex(10, -2)] * -0.62002413794999; + c_out[SHIndex(10, 10)] += c_in[SHIndex(10, 0)] * -0.59362791713657; + c_out[SHIndex(10, 10)] += c_in[SHIndex(10, 2)] * 0.69320806007344; + c_out[SHIndex(10, 10)] += c_in[SHIndex(10, 4)] * -0.38452264694765; + c_out[SHIndex(10, 10)] += c_in[SHIndex(10, 6)] * 0.13594928558824; + c_out[SHIndex(10, 10)] += c_in[SHIndex(10, 8)] * -0.026921970218926; + c_out[SHIndex(10, 10)] += c_in[SHIndex(10, 10)] * 0.001953125; + if (lmax == 10) return; + + + c_out[SHIndex(11, -11)] += c_in[SHIndex(11, 0)] * 0.57997947393468; + c_out[SHIndex(11, -11)] += c_in[SHIndex(11, 2)] * -0.68875008418642; + c_out[SHIndex(11, -11)] += c_in[SHIndex(11, 4)] * 0.4032907544405; + c_out[SHIndex(11, -11)] += c_in[SHIndex(11, 6)] * -0.158474160191; + c_out[SHIndex(11, -11)] += c_in[SHIndex(11, 8)] * 0.0383230798249; + c_out[SHIndex(11, -11)] += c_in[SHIndex(11, 10)] * -0.0045804841404526; + c_out[SHIndex(11, -10)] += c_in[SHIndex(11, -10)] * 0.01953125; + c_out[SHIndex(11, -10)] += c_in[SHIndex(11, -8)] * -0.13072812914595; + c_out[SHIndex(11, -10)] += c_in[SHIndex(11, -6)] * 0.4054416537189; + c_out[SHIndex(11, -10)] += c_in[SHIndex(11, -4)] * -0.68785502197047; + c_out[SHIndex(11, -10)] += c_in[SHIndex(11, -2)] * 0.58736804535412; + c_out[SHIndex(11, -9)] += c_in[SHIndex(11, 0)] * 0.41975832570892; + c_out[SHIndex(11, -9)] += c_in[SHIndex(11, 2)] * -0.13594928558824; + c_out[SHIndex(11, -9)] += c_in[SHIndex(11, 4)] * -0.55722625443603; + c_out[SHIndex(11, -9)] += c_in[SHIndex(11, 6)] * 0.63603688806046; + c_out[SHIndex(11, -9)] += c_in[SHIndex(11, 8)] * -0.29501240332439; + c_out[SHIndex(11, -9)] += c_in[SHIndex(11, 10)] * 0.0569596350446; + c_out[SHIndex(11, -8)] += c_in[SHIndex(11, -10)] * -0.13072812914595; + c_out[SHIndex(11, -8)] += c_in[SHIndex(11, -8)] * 0.5; + c_out[SHIndex(11, -8)] += c_in[SHIndex(11, -6)] * -0.64612728525423; + c_out[SHIndex(11, -8)] += c_in[SHIndex(11, -2)] * 0.56163127361286; + c_out[SHIndex(11, -7)] += c_in[SHIndex(11, 0)] * 0.37296505974557; + c_out[SHIndex(11, -7)] += c_in[SHIndex(11, 2)] * 0.13689999147559; + c_out[SHIndex(11, -7)] += c_in[SHIndex(11, 4)] * -0.49510851970963; + c_out[SHIndex(11, -7)] += c_in[SHIndex(11, 6)] * -0.32425698663836; + c_out[SHIndex(11, -7)] += c_in[SHIndex(11, 8)] * 0.65553753643092; + c_out[SHIndex(11, -7)] += c_in[SHIndex(11, 10)] * -0.24930093301108; + c_out[SHIndex(11, -6)] += c_in[SHIndex(11, -10)] * 0.4054416537189; + c_out[SHIndex(11, -6)] += c_in[SHIndex(11, -8)] * -0.64612728525423; + c_out[SHIndex(11, -6)] += c_in[SHIndex(11, -6)] * -0.18359375; + c_out[SHIndex(11, -6)] += c_in[SHIndex(11, -4)] * 0.41751216299648; + c_out[SHIndex(11, -6)] += c_in[SHIndex(11, -2)] * 0.45838141911581; + c_out[SHIndex(11, -5)] += c_in[SHIndex(11, 0)] * 0.35033967020805; + c_out[SHIndex(11, -5)] += c_in[SHIndex(11, 2)] * 0.31014124452052; + c_out[SHIndex(11, -5)] += c_in[SHIndex(11, 4)] * -0.134354558765; + c_out[SHIndex(11, -5)] += c_in[SHIndex(11, 6)] * -0.52272828294257; + c_out[SHIndex(11, -5)] += c_in[SHIndex(11, 8)] * -0.40784785676472; + c_out[SHIndex(11, -5)] += c_in[SHIndex(11, 10)] * 0.56871666443773; + c_out[SHIndex(11, -4)] += c_in[SHIndex(11, -10)] * -0.68785502197047; + c_out[SHIndex(11, -4)] += c_in[SHIndex(11, -6)] * 0.41751216299648; + c_out[SHIndex(11, -4)] += c_in[SHIndex(11, -4)] * 0.5; + c_out[SHIndex(11, -4)] += c_in[SHIndex(11, -2)] * 0.32021721143624; + c_out[SHIndex(11, -3)] += c_in[SHIndex(11, 0)] * 0.33846027667471; + c_out[SHIndex(11, -3)] += c_in[SHIndex(11, 2)] * 0.41655170126194; + c_out[SHIndex(11, -3)] += c_in[SHIndex(11, 4)] * 0.235349536428; + c_out[SHIndex(11, -3)] += c_in[SHIndex(11, 6)] * -0.047641839522072; + c_out[SHIndex(11, -3)] += c_in[SHIndex(11, 8)] * -0.3940184631669; + c_out[SHIndex(11, -3)] += c_in[SHIndex(11, 10)] * -0.70641320967457; + c_out[SHIndex(11, -2)] += c_in[SHIndex(11, -10)] * 0.58736804535412; + c_out[SHIndex(11, -2)] += c_in[SHIndex(11, -8)] * 0.56163127361286; + c_out[SHIndex(11, -2)] += c_in[SHIndex(11, -6)] * 0.45838141911581; + c_out[SHIndex(11, -2)] += c_in[SHIndex(11, -4)] * 0.32021721143624; + c_out[SHIndex(11, -2)] += c_in[SHIndex(11, -2)] * 0.1640625; + c_out[SHIndex(11, -1)] += c_in[SHIndex(11, 0)] * 0.33321251269015; + c_out[SHIndex(11, -1)] += c_in[SHIndex(11, 2)] * 0.46765007670082; + c_out[SHIndex(11, -1)] += c_in[SHIndex(11, 4)] * 0.45637974396672; + c_out[SHIndex(11, -1)] += c_in[SHIndex(11, 6)] * 0.4355293578316; + c_out[SHIndex(11, -1)] += c_in[SHIndex(11, 8)] * 0.40022386008782; + c_out[SHIndex(11, -1)] += c_in[SHIndex(11, 10)] * 0.33485130540064; + c_out[SHIndex(11, 0)] += c_in[SHIndex(11, -11)] * 0.57997947393468; + c_out[SHIndex(11, 0)] += c_in[SHIndex(11, -9)] * 0.41975832570892; + c_out[SHIndex(11, 0)] += c_in[SHIndex(11, -7)] * 0.37296505974557; + c_out[SHIndex(11, 0)] += c_in[SHIndex(11, -5)] * 0.35033967020805; + c_out[SHIndex(11, 0)] += c_in[SHIndex(11, -3)] * 0.33846027667471; + c_out[SHIndex(11, 0)] += c_in[SHIndex(11, -1)] * 0.33321251269015; + c_out[SHIndex(11, 1)] += c_in[SHIndex(11, 1)] * -0.041015625; + c_out[SHIndex(11, 1)] += c_in[SHIndex(11, 3)] * -0.1249847402795; + c_out[SHIndex(11, 1)] += c_in[SHIndex(11, 5)] * -0.21561916177558; + c_out[SHIndex(11, 1)] += c_in[SHIndex(11, 7)] * -0.32136177701095; + c_out[SHIndex(11, 1)] += c_in[SHIndex(11, 9)] * -0.46501810346249; + c_out[SHIndex(11, 1)] += c_in[SHIndex(11, 11)] * -0.78529592002432; + c_out[SHIndex(11, 2)] += c_in[SHIndex(11, -11)] * -0.68875008418642; + c_out[SHIndex(11, 2)] += c_in[SHIndex(11, -9)] * -0.13594928558824; + c_out[SHIndex(11, 2)] += c_in[SHIndex(11, -7)] * 0.13689999147559; + c_out[SHIndex(11, 2)] += c_in[SHIndex(11, -5)] * 0.31014124452052; + c_out[SHIndex(11, 2)] += c_in[SHIndex(11, -3)] * 0.41655170126194; + c_out[SHIndex(11, 2)] += c_in[SHIndex(11, -1)] * 0.46765007670082; + c_out[SHIndex(11, 3)] += c_in[SHIndex(11, 1)] * -0.1249847402795; + c_out[SHIndex(11, 3)] += c_in[SHIndex(11, 3)] * -0.349609375; + c_out[SHIndex(11, 3)] += c_in[SHIndex(11, 5)] * -0.49531072862952; + c_out[SHIndex(11, 3)] += c_in[SHIndex(11, 7)] * -0.49716719187292; + c_out[SHIndex(11, 3)] += c_in[SHIndex(11, 9)] * -0.25433782432394; + c_out[SHIndex(11, 3)] += c_in[SHIndex(11, 11)] * 0.55222860860085; + c_out[SHIndex(11, 4)] += c_in[SHIndex(11, -11)] * 0.4032907544405; + c_out[SHIndex(11, 4)] += c_in[SHIndex(11, -9)] * -0.55722625443603; + c_out[SHIndex(11, 4)] += c_in[SHIndex(11, -7)] * -0.49510851970963; + c_out[SHIndex(11, 4)] += c_in[SHIndex(11, -5)] * -0.134354558765; + c_out[SHIndex(11, 4)] += c_in[SHIndex(11, -3)] * 0.235349536428; + c_out[SHIndex(11, 4)] += c_in[SHIndex(11, -1)] * 0.45637974396672; + c_out[SHIndex(11, 5)] += c_in[SHIndex(11, 1)] * -0.21561916177558; + c_out[SHIndex(11, 5)] += c_in[SHIndex(11, 3)] * -0.49531072862952; + c_out[SHIndex(11, 5)] += c_in[SHIndex(11, 5)] * -0.3857421875; + c_out[SHIndex(11, 5)] += c_in[SHIndex(11, 7)] * 0.14035007305082; + c_out[SHIndex(11, 5)] += c_in[SHIndex(11, 9)] * 0.68448811471567; + c_out[SHIndex(11, 5)] += c_in[SHIndex(11, 11)] * -0.2667517605753; + c_out[SHIndex(11, 6)] += c_in[SHIndex(11, -11)] * -0.158474160191; + c_out[SHIndex(11, 6)] += c_in[SHIndex(11, -9)] * 0.63603688806046; + c_out[SHIndex(11, 6)] += c_in[SHIndex(11, -7)] * -0.32425698663836; + c_out[SHIndex(11, 6)] += c_in[SHIndex(11, -5)] * -0.52272828294257; + c_out[SHIndex(11, 6)] += c_in[SHIndex(11, -3)] * -0.047641839522072; + c_out[SHIndex(11, 6)] += c_in[SHIndex(11, -1)] * 0.4355293578316; + c_out[SHIndex(11, 7)] += c_in[SHIndex(11, 1)] * -0.32136177701095; + c_out[SHIndex(11, 7)] += c_in[SHIndex(11, 3)] * -0.49716719187292; + c_out[SHIndex(11, 7)] += c_in[SHIndex(11, 5)] * 0.14035007305082; + c_out[SHIndex(11, 7)] += c_in[SHIndex(11, 7)] * 0.6279296875; + c_out[SHIndex(11, 7)] += c_in[SHIndex(11, 9)] * -0.47810190182411; + c_out[SHIndex(11, 7)] += c_in[SHIndex(11, 11)] * 0.08352321608099; + c_out[SHIndex(11, 8)] += c_in[SHIndex(11, -11)] * 0.0383230798249; + c_out[SHIndex(11, 8)] += c_in[SHIndex(11, -9)] * -0.29501240332439; + c_out[SHIndex(11, 8)] += c_in[SHIndex(11, -7)] * 0.65553753643092; + c_out[SHIndex(11, 8)] += c_in[SHIndex(11, -5)] * -0.40784785676472; + c_out[SHIndex(11, 8)] += c_in[SHIndex(11, -3)] * -0.3940184631669; + c_out[SHIndex(11, 8)] += c_in[SHIndex(11, -1)] * 0.40022386008782; + c_out[SHIndex(11, 9)] += c_in[SHIndex(11, 1)] * -0.46501810346249; + c_out[SHIndex(11, 9)] += c_in[SHIndex(11, 3)] * -0.25433782432394; + c_out[SHIndex(11, 9)] += c_in[SHIndex(11, 5)] * 0.68448811471567; + c_out[SHIndex(11, 9)] += c_in[SHIndex(11, 7)] * -0.47810190182411; + c_out[SHIndex(11, 9)] += c_in[SHIndex(11, 9)] * 0.1474609375; + c_out[SHIndex(11, 9)] += c_in[SHIndex(11, 11)] * -0.014842464993721; + c_out[SHIndex(11, 10)] += c_in[SHIndex(11, -11)] * -0.0045804841404526; + c_out[SHIndex(11, 10)] += c_in[SHIndex(11, -9)] * 0.0569596350446; + c_out[SHIndex(11, 10)] += c_in[SHIndex(11, -7)] * -0.24930093301108; + c_out[SHIndex(11, 10)] += c_in[SHIndex(11, -5)] * 0.56871666443773; + c_out[SHIndex(11, 10)] += c_in[SHIndex(11, -3)] * -0.70641320967457; + c_out[SHIndex(11, 10)] += c_in[SHIndex(11, -1)] * 0.33485130540064; + c_out[SHIndex(11, 11)] += c_in[SHIndex(11, 1)] * -0.78529592002432; + c_out[SHIndex(11, 11)] += c_in[SHIndex(11, 3)] * 0.55222860860085; + c_out[SHIndex(11, 11)] += c_in[SHIndex(11, 5)] * -0.2667517605753; + c_out[SHIndex(11, 11)] += c_in[SHIndex(11, 7)] * 0.08352321608099; + c_out[SHIndex(11, 11)] += c_in[SHIndex(11, 9)] * -0.014842464993721; + c_out[SHIndex(11, 11)] += c_in[SHIndex(11, 11)] * 0.0009765625; + if (lmax == 11) return; + + + c_out[SHIndex(12, -12)] += c_in[SHIndex(12, 1)] * 0.7714448170238; + c_out[SHIndex(12, -12)] += c_in[SHIndex(12, 3)] * -0.55833076742161; + c_out[SHIndex(12, -12)] += c_in[SHIndex(12, 5)] * 0.28725880996301; + c_out[SHIndex(12, -12)] += c_in[SHIndex(12, 7)] * -0.1006664953504; + c_out[SHIndex(12, -12)] += c_in[SHIndex(12, 9)] * 0.021967230232816; + c_out[SHIndex(12, -12)] += c_in[SHIndex(12, 11)] * -0.0023920798269367; + c_out[SHIndex(12, -11)] += c_in[SHIndex(12, -11)] * 0.0107421875; + c_out[SHIndex(12, -11)] += c_in[SHIndex(12, -9)] * -0.08071275769896; + c_out[SHIndex(12, -11)] += c_in[SHIndex(12, -7)] * 0.28767847243653; + c_out[SHIndex(12, -11)] += c_in[SHIndex(12, -5)] * -0.58636459044042; + c_out[SHIndex(12, -11)] += c_in[SHIndex(12, -3)] * 0.68381274393975; + c_out[SHIndex(12, -11)] += c_in[SHIndex(12, -1)] * -0.31494102773718; + c_out[SHIndex(12, -10)] += c_in[SHIndex(12, 1)] * 0.46435521203003; + c_out[SHIndex(12, -10)] += c_in[SHIndex(12, 3)] * 0.20164537722025; + c_out[SHIndex(12, -10)] += c_in[SHIndex(12, 5)] * -0.65705604098221; + c_out[SHIndex(12, -10)] += c_in[SHIndex(12, 7)] * 0.52110934255626; + c_out[SHIndex(12, -10)] += c_in[SHIndex(12, 9)] * -0.19834078136318; + c_out[SHIndex(12, -10)] += c_in[SHIndex(12, 11)] * 0.033116845620729; + c_out[SHIndex(12, -9)] += c_in[SHIndex(12, -11)] * -0.08071275769896; + c_out[SHIndex(12, -9)] += c_in[SHIndex(12, -9)] * 0.3720703125; + c_out[SHIndex(12, -9)] += c_in[SHIndex(12, -7)] * -0.65785022183448; + c_out[SHIndex(12, -9)] += c_in[SHIndex(12, -5)] * 0.31925529371636; + c_out[SHIndex(12, -9)] += c_in[SHIndex(12, -3)] * 0.42195411222922; + c_out[SHIndex(12, -9)] += c_in[SHIndex(12, -1)] * -0.37724395759248; + c_out[SHIndex(12, -8)] += c_in[SHIndex(12, 1)] * 0.32928552212043; + c_out[SHIndex(12, -8)] += c_in[SHIndex(12, 3)] * 0.45497333155019; + c_out[SHIndex(12, -8)] += c_in[SHIndex(12, 5)] * -0.23408184791529; + c_out[SHIndex(12, -8)] += c_in[SHIndex(12, 7)] * -0.54296875; + c_out[SHIndex(12, -8)] += c_in[SHIndex(12, 9)] * 0.55492127556106; + c_out[SHIndex(12, -8)] += c_in[SHIndex(12, 11)] * -0.16438769853516; + c_out[SHIndex(12, -7)] += c_in[SHIndex(12, -11)] * 0.28767847243653; + c_out[SHIndex(12, -7)] += c_in[SHIndex(12, -9)] * -0.65785022183448; + c_out[SHIndex(12, -7)] += c_in[SHIndex(12, -7)] * 0.1572265625; + c_out[SHIndex(12, -7)] += c_in[SHIndex(12, -5)] * 0.52668415780941; + c_out[SHIndex(12, -7)] += c_in[SHIndex(12, -3)] * 0.11374333288755; + c_out[SHIndex(12, -7)] += c_in[SHIndex(12, -1)] * -0.41160690265054; + c_out[SHIndex(12, -6)] += c_in[SHIndex(12, 1)] * 0.23130311098295; + c_out[SHIndex(12, -6)] += c_in[SHIndex(12, 3)] * 0.49003980202465; + c_out[SHIndex(12, -6)] += c_in[SHIndex(12, 5)] * 0.27404717188286; + c_out[SHIndex(12, -6)] += c_in[SHIndex(12, 7)] * -0.30237819268448; + c_out[SHIndex(12, -6)] += c_in[SHIndex(12, 9)] * -0.58930833781358; + c_out[SHIndex(12, -6)] += c_in[SHIndex(12, 11)] * 0.43879508023282; + c_out[SHIndex(12, -5)] += c_in[SHIndex(12, -11)] * -0.58636459044042; + c_out[SHIndex(12, -5)] += c_in[SHIndex(12, -9)] * 0.31925529371636; + c_out[SHIndex(12, -5)] += c_in[SHIndex(12, -7)] * 0.52668415780941; + c_out[SHIndex(12, -5)] += c_in[SHIndex(12, -5)] * 0.2568359375; + c_out[SHIndex(12, -5)] += c_in[SHIndex(12, -3)] * -0.15374580191487; + c_out[SHIndex(12, -5)] += c_in[SHIndex(12, -1)] * -0.43272849689657; + c_out[SHIndex(12, -4)] += c_in[SHIndex(12, 1)] * 0.14842464993721; + c_out[SHIndex(12, -4)] += c_in[SHIndex(12, 3)] * 0.392578125; + c_out[SHIndex(12, -4)] += c_in[SHIndex(12, 5)] * 0.48401456158384; + c_out[SHIndex(12, -4)] += c_in[SHIndex(12, 7)] * 0.34122999866264; + c_out[SHIndex(12, -4)] += c_in[SHIndex(12, 9)] * -0.074462490393392; + c_out[SHIndex(12, -4)] += c_in[SHIndex(12, 11)] * -0.68381274393975; + c_out[SHIndex(12, -3)] += c_in[SHIndex(12, -11)] * 0.68381274393975; + c_out[SHIndex(12, -3)] += c_in[SHIndex(12, -9)] * 0.42195411222922; + c_out[SHIndex(12, -3)] += c_in[SHIndex(12, -7)] * 0.11374333288755; + c_out[SHIndex(12, -3)] += c_in[SHIndex(12, -5)] * -0.15374580191487; + c_out[SHIndex(12, -3)] += c_in[SHIndex(12, -3)] * -0.345703125; + c_out[SHIndex(12, -3)] += c_in[SHIndex(12, -1)] * -0.44527394981164; + c_out[SHIndex(12, -2)] += c_in[SHIndex(12, 1)] * 0.072712931519478; + c_out[SHIndex(12, -2)] += c_in[SHIndex(12, 3)] * 0.2152871844243; + c_out[SHIndex(12, -2)] += c_in[SHIndex(12, 5)] * 0.34870255998744; + c_out[SHIndex(12, -2)] += c_in[SHIndex(12, 7)] * 0.46435521203003; + c_out[SHIndex(12, -2)] += c_in[SHIndex(12, 9)] * 0.54718531932211; + c_out[SHIndex(12, -2)] += c_in[SHIndex(12, 11)] * 0.55833076742161; + c_out[SHIndex(12, -1)] += c_in[SHIndex(12, -11)] * -0.31494102773718; + c_out[SHIndex(12, -1)] += c_in[SHIndex(12, -9)] * -0.37724395759248; + c_out[SHIndex(12, -1)] += c_in[SHIndex(12, -7)] * -0.41160690265054; + c_out[SHIndex(12, -1)] += c_in[SHIndex(12, -5)] * -0.43272849689657; + c_out[SHIndex(12, -1)] += c_in[SHIndex(12, -3)] * -0.44527394981164; + c_out[SHIndex(12, -1)] += c_in[SHIndex(12, -1)] * -0.451171875; + c_out[SHIndex(12, 0)] += c_in[SHIndex(12, 0)] * 0.2255859375; + c_out[SHIndex(12, 0)] += c_in[SHIndex(12, 2)] * 0.32109161153485; + c_out[SHIndex(12, 0)] += c_in[SHIndex(12, 4)] * 0.32771275372847; + c_out[SHIndex(12, 0)] += c_in[SHIndex(12, 6)] * 0.34046896063985; + c_out[SHIndex(12, 0)] += c_in[SHIndex(12, 8)] * 0.36352137351394; + c_out[SHIndex(12, 0)] += c_in[SHIndex(12, 10)] * 0.41010741896822; + c_out[SHIndex(12, 0)] += c_in[SHIndex(12, 12)] * 0.56776801212686; + c_out[SHIndex(12, 1)] += c_in[SHIndex(12, -12)] * 0.7714448170238; + c_out[SHIndex(12, 1)] += c_in[SHIndex(12, -10)] * 0.46435521203003; + c_out[SHIndex(12, 1)] += c_in[SHIndex(12, -8)] * 0.32928552212043; + c_out[SHIndex(12, 1)] += c_in[SHIndex(12, -6)] * 0.23130311098295; + c_out[SHIndex(12, 1)] += c_in[SHIndex(12, -4)] * 0.14842464993721; + c_out[SHIndex(12, 1)] += c_in[SHIndex(12, -2)] * 0.072712931519478; + c_out[SHIndex(12, 2)] += c_in[SHIndex(12, 0)] * 0.32109161153485; + c_out[SHIndex(12, 2)] += c_in[SHIndex(12, 2)] * 0.43359375; + c_out[SHIndex(12, 2)] += c_in[SHIndex(12, 4)] * 0.37077237317519; + c_out[SHIndex(12, 2)] += c_in[SHIndex(12, 6)] * 0.2609451018728; + c_out[SHIndex(12, 2)] += c_in[SHIndex(12, 8)] * 0.092871042406006; + c_out[SHIndex(12, 2)] += c_in[SHIndex(12, 10)] * -0.16464276106022; + c_out[SHIndex(12, 2)] += c_in[SHIndex(12, 12)] * -0.68381274393975; + c_out[SHIndex(12, 3)] += c_in[SHIndex(12, -12)] * -0.55833076742161; + c_out[SHIndex(12, 3)] += c_in[SHIndex(12, -10)] * 0.20164537722025; + c_out[SHIndex(12, 3)] += c_in[SHIndex(12, -8)] * 0.45497333155019; + c_out[SHIndex(12, 3)] += c_in[SHIndex(12, -6)] * 0.49003980202465; + c_out[SHIndex(12, 3)] += c_in[SHIndex(12, -4)] * 0.392578125; + c_out[SHIndex(12, 3)] += c_in[SHIndex(12, -2)] * 0.2152871844243; + c_out[SHIndex(12, 4)] += c_in[SHIndex(12, 0)] * 0.32771275372847; + c_out[SHIndex(12, 4)] += c_in[SHIndex(12, 2)] * 0.37077237317519; + c_out[SHIndex(12, 4)] += c_in[SHIndex(12, 4)] * 0.11669921875; + c_out[SHIndex(12, 4)] += c_in[SHIndex(12, 6)] * -0.22371382266343; + c_out[SHIndex(12, 4)] += c_in[SHIndex(12, 8)] * -0.51184499799396; + c_out[SHIndex(12, 4)] += c_in[SHIndex(12, 10)] * -0.50411344305062; + c_out[SHIndex(12, 4)] += c_in[SHIndex(12, 12)] * 0.41874807556621; + c_out[SHIndex(12, 5)] += c_in[SHIndex(12, -12)] * 0.28725880996301; + c_out[SHIndex(12, 5)] += c_in[SHIndex(12, -10)] * -0.65705604098221; + c_out[SHIndex(12, 5)] += c_in[SHIndex(12, -8)] * -0.23408184791529; + c_out[SHIndex(12, 5)] += c_in[SHIndex(12, -6)] * 0.27404717188286; + c_out[SHIndex(12, 5)] += c_in[SHIndex(12, -4)] * 0.48401456158384; + c_out[SHIndex(12, 5)] += c_in[SHIndex(12, -2)] * 0.34870255998744; + c_out[SHIndex(12, 6)] += c_in[SHIndex(12, 0)] * 0.34046896063985; + c_out[SHIndex(12, 6)] += c_in[SHIndex(12, 2)] * 0.2609451018728; + c_out[SHIndex(12, 6)] += c_in[SHIndex(12, 4)] * -0.22371382266343; + c_out[SHIndex(12, 6)] += c_in[SHIndex(12, 6)] * -0.525390625; + c_out[SHIndex(12, 6)] += c_in[SHIndex(12, 8)] * -0.19810985037949; + c_out[SHIndex(12, 6)] += c_in[SHIndex(12, 10)] * 0.64696804980671; + c_out[SHIndex(12, 6)] += c_in[SHIndex(12, 12)] * -0.179137341369; + c_out[SHIndex(12, 7)] += c_in[SHIndex(12, -12)] * -0.1006664953504; + c_out[SHIndex(12, 7)] += c_in[SHIndex(12, -10)] * 0.52110934255626; + c_out[SHIndex(12, 7)] += c_in[SHIndex(12, -8)] * -0.54296875; + c_out[SHIndex(12, 7)] += c_in[SHIndex(12, -6)] * -0.30237819268448; + c_out[SHIndex(12, 7)] += c_in[SHIndex(12, -4)] * 0.34122999866264; + c_out[SHIndex(12, 7)] += c_in[SHIndex(12, -2)] * 0.46435521203003; + c_out[SHIndex(12, 8)] += c_in[SHIndex(12, 0)] * 0.36352137351394; + c_out[SHIndex(12, 8)] += c_in[SHIndex(12, 2)] * 0.092871042406006; + c_out[SHIndex(12, 8)] += c_in[SHIndex(12, 4)] * -0.51184499799396; + c_out[SHIndex(12, 8)] += c_in[SHIndex(12, 6)] * -0.19810985037949; + c_out[SHIndex(12, 8)] += c_in[SHIndex(12, 8)] * 0.6572265625; + c_out[SHIndex(12, 8)] += c_in[SHIndex(12, 10)] * -0.35144583567748; + c_out[SHIndex(12, 8)] += c_in[SHIndex(12, 12)] * 0.050333247675202; + c_out[SHIndex(12, 9)] += c_in[SHIndex(12, -12)] * 0.021967230232816; + c_out[SHIndex(12, 9)] += c_in[SHIndex(12, -10)] * -0.19834078136318; + c_out[SHIndex(12, 9)] += c_in[SHIndex(12, -8)] * 0.55492127556106; + c_out[SHIndex(12, 9)] += c_in[SHIndex(12, -6)] * -0.58930833781358; + c_out[SHIndex(12, 9)] += c_in[SHIndex(12, -4)] * -0.074462490393392; + c_out[SHIndex(12, 9)] += c_in[SHIndex(12, -2)] * 0.54718531932211; + c_out[SHIndex(12, 10)] += c_in[SHIndex(12, 0)] * 0.41010741896822; + c_out[SHIndex(12, 10)] += c_in[SHIndex(12, 2)] * -0.16464276106022; + c_out[SHIndex(12, 10)] += c_in[SHIndex(12, 4)] * -0.50411344305062; + c_out[SHIndex(12, 10)] += c_in[SHIndex(12, 6)] * 0.64696804980671; + c_out[SHIndex(12, 10)] += c_in[SHIndex(12, 8)] * -0.35144583567748; + c_out[SHIndex(12, 10)] += c_in[SHIndex(12, 10)] * 0.091796875; + c_out[SHIndex(12, 10)] += c_in[SHIndex(12, 12)] * -0.0081119373661309; + c_out[SHIndex(12, 11)] += c_in[SHIndex(12, -12)] * -0.0023920798269367; + c_out[SHIndex(12, 11)] += c_in[SHIndex(12, -10)] * 0.033116845620729; + c_out[SHIndex(12, 11)] += c_in[SHIndex(12, -8)] * -0.16438769853516; + c_out[SHIndex(12, 11)] += c_in[SHIndex(12, -6)] * 0.43879508023282; + c_out[SHIndex(12, 11)] += c_in[SHIndex(12, -4)] * -0.68381274393975; + c_out[SHIndex(12, 11)] += c_in[SHIndex(12, -2)] * 0.55833076742161; + c_out[SHIndex(12, 12)] += c_in[SHIndex(12, 0)] * 0.56776801212686; + c_out[SHIndex(12, 12)] += c_in[SHIndex(12, 2)] * -0.68381274393975; + c_out[SHIndex(12, 12)] += c_in[SHIndex(12, 4)] * 0.41874807556621; + c_out[SHIndex(12, 12)] += c_in[SHIndex(12, 6)] * -0.179137341369; + c_out[SHIndex(12, 12)] += c_in[SHIndex(12, 8)] * 0.050333247675202; + c_out[SHIndex(12, 12)] += c_in[SHIndex(12, 10)] * -0.0081119373661309; + c_out[SHIndex(12, 12)] += c_in[SHIndex(12, 12)] * 0.00048828125; + if (lmax == 12) return; + + + c_out[SHIndex(13, -13)] += c_in[SHIndex(13, 0)] * -0.55674234096704; + c_out[SHIndex(13, -13)] += c_in[SHIndex(13, 2)] * 0.67861257155894; + c_out[SHIndex(13, -13)] += c_in[SHIndex(13, 4)] * -0.43155265360434; + c_out[SHIndex(13, -13)] += c_in[SHIndex(13, 6)] * 0.19800993746086; + c_out[SHIndex(13, -13)] += c_in[SHIndex(13, 8)] * -0.06261624017238; + c_out[SHIndex(13, -13)] += c_in[SHIndex(13, 10)] * 0.012448778109357; + c_out[SHIndex(13, -13)] += c_in[SHIndex(13, 12)] * -0.0012448778109357; + c_out[SHIndex(13, -12)] += c_in[SHIndex(13, -12)] * 0.005859375; + c_out[SHIndex(13, -12)] += c_in[SHIndex(13, -10)] * -0.048828125; + c_out[SHIndex(13, -12)] += c_in[SHIndex(13, -8)] * 0.19648088031186; + c_out[SHIndex(13, -12)] += c_in[SHIndex(13, -6)] * -0.46599532384532; + c_out[SHIndex(13, -12)] += c_in[SHIndex(13, -4)] * 0.67707550826808; + c_out[SHIndex(13, -12)] += c_in[SHIndex(13, -2)] * -0.53234749916129; + c_out[SHIndex(13, -11)] += c_in[SHIndex(13, 0)] * -0.40147261151571; + c_out[SHIndex(13, -11)] += c_in[SHIndex(13, 2)] * 0.18821326330232; + c_out[SHIndex(13, -11)] += c_in[SHIndex(13, 4)] * 0.45482644910811; + c_out[SHIndex(13, -11)] += c_in[SHIndex(13, 6)] * -0.64803329186808; + c_out[SHIndex(13, -11)] += c_in[SHIndex(13, 8)] * 0.39943226817081; + c_out[SHIndex(13, -11)] += c_in[SHIndex(13, 10)] * -0.12912985164247; + c_out[SHIndex(13, -11)] += c_in[SHIndex(13, 12)] * 0.018989684065068; + c_out[SHIndex(13, -10)] += c_in[SHIndex(13, -12)] * -0.048828125; + c_out[SHIndex(13, -10)] += c_in[SHIndex(13, -10)] * 0.263671875; + c_out[SHIndex(13, -10)] += c_in[SHIndex(13, -8)] * -0.58944264093559; + c_out[SHIndex(13, -10)] += c_in[SHIndex(13, -6)] * 0.52812803369136; + c_out[SHIndex(13, -10)] += c_in[SHIndex(13, -4)] * 0.13541510165362; + c_out[SHIndex(13, -10)] += c_in[SHIndex(13, -2)] * -0.53234749916129; + c_out[SHIndex(13, -9)] += c_in[SHIndex(13, 0)] * -0.35516344310694; + c_out[SHIndex(13, -9)] += c_in[SHIndex(13, 2)] * -0.055501063431183; + c_out[SHIndex(13, -9)] += c_in[SHIndex(13, 4)] * 0.51530701050804; + c_out[SHIndex(13, -9)] += c_in[SHIndex(13, 6)] * 0.087450067714449; + c_out[SHIndex(13, -9)] += c_in[SHIndex(13, 8)] * -0.62989984533657; + c_out[SHIndex(13, -9)] += c_in[SHIndex(13, 10)] * 0.43555891764461; + c_out[SHIndex(13, -9)] += c_in[SHIndex(13, 12)] * -0.10537715749466; + c_out[SHIndex(13, -8)] += c_in[SHIndex(13, -12)] * 0.19648088031186; + c_out[SHIndex(13, -8)] += c_in[SHIndex(13, -10)] * -0.58944264093559; + c_out[SHIndex(13, -8)] += c_in[SHIndex(13, -8)] * 0.421875; + c_out[SHIndex(13, -8)] += c_in[SHIndex(13, -6)] * 0.38293206041101; + c_out[SHIndex(13, -8)] += c_in[SHIndex(13, -4)] * -0.26921970218926; + c_out[SHIndex(13, -8)] += c_in[SHIndex(13, -2)] * -0.46568005127582; + c_out[SHIndex(13, -7)] += c_in[SHIndex(13, 0)] * -0.33184809401475; + c_out[SHIndex(13, -7)] += c_in[SHIndex(13, 2)] * -0.21780190046618; + c_out[SHIndex(13, -7)] += c_in[SHIndex(13, 4)] * 0.28960676761644; + c_out[SHIndex(13, -7)] += c_in[SHIndex(13, 6)] * 0.49108084137057; + c_out[SHIndex(13, -7)] += c_in[SHIndex(13, 8)] * 0.0127888680212; + c_out[SHIndex(13, -7)] += c_in[SHIndex(13, 10)] * -0.64326862003139; + c_out[SHIndex(13, -7)] += c_in[SHIndex(13, 12)] * 0.3216343100157; + c_out[SHIndex(13, -6)] += c_in[SHIndex(13, -12)] * -0.46599532384532; + c_out[SHIndex(13, -6)] += c_in[SHIndex(13, -10)] * 0.52812803369136; + c_out[SHIndex(13, -6)] += c_in[SHIndex(13, -8)] * 0.38293206041101; + c_out[SHIndex(13, -6)] += c_in[SHIndex(13, -6)] * -0.134765625; + c_out[SHIndex(13, -6)] += c_in[SHIndex(13, -4)] * -0.45121414845245; + c_out[SHIndex(13, -6)] += c_in[SHIndex(13, -2)] * -0.3681524057339; + c_out[SHIndex(13, -5)] += c_in[SHIndex(13, 0)] * -0.31847955038634; + c_out[SHIndex(13, -5)] += c_in[SHIndex(13, 2)] * -0.32847213547974; + c_out[SHIndex(13, -5)] += c_in[SHIndex(13, 4)] * -0.014846480269053; + c_out[SHIndex(13, -5)] += c_in[SHIndex(13, 6)] * 0.34012635856225; + c_out[SHIndex(13, -5)] += c_in[SHIndex(13, 8)] * 0.50923193110086; + c_out[SHIndex(13, -5)] += c_in[SHIndex(13, 10)] * 0.23938234163585; + c_out[SHIndex(13, -5)] += c_in[SHIndex(13, 12)] * -0.59845585408961; + c_out[SHIndex(13, -4)] += c_in[SHIndex(13, -12)] * 0.67707550826808; + c_out[SHIndex(13, -4)] += c_in[SHIndex(13, -10)] * 0.13541510165362; + c_out[SHIndex(13, -4)] += c_in[SHIndex(13, -8)] * -0.26921970218926; + c_out[SHIndex(13, -4)] += c_in[SHIndex(13, -6)] * -0.45121414845245; + c_out[SHIndex(13, -4)] += c_in[SHIndex(13, -4)] * -0.427734375; + c_out[SHIndex(13, -4)] += c_in[SHIndex(13, -2)] * -0.25337986301296; + c_out[SHIndex(13, -3)] += c_in[SHIndex(13, 0)] * -0.31089561602034; + c_out[SHIndex(13, -3)] += c_in[SHIndex(13, 2)] * -0.39838364181027; + c_out[SHIndex(13, -3)] += c_in[SHIndex(13, 4)] * -0.27693877404914; + c_out[SHIndex(13, -3)] += c_in[SHIndex(13, 6)] * -0.083251595146774; + c_out[SHIndex(13, -3)] += c_in[SHIndex(13, 8)] * 0.16673428435382; + c_out[SHIndex(13, -3)] += c_in[SHIndex(13, 10)] * 0.44139922820051; + c_out[SHIndex(13, -3)] += c_in[SHIndex(13, 12)] * 0.66209884230076; + c_out[SHIndex(13, -2)] += c_in[SHIndex(13, -12)] * -0.53234749916129; + c_out[SHIndex(13, -2)] += c_in[SHIndex(13, -10)] * -0.53234749916129; + c_out[SHIndex(13, -2)] += c_in[SHIndex(13, -8)] * -0.46568005127582; + c_out[SHIndex(13, -2)] += c_in[SHIndex(13, -6)] * -0.3681524057339; + c_out[SHIndex(13, -2)] += c_in[SHIndex(13, -4)] * -0.25337986301296; + c_out[SHIndex(13, -2)] += c_in[SHIndex(13, -2)] * -0.12890625; + c_out[SHIndex(13, -1)] += c_in[SHIndex(13, 0)] * -0.30742181295663; + c_out[SHIndex(13, -1)] += c_in[SHIndex(13, 2)] * -0.43236470658687; + c_out[SHIndex(13, -1)] += c_in[SHIndex(13, 4)] * -0.42493094836993; + c_out[SHIndex(13, -1)] += c_in[SHIndex(13, 6)] * -0.41160690265054; + c_out[SHIndex(13, -1)] += c_in[SHIndex(13, 8)] * -0.39048459390687; + c_out[SHIndex(13, -1)] += c_in[SHIndex(13, 10)] * -0.357109558733; + c_out[SHIndex(13, -1)] += c_in[SHIndex(13, 12)] * -0.29759129894417; + c_out[SHIndex(13, 0)] += c_in[SHIndex(13, -13)] * -0.55674234096704; + c_out[SHIndex(13, 0)] += c_in[SHIndex(13, -11)] * -0.40147261151571; + c_out[SHIndex(13, 0)] += c_in[SHIndex(13, -9)] * -0.35516344310694; + c_out[SHIndex(13, 0)] += c_in[SHIndex(13, -7)] * -0.33184809401475; + c_out[SHIndex(13, 0)] += c_in[SHIndex(13, -5)] * -0.31847955038634; + c_out[SHIndex(13, 0)] += c_in[SHIndex(13, -3)] * -0.31089561602034; + c_out[SHIndex(13, 0)] += c_in[SHIndex(13, -1)] * -0.30742181295663; + c_out[SHIndex(13, 1)] += c_in[SHIndex(13, 1)] * 0.0322265625; + c_out[SHIndex(13, 1)] += c_in[SHIndex(13, 3)] * 0.097772148023234; + c_out[SHIndex(13, 1)] += c_in[SHIndex(13, 5)] * 0.166928641738; + c_out[SHIndex(13, 1)] += c_in[SHIndex(13, 7)] * 0.24350992753551; + c_out[SHIndex(13, 1)] += c_in[SHIndex(13, 9)] * 0.33508120677026; + c_out[SHIndex(13, 1)] += c_in[SHIndex(13, 11)] * 0.46294341611217; + c_out[SHIndex(13, 1)] += c_in[SHIndex(13, 13)] * 0.75871192019586; + c_out[SHIndex(13, 2)] += c_in[SHIndex(13, -13)] * 0.67861257155894; + c_out[SHIndex(13, 2)] += c_in[SHIndex(13, -11)] * 0.18821326330232; + c_out[SHIndex(13, 2)] += c_in[SHIndex(13, -9)] * -0.055501063431183; + c_out[SHIndex(13, 2)] += c_in[SHIndex(13, -7)] * -0.21780190046618; + c_out[SHIndex(13, 2)] += c_in[SHIndex(13, -5)] * -0.32847213547974; + c_out[SHIndex(13, 2)] += c_in[SHIndex(13, -3)] * -0.39838364181027; + c_out[SHIndex(13, 2)] += c_in[SHIndex(13, -1)] * -0.43236470658687; + c_out[SHIndex(13, 3)] += c_in[SHIndex(13, 1)] * 0.097772148023234; + c_out[SHIndex(13, 3)] += c_in[SHIndex(13, 3)] * 0.279052734375; + c_out[SHIndex(13, 3)] += c_in[SHIndex(13, 5)] * 0.41641008901347; + c_out[SHIndex(13, 3)] += c_in[SHIndex(13, 7)] * 0.47610564299334; + c_out[SHIndex(13, 3)] += c_in[SHIndex(13, 9)] * 0.41417145645063; + c_out[SHIndex(13, 3)] += c_in[SHIndex(13, 11)] * 0.15605819373554; + c_out[SHIndex(13, 3)] += c_in[SHIndex(13, 13)] * -0.5626758194698; + c_out[SHIndex(13, 4)] += c_in[SHIndex(13, -13)] * -0.43155265360434; + c_out[SHIndex(13, 4)] += c_in[SHIndex(13, -11)] * 0.45482644910811; + c_out[SHIndex(13, 4)] += c_in[SHIndex(13, -9)] * 0.51530701050804; + c_out[SHIndex(13, 4)] += c_in[SHIndex(13, -7)] * 0.28960676761644; + c_out[SHIndex(13, 4)] += c_in[SHIndex(13, -5)] * -0.014846480269053; + c_out[SHIndex(13, 4)] += c_in[SHIndex(13, -3)] * -0.27693877404914; + c_out[SHIndex(13, 4)] += c_in[SHIndex(13, -1)] * -0.42493094836993; + c_out[SHIndex(13, 5)] += c_in[SHIndex(13, 1)] * 0.166928641738; + c_out[SHIndex(13, 5)] += c_in[SHIndex(13, 3)] * 0.41641008901347; + c_out[SHIndex(13, 5)] += c_in[SHIndex(13, 5)] * 0.438232421875; + c_out[SHIndex(13, 5)] += c_in[SHIndex(13, 7)] * 0.16916849025752; + c_out[SHIndex(13, 5)] += c_in[SHIndex(13, 9)] * -0.30447947908103; + c_out[SHIndex(13, 5)] += c_in[SHIndex(13, 11)] * -0.62629484514798; + c_out[SHIndex(13, 5)] += c_in[SHIndex(13, 13)] * 0.30515380780268; + c_out[SHIndex(13, 6)] += c_in[SHIndex(13, -13)] * 0.19800993746086; + c_out[SHIndex(13, 6)] += c_in[SHIndex(13, -11)] * -0.64803329186808; + c_out[SHIndex(13, 6)] += c_in[SHIndex(13, -9)] * 0.087450067714449; + c_out[SHIndex(13, 6)] += c_in[SHIndex(13, -7)] * 0.49108084137057; + c_out[SHIndex(13, 6)] += c_in[SHIndex(13, -5)] * 0.34012635856225; + c_out[SHIndex(13, 6)] += c_in[SHIndex(13, -3)] * -0.083251595146774; + c_out[SHIndex(13, 6)] += c_in[SHIndex(13, -1)] * -0.41160690265054; + c_out[SHIndex(13, 7)] += c_in[SHIndex(13, 1)] * 0.24350992753551; + c_out[SHIndex(13, 7)] += c_in[SHIndex(13, 3)] * 0.47610564299334; + c_out[SHIndex(13, 7)] += c_in[SHIndex(13, 5)] * 0.16916849025752; + c_out[SHIndex(13, 7)] += c_in[SHIndex(13, 7)] * -0.40478515625; + c_out[SHIndex(13, 7)] += c_in[SHIndex(13, 9)] * -0.45029618794257; + c_out[SHIndex(13, 7)] += c_in[SHIndex(13, 11)] * 0.552329518352; + c_out[SHIndex(13, 7)] += c_in[SHIndex(13, 13)] * -0.1171442587865; + c_out[SHIndex(13, 8)] += c_in[SHIndex(13, -13)] * -0.06261624017238; + c_out[SHIndex(13, 8)] += c_in[SHIndex(13, -11)] * 0.39943226817081; + c_out[SHIndex(13, 8)] += c_in[SHIndex(13, -9)] * -0.62989984533657; + c_out[SHIndex(13, 8)] += c_in[SHIndex(13, -7)] * 0.0127888680212; + c_out[SHIndex(13, 8)] += c_in[SHIndex(13, -5)] * 0.50923193110086; + c_out[SHIndex(13, 8)] += c_in[SHIndex(13, -3)] * 0.16673428435382; + c_out[SHIndex(13, 8)] += c_in[SHIndex(13, -1)] * -0.39048459390687; + c_out[SHIndex(13, 9)] += c_in[SHIndex(13, 1)] * 0.33508120677026; + c_out[SHIndex(13, 9)] += c_in[SHIndex(13, 3)] * 0.41417145645063; + c_out[SHIndex(13, 9)] += c_in[SHIndex(13, 5)] * -0.30447947908103; + c_out[SHIndex(13, 9)] += c_in[SHIndex(13, 7)] * -0.45029618794257; + c_out[SHIndex(13, 9)] += c_in[SHIndex(13, 9)] * 0.59912109375; + c_out[SHIndex(13, 9)] += c_in[SHIndex(13, 11)] * -0.24672049987443; + c_out[SHIndex(13, 9)] += c_in[SHIndex(13, 13)] * 0.029851121241791; + c_out[SHIndex(13, 10)] += c_in[SHIndex(13, -13)] * 0.012448778109357; + c_out[SHIndex(13, 10)] += c_in[SHIndex(13, -11)] * -0.12912985164247; + c_out[SHIndex(13, 10)] += c_in[SHIndex(13, -9)] * 0.43555891764461; + c_out[SHIndex(13, 10)] += c_in[SHIndex(13, -7)] * -0.64326862003139; + c_out[SHIndex(13, 10)] += c_in[SHIndex(13, -5)] * 0.23938234163585; + c_out[SHIndex(13, 10)] += c_in[SHIndex(13, -3)] * 0.44139922820051; + c_out[SHIndex(13, 10)] += c_in[SHIndex(13, -1)] * -0.357109558733; + c_out[SHIndex(13, 11)] += c_in[SHIndex(13, 1)] * 0.46294341611217; + c_out[SHIndex(13, 11)] += c_in[SHIndex(13, 3)] * 0.15605819373554; + c_out[SHIndex(13, 11)] += c_in[SHIndex(13, 5)] * -0.62629484514798; + c_out[SHIndex(13, 11)] += c_in[SHIndex(13, 7)] * 0.552329518352; + c_out[SHIndex(13, 11)] += c_in[SHIndex(13, 9)] * -0.24672049987443; + c_out[SHIndex(13, 11)] += c_in[SHIndex(13, 11)] * 0.055908203125; + c_out[SHIndex(13, 11)] += c_in[SHIndex(13, 13)] * -0.0044013077093066; + c_out[SHIndex(13, 12)] += c_in[SHIndex(13, -13)] * -0.0012448778109357; + c_out[SHIndex(13, 12)] += c_in[SHIndex(13, -11)] * 0.018989684065068; + c_out[SHIndex(13, 12)] += c_in[SHIndex(13, -9)] * -0.10537715749466; + c_out[SHIndex(13, 12)] += c_in[SHIndex(13, -7)] * 0.3216343100157; + c_out[SHIndex(13, 12)] += c_in[SHIndex(13, -5)] * -0.59845585408961; + c_out[SHIndex(13, 12)] += c_in[SHIndex(13, -3)] * 0.66209884230076; + c_out[SHIndex(13, 12)] += c_in[SHIndex(13, -1)] * -0.29759129894417; + c_out[SHIndex(13, 13)] += c_in[SHIndex(13, 1)] * 0.75871192019586; + c_out[SHIndex(13, 13)] += c_in[SHIndex(13, 3)] * -0.5626758194698; + c_out[SHIndex(13, 13)] += c_in[SHIndex(13, 5)] * 0.30515380780268; + c_out[SHIndex(13, 13)] += c_in[SHIndex(13, 7)] * -0.1171442587865; + c_out[SHIndex(13, 13)] += c_in[SHIndex(13, 9)] * 0.029851121241791; + c_out[SHIndex(13, 13)] += c_in[SHIndex(13, 11)] * -0.0044013077093066; + c_out[SHIndex(13, 13)] += c_in[SHIndex(13, 13)] * 0.000244140625; + if (lmax == 13) return; + + c_out[SHIndex(14, -14)] += c_in[SHIndex(14, 1)] * -0.74694823221281; + c_out[SHIndex(14, -14)] += c_in[SHIndex(14, 3)] * 0.56567677845719; + c_out[SHIndex(14, -14)] += c_in[SHIndex(14, 5)] * -0.32081276509794; + c_out[SHIndex(14, -14)] += c_in[SHIndex(14, 7)] * 0.13282910411489; + c_out[SHIndex(14, -14)] += c_in[SHIndex(14, 9)] * -0.038268604914882; + c_out[SHIndex(14, -14)] += c_in[SHIndex(14, 11)] * 0.006986859385378; + c_out[SHIndex(14, -14)] += c_in[SHIndex(14, 13)] * -0.00064593537867788; + c_out[SHIndex(14, -13)] += c_in[SHIndex(14, -13)] * 0.003173828125; + c_out[SHIndex(14, -13)] += c_in[SHIndex(14, -11)] * -0.029048630881424; + c_out[SHIndex(14, -13)] += c_in[SHIndex(14, -9)] * 0.13017755780507; + c_out[SHIndex(14, -13)] += c_in[SHIndex(14, -7)] * -0.3514327763595; + c_out[SHIndex(14, -13)] += c_in[SHIndex(14, -5)] * 0.60627913847438; + c_out[SHIndex(14, -13)] += c_in[SHIndex(14, -3)] * -0.64141717638938; + c_out[SHIndex(14, -13)] += c_in[SHIndex(14, -1)] * 0.28231989495349; + c_out[SHIndex(14, -12)] += c_in[SHIndex(14, 1)] * -0.46102645791479; + c_out[SHIndex(14, -12)] += c_in[SHIndex(14, 3)] * -0.11638109588228; + c_out[SHIndex(14, -12)] += c_in[SHIndex(14, 5)] * 0.59402981238257; + c_out[SHIndex(14, -12)] += c_in[SHIndex(14, 7)] * -0.57388732064693; + c_out[SHIndex(14, -12)] += c_in[SHIndex(14, 9)] * 0.29131204754594; + c_out[SHIndex(14, -12)] += c_in[SHIndex(14, 11)] * -0.081935281474721; + c_out[SHIndex(14, -12)] += c_in[SHIndex(14, 13)] * 0.010764359221215; + c_out[SHIndex(14, -11)] += c_in[SHIndex(14, -13)] * -0.029048630881424; + c_out[SHIndex(14, -11)] += c_in[SHIndex(14, -11)] * 0.179931640625; + c_out[SHIndex(14, -11)] += c_in[SHIndex(14, -9)] * -0.48540841888275; + c_out[SHIndex(14, -11)] += c_in[SHIndex(14, -7)] * 0.61730946168753; + c_out[SHIndex(14, -11)] += c_in[SHIndex(14, -5)] * -0.1681515785395; + c_out[SHIndex(14, -11)] += c_in[SHIndex(14, -3)] * -0.45462596516248; + c_out[SHIndex(14, -11)] += c_in[SHIndex(14, -1)] * 0.33930628577947; + c_out[SHIndex(14, -10)] += c_in[SHIndex(14, 1)] * -0.33930628577947; + c_out[SHIndex(14, -10)] += c_in[SHIndex(14, 3)] * -0.37556057991684; + c_out[SHIndex(14, -10)] += c_in[SHIndex(14, 5)] * 0.35648134650374; + c_out[SHIndex(14, -10)] += c_in[SHIndex(14, 7)] * 0.35738968834541; + c_out[SHIndex(14, -10)] += c_in[SHIndex(14, 9)] * -0.61645531984834; + c_out[SHIndex(14, -10)] += c_in[SHIndex(14, 11)] * 0.323486328125; + c_out[SHIndex(14, -10)] += c_in[SHIndex(14, 13)] * -0.066019615639599; + c_out[SHIndex(14, -9)] += c_in[SHIndex(14, -13)] * 0.13017755780507; + c_out[SHIndex(14, -9)] += c_in[SHIndex(14, -11)] * -0.48540841888275; + c_out[SHIndex(14, -9)] += c_in[SHIndex(14, -9)] * 0.56982421875; + c_out[SHIndex(14, -9)] += c_in[SHIndex(14, -7)] * 0.10677294225083; + c_out[SHIndex(14, -9)] += c_in[SHIndex(14, -5)] * -0.47892214576017; + c_out[SHIndex(14, -9)] += c_in[SHIndex(14, -3)] * -0.20931182591491; + c_out[SHIndex(14, -9)] += c_in[SHIndex(14, -1)] * 0.37169141324942; + c_out[SHIndex(14, -8)] += c_in[SHIndex(14, 1)] * -0.25312379436441; + c_out[SHIndex(14, -8)] += c_in[SHIndex(14, 3)] * -0.45711888182303; + c_out[SHIndex(14, -8)] += c_in[SHIndex(14, 5)] * -0.075265034640616; + c_out[SHIndex(14, -8)] += c_in[SHIndex(14, 7)] * 0.46051523295669; + c_out[SHIndex(14, -8)] += c_in[SHIndex(14, 9)] * 0.29827230784789; + c_out[SHIndex(14, -8)] += c_in[SHIndex(14, 11)] * -0.60740303427372; + c_out[SHIndex(14, -8)] += c_in[SHIndex(14, 13)] * 0.22655408120134; + c_out[SHIndex(14, -7)] += c_in[SHIndex(14, -13)] * -0.3514327763595; + c_out[SHIndex(14, -7)] += c_in[SHIndex(14, -11)] * 0.61730946168753; + c_out[SHIndex(14, -7)] += c_in[SHIndex(14, -9)] * 0.10677294225083; + c_out[SHIndex(14, -7)] += c_in[SHIndex(14, -7)] * -0.41845703125; + c_out[SHIndex(14, -7)] += c_in[SHIndex(14, -5)] * -0.39271064912769; + c_out[SHIndex(14, -7)] += c_in[SHIndex(14, -3)] * 0.022873774761468; + c_out[SHIndex(14, -7)] += c_in[SHIndex(14, -1)] * 0.39264796001216; + c_out[SHIndex(14, -6)] += c_in[SHIndex(14, 1)] * -0.18176068675697; + c_out[SHIndex(14, -6)] += c_in[SHIndex(14, 3)] * -0.42706950870872; + c_out[SHIndex(14, -6)] += c_in[SHIndex(14, 5)] * -0.3750436280621; + c_out[SHIndex(14, -6)] += c_in[SHIndex(14, 7)] * -0.011075484592006; + c_out[SHIndex(14, -6)] += c_in[SHIndex(14, 9)] * 0.43385279709812; + c_out[SHIndex(14, -6)] += c_in[SHIndex(14, 11)] * 0.46623796657139; + c_out[SHIndex(14, -6)] += c_in[SHIndex(14, 13)] * -0.48804529210874; + c_out[SHIndex(14, -5)] += c_in[SHIndex(14, -13)] * 0.60627913847438; + c_out[SHIndex(14, -5)] += c_in[SHIndex(14, -11)] * -0.1681515785395; + c_out[SHIndex(14, -5)] += c_in[SHIndex(14, -9)] * -0.47892214576017; + c_out[SHIndex(14, -5)] += c_in[SHIndex(14, -7)] * -0.39271064912769; + c_out[SHIndex(14, -5)] += c_in[SHIndex(14, -5)] * -0.099853515625; + c_out[SHIndex(14, -5)] += c_in[SHIndex(14, -3)] * 0.21308945636309; + c_out[SHIndex(14, -5)] += c_in[SHIndex(14, -1)] * 0.40642925122564; + c_out[SHIndex(14, -4)] += c_in[SHIndex(14, 1)] * -0.11794190764568; + c_out[SHIndex(14, -4)] += c_in[SHIndex(14, 3)] * -0.32292413190191; + c_out[SHIndex(14, -4)] += c_in[SHIndex(14, 5)] * -0.43748201605755; + c_out[SHIndex(14, -4)] += c_in[SHIndex(14, 7)] * -0.40964323385176; + c_out[SHIndex(14, -4)] += c_in[SHIndex(14, 9)] * -0.20312265248043; + c_out[SHIndex(14, -4)] += c_in[SHIndex(14, 11)] * 0.18542476450635; + c_out[SHIndex(14, -4)] += c_in[SHIndex(14, 13)] * 0.66855849616849; + c_out[SHIndex(14, -3)] += c_in[SHIndex(14, -13)] * -0.64141717638938; + c_out[SHIndex(14, -3)] += c_in[SHIndex(14, -11)] * -0.45462596516248; + c_out[SHIndex(14, -3)] += c_in[SHIndex(14, -9)] * -0.20931182591491; + c_out[SHIndex(14, -3)] += c_in[SHIndex(14, -7)] * 0.022873774761468; + c_out[SHIndex(14, -3)] += c_in[SHIndex(14, -5)] * 0.21308945636309; + c_out[SHIndex(14, -3)] += c_in[SHIndex(14, -3)] * 0.346435546875; + c_out[SHIndex(14, -3)] += c_in[SHIndex(14, -1)] * 0.41489743677369; + c_out[SHIndex(14, -2)] += c_in[SHIndex(14, 1)] * -0.058097261762847; + c_out[SHIndex(14, -2)] += c_in[SHIndex(14, 3)] * -0.17260776719378; + c_out[SHIndex(14, -2)] += c_in[SHIndex(14, 5)] * -0.28180798175817; + c_out[SHIndex(14, -2)] += c_in[SHIndex(14, 7)] * -0.38115332581581; + c_out[SHIndex(14, -2)] += c_in[SHIndex(14, 9)] * -0.46389892469554; + c_out[SHIndex(14, -2)] += c_in[SHIndex(14, 11)] * -0.51758647408139; + c_out[SHIndex(14, -2)] += c_in[SHIndex(14, 13)] * -0.5089594286692; + c_out[SHIndex(14, -1)] += c_in[SHIndex(14, -13)] * 0.28231989495349; + c_out[SHIndex(14, -1)] += c_in[SHIndex(14, -11)] * 0.33930628577947; + c_out[SHIndex(14, -1)] += c_in[SHIndex(14, -9)] * 0.37169141324942; + c_out[SHIndex(14, -1)] += c_in[SHIndex(14, -7)] * 0.39264796001216; + c_out[SHIndex(14, -1)] += c_in[SHIndex(14, -5)] * 0.40642925122564; + c_out[SHIndex(14, -1)] += c_in[SHIndex(14, -3)] * 0.41489743677369; + c_out[SHIndex(14, -1)] += c_in[SHIndex(14, -1)] * 0.4189453125; + c_out[SHIndex(14, 0)] += c_in[SHIndex(14, 0)] * -0.20947265625; + c_out[SHIndex(14, 0)] += c_in[SHIndex(14, 2)] * -0.29765989046048; + c_out[SHIndex(14, 0)] += c_in[SHIndex(14, 4)] * -0.30213623022215; + c_out[SHIndex(14, 0)] += c_in[SHIndex(14, 6)] * -0.31041546806428; + c_out[SHIndex(14, 0)] += c_in[SHIndex(14, 8)] * -0.32421838231813; + c_out[SHIndex(14, 0)] += c_in[SHIndex(14, 10)] * -0.34768548049628; + c_out[SHIndex(14, 0)] += c_in[SHIndex(14, 12)] * -0.39367628467147; + c_out[SHIndex(14, 0)] += c_in[SHIndex(14, 14)] * -0.54671012572894; + c_out[SHIndex(14, 1)] += c_in[SHIndex(14, -14)] * -0.74694823221281; + c_out[SHIndex(14, 1)] += c_in[SHIndex(14, -12)] * -0.46102645791479; + c_out[SHIndex(14, 1)] += c_in[SHIndex(14, -10)] * -0.33930628577947; + c_out[SHIndex(14, 1)] += c_in[SHIndex(14, -8)] * -0.25312379436441; + c_out[SHIndex(14, 1)] += c_in[SHIndex(14, -6)] * -0.18176068675697; + c_out[SHIndex(14, 1)] += c_in[SHIndex(14, -4)] * -0.11794190764568; + c_out[SHIndex(14, 1)] += c_in[SHIndex(14, -2)] * -0.058097261762847; + c_out[SHIndex(14, 2)] += c_in[SHIndex(14, 0)] * -0.29765989046048; + c_out[SHIndex(14, 2)] += c_in[SHIndex(14, 2)] * -0.4068603515625; + c_out[SHIndex(14, 2)] += c_in[SHIndex(14, 4)] * -0.36391209618543; + c_out[SHIndex(14, 2)] += c_in[SHIndex(14, 6)] * -0.28986522975411; + c_out[SHIndex(14, 2)] += c_in[SHIndex(14, 8)] * -0.17989751732912; + c_out[SHIndex(14, 2)] += c_in[SHIndex(14, 10)] * -0.023526657912791; + c_out[SHIndex(14, 2)] += c_in[SHIndex(14, 12)] * 0.20778181666967; + c_out[SHIndex(14, 2)] += c_in[SHIndex(14, 14)] * 0.67329003784011; + c_out[SHIndex(14, 3)] += c_in[SHIndex(14, -14)] * 0.56567677845719; + c_out[SHIndex(14, 3)] += c_in[SHIndex(14, -12)] * -0.11638109588228; + c_out[SHIndex(14, 3)] += c_in[SHIndex(14, -10)] * -0.37556057991684; + c_out[SHIndex(14, 3)] += c_in[SHIndex(14, -8)] * -0.45711888182303; + c_out[SHIndex(14, 3)] += c_in[SHIndex(14, -6)] * -0.42706950870872; + c_out[SHIndex(14, 3)] += c_in[SHIndex(14, -4)] * -0.32292413190191; + c_out[SHIndex(14, 3)] += c_in[SHIndex(14, -2)] * -0.17260776719378; + c_out[SHIndex(14, 4)] += c_in[SHIndex(14, 0)] * -0.30213623022215; + c_out[SHIndex(14, 4)] += c_in[SHIndex(14, 2)] * -0.36391209618543; + c_out[SHIndex(14, 4)] += c_in[SHIndex(14, 4)] * -0.185791015625; + c_out[SHIndex(14, 4)] += c_in[SHIndex(14, 6)] * 0.069981750766127; + c_out[SHIndex(14, 4)] += c_in[SHIndex(14, 8)] * 0.33717349471455; + c_out[SHIndex(14, 4)] += c_in[SHIndex(14, 10)] * 0.50991810239247; + c_out[SHIndex(14, 4)] += c_in[SHIndex(14, 12)] * 0.40940679470382; + c_out[SHIndex(14, 4)] += c_in[SHIndex(14, 14)] * -0.44220987944029; + c_out[SHIndex(14, 5)] += c_in[SHIndex(14, -14)] * -0.32081276509794; + c_out[SHIndex(14, 5)] += c_in[SHIndex(14, -12)] * 0.59402981238257; + c_out[SHIndex(14, 5)] += c_in[SHIndex(14, -10)] * 0.35648134650374; + c_out[SHIndex(14, 5)] += c_in[SHIndex(14, -8)] * -0.075265034640616; + c_out[SHIndex(14, 5)] += c_in[SHIndex(14, -6)] * -0.3750436280621; + c_out[SHIndex(14, 5)] += c_in[SHIndex(14, -4)] * -0.43748201605755; + c_out[SHIndex(14, 5)] += c_in[SHIndex(14, -2)] * -0.28180798175817; + c_out[SHIndex(14, 6)] += c_in[SHIndex(14, 0)] * -0.31041546806428; + c_out[SHIndex(14, 6)] += c_in[SHIndex(14, 2)] * -0.28986522975411; + c_out[SHIndex(14, 6)] += c_in[SHIndex(14, 4)] * 0.069981750766127; + c_out[SHIndex(14, 6)] += c_in[SHIndex(14, 6)] * 0.4073486328125; + c_out[SHIndex(14, 6)] += c_in[SHIndex(14, 8)] * 0.43617162672689; + c_out[SHIndex(14, 6)] += c_in[SHIndex(14, 10)] * -0.0075199672027644; + c_out[SHIndex(14, 6)] += c_in[SHIndex(14, 12)] * -0.64200733655529; + c_out[SHIndex(14, 6)] += c_in[SHIndex(14, 14)] * 0.2152077452426; + c_out[SHIndex(14, 7)] += c_in[SHIndex(14, -14)] * 0.13282910411489; + c_out[SHIndex(14, 7)] += c_in[SHIndex(14, -12)] * -0.57388732064693; + c_out[SHIndex(14, 7)] += c_in[SHIndex(14, -10)] * 0.35738968834541; + c_out[SHIndex(14, 7)] += c_in[SHIndex(14, -8)] * 0.46051523295669; + c_out[SHIndex(14, 7)] += c_in[SHIndex(14, -6)] * -0.011075484592006; + c_out[SHIndex(14, 7)] += c_in[SHIndex(14, -4)] * -0.40964323385176; + c_out[SHIndex(14, 7)] += c_in[SHIndex(14, -2)] * -0.38115332581581; + c_out[SHIndex(14, 8)] += c_in[SHIndex(14, 0)] * -0.32421838231813; + c_out[SHIndex(14, 8)] += c_in[SHIndex(14, 2)] * -0.17989751732912; + c_out[SHIndex(14, 8)] += c_in[SHIndex(14, 4)] * 0.33717349471455; + c_out[SHIndex(14, 8)] += c_in[SHIndex(14, 6)] * 0.43617162672689; + c_out[SHIndex(14, 8)] += c_in[SHIndex(14, 8)] * -0.13818359375; + c_out[SHIndex(14, 8)] += c_in[SHIndex(14, 10)] * -0.58383998553034; + c_out[SHIndex(14, 8)] += c_in[SHIndex(14, 12)] * 0.43932900265328; + c_out[SHIndex(14, 8)] += c_in[SHIndex(14, 14)] * -0.074925719670686; + c_out[SHIndex(14, 9)] += c_in[SHIndex(14, -14)] * -0.038268604914882; + c_out[SHIndex(14, 9)] += c_in[SHIndex(14, -12)] * 0.29131204754594; + c_out[SHIndex(14, 9)] += c_in[SHIndex(14, -10)] * -0.61645531984834; + c_out[SHIndex(14, 9)] += c_in[SHIndex(14, -8)] * 0.29827230784789; + c_out[SHIndex(14, 9)] += c_in[SHIndex(14, -6)] * 0.43385279709812; + c_out[SHIndex(14, 9)] += c_in[SHIndex(14, -4)] * -0.20312265248043; + c_out[SHIndex(14, 9)] += c_in[SHIndex(14, -2)] * -0.46389892469554; + c_out[SHIndex(14, 10)] += c_in[SHIndex(14, 0)] * -0.34768548049628; + c_out[SHIndex(14, 10)] += c_in[SHIndex(14, 2)] * -0.023526657912791; + c_out[SHIndex(14, 10)] += c_in[SHIndex(14, 4)] * 0.50991810239247; + c_out[SHIndex(14, 10)] += c_in[SHIndex(14, 6)] * -0.0075199672027644; + c_out[SHIndex(14, 10)] += c_in[SHIndex(14, 8)] * -0.58383998553034; + c_out[SHIndex(14, 10)] += c_in[SHIndex(14, 10)] * 0.4993896484375; + c_out[SHIndex(14, 10)] += c_in[SHIndex(14, 12)] * -0.16710485037608; + c_out[SHIndex(14, 10)] += c_in[SHIndex(14, 14)] * 0.017467148463445; + c_out[SHIndex(14, 11)] += c_in[SHIndex(14, -14)] * 0.006986859385378; + c_out[SHIndex(14, 11)] += c_in[SHIndex(14, -12)] * -0.081935281474721; + c_out[SHIndex(14, 11)] += c_in[SHIndex(14, -10)] * 0.323486328125; + c_out[SHIndex(14, 11)] += c_in[SHIndex(14, -8)] * -0.60740303427372; + c_out[SHIndex(14, 11)] += c_in[SHIndex(14, -6)] * 0.46623796657139; + c_out[SHIndex(14, 11)] += c_in[SHIndex(14, -4)] * 0.18542476450635; + c_out[SHIndex(14, 11)] += c_in[SHIndex(14, -2)] * -0.51758647408139; + c_out[SHIndex(14, 12)] += c_in[SHIndex(14, 0)] * -0.39367628467147; + c_out[SHIndex(14, 12)] += c_in[SHIndex(14, 2)] * 0.20778181666967; + c_out[SHIndex(14, 12)] += c_in[SHIndex(14, 4)] * 0.40940679470382; + c_out[SHIndex(14, 12)] += c_in[SHIndex(14, 6)] * -0.64200733655529; + c_out[SHIndex(14, 12)] += c_in[SHIndex(14, 8)] * 0.43932900265328; + c_out[SHIndex(14, 12)] += c_in[SHIndex(14, 10)] * -0.16710485037608; + c_out[SHIndex(14, 12)] += c_in[SHIndex(14, 12)] * 0.033447265625; + c_out[SHIndex(14, 12)] += c_in[SHIndex(14, 14)] * -0.0023733181268583; + c_out[SHIndex(14, 13)] += c_in[SHIndex(14, -14)] * -0.00064593537867788; + c_out[SHIndex(14, 13)] += c_in[SHIndex(14, -12)] * 0.010764359221215; + c_out[SHIndex(14, 13)] += c_in[SHIndex(14, -10)] * -0.066019615639599; + c_out[SHIndex(14, 13)] += c_in[SHIndex(14, -8)] * 0.22655408120134; + c_out[SHIndex(14, 13)] += c_in[SHIndex(14, -6)] * -0.48804529210874; + c_out[SHIndex(14, 13)] += c_in[SHIndex(14, -4)] * 0.66855849616849; + c_out[SHIndex(14, 13)] += c_in[SHIndex(14, -2)] * -0.5089594286692; + c_out[SHIndex(14, 14)] += c_in[SHIndex(14, 0)] * -0.54671012572894; + c_out[SHIndex(14, 14)] += c_in[SHIndex(14, 2)] * 0.67329003784011; + c_out[SHIndex(14, 14)] += c_in[SHIndex(14, 4)] * -0.44220987944029; + c_out[SHIndex(14, 14)] += c_in[SHIndex(14, 6)] * 0.2152077452426; + c_out[SHIndex(14, 14)] += c_in[SHIndex(14, 8)] * -0.074925719670686; + c_out[SHIndex(14, 14)] += c_in[SHIndex(14, 10)] * 0.017467148463445; + c_out[SHIndex(14, 14)] += c_in[SHIndex(14, 12)] * -0.0023733181268583; + c_out[SHIndex(14, 14)] += c_in[SHIndex(14, 14)] * 0.0001220703125; + Assert(lmax == 14); +} + + +#endif diff --git a/core/spectrum.cpp b/core/spectrum.cpp new file mode 100644 index 0000000..949cedb --- /dev/null +++ b/core/spectrum.cpp @@ -0,0 +1,899 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/spectrum.cpp* +#include "stdafx.h" +#include "spectrum.h" + +// Spectrum Method Definitions +bool SpectrumSamplesSorted(const float *lambda, const float *vals, int n) { + for (int i = 0; i < n-1; ++i) + if (lambda[i] > lambda[i+1]) return false; + return true; +} + + +void SortSpectrumSamples(float *lambda, float *vals, int n) { + std::vector > sortVec; + sortVec.reserve(n); + for (int i = 0; i < n; ++i) + sortVec.push_back(std::make_pair(lambda[i], vals[i])); + std::sort(sortVec.begin(), sortVec.end()); + for (int i = 0; i < n; ++i) { + lambda[i] = sortVec[i].first; + vals[i] = sortVec[i].second; + } +} + + +float AverageSpectrumSamples(const float *lambda, const float *vals, + int n, float lambdaStart, float lambdaEnd) { + for (int i = 0; i < n-1; ++i) Assert(lambda[i+1] > lambda[i]); + Assert(lambdaStart < lambdaEnd); + // Handle cases with out-of-bounds range or single sample only + if (lambdaEnd <= lambda[0]) return vals[0]; + if (lambdaStart >= lambda[n-1]) return vals[n-1]; + if (n == 1) return vals[0]; + float sum = 0.f; + // Add contributions of constant segments before/after samples + if (lambdaStart < lambda[0]) + sum += vals[0] * (lambda[0] - lambdaStart); + if (lambdaEnd > lambda[n-1]) + sum += vals[n-1] * (lambdaEnd - lambda[n-1]); + + // Advance to first relevant wavelength segment + int i = 0; + while (lambdaStart > lambda[i+1]) ++i; + Assert(i+1 < n); + + // Loop over wavelength sample segments and add contributions +#define INTERP(w, i) \ + Lerp(((w) - lambda[i]) / (lambda[(i)+1] - lambda[i]), \ + vals[i], vals[(i)+1]) +#define SEG_AVG(wl0, wl1, i) (0.5f * (INTERP(wl0, i) + INTERP(wl1, i))) + for (; i+1 < n && lambdaEnd >= lambda[i]; ++i) { + float segStart = max(lambdaStart, lambda[i]); + float segEnd = min(lambdaEnd, lambda[i+1]); + sum += SEG_AVG(segStart, segEnd, i) * (segEnd - segStart); + } +#undef INTERP +#undef SEG_AVG + return sum / (lambdaEnd - lambdaStart); +} + + +RGBSpectrum SampledSpectrum::ToRGBSpectrum() const { + float rgb[3]; + ToRGB(rgb); + return RGBSpectrum::FromRGB(rgb); +} + + +SampledSpectrum SampledSpectrum::FromRGB(const float rgb[3], + SpectrumType type) { + SampledSpectrum r; + if (type == SPECTRUM_REFLECTANCE) { + // Convert reflectance spectrum to RGB + if (rgb[0] <= rgb[1] && rgb[0] <= rgb[2]) { + // Compute reflectance _SampledSpectrum_ with _rgb[0]_ as minimum + r += rgb[0] * rgbRefl2SpectWhite; + if (rgb[1] <= rgb[2]) { + r += (rgb[1] - rgb[0]) * rgbRefl2SpectCyan; + r += (rgb[2] - rgb[1]) * rgbRefl2SpectBlue; + } + else { + r += (rgb[2] - rgb[0]) * rgbRefl2SpectCyan; + r += (rgb[1] - rgb[2]) * rgbRefl2SpectGreen; + } + } + else if (rgb[1] <= rgb[0] && rgb[1] <= rgb[2]) { + // Compute reflectance _SampledSpectrum_ with _rgb[1]_ as minimum + r += rgb[1] * rgbRefl2SpectWhite; + if (rgb[0] <= rgb[2]) { + r += (rgb[0] - rgb[1]) * rgbRefl2SpectMagenta; + r += (rgb[2] - rgb[0]) * rgbRefl2SpectBlue; + } + else { + r += (rgb[2] - rgb[1]) * rgbRefl2SpectMagenta; + r += (rgb[0] - rgb[2]) * rgbRefl2SpectRed; + } + } + else { + // Compute reflectance _SampledSpectrum_ with _rgb[2]_ as minimum + r += rgb[2] * rgbRefl2SpectWhite; + if (rgb[0] <= rgb[1]) { + r += (rgb[0] - rgb[2]) * rgbRefl2SpectYellow; + r += (rgb[1] - rgb[0]) * rgbRefl2SpectGreen; + } + else { + r += (rgb[1] - rgb[2]) * rgbRefl2SpectYellow; + r += (rgb[0] - rgb[1]) * rgbRefl2SpectRed; + } + } + r *= .94; + } + else { + // Convert illuminant spectrum to RGB + if (rgb[0] <= rgb[1] && rgb[0] <= rgb[2]) { + // Compute illuminant _SampledSpectrum_ with _rgb[0]_ as minimum + r += rgb[0] * rgbIllum2SpectWhite; + if (rgb[1] <= rgb[2]) { + r += (rgb[1] - rgb[0]) * rgbIllum2SpectCyan; + r += (rgb[2] - rgb[1]) * rgbIllum2SpectBlue; + } + else { + r += (rgb[2] - rgb[0]) * rgbIllum2SpectCyan; + r += (rgb[1] - rgb[2]) * rgbIllum2SpectGreen; + } + } + else if (rgb[1] <= rgb[0] && rgb[1] <= rgb[2]) { + // Compute illuminant _SampledSpectrum_ with _rgb[1]_ as minimum + r += rgb[1] * rgbIllum2SpectWhite; + if (rgb[0] <= rgb[2]) { + r += (rgb[0] - rgb[1]) * rgbIllum2SpectMagenta; + r += (rgb[2] - rgb[0]) * rgbIllum2SpectBlue; + } + else { + r += (rgb[2] - rgb[1]) * rgbIllum2SpectMagenta; + r += (rgb[0] - rgb[2]) * rgbIllum2SpectRed; + } + } + else { + // Compute illuminant _SampledSpectrum_ with _rgb[2]_ as minimum + r += rgb[2] * rgbIllum2SpectWhite; + if (rgb[0] <= rgb[1]) { + r += (rgb[0] - rgb[2]) * rgbIllum2SpectYellow; + r += (rgb[1] - rgb[0]) * rgbIllum2SpectGreen; + } + else { + r += (rgb[1] - rgb[2]) * rgbIllum2SpectYellow; + r += (rgb[0] - rgb[1]) * rgbIllum2SpectRed; + } + } + r *= .86445f; + } + return r.Clamp(); +} + + +SampledSpectrum::SampledSpectrum(const RGBSpectrum &r, SpectrumType t) { + float rgb[3]; + r.ToRGB(rgb); + *this = SampledSpectrum::FromRGB(rgb, t); +} + + +void Blackbody(const float *wl, int n, float temp, float *vals) { + if (temp <= 0) { + for (int i = 0; i < n; ++i) vals[i] = 0.f; + return; + } + const double C2 = 1.4388e7; + double norm = pow(555.0, 5.0) * (exp(C2/(555.0*temp)) - 1.); + for (int i = 0; i < n; ++i) + vals[i] = float(norm/(pow(double(wl[i]), 5.0)*(exp(C2/(wl[i]*temp))-1.))); +} + + +float InterpolateSpectrumSamples(const float *lambda, const float *vals, + int n, float l) { + for (int i = 0; i < n-1; ++i) Assert(lambda[i+1] > lambda[i]); + if (l <= lambda[0]) return vals[0]; + if (l >= lambda[n-1]) return vals[n-1]; + for (int i = 0; i < n-1; ++i) { + if (l >= lambda[i] && l <= lambda[i+1]) { + float t = (l - lambda[i]) / (lambda[i+1] - lambda[i]); + return Lerp(t, vals[i], vals[i+1]); + } + } + Severe("Fatal logic error in InterpolateSpectrumSamples()"); + return 0.f; +} + + +const float CIE_X[nCIESamples] = { + // CIE X function values + 0.0001299000f, 0.0001458470f, 0.0001638021f, 0.0001840037f, + 0.0002066902f, 0.0002321000f, 0.0002607280f, 0.0002930750f, + 0.0003293880f, 0.0003699140f, 0.0004149000f, 0.0004641587f, + 0.0005189860f, 0.0005818540f, 0.0006552347f, 0.0007416000f, + 0.0008450296f, 0.0009645268f, 0.001094949f, 0.001231154f, + 0.001368000f, 0.001502050f, 0.001642328f, 0.001802382f, + 0.001995757f, 0.002236000f, 0.002535385f, 0.002892603f, + 0.003300829f, 0.003753236f, 0.004243000f, 0.004762389f, + 0.005330048f, 0.005978712f, 0.006741117f, 0.007650000f, + 0.008751373f, 0.01002888f, 0.01142170f, 0.01286901f, + 0.01431000f, 0.01570443f, 0.01714744f, 0.01878122f, + 0.02074801f, 0.02319000f, 0.02620736f, 0.02978248f, + 0.03388092f, 0.03846824f, 0.04351000f, 0.04899560f, + 0.05502260f, 0.06171880f, 0.06921200f, 0.07763000f, + 0.08695811f, 0.09717672f, 0.1084063f, 0.1207672f, + 0.1343800f, 0.1493582f, 0.1653957f, 0.1819831f, + 0.1986110f, 0.2147700f, 0.2301868f, 0.2448797f, + 0.2587773f, 0.2718079f, 0.2839000f, 0.2949438f, + 0.3048965f, 0.3137873f, 0.3216454f, 0.3285000f, + 0.3343513f, 0.3392101f, 0.3431213f, 0.3461296f, + 0.3482800f, 0.3495999f, 0.3501474f, 0.3500130f, + 0.3492870f, 0.3480600f, 0.3463733f, 0.3442624f, + 0.3418088f, 0.3390941f, 0.3362000f, 0.3331977f, + 0.3300411f, 0.3266357f, 0.3228868f, 0.3187000f, + 0.3140251f, 0.3088840f, 0.3032904f, 0.2972579f, + 0.2908000f, 0.2839701f, 0.2767214f, 0.2689178f, + 0.2604227f, 0.2511000f, 0.2408475f, 0.2298512f, + 0.2184072f, 0.2068115f, 0.1953600f, 0.1842136f, + 0.1733273f, 0.1626881f, 0.1522833f, 0.1421000f, + 0.1321786f, 0.1225696f, 0.1132752f, 0.1042979f, + 0.09564000f, 0.08729955f, 0.07930804f, 0.07171776f, + 0.06458099f, 0.05795001f, 0.05186211f, 0.04628152f, + 0.04115088f, 0.03641283f, 0.03201000f, 0.02791720f, + 0.02414440f, 0.02068700f, 0.01754040f, 0.01470000f, + 0.01216179f, 0.009919960f, 0.007967240f, 0.006296346f, + 0.004900000f, 0.003777173f, 0.002945320f, 0.002424880f, + 0.002236293f, 0.002400000f, 0.002925520f, 0.003836560f, + 0.005174840f, 0.006982080f, 0.009300000f, 0.01214949f, + 0.01553588f, 0.01947752f, 0.02399277f, 0.02910000f, + 0.03481485f, 0.04112016f, 0.04798504f, 0.05537861f, + 0.06327000f, 0.07163501f, 0.08046224f, 0.08973996f, + 0.09945645f, 0.1096000f, 0.1201674f, 0.1311145f, + 0.1423679f, 0.1538542f, 0.1655000f, 0.1772571f, + 0.1891400f, 0.2011694f, 0.2133658f, 0.2257499f, + 0.2383209f, 0.2510668f, 0.2639922f, 0.2771017f, + 0.2904000f, 0.3038912f, 0.3175726f, 0.3314384f, + 0.3454828f, 0.3597000f, 0.3740839f, 0.3886396f, + 0.4033784f, 0.4183115f, 0.4334499f, 0.4487953f, + 0.4643360f, 0.4800640f, 0.4959713f, 0.5120501f, + 0.5282959f, 0.5446916f, 0.5612094f, 0.5778215f, + 0.5945000f, 0.6112209f, 0.6279758f, 0.6447602f, + 0.6615697f, 0.6784000f, 0.6952392f, 0.7120586f, + 0.7288284f, 0.7455188f, 0.7621000f, 0.7785432f, + 0.7948256f, 0.8109264f, 0.8268248f, 0.8425000f, + 0.8579325f, 0.8730816f, 0.8878944f, 0.9023181f, + 0.9163000f, 0.9297995f, 0.9427984f, 0.9552776f, + 0.9672179f, 0.9786000f, 0.9893856f, 0.9995488f, + 1.0090892f, 1.0180064f, 1.0263000f, 1.0339827f, + 1.0409860f, 1.0471880f, 1.0524667f, 1.0567000f, + 1.0597944f, 1.0617992f, 1.0628068f, 1.0629096f, + 1.0622000f, 1.0607352f, 1.0584436f, 1.0552244f, + 1.0509768f, 1.0456000f, 1.0390369f, 1.0313608f, + 1.0226662f, 1.0130477f, 1.0026000f, 0.9913675f, + 0.9793314f, 0.9664916f, 0.9528479f, 0.9384000f, + 0.9231940f, 0.9072440f, 0.8905020f, 0.8729200f, + 0.8544499f, 0.8350840f, 0.8149460f, 0.7941860f, + 0.7729540f, 0.7514000f, 0.7295836f, 0.7075888f, + 0.6856022f, 0.6638104f, 0.6424000f, 0.6215149f, + 0.6011138f, 0.5811052f, 0.5613977f, 0.5419000f, + 0.5225995f, 0.5035464f, 0.4847436f, 0.4661939f, + 0.4479000f, 0.4298613f, 0.4120980f, 0.3946440f, + 0.3775333f, 0.3608000f, 0.3444563f, 0.3285168f, + 0.3130192f, 0.2980011f, 0.2835000f, 0.2695448f, + 0.2561184f, 0.2431896f, 0.2307272f, 0.2187000f, + 0.2070971f, 0.1959232f, 0.1851708f, 0.1748323f, + 0.1649000f, 0.1553667f, 0.1462300f, 0.1374900f, + 0.1291467f, 0.1212000f, 0.1136397f, 0.1064650f, + 0.09969044f, 0.09333061f, 0.08740000f, 0.08190096f, + 0.07680428f, 0.07207712f, 0.06768664f, 0.06360000f, + 0.05980685f, 0.05628216f, 0.05297104f, 0.04981861f, + 0.04677000f, 0.04378405f, 0.04087536f, 0.03807264f, + 0.03540461f, 0.03290000f, 0.03056419f, 0.02838056f, + 0.02634484f, 0.02445275f, 0.02270000f, 0.02108429f, + 0.01959988f, 0.01823732f, 0.01698717f, 0.01584000f, + 0.01479064f, 0.01383132f, 0.01294868f, 0.01212920f, + 0.01135916f, 0.01062935f, 0.009938846f, 0.009288422f, + 0.008678854f, 0.008110916f, 0.007582388f, 0.007088746f, + 0.006627313f, 0.006195408f, 0.005790346f, 0.005409826f, + 0.005052583f, 0.004717512f, 0.004403507f, 0.004109457f, + 0.003833913f, 0.003575748f, 0.003334342f, 0.003109075f, + 0.002899327f, 0.002704348f, 0.002523020f, 0.002354168f, + 0.002196616f, 0.002049190f, 0.001910960f, 0.001781438f, + 0.001660110f, 0.001546459f, 0.001439971f, 0.001340042f, + 0.001246275f, 0.001158471f, 0.001076430f, 0.0009999493f, + 0.0009287358f, 0.0008624332f, 0.0008007503f, 0.0007433960f, + 0.0006900786f, 0.0006405156f, 0.0005945021f, 0.0005518646f, + 0.0005124290f, 0.0004760213f, 0.0004424536f, 0.0004115117f, + 0.0003829814f, 0.0003566491f, 0.0003323011f, 0.0003097586f, + 0.0002888871f, 0.0002695394f, 0.0002515682f, 0.0002348261f, + 0.0002191710f, 0.0002045258f, 0.0001908405f, 0.0001780654f, + 0.0001661505f, 0.0001550236f, 0.0001446219f, 0.0001349098f, + 0.0001258520f, 0.0001174130f, 0.0001095515f, 0.0001022245f, + 0.00009539445f, 0.00008902390f, 0.00008307527f, 0.00007751269f, + 0.00007231304f, 0.00006745778f, 0.00006292844f, 0.00005870652f, + 0.00005477028f, 0.00005109918f, 0.00004767654f, 0.00004448567f, + 0.00004150994f, 0.00003873324f, 0.00003614203f, 0.00003372352f, + 0.00003146487f, 0.00002935326f, 0.00002737573f, 0.00002552433f, + 0.00002379376f, 0.00002217870f, 0.00002067383f, 0.00001927226f, + 0.00001796640f, 0.00001674991f, 0.00001561648f, 0.00001455977f, + 0.00001357387f, 0.00001265436f, 0.00001179723f, 0.00001099844f, + 0.00001025398f, 0.000009559646f, 0.000008912044f, 0.000008308358f, + 0.000007745769f, 0.000007221456f, 0.000006732475f, 0.000006276423f, + 0.000005851304f, 0.000005455118f, 0.000005085868f, 0.000004741466f, + 0.000004420236f, 0.000004120783f, 0.000003841716f, 0.000003581652f, + 0.000003339127f, 0.000003112949f, 0.000002902121f, 0.000002705645f, + 0.000002522525f, 0.000002351726f, 0.000002192415f, 0.000002043902f, + 0.000001905497f, 0.000001776509f, 0.000001656215f, 0.000001544022f, + 0.000001439440f, 0.000001341977f, 0.000001251141f +}; + + +const float CIE_Y[nCIESamples] = { + // CIE Y function values + 0.000003917000f, 0.000004393581f, 0.000004929604f, 0.000005532136f, + 0.000006208245f, 0.000006965000f, 0.000007813219f, 0.000008767336f, + 0.000009839844f, 0.00001104323f, 0.00001239000f, 0.00001388641f, + 0.00001555728f, 0.00001744296f, 0.00001958375f, 0.00002202000f, + 0.00002483965f, 0.00002804126f, 0.00003153104f, 0.00003521521f, + 0.00003900000f, 0.00004282640f, 0.00004691460f, 0.00005158960f, + 0.00005717640f, 0.00006400000f, 0.00007234421f, 0.00008221224f, + 0.00009350816f, 0.0001061361f, 0.0001200000f, 0.0001349840f, + 0.0001514920f, 0.0001702080f, 0.0001918160f, 0.0002170000f, + 0.0002469067f, 0.0002812400f, 0.0003185200f, 0.0003572667f, + 0.0003960000f, 0.0004337147f, 0.0004730240f, 0.0005178760f, + 0.0005722187f, 0.0006400000f, 0.0007245600f, 0.0008255000f, + 0.0009411600f, 0.001069880f, 0.001210000f, 0.001362091f, + 0.001530752f, 0.001720368f, 0.001935323f, 0.002180000f, + 0.002454800f, 0.002764000f, 0.003117800f, 0.003526400f, + 0.004000000f, 0.004546240f, 0.005159320f, 0.005829280f, + 0.006546160f, 0.007300000f, 0.008086507f, 0.008908720f, + 0.009767680f, 0.01066443f, 0.01160000f, 0.01257317f, + 0.01358272f, 0.01462968f, 0.01571509f, 0.01684000f, + 0.01800736f, 0.01921448f, 0.02045392f, 0.02171824f, + 0.02300000f, 0.02429461f, 0.02561024f, 0.02695857f, + 0.02835125f, 0.02980000f, 0.03131083f, 0.03288368f, + 0.03452112f, 0.03622571f, 0.03800000f, 0.03984667f, + 0.04176800f, 0.04376600f, 0.04584267f, 0.04800000f, + 0.05024368f, 0.05257304f, 0.05498056f, 0.05745872f, + 0.06000000f, 0.06260197f, 0.06527752f, 0.06804208f, + 0.07091109f, 0.07390000f, 0.07701600f, 0.08026640f, + 0.08366680f, 0.08723280f, 0.09098000f, 0.09491755f, + 0.09904584f, 0.1033674f, 0.1078846f, 0.1126000f, + 0.1175320f, 0.1226744f, 0.1279928f, 0.1334528f, + 0.1390200f, 0.1446764f, 0.1504693f, 0.1564619f, + 0.1627177f, 0.1693000f, 0.1762431f, 0.1835581f, + 0.1912735f, 0.1994180f, 0.2080200f, 0.2171199f, + 0.2267345f, 0.2368571f, 0.2474812f, 0.2586000f, + 0.2701849f, 0.2822939f, 0.2950505f, 0.3085780f, + 0.3230000f, 0.3384021f, 0.3546858f, 0.3716986f, + 0.3892875f, 0.4073000f, 0.4256299f, 0.4443096f, + 0.4633944f, 0.4829395f, 0.5030000f, 0.5235693f, + 0.5445120f, 0.5656900f, 0.5869653f, 0.6082000f, + 0.6293456f, 0.6503068f, 0.6708752f, 0.6908424f, + 0.7100000f, 0.7281852f, 0.7454636f, 0.7619694f, + 0.7778368f, 0.7932000f, 0.8081104f, 0.8224962f, + 0.8363068f, 0.8494916f, 0.8620000f, 0.8738108f, + 0.8849624f, 0.8954936f, 0.9054432f, 0.9148501f, + 0.9237348f, 0.9320924f, 0.9399226f, 0.9472252f, + 0.9540000f, 0.9602561f, 0.9660074f, 0.9712606f, + 0.9760225f, 0.9803000f, 0.9840924f, 0.9874812f, + 0.9903128f, 0.9928116f, 0.9949501f, 0.9967108f, + 0.9980983f, 0.9991120f, 0.9997482f, 1.0000000f, + 0.9998567f, 0.9993046f, 0.9983255f, 0.9968987f, + 0.9950000f, 0.9926005f, 0.9897426f, 0.9864444f, + 0.9827241f, 0.9786000f, 0.9740837f, 0.9691712f, + 0.9638568f, 0.9581349f, 0.9520000f, 0.9454504f, + 0.9384992f, 0.9311628f, 0.9234576f, 0.9154000f, + 0.9070064f, 0.8982772f, 0.8892048f, 0.8797816f, + 0.8700000f, 0.8598613f, 0.8493920f, 0.8386220f, + 0.8275813f, 0.8163000f, 0.8047947f, 0.7930820f, + 0.7811920f, 0.7691547f, 0.7570000f, 0.7447541f, + 0.7324224f, 0.7200036f, 0.7074965f, 0.6949000f, + 0.6822192f, 0.6694716f, 0.6566744f, 0.6438448f, + 0.6310000f, 0.6181555f, 0.6053144f, 0.5924756f, + 0.5796379f, 0.5668000f, 0.5539611f, 0.5411372f, + 0.5283528f, 0.5156323f, 0.5030000f, 0.4904688f, + 0.4780304f, 0.4656776f, 0.4534032f, 0.4412000f, + 0.4290800f, 0.4170360f, 0.4050320f, 0.3930320f, + 0.3810000f, 0.3689184f, 0.3568272f, 0.3447768f, + 0.3328176f, 0.3210000f, 0.3093381f, 0.2978504f, + 0.2865936f, 0.2756245f, 0.2650000f, 0.2547632f, + 0.2448896f, 0.2353344f, 0.2260528f, 0.2170000f, + 0.2081616f, 0.1995488f, 0.1911552f, 0.1829744f, + 0.1750000f, 0.1672235f, 0.1596464f, 0.1522776f, + 0.1451259f, 0.1382000f, 0.1315003f, 0.1250248f, + 0.1187792f, 0.1127691f, 0.1070000f, 0.1014762f, + 0.09618864f, 0.09112296f, 0.08626485f, 0.08160000f, + 0.07712064f, 0.07282552f, 0.06871008f, 0.06476976f, + 0.06100000f, 0.05739621f, 0.05395504f, 0.05067376f, + 0.04754965f, 0.04458000f, 0.04175872f, 0.03908496f, + 0.03656384f, 0.03420048f, 0.03200000f, 0.02996261f, + 0.02807664f, 0.02632936f, 0.02470805f, 0.02320000f, + 0.02180077f, 0.02050112f, 0.01928108f, 0.01812069f, + 0.01700000f, 0.01590379f, 0.01483718f, 0.01381068f, + 0.01283478f, 0.01192000f, 0.01106831f, 0.01027339f, + 0.009533311f, 0.008846157f, 0.008210000f, 0.007623781f, + 0.007085424f, 0.006591476f, 0.006138485f, 0.005723000f, + 0.005343059f, 0.004995796f, 0.004676404f, 0.004380075f, + 0.004102000f, 0.003838453f, 0.003589099f, 0.003354219f, + 0.003134093f, 0.002929000f, 0.002738139f, 0.002559876f, + 0.002393244f, 0.002237275f, 0.002091000f, 0.001953587f, + 0.001824580f, 0.001703580f, 0.001590187f, 0.001484000f, + 0.001384496f, 0.001291268f, 0.001204092f, 0.001122744f, + 0.001047000f, 0.0009765896f, 0.0009111088f, 0.0008501332f, + 0.0007932384f, 0.0007400000f, 0.0006900827f, 0.0006433100f, + 0.0005994960f, 0.0005584547f, 0.0005200000f, 0.0004839136f, + 0.0004500528f, 0.0004183452f, 0.0003887184f, 0.0003611000f, + 0.0003353835f, 0.0003114404f, 0.0002891656f, 0.0002684539f, + 0.0002492000f, 0.0002313019f, 0.0002146856f, 0.0001992884f, + 0.0001850475f, 0.0001719000f, 0.0001597781f, 0.0001486044f, + 0.0001383016f, 0.0001287925f, 0.0001200000f, 0.0001118595f, + 0.0001043224f, 0.00009733560f, 0.00009084587f, 0.00008480000f, + 0.00007914667f, 0.00007385800f, 0.00006891600f, 0.00006430267f, + 0.00006000000f, 0.00005598187f, 0.00005222560f, 0.00004871840f, + 0.00004544747f, 0.00004240000f, 0.00003956104f, 0.00003691512f, + 0.00003444868f, 0.00003214816f, 0.00003000000f, 0.00002799125f, + 0.00002611356f, 0.00002436024f, 0.00002272461f, 0.00002120000f, + 0.00001977855f, 0.00001845285f, 0.00001721687f, 0.00001606459f, + 0.00001499000f, 0.00001398728f, 0.00001305155f, 0.00001217818f, + 0.00001136254f, 0.00001060000f, 0.000009885877f, 0.000009217304f, + 0.000008592362f, 0.000008009133f, 0.000007465700f, 0.000006959567f, + 0.000006487995f, 0.000006048699f, 0.000005639396f, 0.000005257800f, + 0.000004901771f, 0.000004569720f, 0.000004260194f, 0.000003971739f, + 0.000003702900f, 0.000003452163f, 0.000003218302f, 0.000003000300f, + 0.000002797139f, 0.000002607800f, 0.000002431220f, 0.000002266531f, + 0.000002113013f, 0.000001969943f, 0.000001836600f, 0.000001712230f, + 0.000001596228f, 0.000001488090f, 0.000001387314f, 0.000001293400f, + 0.000001205820f, 0.000001124143f, 0.000001048009f, 0.0000009770578f, + 0.0000009109300f, 0.0000008492513f, 0.0000007917212f, 0.0000007380904f, + 0.0000006881098f, 0.0000006415300f, 0.0000005980895f, 0.0000005575746f, + 0.0000005198080f, 0.0000004846123f, 0.0000004518100f +}; + + +const float CIE_Z[nCIESamples] = { + // CIE Z function values + 0.0006061000f, 0.0006808792f, 0.0007651456f, 0.0008600124f, + 0.0009665928f, 0.001086000f, 0.001220586f, 0.001372729f, + 0.001543579f, 0.001734286f, 0.001946000f, 0.002177777f, + 0.002435809f, 0.002731953f, 0.003078064f, 0.003486000f, + 0.003975227f, 0.004540880f, 0.005158320f, 0.005802907f, + 0.006450001f, 0.007083216f, 0.007745488f, 0.008501152f, + 0.009414544f, 0.01054999f, 0.01196580f, 0.01365587f, + 0.01558805f, 0.01773015f, 0.02005001f, 0.02251136f, + 0.02520288f, 0.02827972f, 0.03189704f, 0.03621000f, + 0.04143771f, 0.04750372f, 0.05411988f, 0.06099803f, + 0.06785001f, 0.07448632f, 0.08136156f, 0.08915364f, + 0.09854048f, 0.1102000f, 0.1246133f, 0.1417017f, + 0.1613035f, 0.1832568f, 0.2074000f, 0.2336921f, + 0.2626114f, 0.2947746f, 0.3307985f, 0.3713000f, + 0.4162091f, 0.4654642f, 0.5196948f, 0.5795303f, + 0.6456000f, 0.7184838f, 0.7967133f, 0.8778459f, + 0.9594390f, 1.0390501f, 1.1153673f, 1.1884971f, + 1.2581233f, 1.3239296f, 1.3856000f, 1.4426352f, + 1.4948035f, 1.5421903f, 1.5848807f, 1.6229600f, + 1.6564048f, 1.6852959f, 1.7098745f, 1.7303821f, + 1.7470600f, 1.7600446f, 1.7696233f, 1.7762637f, + 1.7804334f, 1.7826000f, 1.7829682f, 1.7816998f, + 1.7791982f, 1.7758671f, 1.7721100f, 1.7682589f, + 1.7640390f, 1.7589438f, 1.7524663f, 1.7441000f, + 1.7335595f, 1.7208581f, 1.7059369f, 1.6887372f, + 1.6692000f, 1.6475287f, 1.6234127f, 1.5960223f, + 1.5645280f, 1.5281000f, 1.4861114f, 1.4395215f, + 1.3898799f, 1.3387362f, 1.2876400f, 1.2374223f, + 1.1878243f, 1.1387611f, 1.0901480f, 1.0419000f, + 0.9941976f, 0.9473473f, 0.9014531f, 0.8566193f, + 0.8129501f, 0.7705173f, 0.7294448f, 0.6899136f, + 0.6521049f, 0.6162000f, 0.5823286f, 0.5504162f, + 0.5203376f, 0.4919673f, 0.4651800f, 0.4399246f, + 0.4161836f, 0.3938822f, 0.3729459f, 0.3533000f, + 0.3348578f, 0.3175521f, 0.3013375f, 0.2861686f, + 0.2720000f, 0.2588171f, 0.2464838f, 0.2347718f, + 0.2234533f, 0.2123000f, 0.2011692f, 0.1901196f, + 0.1792254f, 0.1685608f, 0.1582000f, 0.1481383f, + 0.1383758f, 0.1289942f, 0.1200751f, 0.1117000f, + 0.1039048f, 0.09666748f, 0.08998272f, 0.08384531f, + 0.07824999f, 0.07320899f, 0.06867816f, 0.06456784f, + 0.06078835f, 0.05725001f, 0.05390435f, 0.05074664f, + 0.04775276f, 0.04489859f, 0.04216000f, 0.03950728f, + 0.03693564f, 0.03445836f, 0.03208872f, 0.02984000f, + 0.02771181f, 0.02569444f, 0.02378716f, 0.02198925f, + 0.02030000f, 0.01871805f, 0.01724036f, 0.01586364f, + 0.01458461f, 0.01340000f, 0.01230723f, 0.01130188f, + 0.01037792f, 0.009529306f, 0.008749999f, 0.008035200f, + 0.007381600f, 0.006785400f, 0.006242800f, 0.005749999f, + 0.005303600f, 0.004899800f, 0.004534200f, 0.004202400f, + 0.003900000f, 0.003623200f, 0.003370600f, 0.003141400f, + 0.002934800f, 0.002749999f, 0.002585200f, 0.002438600f, + 0.002309400f, 0.002196800f, 0.002100000f, 0.002017733f, + 0.001948200f, 0.001889800f, 0.001840933f, 0.001800000f, + 0.001766267f, 0.001737800f, 0.001711200f, 0.001683067f, + 0.001650001f, 0.001610133f, 0.001564400f, 0.001513600f, + 0.001458533f, 0.001400000f, 0.001336667f, 0.001270000f, + 0.001205000f, 0.001146667f, 0.001100000f, 0.001068800f, + 0.001049400f, 0.001035600f, 0.001021200f, 0.001000000f, + 0.0009686400f, 0.0009299200f, 0.0008868800f, 0.0008425600f, + 0.0008000000f, 0.0007609600f, 0.0007236800f, 0.0006859200f, + 0.0006454400f, 0.0006000000f, 0.0005478667f, 0.0004916000f, + 0.0004354000f, 0.0003834667f, 0.0003400000f, 0.0003072533f, + 0.0002831600f, 0.0002654400f, 0.0002518133f, 0.0002400000f, + 0.0002295467f, 0.0002206400f, 0.0002119600f, 0.0002021867f, + 0.0001900000f, 0.0001742133f, 0.0001556400f, 0.0001359600f, + 0.0001168533f, 0.0001000000f, 0.00008613333f, 0.00007460000f, + 0.00006500000f, 0.00005693333f, 0.00004999999f, 0.00004416000f, + 0.00003948000f, 0.00003572000f, 0.00003264000f, 0.00003000000f, + 0.00002765333f, 0.00002556000f, 0.00002364000f, 0.00002181333f, + 0.00002000000f, 0.00001813333f, 0.00001620000f, 0.00001420000f, + 0.00001213333f, 0.00001000000f, 0.000007733333f, 0.000005400000f, + 0.000003200000f, 0.000001333333f, 0.000000000000f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f +}; + + +const float CIE_lambda[nCIESamples] = { + 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, + 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, + 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, + 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, + 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, + 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, + 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, + 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, + 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, + 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, + 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, + 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, + 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, + 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, + 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, + 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, + 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, + 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, + 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, + 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, + 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, + 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, + 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, + 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, + 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, + 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, + 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, + 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, + 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, + 822, 823, 824, 825, 826, 827, 828, 829, 830 }; + +// Spectral Data Definitions +SampledSpectrum SampledSpectrum::X; +SampledSpectrum SampledSpectrum::Y; +SampledSpectrum SampledSpectrum::Z; +float SampledSpectrum::yint; +SampledSpectrum SampledSpectrum::rgbRefl2SpectWhite; +SampledSpectrum SampledSpectrum::rgbRefl2SpectCyan; +SampledSpectrum SampledSpectrum::rgbRefl2SpectMagenta; +SampledSpectrum SampledSpectrum::rgbRefl2SpectYellow; +SampledSpectrum SampledSpectrum::rgbRefl2SpectRed; +SampledSpectrum SampledSpectrum::rgbRefl2SpectGreen; +SampledSpectrum SampledSpectrum::rgbRefl2SpectBlue; +SampledSpectrum SampledSpectrum::rgbIllum2SpectWhite; +SampledSpectrum SampledSpectrum::rgbIllum2SpectCyan; +SampledSpectrum SampledSpectrum::rgbIllum2SpectMagenta; +SampledSpectrum SampledSpectrum::rgbIllum2SpectYellow; +SampledSpectrum SampledSpectrum::rgbIllum2SpectRed; +SampledSpectrum SampledSpectrum::rgbIllum2SpectGreen; +SampledSpectrum SampledSpectrum::rgbIllum2SpectBlue; +const float RGB2SpectLambda[nRGB2SpectSamples] = { + 380.000000, 390.967743, 401.935486, 412.903229, 423.870972, 434.838715, + 445.806458, 456.774200, 467.741943, 478.709686, 489.677429, 500.645172, + 511.612915, 522.580627, 533.548340, 544.516052, 555.483765, 566.451477, + 577.419189, 588.386902, 599.354614, 610.322327, 621.290039, 632.257751, + 643.225464, 654.193176, 665.160889, 676.128601, 687.096313, 698.064026, + 709.031738, 720.000000 +}; + + + +const float RGBRefl2SpectWhite[nRGB2SpectSamples] = { + 1.0618958571272863e+00, 1.0615019980348779e+00, + 1.0614335379927147e+00, 1.0622711654692485e+00, + 1.0622036218416742e+00, 1.0625059965187085e+00, + 1.0623938486985884e+00, 1.0624706448043137e+00, + 1.0625048144827762e+00, 1.0624366131308856e+00, + 1.0620694238892607e+00, 1.0613167586932164e+00, + 1.0610334029377020e+00, 1.0613868564828413e+00, + 1.0614215366116762e+00, 1.0620336151299086e+00, + 1.0625497454805051e+00, 1.0624317487992085e+00, + 1.0625249140554480e+00, 1.0624277664486914e+00, + 1.0624749854090769e+00, 1.0625538581025402e+00, + 1.0625326910104864e+00, 1.0623922312225325e+00, + 1.0623650980354129e+00, 1.0625256476715284e+00, + 1.0612277619533155e+00, 1.0594262608698046e+00, + 1.0599810758292072e+00, 1.0602547314449409e+00, + 1.0601263046243634e+00, 1.0606565756823634e+00 }; + +const float RGBRefl2SpectCyan[nRGB2SpectSamples] = { + 1.0414628021426751e+00, 1.0328661533771188e+00, + 1.0126146228964314e+00, 1.0350460524836209e+00, + 1.0078661447098567e+00, 1.0422280385081280e+00, + 1.0442596738499825e+00, 1.0535238290294409e+00, + 1.0180776226938120e+00, 1.0442729908727713e+00, + 1.0529362541920750e+00, 1.0537034271160244e+00, + 1.0533901869215969e+00, 1.0537782700979574e+00, + 1.0527093770467102e+00, 1.0530449040446797e+00, + 1.0550554640191208e+00, 1.0553673610724821e+00, + 1.0454306634683976e+00, 6.2348950639230805e-01, + 1.8038071613188977e-01, -7.6303759201984539e-03, + -1.5217847035781367e-04, -7.5102257347258311e-03, + -2.1708639328491472e-03, 6.5919466602369636e-04, + 1.2278815318539780e-02, -4.4669775637208031e-03, + 1.7119799082865147e-02, 4.9211089759759801e-03, + 5.8762925143334985e-03, 2.5259399415550079e-02 }; + +const float RGBRefl2SpectMagenta[nRGB2SpectSamples] = { + 9.9422138151236850e-01, 9.8986937122975682e-01, + 9.8293658286116958e-01, 9.9627868399859310e-01, + 1.0198955019000133e+00, 1.0166395501210359e+00, + 1.0220913178757398e+00, 9.9651666040682441e-01, + 1.0097766178917882e+00, 1.0215422470827016e+00, + 6.4031953387790963e-01, 2.5012379477078184e-03, + 6.5339939555769944e-03, 2.8334080462675826e-03, + -5.1209675389074505e-11, -9.0592291646646381e-03, + 3.3936718323331200e-03, -3.0638741121828406e-03, + 2.2203936168286292e-01, 6.3141140024811970e-01, + 9.7480985576500956e-01, 9.7209562333590571e-01, + 1.0173770302868150e+00, 9.9875194322734129e-01, + 9.4701725739602238e-01, 8.5258623154354796e-01, + 9.4897798581660842e-01, 9.4751876096521492e-01, + 9.9598944191059791e-01, 8.6301351503809076e-01, + 8.9150987853523145e-01, 8.4866492652845082e-01 }; + +const float RGBRefl2SpectYellow[nRGB2SpectSamples] = { + 5.5740622924920873e-03, -4.7982831631446787e-03, + -5.2536564298613798e-03, -6.4571480044499710e-03, + -5.9693514658007013e-03, -2.1836716037686721e-03, + 1.6781120601055327e-02, 9.6096355429062641e-02, + 2.1217357081986446e-01, 3.6169133290685068e-01, + 5.3961011543232529e-01, 7.4408810492171507e-01, + 9.2209571148394054e-01, 1.0460304298411225e+00, + 1.0513824989063714e+00, 1.0511991822135085e+00, + 1.0510530911991052e+00, 1.0517397230360510e+00, + 1.0516043086790485e+00, 1.0511944032061460e+00, + 1.0511590325868068e+00, 1.0516612465483031e+00, + 1.0514038526836869e+00, 1.0515941029228475e+00, + 1.0511460436960840e+00, 1.0515123758830476e+00, + 1.0508871369510702e+00, 1.0508923708102380e+00, + 1.0477492815668303e+00, 1.0493272144017338e+00, + 1.0435963333422726e+00, 1.0392280772051465e+00 }; + +const float RGBRefl2SpectRed[nRGB2SpectSamples] = { + 1.6575604867086180e-01, 1.1846442802747797e-01, + 1.2408293329637447e-01, 1.1371272058349924e-01, + 7.8992434518899132e-02, 3.2205603593106549e-02, + -1.0798365407877875e-02, 1.8051975516730392e-02, + 5.3407196598730527e-03, 1.3654918729501336e-02, + -5.9564213545642841e-03, -1.8444365067353252e-03, + -1.0571884361529504e-02, -2.9375521078000011e-03, + -1.0790476271835936e-02, -8.0224306697503633e-03, + -2.2669167702495940e-03, 7.0200240494706634e-03, + -8.1528469000299308e-03, 6.0772866969252792e-01, + 9.8831560865432400e-01, 9.9391691044078823e-01, + 1.0039338994753197e+00, 9.9234499861167125e-01, + 9.9926530858855522e-01, 1.0084621557617270e+00, + 9.8358296827441216e-01, 1.0085023660099048e+00, + 9.7451138326568698e-01, 9.8543269570059944e-01, + 9.3495763980962043e-01, 9.8713907792319400e-01 }; + +const float RGBRefl2SpectGreen[nRGB2SpectSamples] = { + 2.6494153587602255e-03, -5.0175013429732242e-03, + -1.2547236272489583e-02, -9.4554964308388671e-03, + -1.2526086181600525e-02, -7.9170697760437767e-03, + -7.9955735204175690e-03, -9.3559433444469070e-03, + 6.5468611982999303e-02, 3.9572875517634137e-01, + 7.5244022299886659e-01, 9.6376478690218559e-01, + 9.9854433855162328e-01, 9.9992977025287921e-01, + 9.9939086751140449e-01, 9.9994372267071396e-01, + 9.9939121813418674e-01, 9.9911237310424483e-01, + 9.6019584878271580e-01, 6.3186279338432438e-01, + 2.5797401028763473e-01, 9.4014888527335638e-03, + -3.0798345608649747e-03, -4.5230367033685034e-03, + -6.8933410388274038e-03, -9.0352195539015398e-03, + -8.5913667165340209e-03, -8.3690869120289398e-03, + -7.8685832338754313e-03, -8.3657578711085132e-06, + 5.4301225442817177e-03, -2.7745589759259194e-03 }; + +const float RGBRefl2SpectBlue[nRGB2SpectSamples] = { + 9.9209771469720676e-01, 9.8876426059369127e-01, + 9.9539040744505636e-01, 9.9529317353008218e-01, + 9.9181447411633950e-01, 1.0002584039673432e+00, + 9.9968478437342512e-01, 9.9988120766657174e-01, + 9.8504012146370434e-01, 7.9029849053031276e-01, + 5.6082198617463974e-01, 3.3133458513996528e-01, + 1.3692410840839175e-01, 1.8914906559664151e-02, + -5.1129770932550889e-06, -4.2395493167891873e-04, + -4.1934593101534273e-04, 1.7473028136486615e-03, + 3.7999160177631316e-03, -5.5101474906588642e-04, + -4.3716662898480967e-05, 7.5874501748732798e-03, + 2.5795650780554021e-02, 3.8168376532500548e-02, + 4.9489586408030833e-02, 4.9595992290102905e-02, + 4.9814819505812249e-02, 3.9840911064978023e-02, + 3.0501024937233868e-02, 2.1243054765241080e-02, + 6.9596532104356399e-03, 4.1733649330980525e-03 }; +const float RGBIllum2SpectWhite[nRGB2SpectSamples] = { + 1.1565232050369776e+00, 1.1567225000119139e+00, + 1.1566203150243823e+00, 1.1555782088080084e+00, + 1.1562175509215700e+00, 1.1567674012207332e+00, + 1.1568023194808630e+00, 1.1567677445485520e+00, + 1.1563563182952830e+00, 1.1567054702510189e+00, + 1.1565134139372772e+00, 1.1564336176499312e+00, + 1.1568023181530034e+00, 1.1473147688514642e+00, + 1.1339317140561065e+00, 1.1293876490671435e+00, + 1.1290515328639648e+00, 1.0504864823782283e+00, + 1.0459696042230884e+00, 9.9366687168595691e-01, + 9.5601669265393940e-01, 9.2467482033511805e-01, + 9.1499944702051761e-01, 8.9939467658453465e-01, + 8.9542520751331112e-01, 8.8870566693814745e-01, + 8.8222843814228114e-01, 8.7998311373826676e-01, + 8.7635244612244578e-01, 8.8000368331709111e-01, + 8.8065665428441120e-01, 8.8304706460276905e-01 }; + +const float RGBIllum2SpectCyan[nRGB2SpectSamples] = { + 1.1334479663682135e+00, 1.1266762330194116e+00, + 1.1346827504710164e+00, 1.1357395805744794e+00, + 1.1356371830149636e+00, 1.1361152989346193e+00, + 1.1362179057706772e+00, 1.1364819652587022e+00, + 1.1355107110714324e+00, 1.1364060941199556e+00, + 1.1360363621722465e+00, 1.1360122641141395e+00, + 1.1354266882467030e+00, 1.1363099407179136e+00, + 1.1355450412632506e+00, 1.1353732327376378e+00, + 1.1349496420726002e+00, 1.1111113947168556e+00, + 9.0598740429727143e-01, 6.1160780787465330e-01, + 2.9539752170999634e-01, 9.5954200671150097e-02, + -1.1650792030826267e-02, -1.2144633073395025e-02, + -1.1148167569748318e-02, -1.1997606668458151e-02, + -5.0506855475394852e-03, -7.9982745819542154e-03, + -9.4722817708236418e-03, -5.5329541006658815e-03, + -4.5428914028274488e-03, -1.2541015360921132e-02 }; + +const float RGBIllum2SpectMagenta[nRGB2SpectSamples] = { + 1.0371892935878366e+00, 1.0587542891035364e+00, + 1.0767271213688903e+00, 1.0762706844110288e+00, + 1.0795289105258212e+00, 1.0743644742950074e+00, + 1.0727028691194342e+00, 1.0732447452056488e+00, + 1.0823760816041414e+00, 1.0840545681409282e+00, + 9.5607567526306658e-01, 5.5197896855064665e-01, + 8.4191094887247575e-02, 8.7940070557041006e-05, + -2.3086408335071251e-03, -1.1248136628651192e-03, + -7.7297612754989586e-11, -2.7270769006770834e-04, + 1.4466473094035592e-02, 2.5883116027169478e-01, + 5.2907999827566732e-01, 9.0966624097105164e-01, + 1.0690571327307956e+00, 1.0887326064796272e+00, + 1.0637622289511852e+00, 1.0201812918094260e+00, + 1.0262196688979945e+00, 1.0783085560613190e+00, + 9.8333849623218872e-01, 1.0707246342802621e+00, + 1.0634247770423768e+00, 1.0150875475729566e+00 }; + +const float RGBIllum2SpectYellow[nRGB2SpectSamples] = { + 2.7756958965811972e-03, 3.9673820990646612e-03, + -1.4606936788606750e-04, 3.6198394557748065e-04, + -2.5819258699309733e-04, -5.0133191628082274e-05, + -2.4437242866157116e-04, -7.8061419948038946e-05, + 4.9690301207540921e-02, 4.8515973574763166e-01, + 1.0295725854360589e+00, 1.0333210878457741e+00, + 1.0368102644026933e+00, 1.0364884018886333e+00, + 1.0365427939411784e+00, 1.0368595402854539e+00, + 1.0365645405660555e+00, 1.0363938240707142e+00, + 1.0367205578770746e+00, 1.0365239329446050e+00, + 1.0361531226427443e+00, 1.0348785007827348e+00, + 1.0042729660717318e+00, 8.4218486432354278e-01, + 7.3759394894801567e-01, 6.5853154500294642e-01, + 6.0531682444066282e-01, 5.9549794132420741e-01, + 5.9419261278443136e-01, 5.6517682326634266e-01, + 5.6061186014968556e-01, 5.8228610381018719e-01 }; + +const float RGBIllum2SpectRed[nRGB2SpectSamples] = { + 5.4711187157291841e-02, 5.5609066498303397e-02, + 6.0755873790918236e-02, 5.6232948615962369e-02, + 4.6169940535708678e-02, 3.8012808167818095e-02, + 2.4424225756670338e-02, 3.8983580581592181e-03, + -5.6082252172734437e-04, 9.6493871255194652e-04, + 3.7341198051510371e-04, -4.3367389093135200e-04, + -9.3533962256892034e-05, -1.2354967412842033e-04, + -1.4524548081687461e-04, -2.0047691915543731e-04, + -4.9938587694693670e-04, 2.7255083540032476e-02, + 1.6067405906297061e-01, 3.5069788873150953e-01, + 5.7357465538418961e-01, 7.6392091890718949e-01, + 8.9144466740381523e-01, 9.6394609909574891e-01, + 9.8879464276016282e-01, 9.9897449966227203e-01, + 9.8605140403564162e-01, 9.9532502805345202e-01, + 9.7433478377305371e-01, 9.9134364616871407e-01, + 9.8866287772174755e-01, 9.9713856089735531e-01 }; + +const float RGBIllum2SpectGreen[nRGB2SpectSamples] = { + 2.5168388755514630e-02, 3.9427438169423720e-02, + 6.2059571596425793e-03, 7.1120859807429554e-03, + 2.1760044649139429e-04, 7.3271839984290210e-12, + -2.1623066217181700e-02, 1.5670209409407512e-02, + 2.8019603188636222e-03, 3.2494773799897647e-01, + 1.0164917292316602e+00, 1.0329476657890369e+00, + 1.0321586962991549e+00, 1.0358667411948619e+00, + 1.0151235476834941e+00, 1.0338076690093119e+00, + 1.0371372378155013e+00, 1.0361377027692558e+00, + 1.0229822432557210e+00, 9.6910327335652324e-01, + -5.1785923899878572e-03, 1.1131261971061429e-03, + 6.6675503033011771e-03, 7.4024315686001957e-04, + 2.1591567633473925e-02, 5.1481620056217231e-03, + 1.4561928645728216e-03, 1.6414511045291513e-04, + -6.4630764968453287e-03, 1.0250854718507939e-02, + 4.2387394733956134e-02, 2.1252716926861620e-02 }; + +const float RGBIllum2SpectBlue[nRGB2SpectSamples] = { + 1.0570490759328752e+00, 1.0538466912851301e+00, + 1.0550494258140670e+00, 1.0530407754701832e+00, + 1.0579930596460185e+00, 1.0578439494812371e+00, + 1.0583132387180239e+00, 1.0579712943137616e+00, + 1.0561884233578465e+00, 1.0571399285426490e+00, + 1.0425795187752152e+00, 3.2603084374056102e-01, + -1.9255628442412243e-03, -1.2959221137046478e-03, + -1.4357356276938696e-03, -1.2963697250337886e-03, + -1.9227081162373899e-03, 1.2621152526221778e-03, + -1.6095249003578276e-03, -1.3029983817879568e-03, + -1.7666600873954916e-03, -1.2325281140280050e-03, + 1.0316809673254932e-02, 3.1284512648354357e-02, + 8.8773879881746481e-02, 1.3873621740236541e-01, + 1.5535067531939065e-01, 1.4878477178237029e-01, + 1.6624255403475907e-01, 1.6997613960634927e-01, + 1.5769743995852967e-01, 1.9069090525482305e-01 }; diff --git a/core/spectrum.h b/core/spectrum.h new file mode 100644 index 0000000..d2e556a --- /dev/null +++ b/core/spectrum.h @@ -0,0 +1,463 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_SPECTRUM_H +#define PBRT_CORE_SPECTRUM_H + +// core/spectrum.h* +#include "pbrt.h" +#include "parallel.h" + +// Spectrum Utility Declarations +static const int sampledLambdaStart = 400; +static const int sampledLambdaEnd = 700; +static const int nSpectralSamples = 30; +extern bool SpectrumSamplesSorted(const float *lambda, const float *vals, int n); +extern void SortSpectrumSamples(float *lambda, float *vals, int n); +extern float AverageSpectrumSamples(const float *lambda, const float *vals, + int n, float lambdaStart, float lambdaEnd); +inline void XYZToRGB(const float xyz[3], float rgb[3]) { + rgb[0] = 3.240479f*xyz[0] - 1.537150f*xyz[1] - 0.498535f*xyz[2]; + rgb[1] = -0.969256f*xyz[0] + 1.875991f*xyz[1] + 0.041556f*xyz[2]; + rgb[2] = 0.055648f*xyz[0] - 0.204043f*xyz[1] + 1.057311f*xyz[2]; +} + + +inline void RGBToXYZ(const float rgb[3], float xyz[3]) { + xyz[0] = 0.412453f*rgb[0] + 0.357580f*rgb[1] + 0.180423f*rgb[2]; + xyz[1] = 0.212671f*rgb[0] + 0.715160f*rgb[1] + 0.072169f*rgb[2]; + xyz[2] = 0.019334f*rgb[0] + 0.119193f*rgb[1] + 0.950227f*rgb[2]; +} + + +enum SpectrumType { SPECTRUM_REFLECTANCE, SPECTRUM_ILLUMINANT }; +extern void Blackbody(const float *wl, int n, float temp, float *vals); +extern float InterpolateSpectrumSamples(const float *lambda, const float *vals, + int n, float l); + +// Spectral Data Declarations +static const int nCIESamples = 471; +extern const float CIE_X[nCIESamples]; +extern const float CIE_Y[nCIESamples]; +extern const float CIE_Z[nCIESamples]; +extern const float CIE_lambda[nCIESamples]; +static const int nRGB2SpectSamples = 32; +extern const float RGB2SpectLambda[nRGB2SpectSamples]; +extern const float RGBRefl2SpectWhite[nRGB2SpectSamples]; +extern const float RGBRefl2SpectCyan[nRGB2SpectSamples]; +extern const float RGBRefl2SpectMagenta[nRGB2SpectSamples]; +extern const float RGBRefl2SpectYellow[nRGB2SpectSamples]; +extern const float RGBRefl2SpectRed[nRGB2SpectSamples]; +extern const float RGBRefl2SpectGreen[nRGB2SpectSamples]; +extern const float RGBRefl2SpectBlue[nRGB2SpectSamples]; +extern const float RGBIllum2SpectWhite[nRGB2SpectSamples]; +extern const float RGBIllum2SpectCyan[nRGB2SpectSamples]; +extern const float RGBIllum2SpectMagenta[nRGB2SpectSamples]; +extern const float RGBIllum2SpectYellow[nRGB2SpectSamples]; +extern const float RGBIllum2SpectRed[nRGB2SpectSamples]; +extern const float RGBIllum2SpectGreen[nRGB2SpectSamples]; +extern const float RGBIllum2SpectBlue[nRGB2SpectSamples]; + +// Spectrum Declarations +template class CoefficientSpectrum { +public: + // CoefficientSpectrum Public Methods + CoefficientSpectrum(float v = 0.f) { + for (int i = 0; i < nSamples; ++i) + c[i] = v; + Assert(!HasNaNs()); + } +#ifdef DEBUG + CoefficientSpectrum(const CoefficientSpectrum &s) { + Assert(!s.HasNaNs()); + for (int i = 0; i < nSamples; ++i) + c[i] = s.c[i]; + } + + CoefficientSpectrum &operator=(const CoefficientSpectrum &s) { + Assert(!s.HasNaNs()); + for (int i = 0; i < nSamples; ++i) + c[i] = s.c[i]; + return *this; + } +#endif // DEBUG + void Print(FILE *f) const { + fprintf(f, "[ "); + for (int i = 0; i < nSamples; ++i) { + fprintf(f, "%f", c[i]); + if (i != nSamples-1) fprintf(f, ", "); + } + fprintf(f, "]"); + } + CoefficientSpectrum &operator+=(const CoefficientSpectrum &s2) { + Assert(!s2.HasNaNs()); + for (int i = 0; i < nSamples; ++i) + c[i] += s2.c[i]; + return *this; + } + CoefficientSpectrum operator+(const CoefficientSpectrum &s2) const { + Assert(!s2.HasNaNs()); + CoefficientSpectrum ret = *this; + for (int i = 0; i < nSamples; ++i) + ret.c[i] += s2.c[i]; + return ret; + } + CoefficientSpectrum operator-(const CoefficientSpectrum &s2) const { + Assert(!s2.HasNaNs()); + CoefficientSpectrum ret = *this; + for (int i = 0; i < nSamples; ++i) + ret.c[i] -= s2.c[i]; + return ret; + } + CoefficientSpectrum operator/(const CoefficientSpectrum &s2) const { + Assert(!s2.HasNaNs()); + CoefficientSpectrum ret = *this; + for (int i = 0; i < nSamples; ++i) + ret.c[i] /= s2.c[i]; + return ret; + } + CoefficientSpectrum operator*(const CoefficientSpectrum &sp) const { + Assert(!sp.HasNaNs()); + CoefficientSpectrum ret = *this; + for (int i = 0; i < nSamples; ++i) + ret.c[i] *= sp.c[i]; + return ret; + } + CoefficientSpectrum &operator*=(const CoefficientSpectrum &sp) { + Assert(!sp.HasNaNs()); + for (int i = 0; i < nSamples; ++i) + c[i] *= sp.c[i]; + return *this; + } + CoefficientSpectrum operator*(float a) const { + CoefficientSpectrum ret = *this; + for (int i = 0; i < nSamples; ++i) + ret.c[i] *= a; + Assert(!ret.HasNaNs()); + return ret; + } + CoefficientSpectrum &operator*=(float a) { + for (int i = 0; i < nSamples; ++i) + c[i] *= a; + Assert(!HasNaNs()); + return *this; + } + friend inline + CoefficientSpectrum operator*(float a, const CoefficientSpectrum &s) { + Assert(!isnan(a) && !s.HasNaNs()); + return s * a; + } + CoefficientSpectrum operator/(float a) const { + Assert(!isnan(a)); + CoefficientSpectrum ret = *this; + for (int i = 0; i < nSamples; ++i) + ret.c[i] /= a; + Assert(!ret.HasNaNs()); + return ret; + } + CoefficientSpectrum &operator/=(float a) { + Assert(!isnan(a)); + for (int i = 0; i < nSamples; ++i) + c[i] /= a; + return *this; + } + bool operator==(const CoefficientSpectrum &sp) const { + for (int i = 0; i < nSamples; ++i) + if (c[i] != sp.c[i]) return false; + return true; + } + bool operator!=(const CoefficientSpectrum &sp) const { + return !(*this == sp); + } + bool IsBlack() const { + for (int i = 0; i < nSamples; ++i) + if (c[i] != 0.) return false; + return true; + } + friend CoefficientSpectrum Sqrt(const CoefficientSpectrum &s) { + CoefficientSpectrum ret; + for (int i = 0; i < nSamples; ++i) + ret.c[i] = sqrtf(s.c[i]); + Assert(!ret.HasNaNs()); + return ret; + } + template friend inline CoefficientSpectrum Pow(const CoefficientSpectrum &s, float e); + CoefficientSpectrum operator-() const { + CoefficientSpectrum ret; + for (int i = 0; i < nSamples; ++i) + ret.c[i] = -c[i]; + return ret; + } + friend CoefficientSpectrum Exp(const CoefficientSpectrum &s) { + CoefficientSpectrum ret; + for (int i = 0; i < nSamples; ++i) + ret.c[i] = expf(s.c[i]); + Assert(!ret.HasNaNs()); + return ret; + } + CoefficientSpectrum Clamp(float low = 0, float high = INFINITY) const { + CoefficientSpectrum ret; + for (int i = 0; i < nSamples; ++i) + ret.c[i] = ::Clamp(c[i], low, high); + Assert(!ret.HasNaNs()); + return ret; + } + bool HasNaNs() const { + for (int i = 0; i < nSamples; ++i) + if (isnan(c[i])) return true; + return false; + } + bool Write(FILE *f) const { + for (int i = 0; i < nSamples; ++i) + if (fprintf(f, "%f ", c[i]) < 0) return false; + return true; + } + bool Read(FILE *f) { + for (int i = 0; i < nSamples; ++i) + if (fscanf(f, "%f ", &c[i]) != 1) return false; + return true; + } +protected: + // CoefficientSpectrum Protected Data + float c[nSamples]; +}; + + +class SampledSpectrum : public CoefficientSpectrum { +public: + // SampledSpectrum Public Methods + SampledSpectrum(float v = 0.f) { + for (int i = 0; i < nSpectralSamples; ++i) c[i] = v; + } + SampledSpectrum(const CoefficientSpectrum &v) + : CoefficientSpectrum(v) { } + static SampledSpectrum FromSampled(const float *lambda, + const float *v, int n) { + // Sort samples if unordered, use sorted for returned spectrum + if (!SpectrumSamplesSorted(lambda, v, n)) { + vector slambda(&lambda[0], &lambda[n]); + vector sv(&v[0], &v[n]); + SortSpectrumSamples(&slambda[0], &sv[0], n); + return FromSampled(&slambda[0], &sv[0], n); + } + SampledSpectrum r; + for (int i = 0; i < nSpectralSamples; ++i) { + // Compute average value of given SPD over $i$th sample's range + float lambda0 = Lerp(float(i) / float(nSpectralSamples), + sampledLambdaStart, sampledLambdaEnd); + float lambda1 = Lerp(float(i+1) / float(nSpectralSamples), + sampledLambdaStart, sampledLambdaEnd); + r.c[i] = AverageSpectrumSamples(lambda, v, n, lambda0, lambda1); + } + return r; + } + static void Init() { + // Compute XYZ matching functions for _SampledSpectrum_ + for (int i = 0; i < nSpectralSamples; ++i) { + float wl0 = Lerp(float(i) / float(nSpectralSamples), + sampledLambdaStart, sampledLambdaEnd); + float wl1 = Lerp(float(i+1) / float(nSpectralSamples), + sampledLambdaStart, sampledLambdaEnd); + X.c[i] = AverageSpectrumSamples(CIE_lambda, CIE_X, nCIESamples, + wl0, wl1); + Y.c[i] = AverageSpectrumSamples(CIE_lambda, CIE_Y, nCIESamples, + wl0, wl1); + Z.c[i] = AverageSpectrumSamples(CIE_lambda, CIE_Z, nCIESamples, + wl0, wl1); + yint += Y.c[i]; + } + + // Compute RGB to spectrum functions for _SampledSpectrum_ + for (int i = 0; i < nSpectralSamples; ++i) { + float wl0 = Lerp(float(i) / float(nSpectralSamples), + sampledLambdaStart, sampledLambdaEnd); + float wl1 = Lerp(float(i+1) / float(nSpectralSamples), + sampledLambdaStart, sampledLambdaEnd); + rgbRefl2SpectWhite.c[i] = AverageSpectrumSamples(RGB2SpectLambda, RGBRefl2SpectWhite, + nRGB2SpectSamples, wl0, wl1); + rgbRefl2SpectCyan.c[i] = AverageSpectrumSamples(RGB2SpectLambda, RGBRefl2SpectCyan, + nRGB2SpectSamples, wl0, wl1); + rgbRefl2SpectMagenta.c[i] = AverageSpectrumSamples(RGB2SpectLambda, RGBRefl2SpectMagenta, + nRGB2SpectSamples, wl0, wl1); + rgbRefl2SpectYellow.c[i] = AverageSpectrumSamples(RGB2SpectLambda, RGBRefl2SpectYellow, + nRGB2SpectSamples, wl0, wl1); + rgbRefl2SpectRed.c[i] = AverageSpectrumSamples(RGB2SpectLambda, RGBRefl2SpectRed, + nRGB2SpectSamples, wl0, wl1); + rgbRefl2SpectGreen.c[i] = AverageSpectrumSamples(RGB2SpectLambda, RGBRefl2SpectGreen, + nRGB2SpectSamples, wl0, wl1); + rgbRefl2SpectBlue.c[i] = AverageSpectrumSamples(RGB2SpectLambda, RGBRefl2SpectBlue, + nRGB2SpectSamples, wl0, wl1); + + rgbIllum2SpectWhite.c[i] = AverageSpectrumSamples(RGB2SpectLambda, RGBIllum2SpectWhite, + nRGB2SpectSamples, wl0, wl1); + rgbIllum2SpectCyan.c[i] = AverageSpectrumSamples(RGB2SpectLambda, RGBIllum2SpectCyan, + nRGB2SpectSamples, wl0, wl1); + rgbIllum2SpectMagenta.c[i] = AverageSpectrumSamples(RGB2SpectLambda, RGBIllum2SpectMagenta, + nRGB2SpectSamples, wl0, wl1); + rgbIllum2SpectYellow.c[i] = AverageSpectrumSamples(RGB2SpectLambda, RGBIllum2SpectYellow, + nRGB2SpectSamples, wl0, wl1); + rgbIllum2SpectRed.c[i] = AverageSpectrumSamples(RGB2SpectLambda, RGBIllum2SpectRed, + nRGB2SpectSamples, wl0, wl1); + rgbIllum2SpectGreen.c[i] = AverageSpectrumSamples(RGB2SpectLambda, RGBIllum2SpectGreen, + nRGB2SpectSamples, wl0, wl1); + rgbIllum2SpectBlue.c[i] = AverageSpectrumSamples(RGB2SpectLambda, RGBIllum2SpectBlue, + nRGB2SpectSamples, wl0, wl1); + } + } + void ToXYZ(float xyz[3]) const { + xyz[0] = xyz[1] = xyz[2] = 0.f; + for (int i = 0; i < nSpectralSamples; ++i) { + xyz[0] += X.c[i] * c[i]; + xyz[1] += Y.c[i] * c[i]; + xyz[2] += Z.c[i] * c[i]; + } + xyz[0] /= yint; + xyz[1] /= yint; + xyz[2] /= yint; + } + float y() const { + float yy = 0.f; + for (int i = 0; i < nSpectralSamples; ++i) + yy += Y.c[i] * c[i]; + return yy / yint; + } + void ToRGB(float rgb[3]) const { + float xyz[3]; + ToXYZ(xyz); + XYZToRGB(xyz, rgb); + } + RGBSpectrum ToRGBSpectrum() const; + static SampledSpectrum FromRGB(const float rgb[3], + SpectrumType type = SPECTRUM_REFLECTANCE); + static SampledSpectrum FromXYZ(const float xyz[3], + SpectrumType type = SPECTRUM_REFLECTANCE) { + float rgb[3]; + XYZToRGB(xyz, rgb); + return FromRGB(rgb, type); + } + SampledSpectrum(const RGBSpectrum &r, SpectrumType type = SPECTRUM_REFLECTANCE); +private: + // SampledSpectrum Private Data + static SampledSpectrum X, Y, Z; + static float yint; + static SampledSpectrum rgbRefl2SpectWhite, rgbRefl2SpectCyan; + static SampledSpectrum rgbRefl2SpectMagenta, rgbRefl2SpectYellow; + static SampledSpectrum rgbRefl2SpectRed, rgbRefl2SpectGreen; + static SampledSpectrum rgbRefl2SpectBlue; + static SampledSpectrum rgbIllum2SpectWhite, rgbIllum2SpectCyan; + static SampledSpectrum rgbIllum2SpectMagenta, rgbIllum2SpectYellow; + static SampledSpectrum rgbIllum2SpectRed, rgbIllum2SpectGreen; + static SampledSpectrum rgbIllum2SpectBlue; +}; + + +class RGBSpectrum : public CoefficientSpectrum<3> { + using CoefficientSpectrum<3>::c; +public: + // RGBSpectrum Public Methods + RGBSpectrum(float v = 0.f) : CoefficientSpectrum<3>(v) { } + RGBSpectrum(const CoefficientSpectrum<3> &v) + : CoefficientSpectrum<3>(v) { } + RGBSpectrum(const RGBSpectrum &s, SpectrumType type = SPECTRUM_REFLECTANCE) { + *this = s; + } + static RGBSpectrum FromRGB(const float rgb[3], + SpectrumType type = SPECTRUM_REFLECTANCE) { + RGBSpectrum s; + s.c[0] = rgb[0]; + s.c[1] = rgb[1]; + s.c[2] = rgb[2]; + Assert(!s.HasNaNs()); + return s; + } + void ToRGB(float *rgb) const { + rgb[0] = c[0]; + rgb[1] = c[1]; + rgb[2] = c[2]; + } + const RGBSpectrum &ToRGBSpectrum() const { + return *this; + } + void ToXYZ(float xyz[3]) const { + RGBToXYZ(c, xyz); + } + static RGBSpectrum FromXYZ(const float xyz[3], + SpectrumType type = SPECTRUM_REFLECTANCE) { + RGBSpectrum r; + XYZToRGB(xyz, r.c); + return r; + } + float y() const { + const float YWeight[3] = { 0.212671f, 0.715160f, 0.072169f }; + return YWeight[0] * c[0] + YWeight[1] * c[1] + YWeight[2] * c[2]; + } + static RGBSpectrum FromSampled(const float *lambda, const float *v, + int n) { + // Sort samples if unordered, use sorted for returned spectrum + if (!SpectrumSamplesSorted(lambda, v, n)) { + vector slambda(&lambda[0], &lambda[n]); + vector sv(&v[0], &v[n]); + SortSpectrumSamples(&slambda[0], &sv[0], n); + return FromSampled(&slambda[0], &sv[0], n); + } + float xyz[3] = { 0, 0, 0 }; + float yint = 0.f; + for (int i = 0; i < nCIESamples; ++i) { + yint += CIE_Y[i]; + float val = InterpolateSpectrumSamples(lambda, v, n, + CIE_lambda[i]); + xyz[0] += val * CIE_X[i]; + xyz[1] += val * CIE_Y[i]; + xyz[2] += val * CIE_Z[i]; + } + xyz[0] /= yint; + xyz[1] /= yint; + xyz[2] /= yint; + return FromXYZ(xyz); + } +}; + + + +// Spectrum Inline Functions +template inline CoefficientSpectrum +Pow(const CoefficientSpectrum &s, float e) { + CoefficientSpectrum ret; + for (int i = 0; i < nSamples; ++i) + ret.c[i] = powf(s.c[i], e); + Assert(!ret.HasNaNs()); + return ret; +} + + +inline Spectrum Lerp(float t, const Spectrum &s1, const Spectrum &s2) { + return (1.f - t) * s1 + t * s2; +} + + + +#endif // PBRT_CORE_SPECTRUM_H diff --git a/core/stdafx.h b/core/stdafx.h new file mode 100644 index 0000000..827833c --- /dev/null +++ b/core/stdafx.h @@ -0,0 +1,16 @@ +// header file for building precompiled headers under windows +// a no-op on other architectures + +#if defined(_MSC_VER) + +#include "pbrt.h" +#include "camera.h" +#include "scene.h" +#include "imageio.h" +#include "intersection.h" +#include "montecarlo.h" +#include "sampler.h" +#include "texture.h" +#include "integrator.h" + +#endif // _MSC_VER diff --git a/core/texture.cpp b/core/texture.cpp new file mode 100644 index 0000000..dd1c5a6 --- /dev/null +++ b/core/texture.cpp @@ -0,0 +1,268 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/texture.cpp* +#include "stdafx.h" +#include "texture.h" +#include "shape.h" + +// Texture Inline Functions +inline float SmoothStep(float min, float max, float value) { + float v = Clamp((value - min) / (max - min), 0.f, 1.f); + return v * v * (-2.f * v + 3.f); +} + + + +// Texture Forward Declarations +inline float Grad(int x, int y, int z, float dx, float dy, float dz); +inline float NoiseWeight(float t); + +// Perlin Noise Data +#define NOISE_PERM_SIZE 256 +static int NoisePerm[2 * NOISE_PERM_SIZE] = { + 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, + 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, + // Remainder of the noise permutation table + 8, 99, 37, 240, 21, 10, 23, + 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, + 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, + 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, + 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, + 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, + 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, + 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, + 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, + 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, + 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, + 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180, + 151, 160, 137, 91, 90, 15, + 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, + 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, + 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, + 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, + 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, + 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, + 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, + 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, + 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, + 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, + 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, + 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 +}; + + + +// Texture Method Definitions +UVMapping2D::UVMapping2D(float ssu, float ssv, float ddu, float ddv) + : su(ssu), sv(ssv), du(ddu), dv(ddv) { } +void UVMapping2D::Map(const DifferentialGeometry &dg, + float *s, float *t, float *dsdx, float *dtdx, + float *dsdy, float *dtdy) const { + *s = su * dg.u + du; + *t = sv * dg.v + dv; + // Compute texture differentials for 2D identity mapping + *dsdx = su * dg.dudx; + *dtdx = sv * dg.dvdx; + *dsdy = su * dg.dudy; + *dtdy = sv * dg.dvdy; +} + + +void SphericalMapping2D::Map(const DifferentialGeometry &dg, + float *s, float *t, float *dsdx, float *dtdx, + float *dsdy, float *dtdy) const { + sphere(dg.p, s, t); + // Compute texture coordinate differentials for sphere $(u,v)$ mapping + float sx, tx, sy, ty; + const float delta = .1f; + sphere(dg.p + delta * dg.dpdx, &sx, &tx); + *dsdx = (sx - *s) / delta; + *dtdx = (tx - *t) / delta; + if (*dtdx > .5) *dtdx = 1.f - *dtdx; + else if (*dtdx < -.5f) *dtdx = -(*dtdx + 1); + sphere(dg.p + delta * dg.dpdy, &sy, &ty); + *dsdy = (sy - *s) / delta; + *dtdy = (ty - *t) / delta; + if (*dtdy > .5) *dtdy = 1.f - *dtdy; + else if (*dtdy < -.5f) *dtdy = -(*dtdy + 1); +} + + +void SphericalMapping2D::sphere(const Point &p, float *s, float *t) const { + Vector vec = Normalize(WorldToTexture(p) - Point(0,0,0)); + float theta = SphericalTheta(vec); + float phi = SphericalPhi(vec); + *s = theta * INV_PI; + *t = phi * INV_TWOPI; +} + + +void CylindricalMapping2D::Map(const DifferentialGeometry &dg, + float *s, float *t, float *dsdx, float *dtdx, + float *dsdy, float *dtdy) const { + cylinder(dg.p, s, t); + // Compute texture coordinate differentials for cylinder $(u,v)$ mapping + float sx, tx, sy, ty; + const float delta = .01f; + cylinder(dg.p + delta * dg.dpdx, &sx, &tx); + *dsdx = (sx - *s) / delta; + *dtdx = (tx - *t) / delta; + if (*dtdx > .5) *dtdx = 1.f - *dtdx; + else if (*dtdx < -.5f) *dtdx = -(*dtdx + 1); + cylinder(dg.p + delta * dg.dpdy, &sy, &ty); + *dsdy = (sy - *s) / delta; + *dtdy = (ty - *t) / delta; + if (*dtdy > .5) *dtdy = 1.f - *dtdy; + else if (*dtdy < -.5f) *dtdy = -(*dtdy + 1); +} + + +void PlanarMapping2D::Map(const DifferentialGeometry &dg, + float *s, float *t, float *dsdx, float *dtdx, + float *dsdy, float *dtdy) const { + Vector vec = dg.p - Point(0,0,0); + *s = ds + Dot(vec, vs); + *t = dt + Dot(vec, vt); + *dsdx = Dot(dg.dpdx, vs); + *dtdx = Dot(dg.dpdx, vt); + *dsdy = Dot(dg.dpdy, vs); + *dtdy = Dot(dg.dpdy, vt); +} + + +Point IdentityMapping3D::Map(const DifferentialGeometry &dg, + Vector *dpdx, Vector *dpdy) const { + *dpdx = WorldToTexture(dg.dpdx); + *dpdy = WorldToTexture(dg.dpdy); + return WorldToTexture(dg.p); +} + + +float Noise(float x, float y, float z) { + // Compute noise cell coordinates and offsets + int ix = Floor2Int(x), iy = Floor2Int(y), iz = Floor2Int(z); + float dx = x - ix, dy = y - iy, dz = z - iz; + + // Compute gradient weights + ix &= (NOISE_PERM_SIZE-1); + iy &= (NOISE_PERM_SIZE-1); + iz &= (NOISE_PERM_SIZE-1); + float w000 = Grad(ix, iy, iz, dx, dy, dz); + float w100 = Grad(ix+1, iy, iz, dx-1, dy, dz); + float w010 = Grad(ix, iy+1, iz, dx, dy-1, dz); + float w110 = Grad(ix+1, iy+1, iz, dx-1, dy-1, dz); + float w001 = Grad(ix, iy, iz+1, dx, dy, dz-1); + float w101 = Grad(ix+1, iy, iz+1, dx-1, dy, dz-1); + float w011 = Grad(ix, iy+1, iz+1, dx, dy-1, dz-1); + float w111 = Grad(ix+1, iy+1, iz+1, dx-1, dy-1, dz-1); + + // Compute trilinear interpolation of weights + float wx = NoiseWeight(dx), wy = NoiseWeight(dy), wz = NoiseWeight(dz); + float x00 = Lerp(wx, w000, w100); + float x10 = Lerp(wx, w010, w110); + float x01 = Lerp(wx, w001, w101); + float x11 = Lerp(wx, w011, w111); + float y0 = Lerp(wy, x00, x10); + float y1 = Lerp(wy, x01, x11); + return Lerp(wz, y0, y1); +} + + +float Noise(const Point &P) { return Noise(P.x, P.y, P.z); } +inline float Grad(int x, int y, int z, float dx, float dy, float dz) { + int h = NoisePerm[NoisePerm[NoisePerm[x]+y]+z]; + h &= 15; + float u = h<8 || h==12 || h==13 ? dx : dy; + float v = h<4 || h==12 || h==13 ? dy : dz; + return ((h&1) ? -u : u) + ((h&2) ? -v : v); +} + + +inline float NoiseWeight(float t) { + float t3 = t*t*t; + float t4 = t3*t; + return 6.f*t4*t - 15.f*t4 + 10.f*t3; +} + + +float FBm(const Point &P, const Vector &dpdx, const Vector &dpdy, + float omega, int maxOctaves) { + // Compute number of octaves for antialiased FBm + float s2 = max(dpdx.LengthSquared(), dpdy.LengthSquared()); + float foctaves = min((float)maxOctaves, 1.f - .5f * Log2(s2)); + int octaves = Floor2Int(foctaves); + + // Compute sum of octaves of noise for FBm + float sum = 0., lambda = 1., o = 1.; + for (int i = 0; i < octaves; ++i) { + sum += o * Noise(lambda * P); + lambda *= 1.99f; + o *= omega; + } + float partialOctave = foctaves - octaves; + sum += o * SmoothStep(.3f, .7f, partialOctave) * Noise(lambda * P); + return sum; +} + + +float Turbulence(const Point &P, const Vector &dpdx, const Vector &dpdy, + float omega, int maxOctaves) { + // Compute number of octaves for antialiased FBm + float s2 = max(dpdx.LengthSquared(), dpdy.LengthSquared()); + float foctaves = min((float)maxOctaves, 1.f - .5f * Log2(s2)); + int octaves = Floor2Int(foctaves); + + // Compute sum of octaves of noise for turbulence + float sum = 0., lambda = 1., o = 1.; + for (int i = 0; i < octaves; ++i) { + sum += o * fabsf(Noise(lambda * P)); + lambda *= 1.99f; + o *= omega; + } + float partialOctave = foctaves - octaves; + sum += o * SmoothStep(.3f, .7f, partialOctave) * + fabsf(Noise(lambda * P)); + + // finally, add in value to account for average value of fabsf(Noise()) + // (~0.2) for the remaining octaves... + sum += (maxOctaves - foctaves) * 0.2f; + + return sum; +} + + + +// Texture Function Definitions +float Lanczos(float x, float tau) { + x = fabsf(x); + if (x < 1e-5) return 1; + if (x > 1.) return 0; + x *= M_PI; + float s = sinf(x * tau) / (x * tau); + float lanczos = sinf(x) / x; + return s * lanczos; +} + + diff --git a/core/texture.h b/core/texture.h new file mode 100644 index 0000000..7e117f9 --- /dev/null +++ b/core/texture.h @@ -0,0 +1,144 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_TEXTURE_H +#define PBRT_CORE_TEXTURE_H + +// core/texture.h* +#include "pbrt.h" +#include "spectrum.h" +#include "geometry.h" +#include "transform.h" +#include "memory.h" + +// Texture Declarations +class TextureMapping2D { +public: + // TextureMapping2D Interface + virtual ~TextureMapping2D() { } + virtual void Map(const DifferentialGeometry &dg, + float *s, float *t, float *dsdx, float *dtdx, + float *dsdy, float *dtdy) const = 0; +}; + + +class UVMapping2D : public TextureMapping2D { +public: + // UVMapping2D Public Methods + UVMapping2D(float su = 1, float sv = 1, float du = 0, float dv = 0); + void Map(const DifferentialGeometry &dg, float *s, float *t, + float *dsdx, float *dtdx, float *dsdy, float *dtdy) const; +private: + float su, sv, du, dv; +}; + + +class SphericalMapping2D : public TextureMapping2D { +public: + // SphericalMapping2D Public Methods + SphericalMapping2D(const Transform &toSph) + : WorldToTexture(toSph) { + } + void Map(const DifferentialGeometry &dg, float *s, float *t, + float *dsdx, float *dtdx, + float *dsdy, float *dtdy) const; +private: + void sphere(const Point &P, float *s, float *t) const; + Transform WorldToTexture; +}; + + +class CylindricalMapping2D : public TextureMapping2D { +public: + // CylindricalMapping2D Public Methods + CylindricalMapping2D(const Transform &toCyl) + : WorldToTexture(toCyl) { + } + void Map(const DifferentialGeometry &dg, float *s, float *t, + float *dsdx, float *dtdx, float *dsdy, float *dtdy) const; +private: + // CylindricalMapping2D Private Methods + void cylinder(const Point &p, float *s, float *t) const { + Vector vec = Normalize(WorldToTexture(p) - Point(0,0,0)); + *s = (M_PI + atan2f(vec.y, vec.x)) / (2.f * M_PI); + *t = vec.z; + } + Transform WorldToTexture; +}; + + +class PlanarMapping2D : public TextureMapping2D { +public: + // PlanarMapping2D Public Methods + void Map(const DifferentialGeometry &dg, float *s, float *t, + float *dsdx, float *dtdx, float *dsdy, float *dtdy) const; + PlanarMapping2D(const Vector &vv1, const Vector &vv2, + float dds = 0, float ddt = 0) + : vs(vv1), vt(vv2), ds(dds), dt(ddt) { } +private: + const Vector vs, vt; + const float ds, dt; +}; + + +class TextureMapping3D { +public: + // TextureMapping3D Interface + virtual ~TextureMapping3D() { } + virtual Point Map(const DifferentialGeometry &dg, + Vector *dpdx, Vector *dpdy) const = 0; +}; + + +class IdentityMapping3D : public TextureMapping3D { +public: + IdentityMapping3D(const Transform &x) + : WorldToTexture(x) { } + Point Map(const DifferentialGeometry &dg, Vector *dpdx, + Vector *dpdy) const; +private: + Transform WorldToTexture; +}; + + +template class Texture : public ReferenceCounted { +public: + // Texture Interface + virtual T Evaluate(const DifferentialGeometry &) const = 0; + virtual ~Texture() { } +}; + + +float Lanczos(float, float tau=2); +float Noise(float x, float y = .5f, float z = .5f); +float Noise(const Point &P); +float FBm(const Point &P, const Vector &dpdx, const Vector &dpdy, + float omega, int octaves); +float Turbulence(const Point &P, const Vector &dpdx, const Vector &dpdy, + float omega, int octaves); + +#endif // PBRT_CORE_TEXTURE_H diff --git a/core/timer.cpp b/core/timer.cpp new file mode 100644 index 0000000..c79ed64 --- /dev/null +++ b/core/timer.cpp @@ -0,0 +1,95 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/timer.cpp* +#include "stdafx.h" +#include "timer.h" + +// Timer Method Definitions +Timer::Timer() +{ +#if defined( PBRT_IS_WINDOWS ) + // Windows Timer Initialization + QueryPerformanceFrequency( &performance_frequency ); + one_over_frequency = 1.0/((double)performance_frequency.QuadPart); +#endif + time0 = elapsed = 0; + running = 0; +} + + + + +double Timer::GetTime() +{ +#if defined( PBRT_IS_WINDOWS ) + // Windows GetTime + QueryPerformanceCounter( &performance_counter ); + return (double) performance_counter.QuadPart * one_over_frequency; +#else + // UNIX GetTime + gettimeofday( &timeofday, NULL ); + return timeofday.tv_sec + timeofday.tv_usec / 1000000.0; +#endif +} + + + +void Timer::Start() +{ + Assert( !running ); + running = 1; + time0 = GetTime(); +} + + + +void Timer::Stop() +{ + Assert( running ); + running = 0; + + elapsed += GetTime() - time0; +} + + + +void Timer::Reset() +{ + running = 0; + elapsed = 0; +} + + + +double Timer::Time() +{ + if (running) { + Stop(); + Start(); + } + return elapsed; +} + + diff --git a/core/timer.h b/core/timer.h new file mode 100644 index 0000000..ec0197f --- /dev/null +++ b/core/timer.h @@ -0,0 +1,71 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_TIMER_H +#define PBRT_CORE_TIMER_H + +// core/timer.h* +#include "pbrt.h" +#if defined (PBRT_IS_WINDOWS) +#include +#if (_MSC_VER >= 1400) +#include +#define snprintf _snprintf +#endif +#else +#include +#endif + +// Timer Declarations +class Timer { +public: + // Public Timer Methods + Timer(); + + void Start(); + void Stop(); + void Reset(); + + double Time(); +private: + // Private Timer Data + double time0, elapsed; + bool running; + double GetTime(); +#if defined(PBRT_IS_WINDOWS) + // Private Windows Timer Data + LARGE_INTEGER performance_counter, performance_frequency; + double one_over_frequency; +#else + // Private UNIX Timer Data + struct timeval timeofday; +#endif +}; + + + +#endif // PBRT_CORE_TIMER_H diff --git a/core/transform.cpp b/core/transform.cpp new file mode 100644 index 0000000..7250b32 --- /dev/null +++ b/core/transform.cpp @@ -0,0 +1,457 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/transform.cpp* +#include "stdafx.h" +#include "transform.h" +#include "shape.h" + +// Matrix4x4 Method Definitions +bool SolveLinearSystem2x2(const float A[2][2], + const float B[2], float *x0, float *x1) { + float det = A[0][0]*A[1][1] - A[0][1]*A[1][0]; + if (fabsf(det) < 1e-10f) + return false; + *x0 = (A[1][1]*B[0] - A[0][1]*B[1]) / det; + *x1 = (A[0][0]*B[1] - A[1][0]*B[0]) / det; + if (isnan(*x0) || isnan(*x1)) + return false; + return true; +} + + +Matrix4x4::Matrix4x4(float mat[4][4]) { + memcpy(m, mat, 16*sizeof(float)); +} + + +Matrix4x4::Matrix4x4(float t00, float t01, float t02, float t03, + float t10, float t11, float t12, float t13, + float t20, float t21, float t22, float t23, + float t30, float t31, float t32, float t33) { + m[0][0] = t00; m[0][1] = t01; m[0][2] = t02; m[0][3] = t03; + m[1][0] = t10; m[1][1] = t11; m[1][2] = t12; m[1][3] = t13; + m[2][0] = t20; m[2][1] = t21; m[2][2] = t22; m[2][3] = t23; + m[3][0] = t30; m[3][1] = t31; m[3][2] = t32; m[3][3] = t33; +} + + +Matrix4x4 Transpose(const Matrix4x4 &m) { + return Matrix4x4(m.m[0][0], m.m[1][0], m.m[2][0], m.m[3][0], + m.m[0][1], m.m[1][1], m.m[2][1], m.m[3][1], + m.m[0][2], m.m[1][2], m.m[2][2], m.m[3][2], + m.m[0][3], m.m[1][3], m.m[2][3], m.m[3][3]); +} + + +Matrix4x4 Inverse(const Matrix4x4 &m) { + int indxc[4], indxr[4]; + int ipiv[4] = { 0, 0, 0, 0 }; + float minv[4][4]; + memcpy(minv, m.m, 4*4*sizeof(float)); + for (int i = 0; i < 4; i++) { + int irow = -1, icol = -1; + float big = 0.; + // Choose pivot + for (int j = 0; j < 4; j++) { + if (ipiv[j] != 1) { + for (int k = 0; k < 4; k++) { + if (ipiv[k] == 0) { + if (fabsf(minv[j][k]) >= big) { + big = float(fabsf(minv[j][k])); + irow = j; + icol = k; + } + } + else if (ipiv[k] > 1) + Error("Singular matrix in MatrixInvert"); + } + } + } + ++ipiv[icol]; + // Swap rows _irow_ and _icol_ for pivot + if (irow != icol) { + for (int k = 0; k < 4; ++k) + swap(minv[irow][k], minv[icol][k]); + } + indxr[i] = irow; + indxc[i] = icol; + if (minv[icol][icol] == 0.) + Error("Singular matrix in MatrixInvert"); + + // Set $m[icol][icol]$ to one by scaling row _icol_ appropriately + float pivinv = 1.f / minv[icol][icol]; + minv[icol][icol] = 1.f; + for (int j = 0; j < 4; j++) + minv[icol][j] *= pivinv; + + // Subtract this row from others to zero out their columns + for (int j = 0; j < 4; j++) { + if (j != icol) { + float save = minv[j][icol]; + minv[j][icol] = 0; + for (int k = 0; k < 4; k++) + minv[j][k] -= minv[icol][k]*save; + } + } + } + // Swap columns to reflect permutation + for (int j = 3; j >= 0; j--) { + if (indxr[j] != indxc[j]) { + for (int k = 0; k < 4; k++) + swap(minv[k][indxr[j]], minv[k][indxc[j]]); + } + } + return Matrix4x4(minv); +} + + + +// Transform Method Definitions +void Transform::Print(FILE *f) const { + m.Print(f); +} + + +Transform Translate(const Vector &delta) { + Matrix4x4 m(1, 0, 0, delta.x, + 0, 1, 0, delta.y, + 0, 0, 1, delta.z, + 0, 0, 0, 1); + Matrix4x4 minv(1, 0, 0, -delta.x, + 0, 1, 0, -delta.y, + 0, 0, 1, -delta.z, + 0, 0, 0, 1); + return Transform(m, minv); +} + + +Transform Scale(float x, float y, float z) { + Matrix4x4 m(x, 0, 0, 0, + 0, y, 0, 0, + 0, 0, z, 0, + 0, 0, 0, 1); + Matrix4x4 minv(1.f/x, 0, 0, 0, + 0, 1.f/y, 0, 0, + 0, 0, 1.f/z, 0, + 0, 0, 0, 1); + return Transform(m, minv); +} + + +Transform RotateX(float angle) { + float sin_t = sinf(Radians(angle)); + float cos_t = cosf(Radians(angle)); + Matrix4x4 m(1, 0, 0, 0, + 0, cos_t, -sin_t, 0, + 0, sin_t, cos_t, 0, + 0, 0, 0, 1); + return Transform(m, Transpose(m)); +} + + +Transform RotateY(float angle) { + float sin_t = sinf(Radians(angle)); + float cos_t = cosf(Radians(angle)); + Matrix4x4 m( cos_t, 0, sin_t, 0, + 0, 1, 0, 0, + -sin_t, 0, cos_t, 0, + 0, 0, 0, 1); + return Transform(m, Transpose(m)); +} + + + +Transform RotateZ(float angle) { + float sin_t = sinf(Radians(angle)); + float cos_t = cosf(Radians(angle)); + Matrix4x4 m(cos_t, -sin_t, 0, 0, + sin_t, cos_t, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); + return Transform(m, Transpose(m)); +} + + +Transform Rotate(float angle, const Vector &axis) { + Vector a = Normalize(axis); + float s = sinf(Radians(angle)); + float c = cosf(Radians(angle)); + float m[4][4]; + + m[0][0] = a.x * a.x + (1.f - a.x * a.x) * c; + m[0][1] = a.x * a.y * (1.f - c) - a.z * s; + m[0][2] = a.x * a.z * (1.f - c) + a.y * s; + m[0][3] = 0; + + m[1][0] = a.x * a.y * (1.f - c) + a.z * s; + m[1][1] = a.y * a.y + (1.f - a.y * a.y) * c; + m[1][2] = a.y * a.z * (1.f - c) - a.x * s; + m[1][3] = 0; + + m[2][0] = a.x * a.z * (1.f - c) - a.y * s; + m[2][1] = a.y * a.z * (1.f - c) + a.x * s; + m[2][2] = a.z * a.z + (1.f - a.z * a.z) * c; + m[2][3] = 0; + + m[3][0] = 0; + m[3][1] = 0; + m[3][2] = 0; + m[3][3] = 1; + + Matrix4x4 mat(m); + return Transform(mat, Transpose(mat)); +} + + +Transform LookAt(const Point &pos, const Point &look, const Vector &up) { + float m[4][4]; + // Initialize fourth column of viewing matrix + m[0][3] = pos.x; + m[1][3] = pos.y; + m[2][3] = pos.z; + m[3][3] = 1; + + // Initialize first three columns of viewing matrix + Vector dir = Normalize(look - pos); + Vector left = Normalize(Cross(Normalize(up), dir)); + Vector newUp = Cross(dir, left); + m[0][0] = left.x; + m[1][0] = left.y; + m[2][0] = left.z; + m[3][0] = 0.; + m[0][1] = newUp.x; + m[1][1] = newUp.y; + m[2][1] = newUp.z; + m[3][1] = 0.; + m[0][2] = dir.x; + m[1][2] = dir.y; + m[2][2] = dir.z; + m[3][2] = 0.; + Matrix4x4 camToWorld(m); + return Transform(Inverse(camToWorld), camToWorld); +} + + +BBox Transform::operator()(const BBox &b) const { + const Transform &M = *this; + BBox ret( M(Point(b.pMin.x, b.pMin.y, b.pMin.z))); + ret = Union(ret, M(Point(b.pMax.x, b.pMin.y, b.pMin.z))); + ret = Union(ret, M(Point(b.pMin.x, b.pMax.y, b.pMin.z))); + ret = Union(ret, M(Point(b.pMin.x, b.pMin.y, b.pMax.z))); + ret = Union(ret, M(Point(b.pMin.x, b.pMax.y, b.pMax.z))); + ret = Union(ret, M(Point(b.pMax.x, b.pMax.y, b.pMin.z))); + ret = Union(ret, M(Point(b.pMax.x, b.pMin.y, b.pMax.z))); + ret = Union(ret, M(Point(b.pMax.x, b.pMax.y, b.pMax.z))); + return ret; +} + + +Transform Transform::operator*(const Transform &t2) const { + Matrix4x4 m1 = Matrix4x4::Mul(m, t2.m); + Matrix4x4 m2 = Matrix4x4::Mul(t2.mInv, mInv); + return Transform(m1, m2); +} + + +bool Transform::SwapsHandedness() const { + float det = ((m.m[0][0] * + (m.m[1][1] * m.m[2][2] - + m.m[1][2] * m.m[2][1])) - + (m.m[0][1] * + (m.m[1][0] * m.m[2][2] - + m.m[1][2] * m.m[2][0])) + + (m.m[0][2] * + (m.m[1][0] * m.m[2][1] - + m.m[1][1] * m.m[2][0]))); + return det < 0.f; +} + + +Transform Orthographic(float znear, float zfar) { + return Scale(1.f, 1.f, 1.f / (zfar-znear)) * + Translate(Vector(0.f, 0.f, -znear)); +} + + +Transform Perspective(float fov, float n, float f) { + // Perform projective divide + Matrix4x4 persp = Matrix4x4(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, f / (f - n), -f*n / (f - n), + 0, 0, 1, 0); + + // Scale to canonical viewing volume + float invTanAng = 1.f / tanf(Radians(fov) / 2.f); + return Scale(invTanAng, invTanAng, 1) * Transform(persp); +} + + + +// AnimatedTransform Method Definitions +void AnimatedTransform::Decompose(const Matrix4x4 &m, Vector *T, + Quaternion *Rquat, Matrix4x4 *S) { + // Extract translation _T_ from transformation matrix + T->x = m.m[0][3]; + T->y = m.m[1][3]; + T->z = m.m[2][3]; + + // Compute new transformation matrix _M_ without translation + Matrix4x4 M = m; + for (int i = 0; i < 3; ++i) + M.m[i][3] = M.m[3][i] = 0.f; + M.m[3][3] = 1.f; + + // Extract rotation _R_ from transformation matrix + float norm; + int count = 0; + Matrix4x4 R = M; + do { + // Compute next matrix _Rnext_ in series + Matrix4x4 Rnext; + Matrix4x4 Rit = Inverse(Transpose(R)); + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 4; ++j) + Rnext.m[i][j] = 0.5f * (R.m[i][j] + Rit.m[i][j]); + + // Compute norm of difference between _R_ and _Rnext_ + norm = 0.f; + for (int i = 0; i < 3; ++i) { + float n = fabsf(R.m[i][0] - Rnext.m[i][0]) + + fabsf(R.m[i][1] - Rnext.m[i][1]) + + fabsf(R.m[i][2] - Rnext.m[i][2]); + norm = max(norm, n); + } + R = Rnext; + } while (++count < 100 && norm > .0001f); + // XXX TODO FIXME deal with flip... + *Rquat = Quaternion(R); + + // Compute scale _S_ using rotation and original matrix + *S = Matrix4x4::Mul(Inverse(R), M); +} + + +void AnimatedTransform::Interpolate(float time, Transform *t) const { + // Handle boundary conditions for matrix interpolation + if (!actuallyAnimated || time <= startTime) { + *t = *startTransform; + return; + } + if (time >= endTime) { + *t = *endTransform; + return; + } + float dt = (time - startTime) / (endTime - startTime); + // Interpolate translation at _dt_ + Vector trans = (1.f - dt) * T[0] + dt * T[1]; + + // Interpolate rotation at _dt_ + Quaternion rotate = Slerp(dt, R[0], R[1]); + + // Interpolate scale at _dt_ + Matrix4x4 scale; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + scale.m[i][j] = Lerp(dt, S[0].m[i][j], S[1].m[i][j]); + + // Compute interpolated matrix as product of interpolated components + *t = Translate(trans) * rotate.ToTransform() * Transform(scale); +} + + +BBox AnimatedTransform::MotionBounds(const BBox &b, + bool useInverse) const { + if (!actuallyAnimated) return Inverse(*startTransform)(b); + BBox ret; + const int nSteps = 128; + for (int i = 0; i < nSteps; ++i) { + Transform t; + float time = Lerp(float(i)/float(nSteps-1), startTime, endTime); + Interpolate(time, &t); + if (useInverse) t = Inverse(t); + ret = Union(ret, t(b)); + } + return ret; +} + + +void AnimatedTransform::operator()(const Ray &r, Ray *tr) const { + if (!actuallyAnimated || r.time <= startTime) + (*startTransform)(r, tr); + else if (r.time >= endTime) + (*endTransform)(r, tr); + else { + Transform t; + Interpolate(r.time, &t); + t(r, tr); + } + tr->time = r.time; +} + + +void AnimatedTransform::operator()(const RayDifferential &r, + RayDifferential *tr) const { + if (!actuallyAnimated || r.time <= startTime) + (*startTransform)(r, tr); + else if (r.time >= endTime) + (*endTransform)(r, tr); + else { + Transform t; + Interpolate(r.time, &t); + t(r, tr); + } + tr->time = r.time; +} + + +Point AnimatedTransform::operator()(float time, const Point &p) const { + if (!actuallyAnimated || time <= startTime) + return (*startTransform)(p); + else if (time >= endTime) + return (*endTransform)(p); + Transform t; + Interpolate(time, &t); + return t(p); +} + + +Vector AnimatedTransform::operator()(float time, const Vector &v) const { + if (!actuallyAnimated || time <= startTime) + return (*startTransform)(v); + else if (time >= endTime) + return (*endTransform)(v); + Transform t; + Interpolate(time, &t); + return t(v); +} + + +Ray AnimatedTransform::operator()(const Ray &r) const { + Ray ret; + (*this)(r, &ret); + return ret; +} + + diff --git a/core/transform.h b/core/transform.h new file mode 100644 index 0000000..dbdc788 --- /dev/null +++ b/core/transform.h @@ -0,0 +1,323 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_TRANSFORM_H +#define PBRT_CORE_TRANSFORM_H + +// core/transform.h* +#include "pbrt.h" +#include "geometry.h" +#include "quaternion.h" + +// Matrix4x4 Declarations +struct Matrix4x4 { + // Matrix4x4 Public Methods + Matrix4x4() { + m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.f; + m[0][1] = m[0][2] = m[0][3] = m[1][0] = + m[1][2] = m[1][3] = m[2][0] = m[2][1] = m[2][3] = + m[3][0] = m[3][1] = m[3][2] = 0.f; + } + Matrix4x4(float mat[4][4]); + Matrix4x4(float t00, float t01, float t02, float t03, + float t10, float t11, float t12, float t13, + float t20, float t21, float t22, float t23, + float t30, float t31, float t32, float t33); + bool operator==(const Matrix4x4 &m2) const { + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 4; ++j) + if (m[i][j] != m2.m[i][j]) return false; + return true; + } + bool operator!=(const Matrix4x4 &m2) const { + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 4; ++j) + if (m[i][j] != m2.m[i][j]) return true; + return false; + } + friend Matrix4x4 Transpose(const Matrix4x4 &); + void Print(FILE *f) const { + fprintf(f, "[ "); + for (int i = 0; i < 4; ++i) { + fprintf(f, " [ "); + for (int j = 0; j < 4; ++j) { + fprintf(f, "%f", m[i][j]); + if (j != 3) fprintf(f, ", "); + } + fprintf(f, " ]\n"); + } + fprintf(f, " ] "); + } + static Matrix4x4 Mul(const Matrix4x4 &m1, const Matrix4x4 &m2) { + Matrix4x4 r; + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 4; ++j) + r.m[i][j] = m1.m[i][0] * m2.m[0][j] + + m1.m[i][1] * m2.m[1][j] + + m1.m[i][2] * m2.m[2][j] + + m1.m[i][3] * m2.m[3][j]; + return r; + } + friend Matrix4x4 Inverse(const Matrix4x4 &); + float m[4][4]; +}; + + + +// Transform Declarations +class Transform { +public: + // Transform Public Methods + Transform() { } + Transform(const float mat[4][4]) { + m = Matrix4x4(mat[0][0], mat[0][1], mat[0][2], mat[0][3], + mat[1][0], mat[1][1], mat[1][2], mat[1][3], + mat[2][0], mat[2][1], mat[2][2], mat[2][3], + mat[3][0], mat[3][1], mat[3][2], mat[3][3]); + mInv = Inverse(m); + } + Transform(const Matrix4x4 &mat) + : m(mat), mInv(Inverse(mat)) { + } + Transform(const Matrix4x4 &mat, const Matrix4x4 &minv) + : m(mat), mInv(minv) { + } + void Print(FILE *f) const; + friend Transform Inverse(const Transform &t) { + return Transform(t.mInv, t.m); + } + friend Transform Transpose(const Transform &t) { + return Transform(Transpose(t.m), Transpose(t.mInv)); + } + bool operator==(const Transform &t) const { + return t.m == m && t.mInv == mInv; + } + bool operator!=(const Transform &t) const { + return t.m != m || t.mInv != mInv; + } + bool operator<(const Transform &t2) const { + for (uint32_t i = 0; i < 4; ++i) + for (uint32_t j = 0; j < 4; ++j) { + if (m.m[i][j] < t2.m.m[i][j]) return true; + if (m.m[i][j] > t2.m.m[i][j]) return false; + } + return false; + } + bool IsIdentity() const { + return (m.m[0][0] == 1.f && m.m[0][1] == 0.f && + m.m[0][2] == 0.f && m.m[0][3] == 0.f && + m.m[1][0] == 0.f && m.m[1][1] == 1.f && + m.m[1][2] == 0.f && m.m[1][3] == 0.f && + m.m[2][0] == 0.f && m.m[2][1] == 0.f && + m.m[2][2] == 1.f && m.m[2][3] == 0.f && + m.m[3][0] == 0.f && m.m[3][1] == 0.f && + m.m[3][2] == 0.f && m.m[3][3] == 1.f); + } + const Matrix4x4 &GetMatrix() const { return m; } + const Matrix4x4 &GetInverseMatrix() const { return mInv; } + bool HasScale() const { + float la2 = (*this)(Vector(1,0,0)).LengthSquared(); + float lb2 = (*this)(Vector(0,1,0)).LengthSquared(); + float lc2 = (*this)(Vector(0,0,1)).LengthSquared(); +#define NOT_ONE(x) ((x) < .999f || (x) > 1.001f) + return (NOT_ONE(la2) || NOT_ONE(lb2) || NOT_ONE(lc2)); +#undef NOT_ONE + } + inline Point operator()(const Point &pt) const; + inline void operator()(const Point &pt, Point *ptrans) const; + inline Vector operator()(const Vector &v) const; + inline void operator()(const Vector &v, Vector *vt) const; + inline Normal operator()(const Normal &) const; + inline void operator()(const Normal &, Normal *nt) const; + inline Ray operator()(const Ray &r) const; + inline void operator()(const Ray &r, Ray *rt) const; + inline RayDifferential operator()(const RayDifferential &r) const; + inline void operator()(const RayDifferential &r, RayDifferential *rt) const; + BBox operator()(const BBox &b) const; + Transform operator*(const Transform &t2) const; + bool SwapsHandedness() const; +private: + // Transform Private Data + Matrix4x4 m, mInv; + friend class AnimatedTransform; + friend struct Quaternion; +}; + + +Transform Translate(const Vector &delta); +Transform Scale(float x, float y, float z); +Transform RotateX(float angle); +Transform RotateY(float angle); +Transform RotateZ(float angle); +Transform Rotate(float angle, const Vector &axis); +Transform LookAt(const Point &pos, const Point &look, const Vector &up); +bool SolveLinearSystem2x2(const float A[2][2], const float B[2], + float *x0, float *x1); +Transform Orthographic(float znear, float zfar); +Transform Perspective(float fov, float znear, float zfar); + +// Transform Inline Functions +inline Point Transform::operator()(const Point &pt) const { + float x = pt.x, y = pt.y, z = pt.z; + float xp = m.m[0][0]*x + m.m[0][1]*y + m.m[0][2]*z + m.m[0][3]; + float yp = m.m[1][0]*x + m.m[1][1]*y + m.m[1][2]*z + m.m[1][3]; + float zp = m.m[2][0]*x + m.m[2][1]*y + m.m[2][2]*z + m.m[2][3]; + float wp = m.m[3][0]*x + m.m[3][1]*y + m.m[3][2]*z + m.m[3][3]; + Assert(wp != 0); + if (wp == 1.) return Point(xp, yp, zp); + else return Point(xp, yp, zp)/wp; +} + + +inline void Transform::operator()(const Point &pt, + Point *ptrans) const { + float x = pt.x, y = pt.y, z = pt.z; + ptrans->x = m.m[0][0]*x + m.m[0][1]*y + m.m[0][2]*z + m.m[0][3]; + ptrans->y = m.m[1][0]*x + m.m[1][1]*y + m.m[1][2]*z + m.m[1][3]; + ptrans->z = m.m[2][0]*x + m.m[2][1]*y + m.m[2][2]*z + m.m[2][3]; + float w = m.m[3][0]*x + m.m[3][1]*y + m.m[3][2]*z + m.m[3][3]; + if (w != 1.) *ptrans /= w; +} + + +inline Vector Transform::operator()(const Vector &v) const { + float x = v.x, y = v.y, z = v.z; + return Vector(m.m[0][0]*x + m.m[0][1]*y + m.m[0][2]*z, + m.m[1][0]*x + m.m[1][1]*y + m.m[1][2]*z, + m.m[2][0]*x + m.m[2][1]*y + m.m[2][2]*z); +} + + +inline void Transform::operator()(const Vector &v, + Vector *vt) const { + float x = v.x, y = v.y, z = v.z; + vt->x = m.m[0][0] * x + m.m[0][1] * y + m.m[0][2] * z; + vt->y = m.m[1][0] * x + m.m[1][1] * y + m.m[1][2] * z; + vt->z = m.m[2][0] * x + m.m[2][1] * y + m.m[2][2] * z; +} + + +inline Normal Transform::operator()(const Normal &n) const { + float x = n.x, y = n.y, z = n.z; + return Normal(mInv.m[0][0]*x + mInv.m[1][0]*y + mInv.m[2][0]*z, + mInv.m[0][1]*x + mInv.m[1][1]*y + mInv.m[2][1]*z, + mInv.m[0][2]*x + mInv.m[1][2]*y + mInv.m[2][2]*z); +} + + +inline void Transform::operator()(const Normal &n, + Normal *nt) const { + float x = n.x, y = n.y, z = n.z; + nt->x = mInv.m[0][0] * x + mInv.m[1][0] * y + + mInv.m[2][0] * z; + nt->y = mInv.m[0][1] * x + mInv.m[1][1] * y + + mInv.m[2][1] * z; + nt->z = mInv.m[0][2] * x + mInv.m[1][2] * y + + mInv.m[2][2] * z; +} + + +inline Ray Transform::operator()(const Ray &r) const { + Ray ret = r; + (*this)(ret.o, &ret.o); + (*this)(ret.d, &ret.d); + return ret; +} + + +inline void Transform::operator()(const Ray &r, Ray *rt) const { + (*this)(r.o, &rt->o); + (*this)(r.d, &rt->d); + if (rt != &r) { + rt->mint = r.mint; + rt->maxt = r.maxt; + rt->time = r.time; + rt->depth = r.depth; + } +} + + + +inline void Transform::operator()(const RayDifferential &r, RayDifferential *rt) const { + (*this)(Ray(r), rt); + rt->hasDifferentials = r.hasDifferentials; + (*this)(r.rxOrigin, &rt->rxOrigin); + (*this)(r.ryOrigin, &rt->ryOrigin); + (*this)(r.rxDirection, &rt->rxDirection); + (*this)(r.ryDirection, &rt->ryDirection); +} + + + +inline RayDifferential Transform::operator()(const RayDifferential &r) const { + RayDifferential ret; + (*this)(Ray(r), &ret); + ret.hasDifferentials = r.hasDifferentials; + (*this)(r.rxOrigin, &ret.rxOrigin); + (*this)(r.ryOrigin, &ret.ryOrigin); + (*this)(r.rxDirection, &ret.rxDirection); + (*this)(r.ryDirection, &ret.ryDirection); + return ret; +} + + + + +// AnimatedTransform Declarations +class AnimatedTransform { +public: + // AnimatedTransform Public Methods + AnimatedTransform(const Transform *transform1, float time1, + const Transform *transform2, float time2) + : startTime(time1), endTime(time2), + startTransform(transform1), endTransform(transform2), + actuallyAnimated(*startTransform != *endTransform) { + Decompose(startTransform->m, &T[0], &R[0], &S[0]); + Decompose(endTransform->m, &T[1], &R[1], &S[1]); + } + static void Decompose(const Matrix4x4 &m, Vector *T, Quaternion *R, Matrix4x4 *S); + void Interpolate(float time, Transform *t) const; + void operator()(const Ray &r, Ray *tr) const; + void operator()(const RayDifferential &r, RayDifferential *tr) const; + Point operator()(float time, const Point &p) const; + Vector operator()(float time, const Vector &v) const; + Ray operator()(const Ray &r) const; + BBox MotionBounds(const BBox &b, bool useInverse) const; + bool HasScale() const { return startTransform->HasScale() || endTransform->HasScale(); } +private: + // AnimatedTransform Private Data + const float startTime, endTime; + const Transform *startTransform, *endTransform; + const bool actuallyAnimated; + Vector T[2]; + Quaternion R[2]; + Matrix4x4 S[2]; +}; + + + +#endif // PBRT_CORE_TRANSFORM_H diff --git a/core/volume.cpp b/core/volume.cpp new file mode 100644 index 0000000..7410fba --- /dev/null +++ b/core/volume.cpp @@ -0,0 +1,304 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// core/volume.cpp* +#include "stdafx.h" +#include "volume.h" + +// Volume Scattering Local Definitions +struct MeasuredSS { + const char *name; + float sigma_prime_s[3], sigma_a[3]; // mm^-1 +}; + + +static MeasuredSS mss[] = { +// From "A Practical Model for Subsurface Light Transport" +// Jensen, Marschner, Levoy, Hanrahan +// Proc SIGGRAPH 2001 +{ "Apple", { 2.29, 2.39, 1.97 }, { 0.0030, 0.0034, 0.046 }, }, +{ "Chicken1", { 0.15, 0.21, 0.38 }, { 0.015, 0.077, 0.19 }, }, +{ "Chicken2", { 0.19, 0.25, 0.32 }, { 0.018, 0.088, 0.20 }, }, +{ "Cream", { 7.38, 5.47, 3.15 }, { 0.0002, 0.0028, 0.0163 }, }, +{ "Ketchup", { 0.18, 0.07, 0.03 }, { 0.061, 0.97, 1.45 }, }, +{ "Marble", { 2.19, 2.62, 3.00 }, { 0.0021, 0.0041, 0.0071 }, }, +{ "Potato", { 0.68, 0.70, 0.55 }, { 0.0024, 0.0090, 0.12 }, }, +{ "Skimmilk", { 0.70, 1.22, 1.90 }, { 0.0014, 0.0025, 0.0142 }, }, +{ "Skin1", { 0.74, 0.88, 1.01 }, { 0.032, 0.17, 0.48 }, }, +{ "Skin2", { 1.09, 1.59, 1.79 }, { 0.013, 0.070, 0.145 }, }, +{ "Spectralon", { 11.6, 20.4, 14.9 }, { 0.00, 0.00, 0.00 }, }, +{ "Wholemilk", { 2.55, 3.21, 3.77 }, { 0.0011, 0.0024, 0.014 }, }, + +// From "Acquiring Scattering Properties of Participating Media by Dilution", +// Narasimhan, Gupta, Donner, Ramamoorthi, Nayar, Jensen +// Proc SIGGRAPH 2006 +{ "Lowfat Milk", { 0.912600, 1.074800, 1.250000 }, { 0.000200, 0.000400, 0.000800 } }, +{ "Reduced Milk", { 1.075000, 1.221300, 1.394100 }, { 0.000200, 0.000400, 0.001000 } }, +{ "Regular Milk", { 1.187400, 1.329600, 1.460200 }, { 0.000100, 0.000300, 0.001300 } }, +{ "Espresso", { 0.437600, 0.511500, 0.604800 }, { 0.166900, 0.228700, 0.307800 } }, +{ "Mint Mocha Coffee", { 0.190000, 0.260000, 0.350000 }, { 0.098400, 0.151900, 0.204000 } }, +{ "Lowfat Soy Milk", { 0.141900, 0.162500, 0.274000 }, { 0.000100, 0.000500, 0.002500 } }, +{ "Regular Soy Milk", { 0.243400, 0.271900, 0.459700 }, { 0.000100, 0.000500, 0.003400 } }, +{ "Lowfat Chocolate Milk", { 0.428200, 0.501400, 0.579100 }, { 0.000500, 0.001600, 0.006800 } }, +{ "Regular Chocolate Milk", { 0.735900, 0.917200, 1.068800 }, { 0.000700, 0.003000, 0.010000 } }, +{ "Coke", { 0.714300, 1.168800, 1.716900 }, { 0.696600, 1.148000, 1.716900 } }, +{ "Pepsi", { 0.643300, 0.999000, 1.442000 }, { 0.637500, 0.984900, 1.442000 } }, +{ "Sprite", { 0.129900, 0.128300, 0.139500 }, { 0.123000, 0.119400, 0.130600 } }, +{ "Gatorade", { 0.400900, 0.418500, 0.432400 }, { 0.161700, 0.125800, 0.057900 } }, +{ "Chardonnay", { 0.157700, 0.174800, 0.351200 }, { 0.154700, 0.170100, 0.344300 } }, +{ "White Zinfandel", { 0.176300, 0.237000, 0.291300 }, { 0.173200, 0.232200, 0.284700 } }, +{ "Merlot", { 0.763900, 1.642900, 1.919600 }, { 0.758600, 1.642900, 1.919600 } }, +{ "Budweiser Beer", { 0.148600, 0.321000, 0.736000 }, { 0.144900, 0.314100, 0.728600 } }, +{ "Coors Light Beer", { 0.029500, 0.066300, 0.152100 }, { 0.026800, 0.060800, 0.152100 } }, +{ "Clorox", { 0.160000, 0.250000, 0.330000 }, { 0.017500, 0.077700, 0.137200 } }, +{ "Apple Juice", { 0.121500, 0.210100, 0.440700 }, { 0.101400, 0.185800, 0.408400 } }, +{ "Cranberry Juice", { 0.270000, 0.630000, 0.830000 }, { 0.257200, 0.614500, 0.810400 } }, +{ "Grape Juice", { 0.550000, 1.250000, 1.530000 }, { 0.542800, 1.250000, 1.530000 } }, +{ "Ruby Grapefruit Juice", { 0.251300, 0.351700, 0.430500 }, { 0.089600, 0.191100, 0.263600 } }, +{ "White Grapefruit Juice", { 0.360900, 0.380000, 0.563200 }, { 0.009600, 0.013100, 0.039500 } }, +{ "Shampoo", { 0.028800, 0.071000, 0.095200 }, { 0.018400, 0.059600, 0.080500 } }, +{ "Strawberry Shampoo", { 0.021700, 0.078800, 0.102200 }, { 0.018900, 0.075600, 0.098900 } }, +{ "Head & Shoulders Shampoo", { 0.367400, 0.452700, 0.521100 }, { 0.088300, 0.163700, 0.212500 } }, +{ "Lemon Tea", { 0.340000, 0.580000, 0.880000 }, { 0.260200, 0.490200, 0.772700 } }, +{ "Orange Juice Powder", { 0.337700, 0.557300, 1.012200 }, { 0.144900, 0.344100, 0.786300 } }, +{ "Pink Lemonade", { 0.240000, 0.370000, 0.450000 }, { 0.116500, 0.236600, 0.319500 } }, +{ "Cappuccino Powder", { 0.257400, 0.353600, 0.484000 }, { 0.192000, 0.265400, 0.327200 } }, +{ "Salt Powder", { 0.760000, 0.868500, 0.936300 }, { 0.511500, 0.586300, 0.614700 } }, +{ "Sugar Powder", { 0.079500, 0.175900, 0.278000 }, { 0.065000, 0.159700, 0.257800 } }, +{ "Suisse Mocha", { 0.509800, 0.647600, 0.794400 }, { 0.187500, 0.289300, 0.379600 } }, +{ "Pacific Ocean Surface Water", { 3.364500, 3.315800, 3.242800 }, { 3.184500, 3.132400, 3.014700 } }, + +}; + + +static float RdIntegral(float alphap, float A) { + float sqrtTerm = sqrtf(3.f * (1.f - alphap)); + return alphap / 2.f * (1.f + expf(-4.f/3.f * A * sqrtTerm)) * + expf(-sqrtTerm); +} + + +static float RdToAlphap(float reflectance, float A) { + float alphaLow = 0., alphaHigh = 1.f; + float kd0 = RdIntegral(alphaLow, A); + float kd1 = RdIntegral(alphaHigh, A); + for (int i = 0; i < 16; ++i) { + Assert(kd0 <= reflectance && kd1 >= reflectance); + float alphaMid = (alphaLow + alphaHigh) * 0.5f; + float kd = RdIntegral(alphaMid, A); + if (kd < reflectance) { alphaLow = alphaMid; kd0 = kd; } + else { alphaHigh = alphaMid; kd1 = kd; } + } + return (alphaLow + alphaHigh) * 0.5f; +} + + + +// Volume Scattering Definitions +float PhaseIsotropic(const Vector &, const Vector &) { + return 1.f / (4.f * M_PI); +} + + +float PhaseRayleigh(const Vector &w, const Vector &wp) { + float costheta = Dot(w, wp); + return 3.f/(16.f*M_PI) * (1 + costheta * costheta); +} + + +float PhaseMieHazy(const Vector &w, const Vector &wp) { + float costheta = Dot(w, wp); + return (0.5f + 4.5f * powf(0.5 * (1.f + costheta), 8.f)) / (4.f*M_PI); +} + + +float PhaseMieMurky(const Vector &w, const Vector &wp) { + float costheta = Dot(w, wp); + return (0.5f + 16.5f * powf(0.5 * (1.f + costheta), 32.f)) / (4.f*M_PI); +} + + +float PhaseHG(const Vector &w, const Vector &wp, float g) { + float costheta = Dot(w, wp); + return 1.f / (4.f * M_PI) * + (1.f - g*g) / powf(1.f + g*g - 2.f * g * costheta, 1.5f); +} + + +float PhaseSchlick(const Vector &w, const Vector &wp, float g) { + // improved g->k mapping derived by Thies Heidecke + // see http://pbrt.org/bugtracker/view.php?id=102 + float alpha = 1.5f; + float k = alpha * g - (1.f - alpha) * g * g * g; + float kcostheta = k * Dot(w, wp); + return 1.f / (4.f * M_PI) * + (1.f - k*k) / ((1.f - kcostheta) * (1.f - kcostheta)); +} + + +VolumeRegion::~VolumeRegion() { +} + + +Spectrum VolumeRegion::sigma_t(const Point &p, const Vector &w, + float time) const { + return sigma_a(p, w, time) + sigma_s(p, w, time); +} + + +AggregateVolume::AggregateVolume(const vector &r) { + regions = r; + for (uint32_t i = 0; i < regions.size(); ++i) + bound = Union(bound, regions[i]->WorldBound()); +} + + +Spectrum AggregateVolume::sigma_a(const Point &p, const Vector &w, + float time) const { + Spectrum s(0.); + for (uint32_t i = 0; i < regions.size(); ++i) + s += regions[i]->sigma_a(p, w, time); + return s; +} + + +Spectrum AggregateVolume::sigma_s(const Point &p, const Vector &w, float time) const { + Spectrum s(0.); + for (uint32_t i = 0; i < regions.size(); ++i) + s += regions[i]->sigma_s(p, w, time); + return s; +} + + +Spectrum AggregateVolume::Lve(const Point &p, const Vector &w, float time) const { + Spectrum L(0.); + for (uint32_t i = 0; i < regions.size(); ++i) + L += regions[i]->Lve(p, w, time); + return L; +} + + +float AggregateVolume::p(const Point &p, const Vector &w, const Vector &wp, + float time) const { + float ph = 0, sumWt = 0; + for (uint32_t i = 0; i < regions.size(); ++i) { + float wt = regions[i]->sigma_s(p, w, time).y(); + sumWt += wt; + ph += wt * regions[i]->p(p, w, wp, time); + } + return ph / sumWt; +} + + +Spectrum AggregateVolume::sigma_t(const Point &p, const Vector &w, float time) const { + Spectrum s(0.); + for (uint32_t i = 0; i < regions.size(); ++i) + s += regions[i]->sigma_t(p, w, time); + return s; +} + + +Spectrum AggregateVolume::tau(const Ray &ray, float step, float offset) const { + Spectrum t(0.); + for (uint32_t i = 0; i < regions.size(); ++i) + t += regions[i]->tau(ray, step, offset); + return t; +} + + +bool AggregateVolume::IntersectP(const Ray &ray, + float *t0, float *t1) const { + *t0 = INFINITY; + *t1 = -INFINITY; + for (uint32_t i = 0; i < regions.size(); ++i) { + float tr0, tr1; + if (regions[i]->IntersectP(ray, &tr0, &tr1)) { + *t0 = min(*t0, tr0); + *t1 = max(*t1, tr1); + } + } + return (*t0 < *t1); +} + + +AggregateVolume::~AggregateVolume() { + for (uint32_t i = 0; i < regions.size(); ++i) + delete regions[i]; +} + + +BBox AggregateVolume::WorldBound() const { + return bound; +} + + +bool GetVolumeScatteringProperties(const string &name, Spectrum *sigma_a, + Spectrum *sigma_prime_s) { + for (uint32_t i = 0; i < sizeof(mss) / sizeof(mss[0]); ++i) { + if (name == mss[i].name) { + *sigma_a = Spectrum::FromRGB(mss[i].sigma_a); + *sigma_prime_s = Spectrum::FromRGB(mss[i].sigma_prime_s); + return true; + } + } + return false; +} + + +void SubsurfaceFromDiffuse(const Spectrum &Kd, float meanPathLength, + float eta, Spectrum *sigma_a, Spectrum *sigma_prime_s) { + float A = (1.f + Fdr(eta)) / (1.f - Fdr(eta)); + float rgb[3]; + Kd.ToRGB(rgb); + float sigma_prime_s_rgb[3], sigma_a_rgb[3]; + for (int i = 0; i < 3; ++i) { + // Compute $\alpha'$ for RGB component, compute scattering properties + float alphap = RdToAlphap(rgb[i], A); + float sigma_tr = 1.f / meanPathLength; + float sigma_prime_t = sigma_tr / sqrtf(3.f * 1.f - alphap); + sigma_prime_s_rgb[i] = alphap * sigma_prime_t; + sigma_a_rgb[i] = sigma_prime_t - sigma_prime_s_rgb[i]; + } + *sigma_a = Spectrum::FromRGB(sigma_a_rgb); + *sigma_prime_s = Spectrum::FromRGB(sigma_prime_s_rgb); +} + + +Spectrum DensityRegion::tau(const Ray &r, float stepSize, + float u) const { + float t0, t1; + float length = r.d.Length(); + if (length == 0.f) return 0.f; + Ray rn(r.o, r.d / length, r.mint * length, r.maxt * length, r.time); + if (!IntersectP(rn, &t0, &t1)) return 0.; + Spectrum tau(0.); + t0 += u * stepSize; + while (t0 < t1) { + tau += sigma_t(rn(t0), -rn.d, r.time); + t0 += stepSize; + } + return tau * stepSize; +} + + diff --git a/core/volume.h b/core/volume.h new file mode 100644 index 0000000..e61312b --- /dev/null +++ b/core/volume.h @@ -0,0 +1,134 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_CORE_VOLUME_H +#define PBRT_CORE_VOLUME_H + +// core/volume.h* +#include "pbrt.h" +#include "spectrum.h" +#include "geometry.h" +#include "transform.h" +#include "integrator.h" + +// Volume Scattering Declarations +float PhaseIsotropic(const Vector &w, const Vector &wp); +float PhaseRayleigh(const Vector &w, const Vector &wp); +float PhaseMieHazy(const Vector &w, const Vector &wp); +float PhaseMieMurky(const Vector &w, const Vector &wp); +float PhaseHG(const Vector &w, const Vector &wp, float g); +float PhaseSchlick(const Vector &w, const Vector &wp, float g); +class VolumeRegion { +public: + // VolumeRegion Interface + virtual ~VolumeRegion(); + virtual BBox WorldBound() const = 0; + virtual bool IntersectP(const Ray &ray, float *t0, float *t1) const = 0; + virtual Spectrum sigma_a(const Point &, const Vector &, + float time) const = 0; + virtual Spectrum sigma_s(const Point &, const Vector &, + float time) const = 0; + virtual Spectrum Lve(const Point &, const Vector &, + float time) const = 0; + virtual float p(const Point &, const Vector &, + const Vector &, float time) const = 0; + virtual Spectrum sigma_t(const Point &p, const Vector &wo, float time) const; + virtual Spectrum tau(const Ray &ray, float step = 1.f, + float offset = 0.5) const = 0; +}; + + +class DensityRegion : public VolumeRegion { +public: + // DensityRegion Public Methods + DensityRegion(const Spectrum &sa, const Spectrum &ss, float gg, + const Spectrum &emit, const Transform &VolumeToWorld) + : sig_a(sa), sig_s(ss), le(emit), g(gg), + WorldToVolume(Inverse(VolumeToWorld)) { } + virtual float Density(const Point &Pobj) const = 0; + Spectrum sigma_a(const Point &p, const Vector &, float) const { + return Density(WorldToVolume(p)) * sig_a; + } + Spectrum sigma_s(const Point &p, const Vector &, float) const { + return Density(WorldToVolume(p)) * sig_s; + } + Spectrum sigma_t(const Point &p, const Vector &, float) const { + return Density(WorldToVolume(p)) * (sig_a + sig_s); + } + Spectrum Lve(const Point &p, const Vector &, float) const { + return Density(WorldToVolume(p)) * le; + } + float p(const Point &p, const Vector &w, const Vector &wp, float) const { + return PhaseHG(w, wp, g); + } + Spectrum tau(const Ray &r, float stepSize, float offset) const; +protected: + // DensityRegion Protected Data + Spectrum sig_a, sig_s, le; + float g; + Transform WorldToVolume; +}; + + +class AggregateVolume : public VolumeRegion { +public: + // AggregateVolume Public Methods + AggregateVolume(const vector &r); + ~AggregateVolume(); + BBox WorldBound() const; + bool IntersectP(const Ray &ray, float *t0, float *t1) const; + Spectrum sigma_a(const Point &, const Vector &, float) const; + Spectrum sigma_s(const Point &, const Vector &, float) const; + Spectrum Lve(const Point &, const Vector &, float) const; + float p(const Point &, const Vector &, const Vector &, float) const; + Spectrum sigma_t(const Point &, const Vector &, float) const; + Spectrum tau(const Ray &ray, float, float) const; +private: + // AggregateVolume Private Data + vector regions; + BBox bound; +}; + + +bool GetVolumeScatteringProperties(const string &name, Spectrum *sigma_a, + Spectrum *sigma_prime_s); +class VolumeIntegrator : public Integrator { +public: + // VolumeIntegrator Interface + virtual Spectrum Li(const Scene *scene, const Renderer *renderer, + const RayDifferential &ray, const Sample *sample, RNG &rng, + Spectrum *transmittance, MemoryArena &arena) const = 0; + virtual Spectrum Transmittance(const Scene *scene, + const Renderer *renderer, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena) const = 0; +}; + + +void SubsurfaceFromDiffuse(const Spectrum &Kd, float meanPathLength, float eta, + Spectrum *sigma_a, Spectrum *sigma_prime_s); + +#endif // PBRT_CORE_VOLUME_H diff --git a/dgauss.50mm.dat b/dgauss.50mm.dat new file mode 100644 index 0000000..9bbcb0e --- /dev/null +++ b/dgauss.50mm.dat @@ -0,0 +1,16 @@ +# D-GAUSS F/2 22deg HFOV +# US patent 2,673,491 Tronnier" +# Moden Lens Design, p.312" +# Scaled to 50 mm from 100 mm +# radius axpos N aperture +29.475 3.76 1.67 25.2 +84.83 0.12 1 25.2 +19.275 4.025 1.67 23 +40.77 3.275 1.699 23 +12.75 5.705 1 18 +0 4.5 0 17.1 +-14.495 1.18 1.603 17 +40.77 6.065 1.658 20 +-20.385 0.19 1 20 +437.065 3.22 1.717 20 +-39.73 0 1 20 diff --git a/film/image.cpp b/film/image.cpp new file mode 100644 index 0000000..9e95f00 --- /dev/null +++ b/film/image.cpp @@ -0,0 +1,240 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// film/image.cpp* +#include "stdafx.h" +#include "film/image.h" +#include "spectrum.h" +#include "parallel.h" +#include "imageio.h" + +// ImageFilm Method Definitions +ImageFilm::ImageFilm(int xres, int yres, Filter *filt, const float crop[4], + const string &fn, bool openWindow) + : Film(xres, yres) { + filter = filt; + memcpy(cropWindow, crop, 4 * sizeof(float)); + filename = fn; + // Compute film image extent + xPixelStart = Ceil2Int(xResolution * cropWindow[0]); + xPixelCount = max(1, Ceil2Int(xResolution * cropWindow[1]) - xPixelStart); + yPixelStart = Ceil2Int(yResolution * cropWindow[2]); + yPixelCount = max(1, Ceil2Int(yResolution * cropWindow[3]) - yPixelStart); + + // Allocate film image storage + pixels = new BlockedArray(xPixelCount, yPixelCount); + + // Precompute filter weight table +#define FILTER_TABLE_SIZE 16 + filterTable = new float[FILTER_TABLE_SIZE * FILTER_TABLE_SIZE]; + float *ftp = filterTable; + for (int y = 0; y < FILTER_TABLE_SIZE; ++y) { + float fy = ((float)y + .5f) * + filter->yWidth / FILTER_TABLE_SIZE; + for (int x = 0; x < FILTER_TABLE_SIZE; ++x) { + float fx = ((float)x + .5f) * + filter->xWidth / FILTER_TABLE_SIZE; + *ftp++ = filter->Evaluate(fx, fy); + } + } + + // Possibly open window for image display + if (openWindow || PbrtOptions.openWindow) { + Warning("Support for opening image display window not available in this build."); + } +} + + +void ImageFilm::AddSample(const CameraSample &sample, + const Spectrum &L) { + // Compute sample's raster extent + float dimageX = sample.imageX - 0.5f; + float dimageY = sample.imageY - 0.5f; + int x0 = Ceil2Int (dimageX - filter->xWidth); + int x1 = Floor2Int(dimageX + filter->xWidth); + int y0 = Ceil2Int (dimageY - filter->yWidth); + int y1 = Floor2Int(dimageY + filter->yWidth); + x0 = max(x0, xPixelStart); + x1 = min(x1, xPixelStart + xPixelCount - 1); + y0 = max(y0, yPixelStart); + y1 = min(y1, yPixelStart + yPixelCount - 1); + if ((x1-x0) < 0 || (y1-y0) < 0) + { + PBRT_SAMPLE_OUTSIDE_IMAGE_EXTENT(const_cast(&sample)); + return; + } + + // Loop over filter support and add sample to pixel arrays + float xyz[3]; + L.ToXYZ(xyz); + + // Precompute $x$ and $y$ filter table offsets + int *ifx = ALLOCA(int, x1 - x0 + 1); + for (int x = x0; x <= x1; ++x) { + float fx = fabsf((x - dimageX) * + filter->invXWidth * FILTER_TABLE_SIZE); + ifx[x-x0] = min(Floor2Int(fx), FILTER_TABLE_SIZE-1); + } + int *ify = ALLOCA(int, y1 - y0 + 1); + for (int y = y0; y <= y1; ++y) { + float fy = fabsf((y - dimageY) * + filter->invYWidth * FILTER_TABLE_SIZE); + ify[y-y0] = min(Floor2Int(fy), FILTER_TABLE_SIZE-1); + } + bool syncNeeded = (filter->xWidth > 0.5f || filter->yWidth > 0.5f); + for (int y = y0; y <= y1; ++y) { + for (int x = x0; x <= x1; ++x) { + // Evaluate filter value at $(x,y)$ pixel + int offset = ify[y-y0]*FILTER_TABLE_SIZE + ifx[x-x0]; + float filterWt = filterTable[offset]; + + // Update pixel values with filtered sample contribution + Pixel &pixel = (*pixels)(x - xPixelStart, y - yPixelStart); + if (!syncNeeded) { + pixel.Lxyz[0] += filterWt * xyz[0]; + pixel.Lxyz[1] += filterWt * xyz[1]; + pixel.Lxyz[2] += filterWt * xyz[2]; + pixel.weightSum += filterWt; + } + else { + // Safely update _Lxyz_ and _weightSum_ even with concurrency + AtomicAdd(&pixel.Lxyz[0], filterWt * xyz[0]); + AtomicAdd(&pixel.Lxyz[1], filterWt * xyz[1]); + AtomicAdd(&pixel.Lxyz[2], filterWt * xyz[2]); + AtomicAdd(&pixel.weightSum, filterWt); + } + } + } +} + + +void ImageFilm::Splat(const CameraSample &sample, const Spectrum &L) { + if (L.HasNaNs()) { + Warning("ImageFilm ignoring splatted spectrum with NaN values"); + return; + } + float xyz[3]; + L.ToXYZ(xyz); + int x = Floor2Int(sample.imageX), y = Floor2Int(sample.imageY); + if (x < xPixelStart || x - xPixelStart >= xPixelCount || + y < yPixelStart || y - yPixelStart >= yPixelCount) return; + Pixel &pixel = (*pixels)(x - xPixelStart, y - yPixelStart); + AtomicAdd(&pixel.splatXYZ[0], xyz[0]); + AtomicAdd(&pixel.splatXYZ[1], xyz[1]); + AtomicAdd(&pixel.splatXYZ[2], xyz[2]); +} + + +void ImageFilm::GetSampleExtent(int *xstart, int *xend, + int *ystart, int *yend) const { + *xstart = Floor2Int(xPixelStart + 0.5f - filter->xWidth); + *xend = Floor2Int(xPixelStart + 0.5f + xPixelCount + + filter->xWidth); + + *ystart = Floor2Int(yPixelStart + 0.5f - filter->yWidth); + *yend = Floor2Int(yPixelStart + 0.5f + yPixelCount + + filter->yWidth); +} + + +void ImageFilm::GetPixelExtent(int *xstart, int *xend, + int *ystart, int *yend) const { + *xstart = xPixelStart; + *xend = xPixelStart + xPixelCount; + *ystart = yPixelStart; + *yend = yPixelStart + yPixelCount; +} + + +void ImageFilm::WriteImage(float splatScale) { + // Convert image to RGB and compute final pixel values + int nPix = xPixelCount * yPixelCount; + float *rgb = new float[3*nPix]; + int offset = 0; + for (int y = 0; y < yPixelCount; ++y) { + for (int x = 0; x < xPixelCount; ++x) { + // Convert pixel XYZ color to RGB + XYZToRGB((*pixels)(x, y).Lxyz, &rgb[3*offset]); + + // Normalize pixel with weight sum + float weightSum = (*pixels)(x, y).weightSum; + if (weightSum != 0.f) { + float invWt = 1.f / weightSum; + rgb[3*offset ] = max(0.f, rgb[3*offset ] * invWt); + rgb[3*offset+1] = max(0.f, rgb[3*offset+1] * invWt); + rgb[3*offset+2] = max(0.f, rgb[3*offset+2] * invWt); + } + + // Add splat value at pixel + float splatRGB[3]; + XYZToRGB((*pixels)(x, y).splatXYZ, splatRGB); + rgb[3*offset ] += splatScale * splatRGB[0]; + rgb[3*offset+1] += splatScale * splatRGB[1]; + rgb[3*offset+2] += splatScale * splatRGB[2]; + ++offset; + } + } + + // Write RGB image + ::WriteImage(filename, rgb, NULL, xPixelCount, yPixelCount, + xResolution, yResolution, xPixelStart, yPixelStart); + + // Release temporary image memory + delete[] rgb; +} + + +void ImageFilm::UpdateDisplay(int x0, int y0, int x1, int y1, + float splatScale) { +} + + +ImageFilm *CreateImageFilm(const ParamSet ¶ms, Filter *filter) { + string filename = params.FindOneString("filename", PbrtOptions.imageFile); + if (filename == "") +#ifdef PBRT_HAS_OPENEXR + filename = "pbrt.exr"; +#else + filename = "pbrt.tga"; +#endif + + int xres = params.FindOneInt("xresolution", 640); + int yres = params.FindOneInt("yresolution", 480); + if (PbrtOptions.quickRender) xres = max(1, xres / 4); + if (PbrtOptions.quickRender) yres = max(1, yres / 4); + bool openwin = params.FindOneBool("display", false); + float crop[4] = { 0, 1, 0, 1 }; + int cwi; + const float *cr = params.FindFloat("cropwindow", &cwi); + if (cr && cwi == 4) { + crop[0] = Clamp(min(cr[0], cr[1]), 0., 1.); + crop[1] = Clamp(max(cr[0], cr[1]), 0., 1.); + crop[2] = Clamp(min(cr[2], cr[3]), 0., 1.); + crop[3] = Clamp(max(cr[2], cr[3]), 0., 1.); + } + + return new ImageFilm(xres, yres, filter, crop, filename, openwin); +} + + diff --git a/film/image.h b/film/image.h new file mode 100644 index 0000000..3a4ddaa --- /dev/null +++ b/film/image.h @@ -0,0 +1,78 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_FILM_IMAGE_H +#define PBRT_FILM_IMAGE_H + +// film/image.h* +#include "pbrt.h" +#include "film.h" +#include "sampler.h" +#include "filter.h" +#include "paramset.h" + +// ImageFilm Declarations +class ImageFilm : public Film { +public: + // ImageFilm Public Methods + ImageFilm(int xres, int yres, Filter *filt, const float crop[4], + const string &filename, bool openWindow); + ~ImageFilm() { + delete pixels; + delete filter; + delete[] filterTable; + } + void AddSample(const CameraSample &sample, const Spectrum &L); + void Splat(const CameraSample &sample, const Spectrum &L); + void GetSampleExtent(int *xstart, int *xend, int *ystart, int *yend) const; + void GetPixelExtent(int *xstart, int *xend, int *ystart, int *yend) const; + void WriteImage(float splatScale); + void UpdateDisplay(int x0, int y0, int x1, int y1, float splatScale); +private: + // ImageFilm Private Data + Filter *filter; + float cropWindow[4]; + string filename; + int xPixelStart, yPixelStart, xPixelCount, yPixelCount; + struct Pixel { + Pixel() { + for (int i = 0; i < 3; ++i) Lxyz[i] = splatXYZ[i] = 0.f; + weightSum = 0.f; + } + float Lxyz[3]; + float weightSum; + float splatXYZ[3]; + float pad; + }; + BlockedArray *pixels; + float *filterTable; +}; + + +ImageFilm *CreateImageFilm(const ParamSet ¶ms, Filter *filter); + +#endif // PBRT_FILM_IMAGE_H diff --git a/filters/box.cpp b/filters/box.cpp new file mode 100644 index 0000000..9cd88bd --- /dev/null +++ b/filters/box.cpp @@ -0,0 +1,42 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// filters/box.cpp* +#include "stdafx.h" +#include "filters/box.h" +#include "paramset.h" + +// Box Filter Method Definitions +float BoxFilter::Evaluate(float x, float y) const { + return 1.; +} + + +BoxFilter *CreateBoxFilter(const ParamSet &ps) { + float xw = ps.FindOneFloat("xwidth", 0.5f); + float yw = ps.FindOneFloat("ywidth", 0.5f); + return new BoxFilter(xw, yw); +} + + diff --git a/filters/box.h b/filters/box.h new file mode 100644 index 0000000..3820567 --- /dev/null +++ b/filters/box.h @@ -0,0 +1,44 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_FILTERS_BOX_H +#define PBRT_FILTERS_BOX_H + +// filters/box.h* +#include "filter.h" + +// Box Filter Declarations +class BoxFilter : public Filter { +public: + BoxFilter(float xw, float yw) : Filter(xw, yw) { } + float Evaluate(float x, float y) const; +}; + + +BoxFilter *CreateBoxFilter(const ParamSet &ps); + +#endif // PBRT_FILTERS_BOX_H diff --git a/filters/gaussian.cpp b/filters/gaussian.cpp new file mode 100644 index 0000000..0099024 --- /dev/null +++ b/filters/gaussian.cpp @@ -0,0 +1,44 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// filters/gaussian.cpp* +#include "stdafx.h" +#include "filters/gaussian.h" +#include "paramset.h" + +// Gaussian Filter Method Definitions +float GaussianFilter::Evaluate(float x, float y) const { + return Gaussian(x, expX) * Gaussian(y, expY); +} + + +GaussianFilter *CreateGaussianFilter(const ParamSet &ps) { + // Find common filter parameters + float xw = ps.FindOneFloat("xwidth", 2.f); + float yw = ps.FindOneFloat("ywidth", 2.f); + float alpha = ps.FindOneFloat("alpha", 2.f); + return new GaussianFilter(xw, yw, alpha); +} + + diff --git a/filters/gaussian.h b/filters/gaussian.h new file mode 100644 index 0000000..5936f87 --- /dev/null +++ b/filters/gaussian.h @@ -0,0 +1,56 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_FILTERS_GAUSSIAN_H +#define PBRT_FILTERS_GAUSSIAN_H + +// filters/gaussian.h* +#include "filter.h" + +// Gaussian Filter Declarations +class GaussianFilter : public Filter { +public: + // GaussianFilter Public Methods + GaussianFilter(float xw, float yw, float a) + : Filter(xw, yw), alpha(a), expX(expf(-alpha * xWidth * xWidth)), + expY(expf(-alpha * yWidth * yWidth)) { } + float Evaluate(float x, float y) const; +private: + // GaussianFilter Private Data + const float alpha; + const float expX, expY; + + // GaussianFilter Utility Functions + float Gaussian(float d, float expv) const { + return max(0.f, float(expf(-alpha * d * d) - expv)); + } +}; + + +GaussianFilter *CreateGaussianFilter(const ParamSet &ps); + +#endif // PBRT_FILTERS_GAUSSIAN_H diff --git a/filters/mitchell.cpp b/filters/mitchell.cpp new file mode 100644 index 0000000..c82a3e3 --- /dev/null +++ b/filters/mitchell.cpp @@ -0,0 +1,45 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// filters/mitchell.cpp* +#include "stdafx.h" +#include "filters/mitchell.h" +#include "paramset.h" + +// Mitchell Filter Method Definitions +float MitchellFilter::Evaluate(float x, float y) const { + return Mitchell1D(x * invXWidth) * Mitchell1D(y * invYWidth); +} + + +MitchellFilter *CreateMitchellFilter(const ParamSet &ps) { + // Find common filter parameters + float xw = ps.FindOneFloat("xwidth", 2.f); + float yw = ps.FindOneFloat("ywidth", 2.f); + float B = ps.FindOneFloat("B", 1.f/3.f); + float C = ps.FindOneFloat("C", 1.f/3.f); + return new MitchellFilter(B, C, xw, yw); +} + + diff --git a/filters/mitchell.h b/filters/mitchell.h new file mode 100644 index 0000000..82e3194 --- /dev/null +++ b/filters/mitchell.h @@ -0,0 +1,59 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_FILTERS_MITCHELL_H +#define PBRT_FILTERS_MITCHELL_H + +// filters/mitchell.h* +#include "filter.h" + +// Mitchell Filter Declarations +class MitchellFilter : public Filter { +public: + // MitchellFilter Public Methods + MitchellFilter(float b, float c, float xw, float yw) + : Filter(xw, yw), B(b), C(c) { + } + float Evaluate(float x, float y) const; + float Mitchell1D(float x) const { + x = fabsf(2.f * x); + if (x > 1.f) + return ((-B - 6*C) * x*x*x + (6*B + 30*C) * x*x + + (-12*B - 48*C) * x + (8*B + 24*C)) * (1.f/6.f); + else + return ((12 - 9*B - 6*C) * x*x*x + + (-18 + 12*B + 6*C) * x*x + + (6 - 2*B)) * (1.f/6.f); + } +private: + const float B, C; +}; + + +MitchellFilter *CreateMitchellFilter(const ParamSet &ps); + +#endif // PBRT_FILTERS_MITCHELL_H diff --git a/filters/sinc.cpp b/filters/sinc.cpp new file mode 100644 index 0000000..66f2cb8 --- /dev/null +++ b/filters/sinc.cpp @@ -0,0 +1,43 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// filters/sinc.cpp* +#include "stdafx.h" +#include "filters/sinc.h" +#include "paramset.h" + +// Sinc Filter Method Definitions +float LanczosSincFilter::Evaluate(float x, float y) const { + return Sinc1D(x * invXWidth) * Sinc1D(y * invYWidth); +} + + +LanczosSincFilter *CreateSincFilter(const ParamSet &ps) { + float xw = ps.FindOneFloat("xwidth", 4.); + float yw = ps.FindOneFloat("ywidth", 4.); + float tau = ps.FindOneFloat("tau", 3.f); + return new LanczosSincFilter(xw, yw, tau); +} + + diff --git a/filters/sinc.h b/filters/sinc.h new file mode 100644 index 0000000..c4c1bc1 --- /dev/null +++ b/filters/sinc.h @@ -0,0 +1,57 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_FILTERS_SINC_H +#define PBRT_FILTERS_SINC_H + +// filters/sinc.h* +#include "filter.h" + +// Sinc Filter Declarations +class LanczosSincFilter : public Filter { +public: + // LanczosSincFilter Public Methods + LanczosSincFilter(float xw, float yw, float t) + : Filter(xw, yw), tau(t) { } + float Evaluate(float x, float y) const; + float Sinc1D(float x) const { + x = fabsf(x); + if (x < 1e-5) return 1.f; + if (x > 1.) return 0.f; + x *= M_PI; + float sinc = sinf(x * tau) / (x * tau); + float lanczos = sinf(x) / x; + return sinc * lanczos; + } +private: + const float tau; +}; + + +LanczosSincFilter *CreateSincFilter(const ParamSet &ps); + +#endif // PBRT_FILTERS_SINC_H diff --git a/filters/triangle.cpp b/filters/triangle.cpp new file mode 100644 index 0000000..9a883ae --- /dev/null +++ b/filters/triangle.cpp @@ -0,0 +1,44 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// filters/triangle.cpp* +#include "stdafx.h" +#include "filters/triangle.h" +#include "paramset.h" + +// Triangle Filter Method Definitions +float TriangleFilter::Evaluate(float x, float y) const { + return max(0.f, xWidth - fabsf(x)) * + max(0.f, yWidth - fabsf(y)); +} + + +TriangleFilter *CreateTriangleFilter(const ParamSet &ps) { + // Find common filter parameters + float xw = ps.FindOneFloat("xwidth", 2.f); + float yw = ps.FindOneFloat("ywidth", 2.f); + return new TriangleFilter(xw, yw); +} + + diff --git a/filters/triangle.h b/filters/triangle.h new file mode 100644 index 0000000..a3d1ee3 --- /dev/null +++ b/filters/triangle.h @@ -0,0 +1,44 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_FILTERS_TRIANGLE_H +#define PBRT_FILTERS_TRIANGLE_H + +// filters/triangle.h* +#include "filter.h" + +// Triangle Filter Declarations +class TriangleFilter : public Filter { +public: + TriangleFilter(float xw, float yw) : Filter(xw, yw) { } + float Evaluate(float x, float y) const; +}; + + +TriangleFilter *CreateTriangleFilter(const ParamSet &ps); + +#endif // PBRT_FILTERS_TRIANGLE_H diff --git a/fisheye.10mm.dat b/fisheye.10mm.dat new file mode 100644 index 0000000..1f4a860 --- /dev/null +++ b/fisheye.10mm.dat @@ -0,0 +1,16 @@ +# Muller 16mm/f4 155.9FOV fisheye lens +# MLD p164 +# Scaled to 10 mm from 100 mm +# radius sep n aperture +30.2249 0.8335 1.62 30.34 +11.3931 7.4136 1 20.68 +75.2019 1.0654 1.639 17.8 +8.3349 11.1549 1 13.42 +9.5882 2.0054 1.654 9.02 +43.8677 5.3895 1 8.14 +0 1.4163 0 6.08 +29.4541 2.1934 1.517 5.96 +-5.2265 0.9714 1.805 5.84 +-14.2884 0.0627 1 5.96 +-22.3726 0.94 1.673 5.96 +-15.0404 0 1 6.52 diff --git a/hw3_bunnies.exr b/hw3_bunnies.exr new file mode 100644 index 0000000..2fe5fdc Binary files /dev/null and b/hw3_bunnies.exr differ diff --git a/hw3_bunnies.tiff b/hw3_bunnies.tiff new file mode 100644 index 0000000..1b7d7ec Binary files /dev/null and b/hw3_bunnies.tiff differ diff --git a/hw3_dgauss.exr b/hw3_dgauss.exr new file mode 100644 index 0000000..5c0d904 Binary files /dev/null and b/hw3_dgauss.exr differ diff --git a/hw3_dgauss.tiff b/hw3_dgauss.tiff new file mode 100644 index 0000000..1c5fefe Binary files /dev/null and b/hw3_dgauss.tiff differ diff --git a/hw3_dgauss4.png b/hw3_dgauss4.png new file mode 100644 index 0000000..1d7116c Binary files /dev/null and b/hw3_dgauss4.png differ diff --git a/hw3_dgauss4.tiff b/hw3_dgauss4.tiff new file mode 100644 index 0000000..fff7ab1 Binary files /dev/null and b/hw3_dgauss4.tiff differ diff --git a/hw3_dgauss512.png b/hw3_dgauss512.png new file mode 100644 index 0000000..d919216 Binary files /dev/null and b/hw3_dgauss512.png differ diff --git a/hw3_dgauss512.tiff b/hw3_dgauss512.tiff new file mode 100644 index 0000000..1c5fefe Binary files /dev/null and b/hw3_dgauss512.tiff differ diff --git a/hw3_fisheye.exr b/hw3_fisheye.exr new file mode 100644 index 0000000..3d0075a Binary files /dev/null and b/hw3_fisheye.exr differ diff --git a/hw3_fisheye.tiff b/hw3_fisheye.tiff new file mode 100644 index 0000000..3f3310d Binary files /dev/null and b/hw3_fisheye.tiff differ diff --git a/hw3_fisheye4.png b/hw3_fisheye4.png new file mode 100644 index 0000000..373cde8 Binary files /dev/null and b/hw3_fisheye4.png differ diff --git a/hw3_fisheye4.tiff b/hw3_fisheye4.tiff new file mode 100644 index 0000000..cef31bf Binary files /dev/null and b/hw3_fisheye4.tiff differ diff --git a/hw3_fisheye512.png b/hw3_fisheye512.png new file mode 100644 index 0000000..e5db43f Binary files /dev/null and b/hw3_fisheye512.png differ diff --git a/hw3_fisheye512.tiff b/hw3_fisheye512.tiff new file mode 100644 index 0000000..3f3310d Binary files /dev/null and b/hw3_fisheye512.tiff differ diff --git a/hw3_telephoto.exr b/hw3_telephoto.exr new file mode 100644 index 0000000..00028ad Binary files /dev/null and b/hw3_telephoto.exr differ diff --git a/hw3_telephoto.png b/hw3_telephoto.png new file mode 100644 index 0000000..c52cd86 Binary files /dev/null and b/hw3_telephoto.png differ diff --git a/hw3_telephoto.tiff b/hw3_telephoto.tiff new file mode 100644 index 0000000..7d0f433 Binary files /dev/null and b/hw3_telephoto.tiff differ diff --git a/hw3_telephoto4.png b/hw3_telephoto4.png new file mode 100644 index 0000000..4c13c5a Binary files /dev/null and b/hw3_telephoto4.png differ diff --git a/hw3_telephoto4.tiff b/hw3_telephoto4.tiff new file mode 100644 index 0000000..49c7569 Binary files /dev/null and b/hw3_telephoto4.tiff differ diff --git a/hw3_telephoto512.png b/hw3_telephoto512.png new file mode 100644 index 0000000..2b68a70 Binary files /dev/null and b/hw3_telephoto512.png differ diff --git a/hw3_telephoto512.tiff b/hw3_telephoto512.tiff new file mode 100644 index 0000000..39f81db Binary files /dev/null and b/hw3_telephoto512.tiff differ diff --git a/hw3_wide.exr b/hw3_wide.exr new file mode 100644 index 0000000..b28eeed Binary files /dev/null and b/hw3_wide.exr differ diff --git a/hw3_wide.tiff b/hw3_wide.tiff new file mode 100644 index 0000000..2de4c6f Binary files /dev/null and b/hw3_wide.tiff differ diff --git a/hw3_wide4.png b/hw3_wide4.png new file mode 100644 index 0000000..2ad39f2 Binary files /dev/null and b/hw3_wide4.png differ diff --git a/hw3_wide4.tiff b/hw3_wide4.tiff new file mode 100644 index 0000000..0deb378 Binary files /dev/null and b/hw3_wide4.tiff differ diff --git a/hw3_wide512.png b/hw3_wide512.png new file mode 100644 index 0000000..3a31ea4 Binary files /dev/null and b/hw3_wide512.png differ diff --git a/hw3_wide512.tiff b/hw3_wide512.tiff new file mode 100644 index 0000000..72e0ac5 Binary files /dev/null and b/hw3_wide512.tiff differ diff --git a/integrators/ambientocclusion.cpp b/integrators/ambientocclusion.cpp new file mode 100644 index 0000000..bea2df6 --- /dev/null +++ b/integrators/ambientocclusion.cpp @@ -0,0 +1,63 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// integrators/ambientocclusion.cpp* +#include "stdafx.h" +#include "integrators/ambientocclusion.h" +#include "paramset.h" +#include "montecarlo.h" +#include "scene.h" +#include "intersection.h" + +// AmbientOcclusionIntegrator Method Definitions +Spectrum AmbientOcclusionIntegrator::Li(const Scene *scene, const Renderer *renderer, + const RayDifferential &ray, const Intersection &isect, + const Sample *sample, RNG &rng, MemoryArena &arena) const { + + BSDF *bsdf = isect.GetBSDF(ray, arena); + const Point &p = bsdf->dgShading.p; + Normal n = Faceforward(isect.dg.nn, -ray.d); + + uint32_t scramble[2] = { rng.RandomUInt(), rng.RandomUInt() }; + float u[2]; + int nClear = 0; + for (int i = 0; i < nSamples; ++i) { + Sample02(i, scramble, u); + Vector w = UniformSampleSphere(u[0], u[1]); + if (Dot(w, n) < 0.) w = -w; + Ray r(p, w, .01f, maxDist); + if (!scene->IntersectP(r)) ++nClear; + } + return Spectrum(float(nClear) / float(nSamples)); +} + + +AmbientOcclusionIntegrator *CreateAmbientOcclusionIntegrator(const ParamSet ¶ms) { + int nSamples = params.FindOneInt("nsamples", 2048); + float maxDist = params.FindOneFloat("maxdist", INFINITY); + if (PbrtOptions.quickRender) { nSamples = max(1, nSamples / 4); } + return new AmbientOcclusionIntegrator(nSamples, maxDist); +} + + diff --git a/integrators/ambientocclusion.h b/integrators/ambientocclusion.h new file mode 100644 index 0000000..34ea6bd --- /dev/null +++ b/integrators/ambientocclusion.h @@ -0,0 +1,51 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_INTEGRATORS_AMBIENTOCCLUSION_H +#define PBRT_INTEGRATORS_AMBIENTOCCLUSION_H + +// integrators/ambientocclusion.h* +#include "pbrt.h" +#include "integrator.h" + +// AmbientOcclusionIntegrator Declarations +class AmbientOcclusionIntegrator : public SurfaceIntegrator { +public: + AmbientOcclusionIntegrator(int ns, float md) { nSamples = RoundUpPow2(ns); maxDist = md; } + Spectrum Li(const Scene *scene, const Renderer *renderer, + const RayDifferential &ray, const Intersection &isect, + const Sample *sample, RNG &rng, MemoryArena &arena) const; +private: + int nSamples; + float maxDist; +}; + + + +AmbientOcclusionIntegrator *CreateAmbientOcclusionIntegrator(const ParamSet ¶ms); + +#endif // PBRT_INTEGRATORS_AMBIENTOCCLUSION_H diff --git a/integrators/diffuseprt.cpp b/integrators/diffuseprt.cpp new file mode 100644 index 0000000..9284a58 --- /dev/null +++ b/integrators/diffuseprt.cpp @@ -0,0 +1,97 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// integrators/diffuseprt.cpp* +#include "stdafx.h" +#include "integrators/diffuseprt.h" +#include "sh.h" +#include "light.h" +#include "scene.h" +#include "camera.h" +#include "intersection.h" +#include "paramset.h" +#include "montecarlo.h" + +// DiffusePRTIntegrator Method Definitions +DiffusePRTIntegrator::DiffusePRTIntegrator(int lm, int ns) + : lmax(lm), nSamples(RoundUpPow2(ns)) { + c_in = new Spectrum[SHTerms(lmax)]; +} + + +DiffusePRTIntegrator::~DiffusePRTIntegrator() { + delete[] c_in; +} + + +void DiffusePRTIntegrator::Preprocess(const Scene *scene, + const Camera *camera, const Renderer *renderer) { + BBox bbox = scene->WorldBound(); + Point p = .5f * bbox.pMin + .5f * bbox.pMax; + RNG rng; + MemoryArena arena; + SHProjectIncidentDirectRadiance(p, 0.f, camera->shutterOpen, arena, + scene, false, lmax, rng, c_in); +} + + +void DiffusePRTIntegrator::RequestSamples(Sampler *sampler, Sample *sample, const Scene *scene) { +} + + +Spectrum DiffusePRTIntegrator::Li(const Scene *scene, const Renderer *, + const RayDifferential &ray, const Intersection &isect, + const Sample *sample, RNG &rng, MemoryArena &arena) const { + Spectrum L = 0.f; + Vector wo = -ray.d; + // Compute emitted light if ray hit an area light source + L += isect.Le(wo); + + // Evaluate BSDF at hit point + BSDF *bsdf = isect.GetBSDF(ray, arena); + const Point &p = bsdf->dgShading.p; + const Normal &n = bsdf->dgShading.nn; + // Compute reflected radiance using diffuse PRT + + // Project diffuse transfer function at point to SH + Spectrum *c_transfer = arena.Alloc(SHTerms(lmax)); + SHComputeDiffuseTransfer(p, Faceforward(n, wo), isect.rayEpsilon, + scene, rng, nSamples, lmax, c_transfer); + + // Compute integral of product of incident radiance and transfer function + Spectrum Kd = bsdf->rho(wo, rng, BSDF_ALL_REFLECTION) * INV_PI; + Spectrum Lo = 0.f; + for (int i = 0; i < SHTerms(lmax); ++i) + Lo += c_in[i] * c_transfer[i]; + return L + Kd * Lo.Clamp(); +} + + +DiffusePRTIntegrator *CreateDiffusePRTIntegratorSurfaceIntegrator(const ParamSet ¶ms) { + int lmax = params.FindOneInt("lmax", 4); + int ns = params.FindOneInt("nsamples", 4096); + return new DiffusePRTIntegrator(lmax, ns); +} + + diff --git a/integrators/diffuseprt.h b/integrators/diffuseprt.h new file mode 100644 index 0000000..93cfb70 --- /dev/null +++ b/integrators/diffuseprt.h @@ -0,0 +1,55 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_INTEGRATORS_DIFFUSEPRT_H +#define PBRT_INTEGRATORS_DIFFUSEPRT_H + +// integrators/diffuseprt.h* +#include "pbrt.h" +#include "integrator.h" + +// DiffusePRTIntegrator Declarations +class DiffusePRTIntegrator : public SurfaceIntegrator { +public: + // DiffusePRTIntegrator Public Methods + DiffusePRTIntegrator(int lm, int ns); + ~DiffusePRTIntegrator(); + void Preprocess(const Scene *scene, const Camera *camera, const Renderer *renderer); + void RequestSamples(Sampler *sampler, Sample *sample, const Scene *scene); + Spectrum Li(const Scene *scene, const Renderer *, + const RayDifferential &ray, const Intersection &isect, + const Sample *sample, RNG &rng, MemoryArena &arena) const; +private: + // DiffusePRTIntegrator Private Data + const int lmax, nSamples; + Spectrum *c_in; +}; + + +DiffusePRTIntegrator *CreateDiffusePRTIntegratorSurfaceIntegrator(const ParamSet ¶ms); + +#endif // PBRT_INTEGRATORS_DIFFUSEPRT_H diff --git a/integrators/dipolesubsurface.cpp b/integrators/dipolesubsurface.cpp new file mode 100644 index 0000000..1cf3380 --- /dev/null +++ b/integrators/dipolesubsurface.cpp @@ -0,0 +1,351 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// integrators/dipolesubsurface.cpp* +#include "stdafx.h" +#include "integrators/dipolesubsurface.h" +#include "scene.h" +#include "montecarlo.h" +#include "sampler.h" +#include "progressreporter.h" +#include "intersection.h" +#include "paramset.h" +#include "reflection.h" +#include "octree.h" +#include "camera.h" +#include "floatfile.h" +struct DiffusionReflectance; + +// DipoleSubsurfaceIntegrator Local Declarations +struct SubsurfaceOctreeNode { + // SubsurfaceOctreeNode Methods + SubsurfaceOctreeNode() { + isLeaf = true; + sumArea = 0.f; + for (int i = 0; i < 8; ++i) + ips[i] = NULL; + } + void Insert(const BBox &nodeBound, IrradiancePoint *ip, + MemoryArena &arena) { + Point pMid = .5f * nodeBound.pMin + .5f * nodeBound.pMax; + if (isLeaf) { + // Add _IrradiancePoint_ to leaf octree node + for (int i = 0; i < 8; ++i) { + if (!ips[i]) { + ips[i] = ip; + return; + } + } + + // Convert leaf node to interior node, redistribute points + isLeaf = false; + IrradiancePoint *localIps[8]; + for (int i = 0; i < 8; ++i) { + localIps[i] = ips[i]; + children[i] = NULL; + } + for (int i = 0; i < 8; ++i) { + IrradiancePoint *ip = localIps[i]; + // Add _IrradiancePoint_ _ip_ to interior octree node + int child = (ip->p.x > pMid.x ? 4 : 0) + + (ip->p.y > pMid.y ? 2 : 0) + (ip->p.z > pMid.z ? 1 : 0); + if (!children[child]) + children[child] = arena.Alloc(); + BBox childBound = octreeChildBound(child, nodeBound, pMid); + children[child]->Insert(childBound, ip, arena); + } + /* fall through to interior case to insert the new point... */ + } + // Add _IrradiancePoint_ _ip_ to interior octree node + int child = (ip->p.x > pMid.x ? 4 : 0) + + (ip->p.y > pMid.y ? 2 : 0) + (ip->p.z > pMid.z ? 1 : 0); + if (!children[child]) + children[child] = arena.Alloc(); + BBox childBound = octreeChildBound(child, nodeBound, pMid); + children[child]->Insert(childBound, ip, arena); + } + void InitHierarchy() { + if (isLeaf) { + // Init _SubsurfaceOctreeNode_ leaf from _IrradiancePoint_s + float sumWt = 0.f; + uint32_t i; + for (i = 0; i < 8; ++i) { + if (!ips[i]) break; + float wt = ips[i]->E.y(); + E += ips[i]->E; + p += wt * ips[i]->p; + sumWt += wt; + sumArea += ips[i]->area; + } + if (sumWt > 0.f) p /= sumWt; + E /= i; + } + else { + // Init interior _SubsurfaceOctreeNode_ + float sumWt = 0.f; + uint32_t nChildren = 0; + for (uint32_t i = 0; i < 8; ++i) { + if (!children[i]) continue; + ++nChildren; + children[i]->InitHierarchy(); + float wt = children[i]->E.y(); + E += children[i]->E; + p += wt * children[i]->p; + sumWt += wt; + sumArea += children[i]->sumArea; + } + if (sumWt > 0.f) p /= sumWt; + E /= nChildren; + } + } + Spectrum Mo(const BBox &nodeBound, const Point &p, const DiffusionReflectance &Rd, + float maxError); + + // SubsurfaceOctreeNode Public Data + Point p; + bool isLeaf; + Spectrum E; + float sumArea; + union { + SubsurfaceOctreeNode *children[8]; + IrradiancePoint *ips[8]; + }; +}; + + +struct DiffusionReflectance { + // DiffusionReflectance Public Methods + DiffusionReflectance(const Spectrum &sigma_a, const Spectrum &sigmap_s, + float eta) { + A = (1.f + Fdr(eta)) / (1.f - Fdr(eta)); + sigmap_t = sigma_a + sigmap_s; + sigma_tr = Sqrt(3.f * sigma_a * sigmap_t); + alphap = sigmap_s / sigmap_t; + zpos = Spectrum(1.f) / sigmap_t; + zneg = -zpos * (1.f + (4.f/3.f) * A); + } + Spectrum operator()(float d2) const { + Spectrum dpos = Sqrt(Spectrum(d2) + zpos * zpos); + Spectrum dneg = Sqrt(Spectrum(d2) + zneg * zneg); + Spectrum Rd = (alphap / (4.f * M_PI)) * + ((zpos * (dpos * sigma_tr + Spectrum(1.f)) * + Exp(-sigma_tr * dpos)) / (dpos * dpos * dpos) - + (zneg * (dneg * sigma_tr + Spectrum(1.f)) * + Exp(-sigma_tr * dneg)) / (dneg * dneg * dneg)); + return Rd.Clamp(); + } + + // DiffusionReflectance Data + Spectrum zpos, zneg, sigmap_t, sigma_tr, alphap; + float A; +}; + + + +// DipoleSubsurfaceIntegrator Method Definitions +DipoleSubsurfaceIntegrator::~DipoleSubsurfaceIntegrator() { + delete[] lightSampleOffsets; + delete[] bsdfSampleOffsets; +} + + +void DipoleSubsurfaceIntegrator::RequestSamples(Sampler *sampler, Sample *sample, + const Scene *scene) { + // Allocate and request samples for sampling all lights + uint32_t nLights = scene->lights.size(); + lightSampleOffsets = new LightSampleOffsets[nLights]; + bsdfSampleOffsets = new BSDFSampleOffsets[nLights]; + for (uint32_t i = 0; i < nLights; ++i) { + const Light *light = scene->lights[i]; + int nSamples = light->nSamples; + if (sampler) nSamples = sampler->RoundSize(nSamples); + lightSampleOffsets[i] = LightSampleOffsets(nSamples, sample); + bsdfSampleOffsets[i] = BSDFSampleOffsets(nSamples, sample); + } +} + + +void DipoleSubsurfaceIntegrator::Preprocess(const Scene *scene, + const Camera *camera, const Renderer *renderer) { + if (scene->lights.size() == 0) return; + vector pts; + // Get _SurfacePoint_s for translucent objects in scene + if (filename != "") { + // Initialize _SurfacePoint_s from file + vector fpts; + if (ReadFloatFile(filename.c_str(), &fpts)) { + if ((fpts.size() % 8) != 0) + Error("Excess values (%d) in points file \"%s\"", int(fpts.size() % 8), + filename.c_str()); + for (u_int i = 0; i < fpts.size(); i += 8) + pts.push_back(SurfacePoint(Point(fpts[i], fpts[i+1], fpts[i+2]), + Normal(fpts[i+3], fpts[i+4], fpts[i+5]), + fpts[i+6], fpts[i+7])); + } + } + if (pts.size() == 0) { + Point pCamera = camera->CameraToWorld(camera->shutterOpen, + Point(0, 0, 0)); + FindPoissonPointDistribution(pCamera, camera->shutterOpen, + minSampleDist, scene, &pts); + } + + // Compute irradiance values at sample points + RNG rng; + MemoryArena arena; + PBRT_SUBSURFACE_STARTED_COMPUTING_IRRADIANCE_VALUES(); + ProgressReporter progress(pts.size(), "Computing Irradiances"); + for (uint32_t i = 0; i < pts.size(); ++i) { + SurfacePoint &sp = pts[i]; + Spectrum E(0.f); + for (uint32_t j = 0; j < scene->lights.size(); ++j) { + // Add irradiance from light at point + const Light *light = scene->lights[j]; + Spectrum Elight = 0.f; + int nSamples = RoundUpPow2(light->nSamples); + uint32_t scramble[2] = { rng.RandomUInt(), rng.RandomUInt() }; + uint32_t compScramble = rng.RandomUInt(); + for (int s = 0; s < nSamples; ++s) { + float lpos[2]; + Sample02(s, scramble, lpos); + float lcomp = VanDerCorput(s, compScramble); + LightSample ls(lpos[0], lpos[1], lcomp); + Vector wi; + float lightPdf; + VisibilityTester visibility; + Spectrum Li = light->Sample_L(sp.p, sp.rayEpsilon, + ls, camera->shutterOpen, &wi, &lightPdf, &visibility); + if (Dot(wi, sp.n) <= 0.) continue; + if (Li.IsBlack() || lightPdf == 0.f) continue; + Li *= visibility.Transmittance(scene, renderer, NULL, rng, arena); + if (visibility.Unoccluded(scene)) + Elight += Li * AbsDot(wi, sp.n) / lightPdf; + } + E += Elight / nSamples; + } + irradiancePoints.push_back(IrradiancePoint(sp, E)); + PBRT_SUBSURFACE_COMPUTED_IRRADIANCE_AT_POINT(&sp, &E); + arena.FreeAll(); + progress.Update(); + } + progress.Done(); + PBRT_SUBSURFACE_FINISHED_COMPUTING_IRRADIANCE_VALUES(); + + // Create octree of clustered irradiance samples + octree = octreeArena.Alloc(); + for (uint32_t i = 0; i < irradiancePoints.size(); ++i) + octreeBounds = Union(octreeBounds, irradiancePoints[i].p); + for (uint32_t i = 0; i < irradiancePoints.size(); ++i) + octree->Insert(octreeBounds, &irradiancePoints[i], octreeArena); + octree->InitHierarchy(); +} + + +Spectrum DipoleSubsurfaceIntegrator::Li(const Scene *scene, const Renderer *renderer, + const RayDifferential &ray, const Intersection &isect, + const Sample *sample, RNG &rng, MemoryArena &arena) const { + Spectrum L(0.); + Vector wo = -ray.d; + // Compute emitted light if ray hit an area light source + L += isect.Le(wo); + + // Evaluate BSDF at hit point + BSDF *bsdf = isect.GetBSDF(ray, arena); + const Point &p = bsdf->dgShading.p; + const Normal &n = bsdf->dgShading.nn; + // Evaluate BSSRDF and possibly compute subsurface scattering + BSSRDF *bssrdf = isect.GetBSSRDF(ray, arena); + if (bssrdf && octree) { + Spectrum sigma_a = bssrdf->sigma_a(); + Spectrum sigmap_s = bssrdf->sigma_prime_s(); + Spectrum sigmap_t = sigmap_s + sigma_a; + if (!sigmap_t.IsBlack()) { + // Use hierarchical integration to evaluate reflection from dipole model + PBRT_SUBSURFACE_STARTED_OCTREE_LOOKUP(const_cast(&p)); + DiffusionReflectance Rd(sigma_a, sigmap_s, bssrdf->eta()); + Spectrum Mo = octree->Mo(octreeBounds, p, Rd, maxError); + FresnelDielectric fresnel(1.f, bssrdf->eta()); + Spectrum Ft = Spectrum(1.f) - fresnel.Evaluate(AbsDot(wo, n)); + float Fdt = 1.f - Fdr(bssrdf->eta()); + L += (INV_PI * Ft) * (Fdt * Mo); + PBRT_SUBSURFACE_FINISHED_OCTREE_LOOKUP(); + } + } + L += UniformSampleAllLights(scene, renderer, arena, p, n, + wo, isect.rayEpsilon, ray.time, bsdf, sample, rng, lightSampleOffsets, + bsdfSampleOffsets); + if (ray.depth < maxSpecularDepth) { + // Trace rays for specular reflection and refraction + L += SpecularReflect(ray, bsdf, rng, isect, renderer, scene, sample, + arena); + L += SpecularTransmit(ray, bsdf, rng, isect, renderer, scene, sample, + arena); + } + return L; +} + + +Spectrum SubsurfaceOctreeNode::Mo(const BBox &nodeBound, const Point &pt, + const DiffusionReflectance &Rd, float maxError) { + // Compute $M_\roman{o}$ at node if error is low enough + float dw = sumArea / DistanceSquared(pt, p); + if (dw < maxError && !nodeBound.Inside(pt)) + { + PBRT_SUBSURFACE_ADDED_INTERIOR_CONTRIBUTION(const_cast(this)); + return Rd(DistanceSquared(pt, p)) * E * sumArea; + } + + // Otherwise compute $M_\roman{o}$ from points in leaf or recursively visit children + Spectrum Mo = 0.f; + if (isLeaf) { + // Accumulate $M_\roman{o}$ from leaf node + for (int i = 0; i < 8; ++i) { + if (!ips[i]) break; + PBRT_SUBSURFACE_ADDED_POINT_CONTRIBUTION(const_cast(ips[i])); + Mo += Rd(DistanceSquared(pt, ips[i]->p)) * ips[i]->E * ips[i]->area; + } + } + else { + // Recursively visit children nodes to compute $M_\roman{o}$ + Point pMid = .5f * nodeBound.pMin + .5f * nodeBound.pMax; + for (int child = 0; child < 8; ++child) { + if (!children[child]) continue; + BBox childBound = octreeChildBound(child, nodeBound, pMid); + Mo += children[child]->Mo(childBound, pt, Rd, maxError); + } + } + return Mo; +} + + +DipoleSubsurfaceIntegrator *CreateDipoleSubsurfaceIntegrator(const ParamSet ¶ms) { + int maxDepth = params.FindOneInt("maxdepth", 5); + float maxError = params.FindOneFloat("maxerror", .05f); + float minDist = params.FindOneFloat("minsampledistance", .25f); + string pointsfile = params.FindOneString("pointsfile", ""); + if (PbrtOptions.quickRender) { maxError *= 4.f; minDist *= 4.f; } + return new DipoleSubsurfaceIntegrator(maxDepth, maxError, minDist, pointsfile); +} + + diff --git a/integrators/dipolesubsurface.h b/integrators/dipolesubsurface.h new file mode 100644 index 0000000..8e2a48f --- /dev/null +++ b/integrators/dipolesubsurface.h @@ -0,0 +1,88 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_INTEGRATORS_DIPOLESUBSURFACE_H +#define PBRT_INTEGRATORS_DIPOLESUBSURFACE_H + +// integrators/dipolesubsurface.h* +#include "pbrt.h" +#include "integrator.h" +#include "kdtree.h" +#include "renderers/surfacepoints.h" +struct SubsurfaceOctreeNode; + +// DipoleSubsurfaceIntegrator Helper Declarations +struct IrradiancePoint { + IrradiancePoint() { } + IrradiancePoint(const SurfacePoint &sp, const Spectrum &ee) + : p(sp.p), n(sp.n), E(ee), area(sp.area), + rayEpsilon(sp.rayEpsilon) { } + Point p; + Normal n; + Spectrum E; + float area, rayEpsilon; +}; + + + +// DipoleSubsurfaceIntegrator Declarations +class DipoleSubsurfaceIntegrator : public SurfaceIntegrator { +public: + // DipoleSubsurfaceIntegrator Public Methods + DipoleSubsurfaceIntegrator(int mdepth, float merror, float mindist, + const string &fn) { + maxSpecularDepth = mdepth; + maxError = merror; + minSampleDist = mindist; + filename = fn; + octree = NULL; + } + ~DipoleSubsurfaceIntegrator(); + Spectrum Li(const Scene *scene, const Renderer *renderer, + const RayDifferential &ray, const Intersection &isect, const Sample *sample, + RNG &rng, MemoryArena &arena) const; + void RequestSamples(Sampler *sampler, Sample *sample, const Scene *scene); + void Preprocess(const Scene *, const Camera *, const Renderer *); +private: + // DipoleSubsurfaceIntegrator Private Data + int maxSpecularDepth; + float maxError, minSampleDist; + string filename; + vector irradiancePoints; + BBox octreeBounds; + SubsurfaceOctreeNode *octree; + MemoryArena octreeArena; + + // Declare sample parameters for light source sampling + LightSampleOffsets *lightSampleOffsets; + BSDFSampleOffsets *bsdfSampleOffsets; +}; + + +DipoleSubsurfaceIntegrator *CreateDipoleSubsurfaceIntegrator(const ParamSet ¶ms); + +#endif // PBRT_INTEGRATORS_DIPOLESUBSURFACE_H diff --git a/integrators/directlighting.cpp b/integrators/directlighting.cpp new file mode 100644 index 0000000..50fc581 --- /dev/null +++ b/integrators/directlighting.cpp @@ -0,0 +1,127 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// integrators/directlighting.cpp* +#include "stdafx.h" +#include "integrators/directlighting.h" +#include "intersection.h" +#include "paramset.h" + +// DirectLightingIntegrator Method Definitions +DirectLightingIntegrator::DirectLightingIntegrator(LightStrategy st, int md) { + maxDepth = md; + strategy = st; + lightSampleOffsets = NULL; + bsdfSampleOffsets = NULL; +} + + +DirectLightingIntegrator::~DirectLightingIntegrator() { + delete[] lightSampleOffsets; + delete[] bsdfSampleOffsets; +} + + +void DirectLightingIntegrator::RequestSamples(Sampler *sampler, + Sample *sample, const Scene *scene) { + if (strategy == SAMPLE_ALL_UNIFORM) { + // Allocate and request samples for sampling all lights + uint32_t nLights = scene->lights.size(); + lightSampleOffsets = new LightSampleOffsets[nLights]; + bsdfSampleOffsets = new BSDFSampleOffsets[nLights]; + for (uint32_t i = 0; i < nLights; ++i) { + const Light *light = scene->lights[i]; + int nSamples = light->nSamples; + if (sampler) nSamples = sampler->RoundSize(nSamples); + lightSampleOffsets[i] = LightSampleOffsets(nSamples, sample); + bsdfSampleOffsets[i] = BSDFSampleOffsets(nSamples, sample); + } + lightNumOffset = -1; + } + else { + // Allocate and request samples for sampling one light + lightSampleOffsets = new LightSampleOffsets[1]; + lightSampleOffsets[0] = LightSampleOffsets(1, sample); + lightNumOffset = sample->Add1D(1); + bsdfSampleOffsets = new BSDFSampleOffsets[1]; + bsdfSampleOffsets[0] = BSDFSampleOffsets(1, sample); + } +} + + +Spectrum DirectLightingIntegrator::Li(const Scene *scene, + const Renderer *renderer, const RayDifferential &ray, + const Intersection &isect, const Sample *sample, RNG &rng, MemoryArena &arena) const { + Spectrum L(0.f); + // Evaluate BSDF at hit point + BSDF *bsdf = isect.GetBSDF(ray, arena); + Vector wo = -ray.d; + const Point &p = bsdf->dgShading.p; + const Normal &n = bsdf->dgShading.nn; + // Compute emitted light if ray hit an area light source + L += isect.Le(wo); + + // Compute direct lighting for _DirectLightingIntegrator_ integrator + if (scene->lights.size() > 0) { + // Apply direct lighting strategy + switch (strategy) { + case SAMPLE_ALL_UNIFORM: + L += UniformSampleAllLights(scene, renderer, arena, p, n, wo, + isect.rayEpsilon, ray.time, bsdf, sample, rng, + lightSampleOffsets, bsdfSampleOffsets); + break; + case SAMPLE_ONE_UNIFORM: + L += UniformSampleOneLight(scene, renderer, arena, p, n, wo, + isect.rayEpsilon, ray.time, bsdf, sample, rng, + lightNumOffset, lightSampleOffsets, bsdfSampleOffsets); + break; + } + } + if (ray.depth + 1 < maxDepth) { + Vector wi; + // Trace rays for specular reflection and refraction + L += SpecularReflect(ray, bsdf, rng, isect, renderer, scene, sample, + arena); + L += SpecularTransmit(ray, bsdf, rng, isect, renderer, scene, sample, + arena); + } + return L; +} + + +DirectLightingIntegrator *CreateDirectLightingIntegrator(const ParamSet ¶ms) { + int maxDepth = params.FindOneInt("maxdepth", 5); + LightStrategy strategy; + string st = params.FindOneString("strategy", "all"); + if (st == "one") strategy = SAMPLE_ONE_UNIFORM; + else if (st == "all") strategy = SAMPLE_ALL_UNIFORM; + else { + Warning("Strategy \"%s\" for direct lighting unknown. " + "Using \"all\".", st.c_str()); + strategy = SAMPLE_ALL_UNIFORM; + } + return new DirectLightingIntegrator(strategy, maxDepth); +} + + diff --git a/integrators/directlighting.h b/integrators/directlighting.h new file mode 100644 index 0000000..67cc9bd --- /dev/null +++ b/integrators/directlighting.h @@ -0,0 +1,61 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_INTEGRATORS_DIRECTLIGHTING_H +#define PBRT_INTEGRATORS_DIRECTLIGHTING_H + +// integrators/directlighting.h* +#include "pbrt.h" +#include "integrator.h" +#include "scene.h" + +// DirectLightingIntegrator Declarations +enum LightStrategy { SAMPLE_ALL_UNIFORM, SAMPLE_ONE_UNIFORM }; +class DirectLightingIntegrator : public SurfaceIntegrator { +public: + // DirectLightingIntegrator Public Methods + DirectLightingIntegrator(LightStrategy ls = SAMPLE_ALL_UNIFORM, int md = 5); + ~DirectLightingIntegrator(); + Spectrum Li(const Scene *scene, const Renderer *renderer, + const RayDifferential &ray, const Intersection &isect, + const Sample *sample, RNG &rng, MemoryArena &arena) const; + void RequestSamples(Sampler *sampler, Sample *sample, const Scene *scene); +private: + // DirectLightingIntegrator Private Data + LightStrategy strategy; + int maxDepth; + + // Declare sample parameters for light source sampling + LightSampleOffsets *lightSampleOffsets; + BSDFSampleOffsets *bsdfSampleOffsets; + int lightNumOffset; +}; + + +DirectLightingIntegrator *CreateDirectLightingIntegrator(const ParamSet ¶ms); + +#endif // PBRT_INTEGRATORS_DIRECTLIGHTING_H diff --git a/integrators/emission.cpp b/integrators/emission.cpp new file mode 100644 index 0000000..769674e --- /dev/null +++ b/integrators/emission.cpp @@ -0,0 +1,106 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// integrators/emission.cpp* +#include "stdafx.h" +#include "integrators/emission.h" +#include "paramset.h" + +// EmissionIntegrator Method Definitions +void EmissionIntegrator::RequestSamples(Sampler *sampler, Sample *sample, + const Scene *scene) { + tauSampleOffset = sample->Add1D(1); + scatterSampleOffset = sample->Add1D(1); +} + + +Spectrum EmissionIntegrator::Transmittance(const Scene *scene, + const Renderer *renderer, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena) const { + if (!scene->volumeRegion) return Spectrum(1.f); + float step, offset; + if (sample) { + step = stepSize; + offset = sample->oneD[tauSampleOffset][0]; + } + else { + step = 4.f * stepSize; + offset = rng.RandomFloat(); + } + Spectrum tau = scene->volumeRegion->tau(ray, step, offset); + return Exp(-tau); +} + + +Spectrum EmissionIntegrator::Li(const Scene *scene, + const Renderer *renderer, const RayDifferential &ray, + const Sample *sample, RNG &rng, Spectrum *T, + MemoryArena &arena) const { + VolumeRegion *vr = scene->volumeRegion; + Assert(sample != NULL); + float t0, t1; + if (!vr || !vr->IntersectP(ray, &t0, &t1) || (t1-t0) == 0.f) { + *T = Spectrum(1.f); + return 0.f; + } + // Do emission-only volume integration in _vr_ + Spectrum Lv(0.); + + // Prepare for volume integration stepping + int nSamples = Ceil2Int((t1-t0) / stepSize); + float step = (t1 - t0) / nSamples; + Spectrum Tr(1.f); + Point p = ray(t0), pPrev; + Vector w = -ray.d; + t0 += sample->oneD[scatterSampleOffset][0] * step; + for (int i = 0; i < nSamples; ++i, t0 += step) { + // Advance to sample at _t0_ and update _T_ + pPrev = p; + p = ray(t0); + Ray tauRay(pPrev, p - pPrev, 0.f, 1.f, ray.time, ray.depth); + Spectrum stepTau = vr->tau(tauRay, + .5f * stepSize, rng.RandomFloat()); + Tr *= Exp(-stepTau); + + // Possibly terminate ray marching if transmittance is small + if (Tr.y() < 1e-3) { + const float continueProb = .5f; + if (rng.RandomFloat() > continueProb) break; + Tr /= continueProb; + } + + // Compute emission-only source term at _p_ + Lv += Tr * vr->Lve(p, w, ray.time); + } + *T = Tr; + return Lv * step; +} + + +EmissionIntegrator *CreateEmissionVolumeIntegrator(const ParamSet ¶ms) { + float stepSize = params.FindOneFloat("stepsize", 1.f); + return new EmissionIntegrator(stepSize); +} + + diff --git a/integrators/emission.h b/integrators/emission.h new file mode 100644 index 0000000..b8118c1 --- /dev/null +++ b/integrators/emission.h @@ -0,0 +1,57 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_INTEGRATORS_EMISSION_H +#define PBRT_INTEGRATORS_EMISSION_H + +// integrators/emission.h* +#include "volume.h" +#include "integrator.h" +#include "scene.h" + +// EmissionIntegrator Declarations +class EmissionIntegrator : public VolumeIntegrator { +public: + // EmissionIntegrator Public Methods + EmissionIntegrator(float ss) { stepSize = ss; } + void RequestSamples(Sampler *sampler, Sample *sample, const Scene *scene); + Spectrum Li(const Scene *scene, const Renderer *renderer, + const RayDifferential &ray, const Sample *sample, RNG &rng, + Spectrum *transmittance, MemoryArena &arena) const; + Spectrum Transmittance(const Scene *scene, const Renderer *, + const RayDifferential &ray, const Sample *sample, RNG &rng, + MemoryArena &arena) const; +private: + // EmissionIntegrator Private Data + float stepSize; + int tauSampleOffset, scatterSampleOffset; +}; + + +EmissionIntegrator *CreateEmissionVolumeIntegrator(const ParamSet ¶ms); + +#endif // PBRT_INTEGRATORS_EMISSION_H diff --git a/integrators/glossyprt.cpp b/integrators/glossyprt.cpp new file mode 100644 index 0000000..1541f78 --- /dev/null +++ b/integrators/glossyprt.cpp @@ -0,0 +1,140 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// integrators/glossyprt.cpp* +#include "stdafx.h" +#include "integrators/glossyprt.h" +#include "sh.h" +#include "light.h" +#include "scene.h" +#include "camera.h" +#include "intersection.h" +#include "paramset.h" + +// GlossyPRTIntegrator Method Definitions +GlossyPRTIntegrator::~GlossyPRTIntegrator() { + delete[] c_in; + delete[] B; +} + + +void GlossyPRTIntegrator::Preprocess(const Scene *scene, + const Camera *camera, const Renderer *renderer) { + // Project direct lighting into SH for _GlossyPRTIntegrator_ + BBox bbox = scene->WorldBound(); + Point p = .5f * bbox.pMin + .5f * bbox.pMax; + RNG rng; + MemoryArena arena; + c_in = new Spectrum[SHTerms(lmax)]; + SHProjectIncidentDirectRadiance(p, 0.f, camera->shutterOpen, arena, + scene, false, lmax, rng, c_in); + + // Compute glossy BSDF matrix for PRT + B = new Spectrum[SHTerms(lmax)*SHTerms(lmax)]; + SHComputeBSDFMatrix(Kd, Ks, roughness, rng, 1024, lmax, B); +} + + +void GlossyPRTIntegrator::RequestSamples(Sampler *sampler, Sample *sample, const Scene *scene) { +} + + +Spectrum GlossyPRTIntegrator::Li(const Scene *scene, const Renderer *, + const RayDifferential &ray, const Intersection &isect, + const Sample *sample, RNG &rng, MemoryArena &arena) const { + Spectrum L = 0.f; + Vector wo = -ray.d; + // Compute emitted light if ray hit an area light source + L += isect.Le(wo); + + // Evaluate BSDF at hit point + BSDF *bsdf = isect.GetBSDF(ray, arena); + const Point &p = bsdf->dgShading.p; + // Compute reflected radiance with glossy PRT at point + + // Compute SH radiance transfer matrix at point and SH coefficients + Spectrum *c_t = arena.Alloc(SHTerms(lmax)); + Spectrum *T = arena.Alloc(SHTerms(lmax)*SHTerms(lmax)); + SHComputeTransferMatrix(p, isect.rayEpsilon, scene, rng, nSamples, + lmax, T); + SHMatrixVectorMultiply(T, c_in, c_t, lmax); + + // Rotate incident SH lighting to local coordinate frame + Vector r1 = bsdf->LocalToWorld(Vector(1,0,0)); + Vector r2 = bsdf->LocalToWorld(Vector(0,1,0)); + Normal nl = Normal(bsdf->LocalToWorld(Vector(0,0,1))); + Matrix4x4 rot(r1.x, r2.x, nl.x, 0, + r1.y, r2.y, nl.y, 0, + r1.z, r2.z, nl.z, 0, + 0, 0, 0, 1); + Spectrum *c_l = arena.Alloc(SHTerms(lmax)); + SHRotate(c_t, c_l, rot, lmax, arena); + #if 0 + + // Sample BSDF and integrate against direct SH coefficients + float *Ylm = ALLOCA(float, SHTerms(lmax)); + int ns = 1024; + for (int i = 0; i < ns; ++i) { + Vector wi; + float pdf; + Spectrum f = bsdf->Sample_f(wo, &wi, BSDFSample(rng), &pdf); + if (pdf > 0.f && !f.IsBlack() && !scene->IntersectP(Ray(p, wi))) { + f *= fabsf(Dot(wi, n)) / (pdf * ns); + SHEvaluate(bsdf->WorldToLocal(wi), lmax, Ylm); + + Spectrum Li = 0.f; + for (int j = 0; j < SHTerms(lmax); ++j) + Li += Ylm[j] * c_l[j] * f; + L += Li.Clamp(); + } + } + #else + + // Compute final coefficients _c\_o_ using BSDF matrix + Spectrum *c_o = arena.Alloc(SHTerms(lmax)); + SHMatrixVectorMultiply(B, c_l, c_o, lmax); + + // Evaluate outgoing radiance function for $\wo$ and add to _L_ + Vector woLocal = bsdf->WorldToLocal(wo); + float *Ylm = ALLOCA(float, SHTerms(lmax)); + SHEvaluate(woLocal, lmax, Ylm); + Spectrum Li = 0.f; + for (int i = 0; i < SHTerms(lmax); ++i) + Li += Ylm[i] * c_o[i]; + L += Li.Clamp(); + #endif + return L; +} + + +GlossyPRTIntegrator *CreateGlossyPRTIntegratorSurfaceIntegrator(const ParamSet ¶ms) { + int lmax = params.FindOneInt("lmax", 4); + int ns = params.FindOneInt("nsamples", 4096); + Spectrum Kd = params.FindOneSpectrum("Kd", Spectrum(0.5f)); + Spectrum Ks = params.FindOneSpectrum("Ks", Spectrum(0.25f)); + float roughness = params.FindOneFloat("roughness", 0.1f); + return new GlossyPRTIntegrator(Kd, Ks, roughness, lmax, ns); +} + + diff --git a/integrators/glossyprt.h b/integrators/glossyprt.h new file mode 100644 index 0000000..8100816 --- /dev/null +++ b/integrators/glossyprt.h @@ -0,0 +1,63 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_INTEGRATORS_GLOSSYPRT_H +#define PBRT_INTEGRATORS_GLOSSYPRT_H + +// integrators/glossyprt.h* +#include "pbrt.h" +#include "integrator.h" + +// GlossyPRTIntegrator Declarations +class GlossyPRTIntegrator : public SurfaceIntegrator { +public: + // GlossyPRTIntegrator Public Methods + GlossyPRTIntegrator(const Spectrum &kd, const Spectrum &ks, + float rough, int lm, int ns) + : Kd(kd), Ks(ks), roughness(rough), lmax(lm), + nSamples(RoundUpPow2(ns)) { + c_in = B = NULL; + } + ~GlossyPRTIntegrator(); + void Preprocess(const Scene *scene, const Camera *camera, const Renderer *renderer); + void RequestSamples(Sampler *sampler, Sample *sample, const Scene *scene); + Spectrum Li(const Scene *scene, const Renderer *, + const RayDifferential &ray, const Intersection &isect, + const Sample *sample, RNG &rng, MemoryArena &arena) const; +private: + // GlossyPRTIntegrator Private Data + const Spectrum Kd, Ks; + const float roughness; + const int lmax, nSamples; + Spectrum *c_in; + Spectrum *B; +}; + + +GlossyPRTIntegrator *CreateGlossyPRTIntegratorSurfaceIntegrator(const ParamSet ¶ms); + +#endif // PBRT_INTEGRATORS_GLOSSYPRT_H diff --git a/integrators/igi.cpp b/integrators/igi.cpp new file mode 100644 index 0000000..154416c --- /dev/null +++ b/integrators/igi.cpp @@ -0,0 +1,235 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// integrators/igi.cpp* +#include "stdafx.h" +#include "integrators/igi.h" +#include "scene.h" +#include "montecarlo.h" +#include "progressreporter.h" +#include "sampler.h" +#include "intersection.h" +#include "paramset.h" +#include "camera.h" + +// IGIIntegrator Method Definitions +IGIIntegrator::~IGIIntegrator() { + delete[] lightSampleOffsets; + delete[] bsdfSampleOffsets; +} + + +void IGIIntegrator::RequestSamples(Sampler *sampler, Sample *sample, + const Scene *scene) { + // Allocate and request samples for sampling all lights + uint32_t nLights = scene->lights.size(); + lightSampleOffsets = new LightSampleOffsets[nLights]; + bsdfSampleOffsets = new BSDFSampleOffsets[nLights]; + for (uint32_t i = 0; i < nLights; ++i) { + const Light *light = scene->lights[i]; + int nSamples = light->nSamples; + if (sampler) nSamples = sampler->RoundSize(nSamples); + lightSampleOffsets[i] = LightSampleOffsets(nSamples, sample); + bsdfSampleOffsets[i] = BSDFSampleOffsets(nSamples, sample); + } + vlSetOffset = sample->Add1D(1); + + if (sampler) nGatherSamples = sampler->RoundSize(nGatherSamples); + gatherSampleOffset = BSDFSampleOffsets(nGatherSamples, sample); +} + + +void IGIIntegrator::Preprocess(const Scene *scene, const Camera *camera, + const Renderer *renderer) { + if (scene->lights.size() == 0) return; + MemoryArena arena; + RNG rng; + // Compute samples for emitted rays from lights + vector lightNum(nLightPaths * nLightSets); + vector lightSampPos(2 * nLightPaths * nLightSets, 0.f); + vector lightSampComp(nLightPaths * nLightSets, 0.f); + vector lightSampDir(2 * nLightPaths * nLightSets, 0.f); + LDShuffleScrambled1D(nLightPaths, nLightSets, &lightNum[0], rng); + LDShuffleScrambled2D(nLightPaths, nLightSets, &lightSampPos[0], rng); + LDShuffleScrambled1D(nLightPaths, nLightSets, &lightSampComp[0], rng); + LDShuffleScrambled2D(nLightPaths, nLightSets, &lightSampDir[0], rng); + + // Precompute information for light sampling densities + Distribution1D *lightDistribution = ComputeLightSamplingCDF(scene); + for (uint32_t s = 0; s < nLightSets; ++s) { + for (uint32_t i = 0; i < nLightPaths; ++i) { + // Follow path _i_ from light to create virtual lights + int sampOffset = s*nLightPaths + i; + + // Choose light source to trace virtual light path from + float lightPdf; + int ln = lightDistribution->SampleDiscrete(lightNum[sampOffset], + &lightPdf); + Light *light = scene->lights[ln]; + + // Sample ray leaving light source for virtual light path + RayDifferential ray; + float pdf; + LightSample ls(lightSampPos[2*sampOffset], lightSampPos[2*sampOffset+1], + lightSampComp[sampOffset]); + Normal Nl; + Spectrum alpha = light->Sample_L(scene, ls, lightSampDir[2*sampOffset], + lightSampDir[2*sampOffset+1], + camera->shutterOpen, &ray, &Nl, &pdf); + if (pdf == 0.f || alpha.IsBlack()) continue; + alpha /= pdf * lightPdf; + Intersection isect; + while (scene->Intersect(ray, &isect) && !alpha.IsBlack()) { + // Create virtual light and sample new ray for path + alpha *= renderer->Transmittance(scene, RayDifferential(ray), NULL, + rng, arena); + Vector wo = -ray.d; + BSDF *bsdf = isect.GetBSDF(ray, arena); + + // Create virtual light at ray intersection point + Spectrum contrib = alpha * bsdf->rho(wo, rng) / M_PI; + virtualLights[s].push_back(VirtualLight(isect.dg.p, isect.dg.nn, contrib, + isect.rayEpsilon)); + + // Sample new ray direction and update weight for virtual light path + Vector wi; + float pdf; + BSDFSample bsdfSample(rng); + Spectrum fr = bsdf->Sample_f(wo, &wi, bsdfSample, &pdf); + if (fr.IsBlack() || pdf == 0.f) + break; + Spectrum contribScale = fr * AbsDot(wi, bsdf->dgShading.nn) / pdf; + + // Possibly terminate virtual light path with Russian roulette + float rrProb = min(1.f, contribScale.y()); + if (rng.RandomFloat() > rrProb) + break; + alpha *= contribScale / rrProb; + ray = RayDifferential(isect.dg.p, wi, ray, isect.rayEpsilon); + } + arena.FreeAll(); + } + } + delete lightDistribution; +} + + +Spectrum IGIIntegrator::Li(const Scene *scene, const Renderer *renderer, + const RayDifferential &ray, const Intersection &isect, + const Sample *sample, RNG &rng, MemoryArena &arena) const { + Spectrum L(0.); + Vector wo = -ray.d; + // Compute emitted light if ray hit an area light source + L += isect.Le(wo); + + // Evaluate BSDF at hit point + BSDF *bsdf = isect.GetBSDF(ray, arena); + const Point &p = bsdf->dgShading.p; + const Normal &n = bsdf->dgShading.nn; + L += UniformSampleAllLights(scene, renderer, arena, p, n, + wo, isect.rayEpsilon, ray.time, bsdf, sample, rng, + lightSampleOffsets, bsdfSampleOffsets); + // Compute indirect illumination with virtual lights + uint32_t lSet = min(uint32_t(sample->oneD[vlSetOffset][0] * nLightSets), + nLightSets-1); + for (uint32_t i = 0; i < virtualLights[lSet].size(); ++i) { + const VirtualLight &vl = virtualLights[lSet][i]; + // Compute virtual light's tentative contribution _Llight_ + float d2 = DistanceSquared(p, vl.p); + Vector wi = Normalize(vl.p - p); + float G = AbsDot(wi, n) * AbsDot(wi, vl.n) / d2; + G = min(G, gLimit); + Spectrum f = bsdf->f(wo, wi); + if (G == 0.f || f.IsBlack()) continue; + Spectrum Llight = f * G * vl.pathContrib / nLightPaths; + RayDifferential connectRay(p, wi, ray, isect.rayEpsilon, + sqrtf(d2) * (1.f - vl.rayEpsilon)); + Llight *= renderer->Transmittance(scene, connectRay, NULL, rng, arena); + + // Possibly skip virtual light shadow ray with Russian roulette + if (Llight.y() < rrThreshold) { + float continueProbability = .1f; + if (rng.RandomFloat() > continueProbability) + continue; + Llight /= continueProbability; + } + + // Add contribution from _VirtualLight_ _vl_ + if (!scene->IntersectP(connectRay)) + L += Llight; + } + if (ray.depth < maxSpecularDepth) { + // Do bias compensation for bounding geometry term + int nSamples = (ray.depth == 0) ? nGatherSamples : 1; + for (int i = 0; i < nSamples; ++i) { + Vector wi; + float pdf; + BSDFSample bsdfSample = (ray.depth == 0) ? + BSDFSample(sample, gatherSampleOffset, i) : BSDFSample(rng); + Spectrum f = bsdf->Sample_f(wo, &wi, bsdfSample, + &pdf, BxDFType(BSDF_ALL & ~BSDF_SPECULAR)); + if (!f.IsBlack() && pdf > 0.f) { + // Trace ray for bias compensation gather sample + float maxDist = sqrtf(AbsDot(wi, n) / gLimit); + RayDifferential gatherRay(p, wi, ray, isect.rayEpsilon, maxDist); + Intersection gatherIsect; + Spectrum Li = renderer->Li(scene, gatherRay, sample, rng, arena, + &gatherIsect); + if (Li.IsBlack()) continue; + + // Add bias compensation ray contribution to radiance sum + float Ggather = AbsDot(wi, n) * AbsDot(-wi, gatherIsect.dg.nn) / + DistanceSquared(p, gatherIsect.dg.p); + if (Ggather - gLimit > 0.f && !isinf(Ggather)) { + float gs = (Ggather - gLimit) / Ggather; + L += f * Li * (AbsDot(wi, n) * gs / (nSamples * pdf)); + } + } + } + } + if (ray.depth + 1 < maxSpecularDepth) { + Vector wi; + // Trace rays for specular reflection and refraction + L += SpecularReflect(ray, bsdf, rng, isect, renderer, scene, sample, + arena); + L += SpecularTransmit(ray, bsdf, rng, isect, renderer, scene, sample, + arena); + } + return L; +} + + +IGIIntegrator *CreateIGISurfaceIntegrator(const ParamSet ¶ms) { + int nLightPaths = params.FindOneInt("nlights", 64); + if (PbrtOptions.quickRender) nLightPaths = max(1, nLightPaths / 4); + int nLightSets = params.FindOneInt("nsets", 4); + float rrThresh = params.FindOneFloat("rrthreshold", .0001f); + int maxDepth = params.FindOneInt("maxdepth", 5); + float glimit = params.FindOneFloat("glimit", 10.f); + int gatherSamples = params.FindOneInt("gathersamples", 16); + return new IGIIntegrator(nLightPaths, nLightSets, rrThresh, + maxDepth, glimit, gatherSamples); +} + + diff --git a/integrators/igi.h b/integrators/igi.h new file mode 100644 index 0000000..58668fe --- /dev/null +++ b/integrators/igi.h @@ -0,0 +1,89 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_INTEGRATORS_IGI_H +#define PBRT_INTEGRATORS_IGI_H + +// integrators/igi.h* +#include "pbrt.h" +#include "integrator.h" + +// IGIIntegrator Local Structures +struct VirtualLight { + VirtualLight() { } + VirtualLight(const Point &pp, const Normal &nn, const Spectrum &c, + float reps) + : p(pp), n(nn), pathContrib(c), rayEpsilon(reps) { } + Point p; + Normal n; + Spectrum pathContrib; + float rayEpsilon; +}; + + + +// IGIIntegrator Declarations +class IGIIntegrator : public SurfaceIntegrator { +public: + // IGIIntegrator Public Methods + ~IGIIntegrator(); + Spectrum Li(const Scene *scene, const Renderer *renderer, + const RayDifferential &ray, const Intersection &isect, + const Sample *sample, RNG &rng, MemoryArena &arena) const; + void RequestSamples(Sampler *sampler, Sample *sample, const Scene *scene); + void Preprocess(const Scene *, const Camera *, const Renderer *); + IGIIntegrator(uint32_t nl, uint32_t ns, float rrt, int maxd, float gl, int ng) { + nLightPaths = RoundUpPow2(nl); + nLightSets = RoundUpPow2(ns); + rrThreshold = rrt; + maxSpecularDepth = maxd; + virtualLights.resize(nLightSets); + gLimit = gl; + nGatherSamples = ng; + lightSampleOffsets = NULL; + bsdfSampleOffsets = NULL; + } +private: + // IGIIntegrator Private Data + + // Declare sample parameters for light source sampling + LightSampleOffsets *lightSampleOffsets; + BSDFSampleOffsets *bsdfSampleOffsets; + uint32_t nLightPaths, nLightSets; + float gLimit; + int nGatherSamples; + float rrThreshold; + int maxSpecularDepth; + int vlSetOffset; + BSDFSampleOffsets gatherSampleOffset; + vector > virtualLights; +}; + + +IGIIntegrator *CreateIGISurfaceIntegrator(const ParamSet ¶ms); + +#endif // PBRT_INTEGRATORS_IGI_H diff --git a/integrators/irradiancecache.cpp b/integrators/irradiancecache.cpp new file mode 100644 index 0000000..5d5484f --- /dev/null +++ b/integrators/irradiancecache.cpp @@ -0,0 +1,389 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// integrators/irradiancecache.cpp* +#include "stdafx.h" +#include "integrators/irradiancecache.h" +#include "camera.h" +#include "progressreporter.h" +#include "scene.h" +#include "montecarlo.h" +#include "film.h" +#include "samplers/halton.h" +#include "intersection.h" +#include "paramset.h" + +// IrradianceCacheIntegrator Local Declarations +struct IrradiancePrimeTask : public Task { + IrradiancePrimeTask(const Scene *sc, const Renderer *sr, const Camera *c, Sampler *samp, + Sample *s, IrradianceCacheIntegrator *ic, ProgressReporter &pr, + int tn, int nt) : progress(pr) { + scene = sc; + renderer = sr; + camera = c; + origSample = s; + sampler = samp->GetSubSampler(tn, nt); + irradianceCache = ic; + taskNum = tn; + numTasks = nt; + } + void Run(); + + const Scene *scene; + const Camera *camera; + const Renderer *renderer; + Sampler *sampler; + Sample *origSample; + IrradianceCacheIntegrator *irradianceCache; + ProgressReporter &progress; + int taskNum, numTasks; +}; + + +struct IrradProcess { + // IrradProcess Public Methods + IrradProcess(const Point &P, const Normal &N, float mw, float cmsad) { + p = P; + n = N; + minWeight = mw; + cosMaxSampleAngleDifference = cmsad; + nFound = 0; + sumWt = 0.; + E = 0.; + wAvg = Vector(0,0,0); + } + bool operator()(const IrradianceSample *sample); + bool Successful() { + return sumWt >= minWeight; + } + Spectrum GetIrradiance() const { return E / sumWt; } + Vector GetAverageDirection() const { return wAvg; } + + // IrradProcess Data + Point p; + Normal n; + float minWeight, cosMaxSampleAngleDifference, sumWt; + int nFound; + Spectrum E; + Vector wAvg; +}; + + +struct IrradianceSample { + // IrradianceSample Constructor + IrradianceSample() { } + IrradianceSample(const Spectrum &e, const Point &P, const Normal &N, + const Vector &pd, float md) : E(e), n(N), p(P), wAvg(pd) { + maxDist = md; + } + Spectrum E; + Normal n; + Point p; + Vector wAvg; + float maxDist; +}; + + + +// IrradianceCacheIntegrator Method Definitions +void IrradianceCacheIntegrator::RequestSamples(Sampler *sampler, + Sample *sample, const Scene *scene) { +// if (lightSampleOffsets != NULL) return; + // Allocate and request samples for sampling all lights + uint32_t nLights = scene->lights.size(); + lightSampleOffsets = new LightSampleOffsets[nLights]; + bsdfSampleOffsets = new BSDFSampleOffsets[nLights]; + for (uint32_t i = 0; i < nLights; ++i) { + const Light *light = scene->lights[i]; + int nSamples = light->nSamples; + if (sampler) nSamples = sampler->RoundSize(nSamples); + lightSampleOffsets[i] = LightSampleOffsets(nSamples, sample); + bsdfSampleOffsets[i] = BSDFSampleOffsets(nSamples, sample); + } +} + + +void IrradianceCacheIntegrator::Preprocess(const Scene *scene, + const Camera *camera, const Renderer *renderer) { + BBox wb = scene->WorldBound(); + Vector delta = .01f * (wb.pMax - wb.pMin); + wb.pMin -= delta; + wb.pMax += delta; + octree = new Octree(wb); + // Prime irradiance cache + minWeight *= 1.5f; + int xstart, xend, ystart, yend; + camera->film->GetSampleExtent(&xstart, &xend, &ystart, ¥d); + HaltonSampler sampler(xstart, xend, ystart, yend, 1, + camera->shutterOpen, camera->shutterClose); + Sample *sample = new Sample(&sampler, this, NULL, scene); + const int nTasks = 64; + ProgressReporter progress(nTasks, "Priming irradiance cache"); + vector tasks; + for (int i = 0; i < nTasks; ++i) + tasks.push_back(new IrradiancePrimeTask(scene, renderer, camera, + &sampler, sample, this, + progress, i, nTasks)); + EnqueueTasks(tasks); + WaitForAllTasks(); + for (uint32_t i = 0; i < tasks.size(); ++i) + delete tasks[i]; + progress.Done(); + delete sample; + minWeight /= 1.5f; +} + + +IrradianceCacheIntegrator::~IrradianceCacheIntegrator() { + delete octree; + RWMutex::Destroy(mutex); + delete[] lightSampleOffsets; + delete[] bsdfSampleOffsets; +} + + +void IrradiancePrimeTask::Run() { + if (!sampler) { progress.Update(); return; } + MemoryArena arena; + int sampleCount; + RNG rng(29 * taskNum); + int maxSamples = sampler->MaximumSampleCount(); + Sample *samples = origSample->Duplicate(maxSamples); + while ((sampleCount = sampler->GetMoreSamples(samples, rng)) > 0) { + for (int i = 0; i < sampleCount; ++i) { + RayDifferential ray; + camera->GenerateRayDifferential(samples[i], &ray); + Intersection isect; + if (scene->Intersect(ray, &isect)) + (void)irradianceCache->Li(scene, renderer, ray, isect, &samples[i], rng, arena); + } + arena.FreeAll(); + } + delete[] samples; + delete sampler; + progress.Update(); +} + + +Spectrum IrradianceCacheIntegrator::Li(const Scene *scene, + const Renderer *renderer, const RayDifferential &ray, const Intersection &isect, + const Sample *sample, RNG &rng, MemoryArena &arena) const { + Spectrum L(0.); + // Evaluate BSDF at hit point + BSDF *bsdf = isect.GetBSDF(ray, arena); + Vector wo = -ray.d; + const Point &p = bsdf->dgShading.p; + const Normal &n = bsdf->dgShading.nn; + L += isect.Le(wo); + // Compute direct lighting for irradiance cache + L += UniformSampleAllLights(scene, renderer, arena, p, n, wo, + isect.rayEpsilon, ray.time, bsdf, sample, rng, + lightSampleOffsets, bsdfSampleOffsets); + + // Compute indirect lighting for irradiance cache + if (ray.depth + 1 < maxSpecularDepth) { + Vector wi; + // Trace rays for specular reflection and refraction + L += SpecularReflect(ray, bsdf, rng, isect, renderer, scene, sample, + arena); + L += SpecularTransmit(ray, bsdf, rng, isect, renderer, scene, sample, + arena); + } + + // Estimate indirect lighting with irradiance cache + Normal ng = isect.dg.nn; + ng = Faceforward(ng, wo); + + // Compute pixel spacing in world space at intersection point + float pixelSpacing = sqrtf(Cross(isect.dg.dpdx, isect.dg.dpdy).Length()); + BxDFType flags = BxDFType(BSDF_REFLECTION | BSDF_DIFFUSE | BSDF_GLOSSY); + L += indirectLo(p, ng, pixelSpacing, wo, isect.rayEpsilon, + bsdf, flags, rng, scene, renderer, arena); + flags = BxDFType(BSDF_TRANSMISSION | BSDF_DIFFUSE | BSDF_GLOSSY); + L += indirectLo(p, -ng, pixelSpacing, wo, isect.rayEpsilon, + bsdf, flags, rng, scene, renderer, arena); + return L; +} + + +Spectrum IrradianceCacheIntegrator::indirectLo(const Point &p, + const Normal &ng, float pixelSpacing, const Vector &wo, + float rayEpsilon, BSDF *bsdf, BxDFType flags, RNG &rng, + const Scene *scene, const Renderer *renderer, + MemoryArena &arena) const { + if (bsdf->NumComponents(flags) == 0) + return Spectrum(0.); + Spectrum E; + Vector wi; + // Get irradiance _E_ and average incident direction _wi_ at point _p_ + if (!interpolateE(scene, p, ng, &E, &wi)) { + // Compute irradiance at current point + PBRT_IRRADIANCE_CACHE_STARTED_COMPUTING_IRRADIANCE(const_cast(&p), const_cast(&ng)); + uint32_t scramble[2] = { rng.RandomUInt(), rng.RandomUInt() }; + float minHitDistance = INFINITY; + Vector wAvg(0,0,0); + Spectrum LiSum = 0.f; + for (int i = 0; i < nSamples; ++i) { + // Sample direction for irradiance estimate ray + float u[2]; + Sample02(i, scramble, u); + Vector w = CosineSampleHemisphere(u[0], u[1]); + RayDifferential r(p, bsdf->LocalToWorld(w), rayEpsilon); + r.d = Faceforward(r.d, ng); + + // Trace ray to sample radiance for irradiance estimate + PBRT_IRRADIANCE_CACHE_STARTED_RAY(&r); + Spectrum L = pathL(r, scene, renderer, rng, arena); + LiSum += L; + wAvg += r.d * L.y(); + minHitDistance = min(minHitDistance, r.maxt); + PBRT_IRRADIANCE_CACHE_FINISHED_RAY(&r, r.maxt, &L); + } + E = (M_PI / float(nSamples)) * LiSum; + PBRT_IRRADIANCE_CACHE_FINISHED_COMPUTING_IRRADIANCE(const_cast(&p), const_cast(&ng)); + + // Add computed irradiance value to cache + + // Compute irradiance sample's contribution extent and bounding box + float maxDist = maxSamplePixelSpacing * pixelSpacing; + float minDist = minSamplePixelSpacing * pixelSpacing; + float contribExtent = Clamp(minHitDistance / 2.f, minDist, maxDist); + BBox sampleExtent(p); + sampleExtent.Expand(contribExtent); + PBRT_IRRADIANCE_CACHE_ADDED_NEW_SAMPLE(const_cast(&p), const_cast(&ng), contribExtent, &E, &wAvg, pixelSpacing); + + // Allocate _IrradianceSample_, get write lock, add to octree + IrradianceSample *sample = new IrradianceSample(E, p, ng, wAvg, + contribExtent); + RWMutexLock lock(*mutex, WRITE); + octree->Add(sample, sampleExtent); + wi = wAvg; + } + + // Compute reflected radiance due to irradiance and BSDF + if (wi.LengthSquared() == 0.f) return Spectrum(0.); + return bsdf->f(wo, Normalize(wi), flags) * E; +} + + +bool IrradianceCacheIntegrator::interpolateE(const Scene *scene, + const Point &p, const Normal &n, Spectrum *E, + Vector *wi) const { + if (!octree) return false; + PBRT_IRRADIANCE_CACHE_STARTED_INTERPOLATION(const_cast(&p), const_cast(&n)); + IrradProcess proc(p, n, minWeight, cosMaxSampleAngleDifference); + RWMutexLock lock(*mutex, READ); + octree->Lookup(p, proc); + PBRT_IRRADIANCE_CACHE_FINISHED_INTERPOLATION(const_cast(&p), const_cast(&n), + proc.Successful() ? 1 : 0, proc.nFound); + if (!proc.Successful()) return false; + *E = proc.GetIrradiance(); + *wi = proc.GetAverageDirection(); + return true; +} + + +bool IrradProcess::operator()(const IrradianceSample *sample) { + // Compute estimate error term and possibly use sample + float perr = Distance(p, sample->p) / sample->maxDist; + float nerr = sqrtf((1.f - Dot(n, sample->n)) / + (1.f - cosMaxSampleAngleDifference)); + float err = max(perr, nerr); + PBRT_IRRADIANCE_CACHE_CHECKED_SAMPLE(const_cast(sample), perr, nerr); + if (err < 1.) { + ++nFound; + float wt = 1.f - err; + E += wt * sample->E; + wAvg += wt * sample->wAvg; + sumWt += wt; + } + return true; +} + + +Spectrum IrradianceCacheIntegrator::pathL(Ray &r, const Scene *scene, + const Renderer *renderer, RNG &rng, MemoryArena &arena) const { + Spectrum L(0.f); + Spectrum pathThroughput = 1.; + RayDifferential ray(r); + bool specularBounce = false; + for (int pathLength = 0; ; ++pathLength) { + // Find next vertex of path + Intersection isect; + if (!scene->Intersect(ray, &isect)) + break; + if (pathLength == 0) + r.maxt = ray.maxt; + pathThroughput *= renderer->Transmittance(scene, ray, NULL, rng, arena); + // Possibly add emitted light at path vertex + if (specularBounce) + L += pathThroughput * isect.Le(-ray.d); + // Evaluate BSDF at hit point + BSDF *bsdf = isect.GetBSDF(ray, arena); + // Sample illumination from lights to find path contribution + const Point &p = bsdf->dgShading.p; + const Normal &n = bsdf->dgShading.nn; + Vector wo = -ray.d; + L += pathThroughput * + UniformSampleOneLight(scene, renderer, arena, p, n, wo, isect.rayEpsilon, + ray.time, bsdf, NULL, rng); + if (pathLength+1 == maxIndirectDepth) break; + // Sample BSDF to get new path direction + // Get random numbers for sampling new direction, \mono{bs1}, \mono{bs2}, and \mono{bcs} + Vector wi; + float pdf; + BxDFType flags; + Spectrum f = bsdf->Sample_f(wo, &wi, BSDFSample(rng), + &pdf, BSDF_ALL, &flags); + if (f.IsBlack() || pdf == 0.) + break; + specularBounce = (flags & BSDF_SPECULAR) != 0; + pathThroughput *= f * AbsDot(wi, n) / pdf; + ray = RayDifferential(p, wi, ray, isect.rayEpsilon); + // Possibly terminate the path + if (pathLength > 2) { + float rrProb = min(1.f, pathThroughput.y()); + if (rng.RandomFloat() > rrProb) + break; + pathThroughput /= rrProb; + } + } + return L; +} + + +IrradianceCacheIntegrator *CreateIrradianceCacheIntegrator(const ParamSet ¶ms) { + float minWeight = params.FindOneFloat("minweight", 0.5f); + float minSpacing = params.FindOneFloat("minpixelspacing", 2.5f); + float maxSpacing = params.FindOneFloat("maxpixelspacing", 15.f); + float maxAngle = params.FindOneFloat("maxangledifference", 10.f); + int maxSpecularDepth = params.FindOneInt("maxspeculardepth", 5); + int maxIndirectDepth = params.FindOneInt("maxindirectdepth", 3); + int nSamples = params.FindOneInt("nsamples", 4096); + if (PbrtOptions.quickRender) nSamples = max(1, nSamples / 16); + return new IrradianceCacheIntegrator(minWeight, minSpacing, maxSpacing, maxAngle, + maxSpecularDepth, maxIndirectDepth, nSamples); +} + + diff --git a/integrators/irradiancecache.h b/integrators/irradiancecache.h new file mode 100644 index 0000000..ee27ae9 --- /dev/null +++ b/integrators/irradiancecache.h @@ -0,0 +1,88 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_INTEGRATORS_IRRADIANCECACHE_H +#define PBRT_INTEGRATORS_IRRADIANCECACHE_H + +// integrators/irradiancecache.h* +#include "pbrt.h" +#include "integrator.h" +#include "octree.h" +#include "parallel.h" + +// IrradianceCacheIntegrator Forward Declarations +struct IrradianceSample; + +// IrradianceCacheIntegrator Declarations +class IrradianceCacheIntegrator : public SurfaceIntegrator { +public: + // IrradianceCacheIntegrator Public Methods + IrradianceCacheIntegrator(float minwt, float minsp, float maxsp, + float maxang, int maxspec, int maxind, int ns) { + minWeight = minwt; + minSamplePixelSpacing = minsp; + maxSamplePixelSpacing = maxsp; + cosMaxSampleAngleDifference = cosf(Degrees(maxang)); + nSamples = ns; + maxSpecularDepth = maxspec; + maxIndirectDepth = maxind; + mutex = RWMutex::Create(); + lightSampleOffsets = NULL; + bsdfSampleOffsets = NULL; + } + ~IrradianceCacheIntegrator(); + Spectrum Li(const Scene *scene, const Renderer *renderer, + const RayDifferential &ray, const Intersection &isect, + const Sample *sample, RNG &rng, MemoryArena &arena) const; + void RequestSamples(Sampler *sampler, Sample *sample, const Scene *scene); + void Preprocess(const Scene *, const Camera *, const Renderer *); +private: + // IrradianceCacheIntegrator Private Data + float minSamplePixelSpacing, maxSamplePixelSpacing; + float minWeight, cosMaxSampleAngleDifference; + int nSamples, maxSpecularDepth, maxIndirectDepth; + mutable RWMutex *mutex; + + // Declare sample parameters for light source sampling + LightSampleOffsets *lightSampleOffsets; + BSDFSampleOffsets *bsdfSampleOffsets; + mutable Octree *octree; + + // IrradianceCacheIntegrator Private Methods + Spectrum indirectLo(const Point &p, const Normal &ng, float pixelSpacing, + const Vector &wo, float rayEpsilon,BSDF *bsdf, BxDFType flags, RNG &rng, + const Scene *scene, const Renderer *renderer, MemoryArena &arena) const; + bool interpolateE(const Scene *scene, + const Point &p, const Normal &n, Spectrum *E, Vector *wi) const; + Spectrum pathL(Ray &r, const Scene *scene, const Renderer *renderer, + RNG &rng, MemoryArena &arena) const; +}; + + +IrradianceCacheIntegrator *CreateIrradianceCacheIntegrator(const ParamSet ¶ms); + +#endif // PBRT_INTEGRATORS_IRRADIANCECACHE_H diff --git a/integrators/path.cpp b/integrators/path.cpp new file mode 100644 index 0000000..22bd522 --- /dev/null +++ b/integrators/path.cpp @@ -0,0 +1,123 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// integrators/path.cpp* +#include "stdafx.h" +#include "integrators/path.h" +#include "scene.h" +#include "intersection.h" +#include "paramset.h" + +// PathIntegrator Method Definitions +void PathIntegrator::RequestSamples(Sampler *sampler, Sample *sample, + const Scene *scene) { + for (int i = 0; i < SAMPLE_DEPTH; ++i) { + lightSampleOffsets[i] = LightSampleOffsets(1, sample); + lightNumOffset[i] = sample->Add1D(1); + bsdfSampleOffsets[i] = BSDFSampleOffsets(1, sample); + pathSampleOffsets[i] = BSDFSampleOffsets(1, sample); + } +} + + +Spectrum PathIntegrator::Li(const Scene *scene, const Renderer *renderer, + const RayDifferential &r, const Intersection &isect, + const Sample *sample, RNG &rng, MemoryArena &arena) const { + // Declare common path integration variables + Spectrum pathThroughput = 1., L = 0.; + RayDifferential ray(r); + bool specularBounce = false; + Intersection localIsect; + const Intersection *isectp = &isect; + for (int bounces = 0; ; ++bounces) { + // Possibly add emitted light at path vertex + if (bounces == 0 || specularBounce) + L += pathThroughput * isectp->Le(-ray.d); + + // Sample illumination from lights to find path contribution + BSDF *bsdf = isectp->GetBSDF(ray, arena); + const Point &p = bsdf->dgShading.p; + const Normal &n = bsdf->dgShading.nn; + Vector wo = -ray.d; + if (bounces < SAMPLE_DEPTH) + L += pathThroughput * + UniformSampleOneLight(scene, renderer, arena, p, n, wo, + isectp->rayEpsilon, ray.time, bsdf, sample, rng, + lightNumOffset[bounces], &lightSampleOffsets[bounces], + &bsdfSampleOffsets[bounces]); + else + L += pathThroughput * + UniformSampleOneLight(scene, renderer, arena, p, n, wo, + isectp->rayEpsilon, ray.time, bsdf, sample, rng); + + // Sample BSDF to get new path direction + + // Get _outgoingBSDFSample_ for sampling new path direction + BSDFSample outgoingBSDFSample; + if (bounces < SAMPLE_DEPTH) + outgoingBSDFSample = BSDFSample(sample, pathSampleOffsets[bounces], + 0); + else + outgoingBSDFSample = BSDFSample(rng); + Vector wi; + float pdf; + BxDFType flags; + Spectrum f = bsdf->Sample_f(wo, &wi, outgoingBSDFSample, &pdf, + BSDF_ALL, &flags); + if (f.IsBlack() || pdf == 0.) + break; + specularBounce = (flags & BSDF_SPECULAR) != 0; + pathThroughput *= f * AbsDot(wi, n) / pdf; + ray = RayDifferential(p, wi, ray, isectp->rayEpsilon); + + // Possibly terminate the path + if (bounces > 3) { + float continueProbability = min(.5f, pathThroughput.y()); + if (rng.RandomFloat() > continueProbability) + break; + pathThroughput /= continueProbability; + } + if (bounces == maxDepth) + break; + + // Find next vertex of path + if (!scene->Intersect(ray, &localIsect)) { + if (specularBounce) + for (uint32_t i = 0; i < scene->lights.size(); ++i) + L += pathThroughput * scene->lights[i]->Le(ray); + break; + } + pathThroughput *= renderer->Transmittance(scene, ray, NULL, rng, arena); + isectp = &localIsect; + } + return L; +} + + +PathIntegrator *CreatePathSurfaceIntegrator(const ParamSet ¶ms) { + int maxDepth = params.FindOneInt("maxdepth", 5); + return new PathIntegrator(maxDepth); +} + + diff --git a/integrators/path.h b/integrators/path.h new file mode 100644 index 0000000..ec14625 --- /dev/null +++ b/integrators/path.h @@ -0,0 +1,57 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_INTEGRATORS_PATH_H +#define PBRT_INTEGRATORS_PATH_H + +// integrators/path.h* +#include "pbrt.h" +#include "integrator.h" + +// PathIntegrator Declarations +class PathIntegrator : public SurfaceIntegrator { +public: + // PathIntegrator Public Methods + Spectrum Li(const Scene *scene, const Renderer *renderer, + const RayDifferential &ray, const Intersection &isect, + const Sample *sample, RNG &rng, MemoryArena &arena) const; + void RequestSamples(Sampler *sampler, Sample *sample, const Scene *scene); + PathIntegrator(int md) { maxDepth = md; } +private: + // PathIntegrator Private Data + int maxDepth; +#define SAMPLE_DEPTH 3 + LightSampleOffsets lightSampleOffsets[SAMPLE_DEPTH]; + int lightNumOffset[SAMPLE_DEPTH]; + BSDFSampleOffsets bsdfSampleOffsets[SAMPLE_DEPTH]; + BSDFSampleOffsets pathSampleOffsets[SAMPLE_DEPTH]; +}; + + +PathIntegrator *CreatePathSurfaceIntegrator(const ParamSet ¶ms); + +#endif // PBRT_INTEGRATORS_PATH_H diff --git a/integrators/photonmap.cpp b/integrators/photonmap.cpp new file mode 100644 index 0000000..c8fb500 --- /dev/null +++ b/integrators/photonmap.cpp @@ -0,0 +1,795 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// integrators/photonmap.cpp* +#include "stdafx.h" +#include "integrators/photonmap.h" +#include "scene.h" +#include "montecarlo.h" +#include "sampler.h" +#include "progressreporter.h" +#include "intersection.h" +#include "paramset.h" +#include "camera.h" + + +// PhotonIntegrator Local Declarations +struct Photon { + Photon(const Point &pp, const Spectrum &wt, const Vector &w) + : p(pp), alpha(wt), wi(w) { } + Photon() { } + Point p; + Spectrum alpha; + Vector wi; +}; + + +class PhotonShootingTask : public Task { +public: + PhotonShootingTask(int tn, float ti, Mutex &m, PhotonIntegrator *in, + ProgressReporter &prog, bool &at, int &ndp, + vector &direct, vector &indir, vector &caustic, + vector &rps, vector &rpR, vector &rpT, + uint32_t &ns, Distribution1D *distrib, const Scene *sc, + const Renderer *sr) + : taskNum(tn), time(ti), mutex(m), integrator(in), progress(prog), + abortTasks(at), nDirectPaths(ndp), + directPhotons(direct), indirectPhotons(indir), causticPhotons(caustic), + radiancePhotons(rps), rpReflectances(rpR), rpTransmittances(rpT), + nshot(ns), lightDistribution(distrib), scene(sc), renderer (sr) { } + void Run(); + + int taskNum; + float time; + Mutex &mutex; + PhotonIntegrator *integrator; + ProgressReporter &progress; + bool &abortTasks; + int &nDirectPaths; + vector &directPhotons, &indirectPhotons, &causticPhotons; + vector &radiancePhotons; + vector &rpReflectances, &rpTransmittances; + uint32_t &nshot; + const Distribution1D *lightDistribution; + const Scene *scene; + const Renderer *renderer; +}; + + +struct RadiancePhoton { + RadiancePhoton(const Point &pp, const Normal &nn) + : p(pp), n(nn), Lo(0.f) { } + RadiancePhoton() { } + Point p; + Normal n; + Spectrum Lo; +}; + + +class ComputeRadianceTask : public Task { +public: + ComputeRadianceTask(ProgressReporter &prog, uint32_t tn, uint32_t nt, + vector &rps, const vector &rhor, + const vector &rhot, + uint32_t nlookup, float md2, + int ndirect, KdTree *direct, + int nindirect, KdTree *indirect, + int ncaus, KdTree *caustic) + : progress(prog), taskNum(tn), numTasks(nt), radiancePhotons(rps), + rpReflectances(rhor), rpTransmittances(rhot), nLookup(nlookup), + maxDistSquared(md2), + nDirectPaths(ndirect), nIndirectPaths(nindirect), nCausticPaths(ncaus), + directMap(direct), indirectMap(indirect), causticMap(caustic) { } + void Run(); + +private: + ProgressReporter &progress; + uint32_t taskNum, numTasks; + vector &radiancePhotons; + const vector &rpReflectances, &rpTransmittances; + uint32_t nLookup; + float maxDistSquared; + int nDirectPaths, nIndirectPaths, nCausticPaths; + KdTree *directMap, *indirectMap, *causticMap; +}; + + +struct PhotonProcess { + // PhotonProcess Public Methods + PhotonProcess(uint32_t mp, ClosePhoton *buf); + void operator()(const Point &p, const Photon &photon, float dist2, + float &maxDistSquared); + ClosePhoton *photons; + uint32_t nLookup, nFound; +}; + + +struct ClosePhoton { + // ClosePhoton Public Methods + ClosePhoton(const Photon *p = NULL, float md2 = INFINITY) + : photon(p), distanceSquared(md2) { } + bool operator<(const ClosePhoton &p2) const { + return distanceSquared == p2.distanceSquared ? + (photon < p2.photon) : (distanceSquared < p2.distanceSquared); + } + const Photon *photon; + float distanceSquared; +}; + + +PhotonProcess::PhotonProcess(uint32_t mp, ClosePhoton *buf) { + photons = buf; + nLookup = mp; + nFound = 0; +} + + +struct RadiancePhotonProcess { + // RadiancePhotonProcess Methods + RadiancePhotonProcess(const Normal &nn) + : n(nn) { + photon = NULL; + } + void operator()(const Point &p, const RadiancePhoton &rp, + float distSquared, float &maxDistSquared) { + if (Dot(rp.n, n) > 0) { + photon = &rp; + maxDistSquared = distSquared; + } + } + const Normal &n; + const RadiancePhoton *photon; +}; + + +inline float kernel(const Photon *photon, const Point &p, float maxDist2); +static Spectrum LPhoton(KdTree *map, int nPaths, int nLookup, + ClosePhoton *lookupBuf, BSDF *bsdf, RNG &rng, const Intersection &isect, + const Vector &w, float maxDistSquared); +static Spectrum EPhoton(KdTree *map, int count, int nLookup, + ClosePhoton *lookupBuf, float maxDist2, const Point &p, const Normal &n); + +// PhotonIntegrator Local Definitions +inline bool unsuccessful(uint32_t needed, uint32_t found, uint32_t shot) { + return (found < needed && (found == 0 || found < shot / 1024)); +} + + +inline void PhotonProcess::operator()(const Point &p, + const Photon &photon, float distSquared, float &maxDistSquared) { + if (nFound < nLookup) { + // Add photon to unordered array of photons + photons[nFound++] = ClosePhoton(&photon, distSquared); + if (nFound == nLookup) { + std::make_heap(&photons[0], &photons[nLookup]); + maxDistSquared = photons[0].distanceSquared; + } + } + else { + // Remove most distant photon from heap and add new photon + std::pop_heap(&photons[0], &photons[nLookup]); + photons[nLookup-1] = ClosePhoton(&photon, distSquared); + std::push_heap(&photons[0], &photons[nLookup]); + maxDistSquared = photons[0].distanceSquared; + } +} + + +inline float kernel(const Photon *photon, const Point &p, + float maxDist2) { + float s = (1.f - DistanceSquared(photon->p, p) / maxDist2); + return 3.f * INV_PI * s * s; +} + + +Spectrum LPhoton(KdTree *map, int nPaths, int nLookup, + ClosePhoton *lookupBuf, BSDF *bsdf, RNG &rng, + const Intersection &isect, const Vector &wo, float maxDist2) { + Spectrum L(0.); + BxDFType nonSpecular = BxDFType(BSDF_REFLECTION | + BSDF_TRANSMISSION | BSDF_DIFFUSE | BSDF_GLOSSY); + if (map && bsdf->NumComponents(nonSpecular) > 0) { + PBRT_PHOTON_MAP_STARTED_LOOKUP(const_cast(&isect.dg)); + // Do photon map lookup at intersection point + PhotonProcess proc(nLookup, lookupBuf); + map->Lookup(isect.dg.p, proc, maxDist2); + + // Estimate reflected radiance due to incident photons + ClosePhoton *photons = proc.photons; + int nFound = proc.nFound; + Normal Nf = Faceforward(bsdf->dgShading.nn, wo); + if (bsdf->NumComponents(BxDFType(BSDF_REFLECTION | + BSDF_TRANSMISSION | BSDF_GLOSSY)) > 0) { + // Compute exitant radiance from photons for glossy surface + for (int i = 0; i < nFound; ++i) { + const Photon *p = photons[i].photon; + float k = kernel(p, isect.dg.p, maxDist2); + L += (k / (nPaths * maxDist2)) * bsdf->f(wo, p->wi) * + p->alpha; + } + } + else { + // Compute exitant radiance from photons for diffuse surface + Spectrum Lr(0.), Lt(0.); + for (int i = 0; i < nFound; ++i) { + if (Dot(Nf, photons[i].photon->wi) > 0.f) { + float k = kernel(photons[i].photon, isect.dg.p, maxDist2); + Lr += (k / (nPaths * maxDist2)) * photons[i].photon->alpha; + } + else { + float k = kernel(photons[i].photon, isect.dg.p, maxDist2); + Lt += (k / (nPaths * maxDist2)) * photons[i].photon->alpha; + } + } + L += Lr * bsdf->rho(wo, rng, BSDF_ALL_REFLECTION) * INV_PI + + Lt * bsdf->rho(wo, rng, BSDF_ALL_TRANSMISSION) * INV_PI; + } + PBRT_PHOTON_MAP_FINISHED_LOOKUP(const_cast(&isect.dg), + proc.nFound, proc.nLookup, &L); + } + return L; +} + + +Spectrum EPhoton(KdTree *map, int count, int nLookup, + ClosePhoton *lookupBuf, float maxDist2, const Point &p, + const Normal &n) { + if (!map) return 0.f; + // Lookup nearby photons at irradiance computation point + PhotonProcess proc(nLookup, lookupBuf); + float md2 = maxDist2; + map->Lookup(p, proc, md2); + Assert(md2 > 0.f); + + // Accumulate irradiance value from nearby photons + if (proc.nFound == 0) return Spectrum(0.f); + ClosePhoton *photons = proc.photons; + Spectrum E(0.); + for (uint32_t i = 0; i < proc.nFound; ++i) + if (Dot(n, photons[i].photon->wi) > 0.) + E += photons[i].photon->alpha; + return E / (count * md2 * M_PI); +} + + + +// PhotonIntegrator Method Definitions +PhotonIntegrator::PhotonIntegrator(int ncaus, int nind, + int nl, int mdepth, int mphodepth, float mdist, bool fg, + int gs, float ga) { + nCausticPhotonsWanted = ncaus; + nIndirectPhotonsWanted = nind; + nLookup = nl; + maxSpecularDepth = mdepth; + maxPhotonDepth = mphodepth; + maxDistSquared = mdist * mdist; + finalGather = fg; + cosGatherAngle = cos(Radians(ga)); + gatherSamples = gs; + nCausticPaths = nIndirectPaths = 0; + causticMap = indirectMap = NULL; + radianceMap = NULL; + lightSampleOffsets = NULL; + bsdfSampleOffsets = NULL; +} + + +PhotonIntegrator::~PhotonIntegrator() { + delete[] lightSampleOffsets; + delete[] bsdfSampleOffsets; + delete causticMap; + delete indirectMap; + delete radianceMap; +} + + +void PhotonIntegrator::RequestSamples(Sampler *sampler, Sample *sample, + const Scene *scene) { + // Allocate and request samples for sampling all lights + uint32_t nLights = scene->lights.size(); + lightSampleOffsets = new LightSampleOffsets[nLights]; + bsdfSampleOffsets = new BSDFSampleOffsets[nLights]; + for (uint32_t i = 0; i < nLights; ++i) { + const Light *light = scene->lights[i]; + int nSamples = light->nSamples; + if (sampler) nSamples = sampler->RoundSize(nSamples); + lightSampleOffsets[i] = LightSampleOffsets(nSamples, sample); + bsdfSampleOffsets[i] = BSDFSampleOffsets(nSamples, sample); + } + + // Request samples for final gathering + if (finalGather) { + gatherSamples = max(1, gatherSamples/2); + if (sampler) gatherSamples = sampler->RoundSize(gatherSamples); + bsdfGatherSampleOffsets = BSDFSampleOffsets(gatherSamples, sample); + indirGatherSampleOffsets = BSDFSampleOffsets(gatherSamples, sample); + } +} + + +void PhotonIntegrator::Preprocess(const Scene *scene, + const Camera *camera, const Renderer *renderer) { + if (scene->lights.size() == 0) return; + // Declare shared variables for photon shooting + Mutex *mutex = Mutex::Create(); + int nDirectPaths = 0; + vector causticPhotons, directPhotons, indirectPhotons; + vector radiancePhotons; + bool abortTasks = false; + causticPhotons.reserve(nCausticPhotonsWanted); + indirectPhotons.reserve(nIndirectPhotonsWanted); + uint32_t nshot = 0; + vector rpReflectances, rpTransmittances; + + // Compute light power CDF for photon shooting + Distribution1D *lightDistribution = ComputeLightSamplingCDF(scene); + + // Run parallel tasks for photon shooting + ProgressReporter progress(nCausticPhotonsWanted+nIndirectPhotonsWanted, "Shooting photons"); + vector photonShootingTasks; + int nTasks = NumSystemCores(); + for (int i = 0; i < nTasks; ++i) + photonShootingTasks.push_back(new PhotonShootingTask( + i, camera ? camera->shutterOpen : 0.f, *mutex, this, progress, abortTasks, nDirectPaths, + directPhotons, indirectPhotons, causticPhotons, radiancePhotons, + rpReflectances, rpTransmittances, + nshot, lightDistribution, scene, renderer)); + EnqueueTasks(photonShootingTasks); + WaitForAllTasks(); + for (uint32_t i = 0; i < photonShootingTasks.size(); ++i) + delete photonShootingTasks[i]; + Mutex::Destroy(mutex); + progress.Done(); + + // Build kd-trees for indirect and caustic photons + KdTree *directMap = NULL; + if (directPhotons.size() > 0) + directMap = new KdTree(directPhotons); + if (causticPhotons.size() > 0) + causticMap = new KdTree(causticPhotons); + if (indirectPhotons.size() > 0) + indirectMap = new KdTree(indirectPhotons); + + // Precompute radiance at a subset of the photons + if (finalGather && radiancePhotons.size()) { + // Launch tasks to compute photon radiances + vector radianceTasks; + uint32_t numTasks = 64; + ProgressReporter progRadiance(numTasks, "Computing photon radiances"); + for (uint32_t i = 0; i < numTasks; ++i) + radianceTasks.push_back(new ComputeRadianceTask(progRadiance, + i, numTasks, radiancePhotons, rpReflectances, rpTransmittances, + nLookup, maxDistSquared, nDirectPaths, directMap, + nIndirectPaths, indirectMap, + nCausticPaths, causticMap)); + EnqueueTasks(radianceTasks); + WaitForAllTasks(); + for (uint32_t i = 0; i < radianceTasks.size(); ++i) + delete radianceTasks[i]; + progRadiance.Done(); + radianceMap = new KdTree(radiancePhotons); + } + delete directMap; +} + + +void PhotonShootingTask::Run() { + // Declare local variables for _PhotonShootingTask_ + MemoryArena arena; + RNG rng(31 * taskNum); + vector localDirectPhotons, localIndirectPhotons, localCausticPhotons; + vector localRadiancePhotons; + uint32_t totalPaths = 0; + bool causticDone = (integrator->nCausticPhotonsWanted == 0); + bool indirectDone = (integrator->nIndirectPhotonsWanted == 0); + PermutedHalton halton(6, rng); + vector localRpReflectances, localRpTransmittances; + while (true) { + // Follow photon paths for a block of samples + const uint32_t blockSize = 4096; + for (uint32_t i = 0; i < blockSize; ++i) { + float u[6]; + halton.Sample(++totalPaths, u); + // Choose light to shoot photon from + float lightPdf; + int lightNum = lightDistribution->SampleDiscrete(u[0], &lightPdf); + const Light *light = scene->lights[lightNum]; + + // Generate _photonRay_ from light source and initialize _alpha_ + RayDifferential photonRay; + float pdf; + LightSample ls(u[1], u[2], u[3]); + Normal Nl; + Spectrum Le = light->Sample_L(scene, ls, u[4], u[5], + time, &photonRay, &Nl, &pdf); + if (pdf == 0.f || Le.IsBlack()) continue; + Spectrum alpha = (AbsDot(Nl, photonRay.d) * Le) / (pdf * lightPdf); + if (!alpha.IsBlack()) { + // Follow photon path through scene and record intersections + PBRT_PHOTON_MAP_STARTED_RAY_PATH(&photonRay, &alpha); + bool specularPath = true; + Intersection photonIsect; + int nIntersections = 0; + while (scene->Intersect(photonRay, &photonIsect)) { + ++nIntersections; + // Handle photon/surface intersection + alpha *= renderer->Transmittance(scene, photonRay, NULL, rng, arena); + BSDF *photonBSDF = photonIsect.GetBSDF(photonRay, arena); + BxDFType specularType = BxDFType(BSDF_REFLECTION | + BSDF_TRANSMISSION | BSDF_SPECULAR); + bool hasNonSpecular = (photonBSDF->NumComponents() > + photonBSDF->NumComponents(specularType)); + Vector wo = -photonRay.d; + if (hasNonSpecular) { + // Deposit photon at surface + Photon photon(photonIsect.dg.p, alpha, wo); + bool depositedPhoton = false; + if (specularPath && nIntersections > 1) { + if (!causticDone) { + PBRT_PHOTON_MAP_DEPOSITED_CAUSTIC_PHOTON(&photonIsect.dg, &alpha, &wo); + depositedPhoton = true; + localCausticPhotons.push_back(photon); + } + } + else { + // Deposit either direct or indirect photon + // stop depositing direct photons once indirectDone is true; don't + // want to waste memory storing too many if we're going a long time + // trying to get enough caustic photons desposited. + if (nIntersections == 1 && !indirectDone && integrator->finalGather) { + PBRT_PHOTON_MAP_DEPOSITED_DIRECT_PHOTON(&photonIsect.dg, &alpha, &wo); + depositedPhoton = true; + localDirectPhotons.push_back(photon); + } + else if (nIntersections > 1 && !indirectDone) { + PBRT_PHOTON_MAP_DEPOSITED_INDIRECT_PHOTON(&photonIsect.dg, &alpha, &wo); + depositedPhoton = true; + localIndirectPhotons.push_back(photon); + } + } + + // Possibly create radiance photon at photon intersection point + if (depositedPhoton && integrator->finalGather && + rng.RandomFloat() < .125f) { + Normal n = photonIsect.dg.nn; + n = Faceforward(n, -photonRay.d); + localRadiancePhotons.push_back(RadiancePhoton(photonIsect.dg.p, n)); + Spectrum rho_r = photonBSDF->rho(rng, BSDF_ALL_REFLECTION); + localRpReflectances.push_back(rho_r); + Spectrum rho_t = photonBSDF->rho(rng, BSDF_ALL_TRANSMISSION); + localRpTransmittances.push_back(rho_t); + } + } + if (nIntersections >= integrator->maxPhotonDepth) break; + + // Sample new photon ray direction + Vector wi; + float pdf; + BxDFType flags; + Spectrum fr = photonBSDF->Sample_f(wo, &wi, BSDFSample(rng), + &pdf, BSDF_ALL, &flags); + if (fr.IsBlack() || pdf == 0.f) break; + Spectrum anew = alpha * fr * + AbsDot(wi, photonBSDF->dgShading.nn) / pdf; + + // Possibly terminate photon path with Russian roulette + float continueProb = min(1.f, anew.y() / alpha.y()); + if (rng.RandomFloat() > continueProb) + break; + alpha = anew / continueProb; + specularPath &= ((flags & BSDF_SPECULAR) != 0); + + if (indirectDone && !specularPath) break; + photonRay = RayDifferential(photonIsect.dg.p, wi, photonRay, + photonIsect.rayEpsilon); + } + PBRT_PHOTON_MAP_FINISHED_RAY_PATH(&photonRay, &alpha); + } + arena.FreeAll(); + } + + // Merge local photon data with data in _PhotonIntegrator_ + { MutexLock lock(mutex); + + // Give up if we're not storing enough photons + if (abortTasks) + return; + if (nshot > 500000 && + (unsuccessful(integrator->nCausticPhotonsWanted, + causticPhotons.size(), blockSize) || + unsuccessful(integrator->nIndirectPhotonsWanted, + indirectPhotons.size(), blockSize))) { + Error("Unable to store enough photons. Giving up.\n"); + causticPhotons.erase(causticPhotons.begin(), causticPhotons.end()); + indirectPhotons.erase(indirectPhotons.begin(), indirectPhotons.end()); + radiancePhotons.erase(radiancePhotons.begin(), radiancePhotons.end()); + abortTasks = true; + return; + } + progress.Update(localIndirectPhotons.size() + localCausticPhotons.size()); + nshot += blockSize; + + // Merge indirect photons into shared array + if (!indirectDone) { + integrator->nIndirectPaths += blockSize; + for (uint32_t i = 0; i < localIndirectPhotons.size(); ++i) + indirectPhotons.push_back(localIndirectPhotons[i]); + localIndirectPhotons.erase(localIndirectPhotons.begin(), + localIndirectPhotons.end()); + if (indirectPhotons.size() >= integrator->nIndirectPhotonsWanted) + indirectDone = true; + nDirectPaths += blockSize; + for (uint32_t i = 0; i < localDirectPhotons.size(); ++i) + directPhotons.push_back(localDirectPhotons[i]); + localDirectPhotons.erase(localDirectPhotons.begin(), + localDirectPhotons.end()); + } + + // Merge direct, caustic, and radiance photons into shared array + if (!causticDone) { + integrator->nCausticPaths += blockSize; + for (uint32_t i = 0; i < localCausticPhotons.size(); ++i) + causticPhotons.push_back(localCausticPhotons[i]); + localCausticPhotons.erase(localCausticPhotons.begin(), localCausticPhotons.end()); + if (causticPhotons.size() >= integrator->nCausticPhotonsWanted) + causticDone = true; + } + + for (uint32_t i = 0; i < localRadiancePhotons.size(); ++i) + radiancePhotons.push_back(localRadiancePhotons[i]); + localRadiancePhotons.erase(localRadiancePhotons.begin(), localRadiancePhotons.end()); + for (uint32_t i = 0; i < localRpReflectances.size(); ++i) + rpReflectances.push_back(localRpReflectances[i]); + localRpReflectances.erase(localRpReflectances.begin(), localRpReflectances.end()); + for (uint32_t i = 0; i < localRpTransmittances.size(); ++i) + rpTransmittances.push_back(localRpTransmittances[i]); + localRpTransmittances.erase(localRpTransmittances.begin(), localRpTransmittances.end()); + } + + // Exit task if enough photons have been found + if (indirectDone && causticDone) + break; + } +} + + +void ComputeRadianceTask::Run() { + // Compute range of radiance photons to process in task + uint32_t taskSize = radiancePhotons.size() / numTasks; + uint32_t excess = radiancePhotons.size() % numTasks; + uint32_t rpStart = min(taskNum, excess) * (taskSize+1) + + max(0, (int)taskNum-(int)excess) * taskSize; + uint32_t rpEnd = rpStart + taskSize + (taskNum < excess ? 1 : 0); + if (taskNum == numTasks-1) Assert(rpEnd == radiancePhotons.size()); + ClosePhoton *lookupBuf = new ClosePhoton[nLookup]; + for (uint32_t i = rpStart; i < rpEnd; ++i) { + // Compute radiance for radiance photon _i_ + RadiancePhoton &rp = radiancePhotons[i]; + const Spectrum &rho_r = rpReflectances[i], &rho_t = rpTransmittances[i]; + if (!rho_r.IsBlack()) { + // Accumulate outgoing radiance due to reflected irradiance + Spectrum E = EPhoton(directMap, nDirectPaths, nLookup, lookupBuf, + maxDistSquared, rp.p, rp.n) + + EPhoton(indirectMap, nIndirectPaths, nLookup, lookupBuf, + maxDistSquared, rp.p, rp.n) + + EPhoton(causticMap, nCausticPaths, nLookup, lookupBuf, + maxDistSquared, rp.p, rp.n); + rp.Lo += INV_PI * rho_r * E; + } + if (!rho_t.IsBlack()) { + // Accumulate outgoing radiance due to transmitted irradiance + Spectrum E = EPhoton(directMap, nDirectPaths, nLookup, lookupBuf, + maxDistSquared, rp.p, -rp.n) + + EPhoton(indirectMap, nIndirectPaths, nLookup, lookupBuf, + maxDistSquared, rp.p, -rp.n) + + EPhoton(causticMap, nCausticPaths, nLookup, lookupBuf, + maxDistSquared, rp.p, -rp.n); + rp.Lo += INV_PI * rho_t * E; + } + } + delete[] lookupBuf; + progress.Update(); +} + + +Spectrum PhotonIntegrator::Li(const Scene *scene, const Renderer *renderer, + const RayDifferential &ray, const Intersection &isect, + const Sample *sample, RNG &rng, MemoryArena &arena) const { + Spectrum L(0.); + Vector wo = -ray.d; + // Compute emitted light if ray hit an area light source + L += isect.Le(wo); + + // Evaluate BSDF at hit point + BSDF *bsdf = isect.GetBSDF(ray, arena); + const Point &p = bsdf->dgShading.p; + const Normal &n = bsdf->dgShading.nn; + L += UniformSampleAllLights(scene, renderer, arena, p, n, + wo, isect.rayEpsilon, ray.time, bsdf, sample, rng, + lightSampleOffsets, bsdfSampleOffsets); + // Compute caustic lighting for photon map integrator + ClosePhoton *lookupBuf = arena.Alloc(nLookup); + L += LPhoton(causticMap, nCausticPaths, nLookup, lookupBuf, bsdf, + rng, isect, wo, maxDistSquared); + + // Compute indirect lighting for photon map integrator + if (finalGather && indirectMap != NULL) { + #if 1 + // Do one-bounce final gather for photon map + BxDFType nonSpecular = BxDFType(BSDF_REFLECTION | + BSDF_TRANSMISSION | BSDF_DIFFUSE | BSDF_GLOSSY); + if (bsdf->NumComponents(nonSpecular) > 0) { + // Find indirect photons around point for importance sampling + const uint32_t nIndirSamplePhotons = 50; + PhotonProcess proc(nIndirSamplePhotons, + arena.Alloc(nIndirSamplePhotons)); + float searchDist2 = maxDistSquared; + while (proc.nFound < nIndirSamplePhotons) { + float md2 = searchDist2; + proc.nFound = 0; + indirectMap->Lookup(p, proc, md2); + searchDist2 *= 2.f; + } + + // Copy photon directions to local array + Vector *photonDirs = arena.Alloc(nIndirSamplePhotons); + for (uint32_t i = 0; i < nIndirSamplePhotons; ++i) + photonDirs[i] = proc.photons[i].photon->wi; + + // Use BSDF to do final gathering + Spectrum Li = 0.; + for (int i = 0; i < gatherSamples; ++i) { + // Sample random direction from BSDF for final gather ray + Vector wi; + float pdf; + BSDFSample bsdfSample(sample, bsdfGatherSampleOffsets, i); + Spectrum fr = bsdf->Sample_f(wo, &wi, bsdfSample, + &pdf, BxDFType(BSDF_ALL & ~BSDF_SPECULAR)); + if (fr.IsBlack() || pdf == 0.f) continue; + Assert(pdf >= 0.f); + + // Trace BSDF final gather ray and accumulate radiance + RayDifferential bounceRay(p, wi, ray, isect.rayEpsilon); + Intersection gatherIsect; + if (scene->Intersect(bounceRay, &gatherIsect)) { + // Compute exitant radiance _Lindir_ using radiance photons + Spectrum Lindir = 0.f; + Normal nGather = gatherIsect.dg.nn; + nGather = Faceforward(nGather, -bounceRay.d); + RadiancePhotonProcess proc(nGather); + float md2 = INFINITY; + radianceMap->Lookup(gatherIsect.dg.p, proc, md2); + if (proc.photon != NULL) + Lindir = proc.photon->Lo; + Lindir *= renderer->Transmittance(scene, bounceRay, NULL, rng, arena); + + // Compute MIS weight for BSDF-sampled gather ray + + // Compute PDF for photon-sampling of direction _wi_ + float photonPdf = 0.f; + float conePdf = UniformConePdf(cosGatherAngle); + for (uint32_t j = 0; j < nIndirSamplePhotons; ++j) + if (Dot(photonDirs[j], wi) > .999f * cosGatherAngle) + photonPdf += conePdf; + photonPdf /= nIndirSamplePhotons; + float wt = PowerHeuristic(gatherSamples, pdf, gatherSamples, photonPdf); + Li += fr * Lindir * (AbsDot(wi, n) * wt / pdf); + } + } + L += Li / gatherSamples; + + // Use nearby photons to do final gathering + Li = 0.; + for (int i = 0; i < gatherSamples; ++i) { + // Sample random direction using photons for final gather ray + BSDFSample gatherSample(sample, indirGatherSampleOffsets, i); + int photonNum = min((int)nIndirSamplePhotons - 1, + Floor2Int(gatherSample.uComponent * nIndirSamplePhotons)); + + // Sample gather ray direction from _photonNum_ + Vector vx, vy; + CoordinateSystem(photonDirs[photonNum], &vx, &vy); + Vector wi = UniformSampleCone(gatherSample.uDir[0], gatherSample.uDir[1], + cosGatherAngle, vx, vy, photonDirs[photonNum]); + + // Trace photon-sampled final gather ray and accumulate radiance + Spectrum fr = bsdf->f(wo, wi); + if (fr.IsBlack()) continue; + RayDifferential bounceRay(p, wi, ray, isect.rayEpsilon); + Intersection gatherIsect; + PBRT_PHOTON_MAP_STARTED_GATHER_RAY(&bounceRay); + if (scene->Intersect(bounceRay, &gatherIsect)) { + // Compute exitant radiance _Lindir_ using radiance photons + Spectrum Lindir = 0.f; + Normal nGather = gatherIsect.dg.nn; + nGather = Faceforward(nGather, -bounceRay.d); + RadiancePhotonProcess proc(nGather); + float md2 = INFINITY; + radianceMap->Lookup(gatherIsect.dg.p, proc, md2); + if (proc.photon != NULL) + Lindir = proc.photon->Lo; + Lindir *= renderer->Transmittance(scene, bounceRay, NULL, rng, arena); + + // Compute PDF for photon-sampling of direction _wi_ + float photonPdf = 0.f; + float conePdf = UniformConePdf(cosGatherAngle); + for (uint32_t j = 0; j < nIndirSamplePhotons; ++j) + if (Dot(photonDirs[j], wi) > .999f * cosGatherAngle) + photonPdf += conePdf; + photonPdf /= nIndirSamplePhotons; + + // Compute MIS weight for photon-sampled gather ray + float bsdfPdf = bsdf->Pdf(wo, wi); + float wt = PowerHeuristic(gatherSamples, photonPdf, gatherSamples, bsdfPdf); + Li += fr * Lindir * AbsDot(wi, n) * wt / photonPdf; + } + PBRT_PHOTON_MAP_FINISHED_GATHER_RAY(&bounceRay); + } + L += Li / gatherSamples; + } + #else + // for debugging / examples: use the photon map directly + Normal nn = Faceforward(n, -ray.d); + RadiancePhotonProcess proc(nn); + float md2 = INFINITY; + radianceMap->Lookup(p, proc, md2); + if (proc.photon) + L += proc.photon->Lo; + #endif + } + else + L += LPhoton(indirectMap, nIndirectPaths, nLookup, lookupBuf, + bsdf, rng, isect, wo, maxDistSquared); + if (ray.depth+1 < maxSpecularDepth) { + Vector wi; + // Trace rays for specular reflection and refraction + L += SpecularReflect(ray, bsdf, rng, isect, renderer, scene, sample, + arena); + L += SpecularTransmit(ray, bsdf, rng, isect, renderer, scene, sample, + arena); + } + return L; +} + + +PhotonIntegrator *CreatePhotonMapSurfaceIntegrator(const ParamSet ¶ms) { + int nCaustic = params.FindOneInt("causticphotons", 20000); + int nIndirect = params.FindOneInt("indirectphotons", 100000); + int nUsed = params.FindOneInt("nused", 50); + if (PbrtOptions.quickRender) nCaustic = nCaustic / 10; + if (PbrtOptions.quickRender) nIndirect = nIndirect / 10; + if (PbrtOptions.quickRender) nUsed = max(1, nUsed / 10); + int maxSpecularDepth = params.FindOneInt("maxspeculardepth", 5); + int maxPhotonDepth = params.FindOneInt("maxphotondepth", 5); + bool finalGather = params.FindOneBool("finalgather", true); + int gatherSamples = params.FindOneInt("finalgathersamples", 32); + if (PbrtOptions.quickRender) gatherSamples = max(1, gatherSamples / 4); + float maxDist = params.FindOneFloat("maxdist", .1f); + float gatherAngle = params.FindOneFloat("gatherangle", 10.f); + return new PhotonIntegrator(nCaustic, nIndirect, + nUsed, maxSpecularDepth, maxPhotonDepth, maxDist, finalGather, gatherSamples, + gatherAngle); +} + + diff --git a/integrators/photonmap.h b/integrators/photonmap.h new file mode 100644 index 0000000..887baae --- /dev/null +++ b/integrators/photonmap.h @@ -0,0 +1,81 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_INTEGRATORS_PHOTONMAP_H +#define PBRT_INTEGRATORS_PHOTONMAP_H + +// integrators/photonmap.h* +#include "pbrt.h" +#include "integrator.h" +#include "kdtree.h" + +struct Photon; +struct RadiancePhoton; +struct ClosePhoton; +struct PhotonProcess; +struct RadiancePhotonProcess; + + +// PhotonIntegrator Declarations +class PhotonIntegrator : public SurfaceIntegrator { +public: + // PhotonIntegrator Public Methods + PhotonIntegrator(int ncaus, int nindir, int nLookup, int maxspecdepth, + int maxphotondepth, float maxdist, bool finalGather, int gatherSamples, + float ga); + ~PhotonIntegrator(); + Spectrum Li(const Scene *scene, const Renderer *renderer, + const RayDifferential &ray, const Intersection &isect, const Sample *sample, + RNG &rng, MemoryArena &arena) const; + void RequestSamples(Sampler *sampler, Sample *sample, const Scene *scene); + void Preprocess(const Scene *scene, const Camera *camera, const Renderer *renderer); +private: + // PhotonIntegrator Private Methods + friend class PhotonShootingTask; + + // PhotonIntegrator Private Data + uint32_t nCausticPhotonsWanted, nIndirectPhotonsWanted, nLookup; + float maxDistSquared; + int maxSpecularDepth, maxPhotonDepth; + bool finalGather; + int gatherSamples; + float cosGatherAngle; + + // Declare sample parameters for light source sampling + LightSampleOffsets *lightSampleOffsets; + BSDFSampleOffsets *bsdfSampleOffsets; + BSDFSampleOffsets bsdfGatherSampleOffsets, indirGatherSampleOffsets; + int nCausticPaths, nIndirectPaths; + KdTree *causticMap; + KdTree *indirectMap; + KdTree *radianceMap; +}; + + +PhotonIntegrator *CreatePhotonMapSurfaceIntegrator(const ParamSet ¶ms); + +#endif // PBRT_INTEGRATORS_PHOTONMAP_H diff --git a/integrators/single.cpp b/integrators/single.cpp new file mode 100644 index 0000000..d39c934 --- /dev/null +++ b/integrators/single.cpp @@ -0,0 +1,136 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// integrators/single.cpp* +#include "stdafx.h" +#include "integrators/single.h" +#include "scene.h" +#include "paramset.h" +#include "montecarlo.h" + +// SingleScatteringIntegrator Method Definitions +void SingleScatteringIntegrator::RequestSamples(Sampler *sampler, Sample *sample, + const Scene *scene) { + tauSampleOffset = sample->Add1D(1); + scatterSampleOffset = sample->Add1D(1); +} + + +Spectrum SingleScatteringIntegrator::Transmittance(const Scene *scene, + const Renderer *renderer, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena) const { + if (!scene->volumeRegion) return Spectrum(1.f); + float step, offset; + if (sample) { + step = stepSize; + offset = sample->oneD[tauSampleOffset][0]; + } + else { + step = 4.f * stepSize; + offset = rng.RandomFloat(); + } + Spectrum tau = scene->volumeRegion->tau(ray, step, offset); + return Exp(-tau); +} + + +Spectrum SingleScatteringIntegrator::Li(const Scene *scene, const Renderer *renderer, + const RayDifferential &ray, const Sample *sample, RNG &rng, + Spectrum *T, MemoryArena &arena) const { + VolumeRegion *vr = scene->volumeRegion; + float t0, t1; + if (!vr || !vr->IntersectP(ray, &t0, &t1) || (t1-t0) == 0.f) { + *T = 1.f; + return 0.f; + } + // Do single scattering volume integration in _vr_ + Spectrum Lv(0.); + + // Prepare for volume integration stepping + int nSamples = Ceil2Int((t1-t0) / stepSize); + float step = (t1 - t0) / nSamples; + Spectrum Tr(1.f); + Point p = ray(t0), pPrev; + Vector w = -ray.d; + t0 += sample->oneD[scatterSampleOffset][0] * step; + + // Compute sample patterns for single scattering samples + float *lightNum = arena.Alloc(nSamples); + LDShuffleScrambled1D(1, nSamples, lightNum, rng); + float *lightComp = arena.Alloc(nSamples); + LDShuffleScrambled1D(1, nSamples, lightComp, rng); + float *lightPos = arena.Alloc(2*nSamples); + LDShuffleScrambled2D(1, nSamples, lightPos, rng); + uint32_t sampOffset = 0; + for (int i = 0; i < nSamples; ++i, t0 += step) { + // Advance to sample at _t0_ and update _T_ + pPrev = p; + p = ray(t0); + Ray tauRay(pPrev, p - pPrev, 0.f, 1.f, ray.time, ray.depth); + Spectrum stepTau = vr->tau(tauRay, + .5f * stepSize, rng.RandomFloat()); + Tr *= Exp(-stepTau); + + // Possibly terminate ray marching if transmittance is small + if (Tr.y() < 1e-3) { + const float continueProb = .5f; + if (rng.RandomFloat() > continueProb) break; + Tr /= continueProb; + } + + // Compute single-scattering source term at _p_ + Lv += Tr * vr->Lve(p, w, ray.time); + Spectrum ss = vr->sigma_s(p, w, ray.time); + if (!ss.IsBlack() && scene->lights.size() > 0) { + int nLights = scene->lights.size(); + int ln = min(Floor2Int(lightNum[sampOffset] * nLights), + nLights-1); + Light *light = scene->lights[ln]; + // Add contribution of _light_ due to scattering at _p_ + float pdf; + VisibilityTester vis; + Vector wo; + LightSample ls(lightComp[sampOffset], lightPos[2*sampOffset], + lightPos[2*sampOffset+1]); + Spectrum L = light->Sample_L(p, 0.f, ls, ray.time, &wo, &pdf, &vis); + + if (!L.IsBlack() && pdf > 0.f && vis.Unoccluded(scene)) { + Spectrum Ld = L * vis.Transmittance(scene, renderer, NULL, rng, arena); + Lv += Tr * ss * vr->p(p, w, -wo, ray.time) * Ld * float(nLights) / + pdf; + } + } + ++sampOffset; + } + *T = Tr; + return Lv * step; +} + + +SingleScatteringIntegrator *CreateSingleScatteringIntegrator(const ParamSet ¶ms) { + float stepSize = params.FindOneFloat("stepsize", 1.f); + return new SingleScatteringIntegrator(stepSize); +} + + diff --git a/integrators/single.h b/integrators/single.h new file mode 100644 index 0000000..2abe639 --- /dev/null +++ b/integrators/single.h @@ -0,0 +1,56 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_INTEGRATORS_SINGLE_H +#define PBRT_INTEGRATORS_SINGLE_H + +// integrators/single.h* +#include "volume.h" +#include "integrator.h" + +// SingleScatteringIntegrator Declarations +class SingleScatteringIntegrator : public VolumeIntegrator { +public: + // SingleScatteringIntegrator Public Methods + SingleScatteringIntegrator(float ss) { stepSize = ss; } + Spectrum Transmittance(const Scene *, const Renderer *, + const RayDifferential &ray, const Sample *sample, RNG &rng, + MemoryArena &arena) const; + void RequestSamples(Sampler *sampler, Sample *sample, + const Scene *scene); + Spectrum Li(const Scene *, const Renderer *, const RayDifferential &ray, + const Sample *sample, RNG &rng, Spectrum *T, MemoryArena &arena) const; +private: + // SingleScatteringIntegrator Private Data + float stepSize; + int tauSampleOffset, scatterSampleOffset; +}; + + +SingleScatteringIntegrator *CreateSingleScatteringIntegrator(const ParamSet ¶ms); + +#endif // PBRT_INTEGRATORS_SINGLE_H diff --git a/integrators/useprobes.cpp b/integrators/useprobes.cpp new file mode 100644 index 0000000..001f00d --- /dev/null +++ b/integrators/useprobes.cpp @@ -0,0 +1,163 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// integrators/useprobes.cpp* +#include "stdafx.h" +#include "integrators/useprobes.h" +#include "integrators/photonmap.h" +#include "integrators/directlighting.h" +#include "integrators/emission.h" +#include "parallel.h" +#include "scene.h" +#include "progressreporter.h" +#include "camera.h" +#include "intersection.h" +#include "paramset.h" +#include "montecarlo.h" + +// UseRadianceProbes Method Definitions +UseRadianceProbes *CreateRadianceProbesSurfaceIntegrator(const ParamSet ¶mSet) { + string filename = paramSet.FindOneFilename("filename", "probes.out"); + return new UseRadianceProbes(filename); +} + + +UseRadianceProbes::UseRadianceProbes(const string &filename) { + lightSampleOffsets = NULL; + bsdfSampleOffsets = NULL; + // Read precomputed radiance probe values from file + FILE *f = fopen(filename.c_str(), "r"); + if (f) { + if (fscanf(f, "%d %d %d", &lmax, &includeDirectInProbes, + &includeIndirectInProbes) != 3 || + fscanf(f, "%d %d %d", &nProbes[0], &nProbes[1], &nProbes[2]) != 3 || + fscanf(f, "%f %f %f %f %f %f", &bbox.pMin.x, &bbox.pMin.y, &bbox.pMin.z, + &bbox.pMax.x, &bbox.pMax.y, &bbox.pMax.z) != 6) + Severe("Error reading data from radiance probe file \"%s\"", filename.c_str()); + + c_in = new Spectrum[SHTerms(lmax) * nProbes[0] * nProbes[1] * nProbes[2]]; + int offset = 0; + for (int i = 0; i < nProbes[0] * nProbes[1] * nProbes[2]; ++i) { + for (int j = 0; j < SHTerms(lmax); ++j) + if (!c_in[offset++].Read(f)) + Severe("Error reading data from radiance probe file \"%s\"", + filename.c_str()); + } + fclose(f); + } + else + Error("Unable to read saved radiance volume values from file \"%s\"", + filename.c_str()); +} + + +UseRadianceProbes::~UseRadianceProbes() { + delete[] lightSampleOffsets; + delete[] bsdfSampleOffsets; + delete[] c_in; +} + + +void UseRadianceProbes::RequestSamples(Sampler *sampler, Sample *sample, const Scene *scene) { + // Allocate and request samples for sampling all lights + uint32_t nLights = scene->lights.size(); + lightSampleOffsets = new LightSampleOffsets[nLights]; + bsdfSampleOffsets = new BSDFSampleOffsets[nLights]; + for (uint32_t i = 0; i < nLights; ++i) { + const Light *light = scene->lights[i]; + int nSamples = light->nSamples; + if (sampler) nSamples = sampler->RoundSize(nSamples); + lightSampleOffsets[i] = LightSampleOffsets(nSamples, sample); + bsdfSampleOffsets[i] = BSDFSampleOffsets(nSamples, sample); + } +} + + +Spectrum UseRadianceProbes::Li(const Scene *scene, const Renderer *renderer, + const RayDifferential &ray, const Intersection &isect, + const Sample *sample, RNG &rng, MemoryArena &arena) const { + Spectrum L(0.); + Vector wo = -ray.d; + // Compute emitted light if ray hit an area light source + L += isect.Le(wo); + + // Evaluate BSDF at hit point + BSDF *bsdf = isect.GetBSDF(ray, arena); + const Point &p = bsdf->dgShading.p; + const Normal &n = bsdf->dgShading.nn; + // Compute reflection for radiance probes integrator + if (!includeDirectInProbes) + L += UniformSampleAllLights(scene, renderer, arena, p, n, + wo, isect.rayEpsilon, ray.time, bsdf, sample, rng, + lightSampleOffsets, bsdfSampleOffsets); + + // Compute reflected lighting using radiance probes + + // Compute probe coordinates and offsets for lookup point + Vector offset = bbox.Offset(p); + float voxx = (offset.x * nProbes[0]) - 0.5f; + float voxy = (offset.y * nProbes[1]) - 0.5f; + float voxz = (offset.z * nProbes[2]) - 0.5f; + int vx = Floor2Int(voxx), vy = Floor2Int(voxy), vz = Floor2Int(voxz); + float dx = voxx - vx, dy = voxy - vy, dz = voxz - vz; + + // Get radiance probe coefficients around lookup point + const Spectrum *b000 = c_inXYZ(lmax, vx, vy, vz); + const Spectrum *b100 = c_inXYZ(lmax, vx+1, vy, vz); + const Spectrum *b010 = c_inXYZ(lmax, vx, vy+1, vz); + const Spectrum *b110 = c_inXYZ(lmax, vx+1, vy+1, vz); + const Spectrum *b001 = c_inXYZ(lmax, vx, vy, vz+1); + const Spectrum *b101 = c_inXYZ(lmax, vx+1, vy, vz+1); + const Spectrum *b011 = c_inXYZ(lmax, vx, vy+1, vz+1); + const Spectrum *b111 = c_inXYZ(lmax, vx+1, vy+1, vz+1); + + // Compute incident radiance from radiance probe coefficients + Spectrum *c_inp = arena.Alloc(SHTerms(lmax)); + for (int i = 0; i < SHTerms(lmax); ++i) { + // Do trilinear interpolation to compute SH coefficients at point + Spectrum c00 = Lerp(dx, b000[i], b100[i]); + Spectrum c10 = Lerp(dx, b010[i], b110[i]); + Spectrum c01 = Lerp(dx, b001[i], b101[i]); + Spectrum c11 = Lerp(dx, b011[i], b111[i]); + Spectrum c0 = Lerp(dy, c00, c10); + Spectrum c1 = Lerp(dy, c01, c11); + c_inp[i] = Lerp(dz, c0, c1); + } + + // Convolve incident radiance to compute irradiance function + Spectrum *c_E = arena.Alloc(SHTerms(lmax)); + SHConvolveCosTheta(lmax, c_inp, c_E); + + // Evaluate irradiance function and accumulate reflection + Spectrum rho = bsdf->rho(wo, rng, BSDF_ALL_REFLECTION); + float *Ylm = ALLOCA(float, SHTerms(lmax)); + SHEvaluate(Vector(Faceforward(n, wo)), lmax, Ylm); + Spectrum E = 0.f; + for (int i = 0; i < SHTerms(lmax); ++i) + E += c_E[i] * Ylm[i]; + L += rho * INV_PI * E.Clamp(); + return L; +} + + diff --git a/integrators/useprobes.h b/integrators/useprobes.h new file mode 100644 index 0000000..e0bcb30 --- /dev/null +++ b/integrators/useprobes.h @@ -0,0 +1,70 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_INTEGRATORS_USEPROBES_H +#define PBRT_INTEGRATORS_USEPROBES_H + +// integrators/useprobes.h* +#include "pbrt.h" +#include "integrator.h" +#include "sh.h" + +// UseRadianceProbes Declarations +class UseRadianceProbes : public SurfaceIntegrator { +public: + // UseRadianceProbes Public Methods + UseRadianceProbes(const string &filename); + ~UseRadianceProbes(); + void RequestSamples(Sampler *sampler, Sample *sample, const Scene *scene); + Spectrum Li(const Scene *scene, const Renderer *, + const RayDifferential &ray, const Intersection &isect, + const Sample *sample, RNG &rng, MemoryArena &arena) const; +private: + // UseRadianceProbes Private Methods + const Spectrum *c_inXYZ(int lmax, int vx, int vy, int vz) const { + vx = Clamp(vx, 0, nProbes[0]-1); + vy = Clamp(vy, 0, nProbes[1]-1); + vz = Clamp(vz, 0, nProbes[2]-1); + int offset = vx + vy * nProbes[0] + vz * nProbes[0] * nProbes[1]; + return &c_in[SHTerms(lmax) * offset]; + } + + // UseRadianceProbes Private Data + BBox bbox; + int lmax, includeDirectInProbes, includeIndirectInProbes; + int nProbes[3]; + Spectrum *c_in; + + // Declare sample parameters for light source sampling + LightSampleOffsets *lightSampleOffsets; + BSDFSampleOffsets *bsdfSampleOffsets; +}; + + +extern UseRadianceProbes *CreateRadianceProbesSurfaceIntegrator(const ParamSet ¶mSet); + +#endif // PBRT_INTEGRATORS_USEPROBES_H diff --git a/integrators/whitted.cpp b/integrators/whitted.cpp new file mode 100644 index 0000000..ab37831 --- /dev/null +++ b/integrators/whitted.cpp @@ -0,0 +1,81 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// integrators/whitted.cpp* +#include "stdafx.h" +#include "integrators/whitted.h" +#include "intersection.h" +#include "paramset.h" + +// WhittedIntegrator Method Definitions +Spectrum WhittedIntegrator::Li(const Scene *scene, + const Renderer *renderer, const RayDifferential &ray, + const Intersection &isect, const Sample *sample, RNG &rng, + MemoryArena &arena) const { + Spectrum L(0.); + // Compute emitted and reflected light at ray intersection point + + // Evaluate BSDF at hit point + BSDF *bsdf = isect.GetBSDF(ray, arena); + + // Initialize common variables for Whitted integrator + const Point &p = bsdf->dgShading.p; + const Normal &n = bsdf->dgShading.nn; + Vector wo = -ray.d; + + // Compute emitted light if ray hit an area light source + L += isect.Le(wo); + + // Add contribution of each light source + for (uint32_t i = 0; i < scene->lights.size(); ++i) { + Vector wi; + float pdf; + VisibilityTester visibility; + Spectrum Li = scene->lights[i]->Sample_L(p, isect.rayEpsilon, + LightSample(rng), ray.time, &wi, &pdf, &visibility); + if (Li.IsBlack() || pdf == 0.f) continue; + Spectrum f = bsdf->f(wo, wi); + if (!f.IsBlack() && visibility.Unoccluded(scene)) + L += f * Li * AbsDot(wi, n) * + visibility.Transmittance(scene, renderer, + sample, rng, arena) / pdf; + } + if (ray.depth + 1 < maxDepth) { + // Trace rays for specular reflection and refraction + L += SpecularReflect(ray, bsdf, rng, isect, renderer, scene, sample, + arena); + L += SpecularTransmit(ray, bsdf, rng, isect, renderer, scene, sample, + arena); + } + return L; +} + + +WhittedIntegrator *CreateWhittedSurfaceIntegrator(const ParamSet ¶ms) +{ + int maxDepth = params.FindOneInt("maxdepth", 5); + return new WhittedIntegrator(maxDepth); +} + + diff --git a/integrators/whitted.h b/integrators/whitted.h new file mode 100644 index 0000000..3fed8d1 --- /dev/null +++ b/integrators/whitted.h @@ -0,0 +1,54 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_INTEGRATORS_WHITTED_H +#define PBRT_INTEGRATORS_WHITTED_H + +// integrators/whitted.h* +#include "pbrt.h" +#include "integrator.h" +#include "scene.h" + +// WhittedIntegrator Declarations +class WhittedIntegrator : public SurfaceIntegrator { +public: + // WhittedIntegrator Public Methods + Spectrum Li(const Scene *scene, const Renderer *renderer, + const RayDifferential &ray, const Intersection &isect, const Sample *sample, + RNG &rng, MemoryArena &arena) const; + WhittedIntegrator(int md) { + maxDepth = md; + } +private: + // WhittedIntegrator Private Data + int maxDepth; +}; + + +WhittedIntegrator *CreateWhittedSurfaceIntegrator(const ParamSet ¶ms); + +#endif // PBRT_INTEGRATORS_WHITTED_H diff --git a/lights/diffuse.cpp b/lights/diffuse.cpp new file mode 100644 index 0000000..dc9ec22 --- /dev/null +++ b/lights/diffuse.cpp @@ -0,0 +1,95 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// lights/diffuse.cpp* +#include "stdafx.h" +#include "lights/diffuse.h" +#include "paramset.h" +#include "montecarlo.h" + +// DiffuseAreaLight Method Definitions +DiffuseAreaLight::~DiffuseAreaLight() { + delete shapeSet; +} + + +DiffuseAreaLight::DiffuseAreaLight(const Transform &light2world, + const Spectrum &le, int ns, const Reference &s) + : AreaLight(light2world, ns) { + Lemit = le; + shapeSet = new ShapeSet(s); + area = shapeSet->Area(); +} + + +Spectrum DiffuseAreaLight::Power(const Scene *) const { + return Lemit * area * M_PI; +} + + +AreaLight *CreateDiffuseAreaLight(const Transform &light2world, const ParamSet ¶mSet, + const Reference &shape) { + Spectrum L = paramSet.FindOneSpectrum("L", Spectrum(1.0)); + Spectrum sc = paramSet.FindOneSpectrum("scale", Spectrum(1.0)); + int nSamples = paramSet.FindOneInt("nsamples", 1); + if (PbrtOptions.quickRender) nSamples = max(1, nSamples / 4); + return new DiffuseAreaLight(light2world, L * sc, nSamples, shape); +} + + +Spectrum DiffuseAreaLight::Sample_L(const Point &p, float pEpsilon, + const LightSample &ls, float time, Vector *wi, float *pdf, + VisibilityTester *visibility) const { + PBRT_AREA_LIGHT_STARTED_SAMPLE(); + Normal ns; + Point ps = shapeSet->Sample(p, ls, &ns); + *wi = Normalize(ps - p); + *pdf = shapeSet->Pdf(p, *wi); + visibility->SetSegment(p, pEpsilon, ps, 1e-3f, time); + Spectrum Ls = L(ps, ns, -*wi); + PBRT_AREA_LIGHT_FINISHED_SAMPLE(); + return Ls; +} + + +float DiffuseAreaLight::Pdf(const Point &p, const Vector &wi) const { + return shapeSet->Pdf(p, wi); +} + + +Spectrum DiffuseAreaLight::Sample_L(const Scene *scene, + const LightSample &ls, float u1, float u2, float time, + Ray *ray, Normal *Ns, float *pdf) const { + PBRT_AREA_LIGHT_STARTED_SAMPLE(); + Point org = shapeSet->Sample(ls, Ns); + Vector dir = UniformSampleSphere(u1, u2); + if (Dot(dir, *Ns) < 0.) dir *= -1.f; + *ray = Ray(org, dir, 1e-3f, INFINITY, time); + *pdf = shapeSet->Pdf(org) * INV_TWOPI; + Spectrum Ls = L(org, *Ns, dir); + PBRT_AREA_LIGHT_FINISHED_SAMPLE(); + return Ls; +} + + diff --git a/lights/diffuse.h b/lights/diffuse.h new file mode 100644 index 0000000..4349d09 --- /dev/null +++ b/lights/diffuse.h @@ -0,0 +1,64 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_LIGHTS_DIFFUSE_H +#define PBRT_LIGHTS_DIFFUSE_H + +// lights/diffuse.h* +#include "pbrt.h" +#include "light.h" +#include "primitive.h" + +// DiffuseAreaLight Declarations +class DiffuseAreaLight : public AreaLight { +public: + // DiffuseAreaLight Public Methods + DiffuseAreaLight(const Transform &light2world, + const Spectrum &Le, int ns, const Reference &shape); + ~DiffuseAreaLight(); + Spectrum L(const Point &p, const Normal &n, const Vector &w) const { + return Dot(n, w) > 0.f ? Lemit : 0.f; + } + Spectrum Power(const Scene *) const; + bool IsDeltaLight() const { return false; } + float Pdf(const Point &, const Vector &) const; + Spectrum Sample_L(const Point &P, float pEpsilon, const LightSample &ls, float time, + Vector *wo, float *pdf, VisibilityTester *visibility) const; + Spectrum Sample_L(const Scene *scene, const LightSample &ls, float u1, float u2, + float time, Ray *ray, Normal *Ns, float *pdf) const; +protected: + // DiffuseAreaLight Protected Data + Spectrum Lemit; + ShapeSet *shapeSet; + float area; +}; + + +AreaLight *CreateDiffuseAreaLight(const Transform &light2world, const ParamSet ¶mSet, + const Reference &shape); + +#endif // PBRT_LIGHTS_DIFFUSE_H diff --git a/lights/distant.cpp b/lights/distant.cpp new file mode 100644 index 0000000..6f22169 --- /dev/null +++ b/lights/distant.cpp @@ -0,0 +1,96 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// lights/distant.cpp* +#include "stdafx.h" +#include "lights/distant.h" +#include "paramset.h" +#include "montecarlo.h" + +// DistantLight Method Definitions +DistantLight::DistantLight(const Transform &light2world, + const Spectrum &radiance, const Vector &dir) + : Light(light2world) { + lightDir = Normalize(LightToWorld(dir)); + L = radiance; +} + + +Spectrum DistantLight::Sample_L(const Point &p, float pEpsilon, + const LightSample &ls, float time, Vector *wi, float *pdf, + VisibilityTester *visibility) const { + *wi = lightDir; + *pdf = 1.f; + visibility->SetRay(p, pEpsilon, *wi, time); + return L; +} + + +Spectrum DistantLight::Power(const Scene *scene) const { + Point worldCenter; + float worldRadius; + scene->WorldBound().BoundingSphere(&worldCenter, &worldRadius); + return L * M_PI * worldRadius * worldRadius; +} + + +DistantLight *CreateDistantLight(const Transform &light2world, + const ParamSet ¶mSet) { + Spectrum L = paramSet.FindOneSpectrum("L", Spectrum(1.0)); + Spectrum sc = paramSet.FindOneSpectrum("scale", Spectrum(1.0)); + Point from = paramSet.FindOnePoint("from", Point(0,0,0)); + Point to = paramSet.FindOnePoint("to", Point(0,0,1)); + Vector dir = from-to; + return new DistantLight(light2world, L * sc, dir); +} + + +float DistantLight::Pdf(const Point &, const Vector &) const { + return 0.; +} + + +Spectrum DistantLight::Sample_L(const Scene *scene, + const LightSample &ls, float u1, float u2, float time, + Ray *ray, Normal *Ns, float *pdf) const { + // Choose point on disk oriented toward infinite light direction + Point worldCenter; + float worldRadius; + scene->WorldBound().BoundingSphere(&worldCenter, &worldRadius); + Vector v1, v2; + CoordinateSystem(lightDir, &v1, &v2); + float d1, d2; + ConcentricSampleDisk(ls.uPos[0], ls.uPos[1], &d1, &d2); + Point Pdisk = worldCenter + worldRadius * (d1 * v1 + d2 * v2); + + // Set ray origin and direction for infinite light ray + *ray = Ray(Pdisk + worldRadius * lightDir, -lightDir, 0.f, INFINITY, + time); + *Ns = (Normal)ray->d; + + *pdf = 1.f / (M_PI * worldRadius * worldRadius); + return L; +} + + diff --git a/lights/distant.h b/lights/distant.h new file mode 100644 index 0000000..21dbd81 --- /dev/null +++ b/lights/distant.h @@ -0,0 +1,59 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_LIGHTS_DISTANT_H +#define PBRT_LIGHTS_DISTANT_H + +// lights/distant.h* +#include "pbrt.h" +#include "light.h" +#include "shape.h" +#include "scene.h" + +// DistantLight Declarations +class DistantLight : public Light { +public: + // DistantLight Public Methods + DistantLight(const Transform &light2world, const Spectrum &radiance, const Vector &dir); + bool IsDeltaLight() const { return true; } + Spectrum Sample_L(const Point &p, float pEpsilon, const LightSample &ls, + float time, Vector *wi, float *pdf, VisibilityTester *) const; + Spectrum Power(const Scene *) const; + Spectrum Sample_L(const Scene *scene, const LightSample &ls, float u1, + float u2, float time, Ray *ray, Normal *Ns, float *pdf) const; + float Pdf(const Point &, const Vector &) const; +private: + // DistantLight Private Data + Vector lightDir; + Spectrum L; +}; + + +DistantLight *CreateDistantLight(const Transform &light2world, + const ParamSet ¶mSet); + +#endif // PBRT_LIGHTS_DISTANT_H diff --git a/lights/goniometric.cpp b/lights/goniometric.cpp new file mode 100644 index 0000000..61dc6f2 --- /dev/null +++ b/lights/goniometric.cpp @@ -0,0 +1,86 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// lights/goniometric.cpp* +#include "stdafx.h" +#include "lights/goniometric.h" +#include "paramset.h" +#include "montecarlo.h" +#include "imageio.h" + +// GonioPhotometricLight Method Definitions +Spectrum GonioPhotometricLight::Sample_L(const Point &p, float pEpsilon, + const LightSample &ls, float time, Vector *wi, float *pdf, VisibilityTester *visibility) const { + *wi = Normalize(lightPos - p); + *pdf = 1.f; + visibility->SetSegment(p, pEpsilon, lightPos, 0., time); + return Intensity * Scale(-*wi) / DistanceSquared(lightPos, p); +} + + +GonioPhotometricLight::GonioPhotometricLight(const Transform &light2world, + const Spectrum &intensity, const string &texname) + : Light(light2world) { + lightPos = LightToWorld(Point(0,0,0)); + Intensity = intensity; + // Create _mipmap_ for _GonioPhotometricLight_ + int width, height; + RGBSpectrum *texels = ReadImage(texname, &width, &height); + if (texels) { + mipmap = new MIPMap(width, height, texels); + delete[] texels; + } + else mipmap = NULL; +} + + +Spectrum GonioPhotometricLight::Power(const Scene *) const { + return 4.f * M_PI * Intensity * + Spectrum(mipmap ? mipmap->Lookup(.5f, .5f, .5f) : 1.f, SPECTRUM_ILLUMINANT); +} + + +GonioPhotometricLight *CreateGoniometricLight(const Transform &light2world, + const ParamSet ¶mSet) { + Spectrum I = paramSet.FindOneSpectrum("I", Spectrum(1.0)); + Spectrum sc = paramSet.FindOneSpectrum("scale", Spectrum(1.0)); + string texname = paramSet.FindOneFilename("mapname", ""); + return new GonioPhotometricLight(light2world, I * sc, texname); +} + + +Spectrum GonioPhotometricLight::Sample_L(const Scene *scene, const LightSample &ls, + float u1, float u2, float time, Ray *ray, Normal *Ns, float *pdf) const { + *ray = Ray(lightPos, UniformSampleSphere(ls.uPos[0], ls.uPos[1]), 0.f, INFINITY, time); + *Ns = (Normal)ray->d; + *pdf = UniformSpherePdf(); + return Intensity * Scale(ray->d); +} + + +float GonioPhotometricLight::Pdf(const Point &, const Vector &) const { + return 0.; +} + + diff --git a/lights/goniometric.h b/lights/goniometric.h new file mode 100644 index 0000000..7de7596 --- /dev/null +++ b/lights/goniometric.h @@ -0,0 +1,72 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_LIGHTS_GONIOMETRIC_H +#define PBRT_LIGHTS_GONIOMETRIC_H + +// lights/goniometric.h* +#include "pbrt.h" +#include "light.h" +#include "shape.h" +#include "scene.h" +#include "mipmap.h" + +// GonioPhotometricLight Declarations +class GonioPhotometricLight : public Light { +public: + // GonioPhotometricLight Public Methods + GonioPhotometricLight(const Transform &light2world, const Spectrum &, const + string &texname); + Spectrum Sample_L(const Point &p, float pEpsilon, const LightSample &ls, + float time, Vector *wi, float *pdf, VisibilityTester *vis) const; + ~GonioPhotometricLight() { delete mipmap; } + bool IsDeltaLight() const { return true; } + Spectrum Scale(const Vector &w) const { + Vector wp = Normalize(WorldToLight(w)); + swap(wp.y, wp.z); + float theta = SphericalTheta(wp); + float phi = SphericalPhi(wp); + float s = phi * INV_TWOPI, t = theta * INV_PI; + return (mipmap == NULL) ? 1.f : + Spectrum(mipmap->Lookup(s, t, SPECTRUM_ILLUMINANT)); + } + Spectrum Power(const Scene *) const; + Spectrum Sample_L(const Scene *scene, const LightSample &ls, float u1, float u2, + float time, Ray *ray, Normal *Ns, float *pdf) const; + float Pdf(const Point &, const Vector &) const; +private: + // GonioPhotometricLight Private Data + Point lightPos; + Spectrum Intensity; + MIPMap *mipmap; +}; + + +GonioPhotometricLight *CreateGoniometricLight(const Transform &light2world, + const ParamSet ¶mSet); + +#endif // PBRT_LIGHTS_GONIOMETRIC_H diff --git a/lights/infinite.cpp b/lights/infinite.cpp new file mode 100644 index 0000000..0984f50 --- /dev/null +++ b/lights/infinite.cpp @@ -0,0 +1,268 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// lights/infinite.cpp* +#include "stdafx.h" +#include "lights/infinite.h" +#include "sh.h" +#include "montecarlo.h" +#include "paramset.h" +#include "imageio.h" + +// InfiniteAreaLight Utility Classes +struct InfiniteAreaCube { + // InfiniteAreaCube Public Methods + InfiniteAreaCube(const InfiniteAreaLight *l, const Scene *s, + float t, bool cv, float pe) + : light(l), scene(s), time(t), pEpsilon(pe), computeVis(cv) { } + Spectrum operator()(int, int, const Point &p, const Vector &w) { + Ray ray(p, w, pEpsilon, INFINITY, time); + if (!computeVis || !scene->IntersectP(ray)) + return light->Le(RayDifferential(ray)); + return 0.f; + } + const InfiniteAreaLight *light; + const Scene *scene; + float time, pEpsilon; + bool computeVis; +}; + + + +// InfiniteAreaLight Method Definitions +InfiniteAreaLight::~InfiniteAreaLight() { + delete distribution; + delete radianceMap; +} + + +InfiniteAreaLight::InfiniteAreaLight(const Transform &light2world, + const Spectrum &L, int ns, const string &texmap) + : Light(light2world, ns) { + int width = 0, height = 0; + RGBSpectrum *texels = NULL; + // Read texel data from _texmap_ into _texels_ + if (texmap != "") { + texels = ReadImage(texmap, &width, &height); + if (texels) + for (int i = 0; i < width * height; ++i) + texels[i] *= L.ToRGBSpectrum(); + } + if (!texels) { + width = height = 1; + texels = new RGBSpectrum[1]; + texels[0] = L.ToRGBSpectrum(); + } + radianceMap = new MIPMap(width, height, texels); + delete[] texels; + // Initialize sampling PDFs for infinite area light + + // Compute scalar-valued image _img_ from environment map + float filter = 1.f / max(width, height); + float *img = new float[width*height]; + for (int v = 0; v < height; ++v) { + float vp = (float)v / (float)height; + float sinTheta = sinf(M_PI * float(v+.5f)/float(height)); + for (int u = 0; u < width; ++u) { + float up = (float)u / (float)width; + img[u+v*width] = radianceMap->Lookup(up, vp, filter).y(); + img[u+v*width] *= sinTheta; + } + } + + // Compute sampling distributions for rows and columns of image + distribution = new Distribution2D(img, width, height); + delete[] img; +} + + +Spectrum InfiniteAreaLight::Power(const Scene *scene) const { + Point worldCenter; + float worldRadius; + scene->WorldBound().BoundingSphere(&worldCenter, &worldRadius); + return M_PI * worldRadius * worldRadius * + Spectrum(radianceMap->Lookup(.5f, .5f, .5f), SPECTRUM_ILLUMINANT); +} + + +Spectrum InfiniteAreaLight::Le(const RayDifferential &r) const { + Vector wh = Normalize(WorldToLight(r.d)); + float s = SphericalPhi(wh) * INV_TWOPI; + float t = SphericalTheta(wh) * INV_PI; + return Spectrum(radianceMap->Lookup(s, t), SPECTRUM_ILLUMINANT); +} + + +void InfiniteAreaLight::SHProject(const Point &p, float pEpsilon, + int lmax, const Scene *scene, bool computeLightVis, + float time, RNG &rng, Spectrum *coeffs) const { + // Project _InfiniteAreaLight_ to SH using Monte Carlo if visibility needed + if (computeLightVis) { + Light::SHProject(p, pEpsilon, lmax, scene, computeLightVis, + time, rng, coeffs); + return; + } + for (int i = 0; i < SHTerms(lmax); ++i) + coeffs[i] = 0.f; + int ntheta = radianceMap->Height(), nphi = radianceMap->Width(); + if (min(ntheta, nphi) > 50) { + // Project _InfiniteAreaLight_ to SH from lat-long representation + + // Precompute $\theta$ and $\phi$ values for lat-long map projection + float *buf = new float[2*ntheta + 2*nphi]; + float *bufp = buf; + float *sintheta = bufp; bufp += ntheta; + float *costheta = bufp; bufp += ntheta; + float *sinphi = bufp; bufp += nphi; + float *cosphi = bufp; + for (int theta = 0; theta < ntheta; ++theta) { + sintheta[theta] = sinf((theta + .5f)/ntheta * M_PI); + costheta[theta] = cosf((theta + .5f)/ntheta * M_PI); + } + for (int phi = 0; phi < nphi; ++phi) { + sinphi[phi] = sinf((phi + .5f)/nphi * 2.f * M_PI); + cosphi[phi] = cosf((phi + .5f)/nphi * 2.f * M_PI); + } + float *Ylm = ALLOCA(float, SHTerms(lmax)); + for (int theta = 0; theta < ntheta; ++theta) { + for (int phi = 0; phi < nphi; ++phi) { + // Add _InfiniteAreaLight_ texel's contribution to SH coefficients + Vector w = Vector(sintheta[theta] * cosphi[phi], + sintheta[theta] * sinphi[phi], + costheta[theta]); + w = Normalize(LightToWorld(w)); + Spectrum Le = Spectrum(radianceMap->Texel(0, phi, theta), + SPECTRUM_ILLUMINANT); + SHEvaluate(w, lmax, Ylm); + for (int i = 0; i < SHTerms(lmax); ++i) + coeffs[i] += Le * Ylm[i] * sintheta[theta] * + (M_PI / ntheta) * (2.f * M_PI / nphi); + } + } + + // Free memory used for lat-long theta and phi values + delete[] buf; + } + else { + // Project _InfiniteAreaLight_ to SH from cube map sampling + SHProjectCube(InfiniteAreaCube(this, scene, time, computeLightVis, + pEpsilon), + p, 200, lmax, coeffs); + } +} + + +InfiniteAreaLight *CreateInfiniteLight(const Transform &light2world, + const ParamSet ¶mSet) { + Spectrum L = paramSet.FindOneSpectrum("L", Spectrum(1.0)); + Spectrum sc = paramSet.FindOneSpectrum("scale", Spectrum(1.0)); + string texmap = paramSet.FindOneFilename("mapname", ""); + int nSamples = paramSet.FindOneInt("nsamples", 1); + if (PbrtOptions.quickRender) nSamples = max(1, nSamples / 4); + return new InfiniteAreaLight(light2world, L * sc, nSamples, texmap); +} + + +Spectrum InfiniteAreaLight::Sample_L(const Point &p, float pEpsilon, + const LightSample &ls, float time, Vector *wi, float *pdf, + VisibilityTester *visibility) const { + PBRT_INFINITE_LIGHT_STARTED_SAMPLE(); + // Find $(u,v)$ sample coordinates in infinite light texture + float uv[2], mapPdf; + distribution->SampleContinuous(ls.uPos[0], ls.uPos[1], uv, &mapPdf); + if (mapPdf == 0.f) return 0.f; + + // Convert infinite light sample point to direction + float theta = uv[1] * M_PI, phi = uv[0] * 2.f * M_PI; + float costheta = cosf(theta), sintheta = sinf(theta); + float sinphi = sinf(phi), cosphi = cosf(phi); + *wi = LightToWorld(Vector(sintheta * cosphi, sintheta * sinphi, + costheta)); + + // Compute PDF for sampled infinite light direction + *pdf = mapPdf / (2.f * M_PI * M_PI * sintheta); + if (sintheta == 0.f) *pdf = 0.f; + + // Return radiance value for infinite light direction + visibility->SetRay(p, pEpsilon, *wi, time); + Spectrum Ls = Spectrum(radianceMap->Lookup(uv[0], uv[1]), + SPECTRUM_ILLUMINANT); + PBRT_INFINITE_LIGHT_FINISHED_SAMPLE(); + return Ls; +} + + +float InfiniteAreaLight::Pdf(const Point &, const Vector &w) const { + PBRT_INFINITE_LIGHT_STARTED_PDF(); + Vector wi = WorldToLight(w); + float theta = SphericalTheta(wi), phi = SphericalPhi(wi); + float sintheta = sinf(theta); + if (sintheta == 0.f) return 0.f; + float p = distribution->Pdf(phi * INV_TWOPI, theta * INV_PI) / + (2.f * M_PI * M_PI * sintheta); + PBRT_INFINITE_LIGHT_FINISHED_PDF(); + return p; +} + + +Spectrum InfiniteAreaLight::Sample_L(const Scene *scene, + const LightSample &ls, float u1, float u2, float time, + Ray *ray, Normal *Ns, float *pdf) const { + PBRT_INFINITE_LIGHT_STARTED_SAMPLE(); + // Compute direction for infinite light sample ray + + // Find $(u,v)$ sample coordinates in infinite light texture + float uv[2], mapPdf; + distribution->SampleContinuous(ls.uPos[0], ls.uPos[1], uv, &mapPdf); + if (mapPdf == 0.f) return Spectrum(0.f); + + float theta = uv[1] * M_PI, phi = uv[0] * 2.f * M_PI; + float costheta = cosf(theta), sintheta = sinf(theta); + float sinphi = sinf(phi), cosphi = cosf(phi); + Vector d = -LightToWorld(Vector(sintheta * cosphi, sintheta * sinphi, + costheta)); + *Ns = (Normal)d; + + // Compute origin for infinite light sample ray + Point worldCenter; + float worldRadius; + scene->WorldBound().BoundingSphere(&worldCenter, &worldRadius); + Vector v1, v2; + CoordinateSystem(-d, &v1, &v2); + float d1, d2; + ConcentricSampleDisk(u1, u2, &d1, &d2); + Point Pdisk = worldCenter + worldRadius * (d1 * v1 + d2 * v2); + *ray = Ray(Pdisk + worldRadius * -d, d, 0., INFINITY, time); + + // Compute _InfiniteAreaLight_ ray PDF + float directionPdf = mapPdf / (2.f * M_PI * M_PI * sintheta); + float areaPdf = 1.f / (M_PI * worldRadius * worldRadius); + *pdf = directionPdf * areaPdf; + if (sintheta == 0.f) *pdf = 0.f; + Spectrum Ls = (radianceMap->Lookup(uv[0], uv[1]), SPECTRUM_ILLUMINANT); + PBRT_INFINITE_LIGHT_FINISHED_SAMPLE(); + return Ls; +} + + diff --git a/lights/infinite.h b/lights/infinite.h new file mode 100644 index 0000000..8674180 --- /dev/null +++ b/lights/infinite.h @@ -0,0 +1,66 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_LIGHTS_INFINITE_H +#define PBRT_LIGHTS_INFINITE_H + +// lights/infinite.h* +#include "pbrt.h" +#include "light.h" +#include "texture.h" +#include "shape.h" +#include "scene.h" +#include "mipmap.h" + +// InfiniteAreaLight Declarations +class InfiniteAreaLight : public Light { +public: + // InfiniteAreaLight Public Methods + InfiniteAreaLight(const Transform &light2world, const Spectrum &power, int ns, + const string &texmap); + ~InfiniteAreaLight(); + Spectrum Power(const Scene *) const; + bool IsDeltaLight() const { return false; } + Spectrum Le(const RayDifferential &r) const; + Spectrum Sample_L(const Point &p, float pEpsilon, const LightSample &ls, + float time, Vector *wi, float *pdf, VisibilityTester *visibility) const; + Spectrum Sample_L(const Scene *scene, const LightSample &ls, float u1, float u2, + float time, Ray *ray, Normal *Ns, float *pdf) const; + float Pdf(const Point &, const Vector &) const; + void SHProject(const Point &p, float pEpsilon, int lmax, const Scene *scene, + bool computeLightVis, float time, RNG &rng, Spectrum *coeffs) const; +private: + // InfiniteAreaLight Private Data + MIPMap *radianceMap; + Distribution2D *distribution; +}; + + +InfiniteAreaLight *CreateInfiniteLight(const Transform &light2world, + const ParamSet ¶mSet); + +#endif // PBRT_LIGHTS_INFINITE_H diff --git a/lights/point.cpp b/lights/point.cpp new file mode 100644 index 0000000..e7b3dba --- /dev/null +++ b/lights/point.cpp @@ -0,0 +1,101 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// lights/point.cpp* +#include "stdafx.h" +#include "lights/point.h" +#include "sh.h" +#include "scene.h" +#include "paramset.h" +#include "montecarlo.h" + +// PointLight Method Definitions +PointLight::PointLight(const Transform &light2world, + const Spectrum &intensity) + : Light(light2world) { + lightPos = LightToWorld(Point(0,0,0)); + Intensity = intensity; +} + + +Spectrum PointLight::Sample_L(const Point &p, float pEpsilon, + const LightSample &ls, float time, Vector *wi, float *pdf, + VisibilityTester *visibility) const { + *wi = Normalize(lightPos - p); + *pdf = 1.f; + visibility->SetSegment(p, pEpsilon, lightPos, 0., time); + return Intensity / DistanceSquared(lightPos, p); +} + + +Spectrum PointLight::Power(const Scene *) const { + return 4.f * M_PI * Intensity; +} + + +PointLight *CreatePointLight(const Transform &light2world, + const ParamSet ¶mSet) { + Spectrum I = paramSet.FindOneSpectrum("I", Spectrum(1.0)); + Spectrum sc = paramSet.FindOneSpectrum("scale", Spectrum(1.0)); + Point P = paramSet.FindOnePoint("from", Point(0,0,0)); + Transform l2w = Translate(Vector(P.x, P.y, P.z)) * light2world; + return new PointLight(l2w, I * sc); +} + + +float PointLight::Pdf(const Point &, const Vector &) const { + return 0.; +} + + +Spectrum PointLight::Sample_L(const Scene *scene, const LightSample &ls, + float u1, float u2, float time, Ray *ray, Normal *Ns, + float *pdf) const { + *ray = Ray(lightPos, UniformSampleSphere(ls.uPos[0], ls.uPos[1]), + 0.f, INFINITY, time); + *Ns = (Normal)ray->d; + *pdf = UniformSpherePdf(); + return Intensity; +} + + +void PointLight::SHProject(const Point &p, float pEpsilon, int lmax, + const Scene *scene, bool computeLightVisibility, float time, + RNG &rng, Spectrum *coeffs) const { + for (int i = 0; i < SHTerms(lmax); ++i) + coeffs[i] = 0.f; + if (computeLightVisibility && + scene->IntersectP(Ray(p, Normalize(lightPos - p), pEpsilon, + Distance(lightPos, p), time))) + return; + // Project point light source to SH + float *Ylm = ALLOCA(float, SHTerms(lmax)); + Vector wi = Normalize(lightPos - p); + SHEvaluate(wi, lmax, Ylm); + Spectrum Li = Intensity / DistanceSquared(lightPos, p); + for (int i = 0; i < SHTerms(lmax); ++i) + coeffs[i] = Li * Ylm[i]; +} + + diff --git a/lights/point.h b/lights/point.h new file mode 100644 index 0000000..b29be8e --- /dev/null +++ b/lights/point.h @@ -0,0 +1,60 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_LIGHTS_POINT_H +#define PBRT_LIGHTS_POINT_H + +// lights/point.h* +#include "pbrt.h" +#include "light.h" +#include "shape.h" + +// PointLight Declarations +class PointLight : public Light { +public: + // PointLight Public Methods + PointLight(const Transform &light2world, const Spectrum &intensity); + Spectrum Sample_L(const Point &p, float pEpsilon, const LightSample &ls, + float time, Vector *wi, float *pdf, VisibilityTester *vis) const; + Spectrum Power(const Scene *) const; + bool IsDeltaLight() const { return true; } + Spectrum Sample_L(const Scene *scene, const LightSample &ls, float u1, + float u2, float time, Ray *ray, Normal *Ns, float *pdf) const; + float Pdf(const Point &, const Vector &) const; + void SHProject(const Point &p, float pEpsilon, int lmax, const Scene *scene, + bool computeLightVisibility, float time, RNG &rng, Spectrum *coeffs) const; +private: + // PointLight Private Data + Point lightPos; + Spectrum Intensity; +}; + + +PointLight *CreatePointLight(const Transform &light2world, + const ParamSet ¶mSet); + +#endif // PBRT_LIGHTS_POINT_H diff --git a/lights/projection.cpp b/lights/projection.cpp new file mode 100644 index 0000000..2f2b90b --- /dev/null +++ b/lights/projection.cpp @@ -0,0 +1,128 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// lights/projection.cpp* +#include "stdafx.h" +#include "lights/projection.h" +#include "montecarlo.h" +#include "paramset.h" +#include "imageio.h" + +// ProjectionLight Method Definitions +ProjectionLight::ProjectionLight(const Transform &light2world, + const Spectrum &intensity, const string &texname, + float fov) + : Light(light2world) { + lightPos = LightToWorld(Point(0,0,0)); + Intensity = intensity; + // Create _ProjectionLight_ MIP-map + int width, height; + RGBSpectrum *texels = ReadImage(texname, &width, &height); + if (texels) + projectionMap = new MIPMap(width, height, texels); + else + projectionMap = NULL; + delete[] texels; + + // Initialize _ProjectionLight_ projection matrix + float aspect = projectionMap ? float(width) / float(height) : 1.f; + if (aspect > 1.f) { + screenX0 = -aspect; screenX1 = aspect; + screenY0 = -1.f; screenY1 = 1.f; + } + else { + screenX0 = -1.f; screenX1 = 1.f; + screenY0 = -1.f / aspect; screenY1 = 1.f / aspect; + } + hither = 1e-3f; + yon = 1e30f; + lightProjection = Perspective(fov, hither, yon); + + // Compute cosine of cone surrounding projection directions + float opposite = tanf(Radians(fov) / 2.f); + float tanDiag = opposite * sqrtf(1.f + 1.f/(aspect*aspect)); + cosTotalWidth = cosf(atanf(tanDiag)); +} + + +ProjectionLight::~ProjectionLight() { delete projectionMap; } +Spectrum ProjectionLight::Sample_L(const Point &p, float pEpsilon, + const LightSample &ls, float time, Vector *wi, + float *pdf, VisibilityTester *visibility) const { + *wi = Normalize(lightPos - p); + *pdf = 1.f; + visibility->SetSegment(p, pEpsilon, lightPos, 0., time); + return Intensity * Projection(-*wi) / + DistanceSquared(lightPos, p); +} + + +Spectrum ProjectionLight::Projection(const Vector &w) const { + Vector wl = WorldToLight(w); + // Discard directions behind projection light + if (wl.z < hither) return 0.; + + // Project point onto projection plane and compute light + Point Pl = lightProjection(Point(wl.x, wl.y, wl.z)); + if (Pl.x < screenX0 || Pl.x > screenX1 || + Pl.y < screenY0 || Pl.y > screenY1) return 0.; + if (!projectionMap) return 1; + float s = (Pl.x - screenX0) / (screenX1 - screenX0); + float t = (Pl.y - screenY0) / (screenY1 - screenY0); + return Spectrum(projectionMap->Lookup(s, t), SPECTRUM_ILLUMINANT); +} + + +Spectrum ProjectionLight::Power(const Scene *) const { + return (projectionMap ? Spectrum(projectionMap->Lookup(.5f, .5f, .5f), + SPECTRUM_ILLUMINANT) : Spectrum(1.f)) * + Intensity * 2.f * M_PI * (1.f - cosTotalWidth); +} + + +ProjectionLight *CreateProjectionLight(const Transform &light2world, + const ParamSet ¶mSet) { + Spectrum I = paramSet.FindOneSpectrum("I", Spectrum(1.0)); + Spectrum sc = paramSet.FindOneSpectrum("scale", Spectrum(1.0)); + float fov = paramSet.FindOneFloat("fov", 45.); + string texname = paramSet.FindOneFilename("mapname", ""); + return new ProjectionLight(light2world, I * sc, texname, fov); +} + + +Spectrum ProjectionLight::Sample_L(const Scene *scene, const LightSample &ls, + float u1, float u2, float time, Ray *ray, Normal *Ns, float *pdf) const { + Vector v = UniformSampleCone(ls.uPos[0], ls.uPos[1], cosTotalWidth); + *ray = Ray(lightPos, LightToWorld(v), 0.f, INFINITY, time); + *Ns = (Normal)ray->d; + *pdf = UniformConePdf(cosTotalWidth); + return Intensity * Projection(ray->d); +} + + +float ProjectionLight::Pdf(const Point &, const Vector &) const { + return 0.; +} + + diff --git a/lights/projection.h b/lights/projection.h new file mode 100644 index 0000000..3f9343f --- /dev/null +++ b/lights/projection.h @@ -0,0 +1,67 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_LIGHTS_PROJECTION_H +#define PBRT_LIGHTS_PROJECTION_H + +// lights/projection.h* +#include "pbrt.h" +#include "light.h" +#include "shape.h" +#include "mipmap.h" + +// ProjectionLight Declarations +class ProjectionLight : public Light { +public: + // ProjectionLight Public Methods + ProjectionLight(const Transform &light2world, const Spectrum &intensity, + const string &texname, float fov); + ~ProjectionLight(); + Spectrum Sample_L(const Point &p, float pEpsilon, const LightSample &ls, float time, + Vector *wi, float *pdf, VisibilityTester *vis) const; + bool IsDeltaLight() const { return true; } + Spectrum Projection(const Vector &w) const; + Spectrum Power(const Scene *) const; + Spectrum Sample_L(const Scene *scene, const LightSample &ls, float u1, float u2, + float time, Ray *ray, Normal *Ns, float *pdf) const; + float Pdf(const Point &, const Vector &) const; +private: + // ProjectionLight Private Data + MIPMap *projectionMap; + Point lightPos; + Spectrum Intensity; + Transform lightProjection; + float hither, yon; + float screenX0, screenX1, screenY0, screenY1; + float cosTotalWidth; +}; + + +ProjectionLight *CreateProjectionLight(const Transform &light2world, + const ParamSet ¶mSet); + +#endif // PBRT_LIGHTS_PROJECTION_H diff --git a/lights/spot.cpp b/lights/spot.cpp new file mode 100644 index 0000000..f7e48fa --- /dev/null +++ b/lights/spot.cpp @@ -0,0 +1,108 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// lights/spot.cpp* +#include "stdafx.h" +#include "lights/spot.h" +#include "paramset.h" +#include "montecarlo.h" + +// SpotLight Method Definitions +SpotLight::SpotLight(const Transform &light2world, + const Spectrum &intensity, float width, float fall) + : Light(light2world) { + lightPos = LightToWorld(Point(0,0,0)); + Intensity = intensity; + cosTotalWidth = cosf(Radians(width)); + cosFalloffStart = cosf(Radians(fall)); +} + + +Spectrum SpotLight::Sample_L(const Point &p, float pEpsilon, + const LightSample &ls, float time, Vector *wi, + float *pdf, VisibilityTester *visibility) const { + *wi = Normalize(lightPos - p); + *pdf = 1.f; + visibility->SetSegment(p, pEpsilon, lightPos, 0., time); + return Intensity * Falloff(-*wi) / DistanceSquared(lightPos, p); +} + + +float SpotLight::Falloff(const Vector &w) const { + Vector wl = Normalize(WorldToLight(w)); + float costheta = wl.z; + if (costheta < cosTotalWidth) return 0.; + if (costheta > cosFalloffStart) return 1.; + // Compute falloff inside spotlight cone + float delta = (costheta - cosTotalWidth) / + (cosFalloffStart - cosTotalWidth); + return delta*delta*delta*delta; +} + + +Spectrum SpotLight::Power(const Scene *) const { + return Intensity * 2.f * M_PI * + (1.f - .5f * (cosFalloffStart + cosTotalWidth)); +} + + +SpotLight *CreateSpotLight(const Transform &l2w, const ParamSet ¶mSet) { + Spectrum I = paramSet.FindOneSpectrum("I", Spectrum(1.0)); + Spectrum sc = paramSet.FindOneSpectrum("scale", Spectrum(1.0)); + float coneangle = paramSet.FindOneFloat("coneangle", 30.); + float conedelta = paramSet.FindOneFloat("conedeltaangle", 5.); + // Compute spotlight world to light transformation + Point from = paramSet.FindOnePoint("from", Point(0,0,0)); + Point to = paramSet.FindOnePoint("to", Point(0,0,1)); + Vector dir = Normalize(to - from); + Vector du, dv; + CoordinateSystem(dir, &du, &dv); + Transform dirToZ = + Transform(Matrix4x4( du.x, du.y, du.z, 0., + dv.x, dv.y, dv.z, 0., + dir.x, dir.y, dir.z, 0., + 0, 0, 0, 1.)); + Transform light2world = l2w * + Translate(Vector(from.x, from.y, from.z)) * Inverse(dirToZ); + return new SpotLight(light2world, I * sc, coneangle, + coneangle-conedelta); +} + + +float SpotLight::Pdf(const Point &, const Vector &) const { + return 0.; +} + + +Spectrum SpotLight::Sample_L(const Scene *scene, const LightSample &ls, + float u1, float u2, float time, Ray *ray, Normal *Ns, + float *pdf) const { + Vector v = UniformSampleCone(ls.uPos[0], ls.uPos[1], cosTotalWidth); + *ray = Ray(lightPos, LightToWorld(v), 0.f, INFINITY, time); + *Ns = (Normal)ray->d; + *pdf = UniformConePdf(cosTotalWidth); + return Intensity * Falloff(ray->d); +} + + diff --git a/lights/spot.h b/lights/spot.h new file mode 100644 index 0000000..bb6115b --- /dev/null +++ b/lights/spot.h @@ -0,0 +1,59 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_LIGHTS_SPOT_H +#define PBRT_LIGHTS_SPOT_H + +// lights/spot.h* +#include "pbrt.h" +#include "light.h" +#include "shape.h" + +// SpotLight Declarations +class SpotLight : public Light { +public: + // SpotLight Public Methods + SpotLight(const Transform &light2world, const Spectrum &, float width, float fall); + Spectrum Sample_L(const Point &p, float pEpsilon, const LightSample &ls, float time, + Vector *wi, float *pdf, VisibilityTester *vis) const; + bool IsDeltaLight() const { return true; } + float Falloff(const Vector &w) const; + Spectrum Power(const Scene *) const; + Spectrum Sample_L(const Scene *scene, const LightSample &ls, + float u1, float u2, float time, Ray *ray, Normal *Ns, float *pdf) const; + float Pdf(const Point &, const Vector &) const; +private: + // SpotLight Private Data + Point lightPos; + Spectrum Intensity; + float cosTotalWidth, cosFalloffStart; +}; + + +SpotLight *CreateSpotLight(const Transform &l2w, const ParamSet ¶mSet); + +#endif // PBRT_LIGHTS_SPOT_H diff --git a/main/pbrt.cpp b/main/pbrt.cpp new file mode 100644 index 0000000..7d7a31c --- /dev/null +++ b/main/pbrt.cpp @@ -0,0 +1,76 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// main/pbrt.cpp* +#include "stdafx.h" +#include "api.h" +#include "probes.h" +#include "parser.h" +#include "parallel.h" + +// main program +int main(int argc, char *argv[]) { + Options options; + vector filenames; + // Process command-line arguments + for (int i = 1; i < argc; ++i) { + if (!strcmp(argv[i], "--ncores")) options.nCores = atoi(argv[++i]); + else if (!strcmp(argv[i], "--outfile")) options.imageFile = argv[++i]; + else if (!strcmp(argv[i], "--quick")) options.quickRender = true; + else if (!strcmp(argv[i], "--quiet")) options.quiet = true; + else if (!strcmp(argv[i], "--verbose")) options.verbose = true; + else if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) { + printf("usage: pbrt [--ncores n] [--outfile filename] [--quick] [--quiet] " + "[--verbose] [--help] ...\n"); + return 0; + } + else filenames.push_back(argv[i]); + } + + // Print welcome banner + if (!options.quiet) { + printf("pbrt version %s of %s at %s [Detected %d core(s)]\n", + PBRT_VERSION, __DATE__, __TIME__, NumSystemCores()); + printf("Copyright (c)1998-2010 Matt Pharr and Greg Humphreys.\n"); + printf("The source code to pbrt (but *not* the book contents) is covered by the GNU GPL.\n"); + printf("See the file COPYING.txt for the conditions of the license.\n"); + fflush(stdout); + } + pbrtInit(options); + // Process scene description + PBRT_STARTED_PARSING(); + if (filenames.size() == 0) { + // Parse scene from standard input + ParseFile("-"); + } else { + // Parse scene from input files + for (u_int i = 0; i < filenames.size(); i++) + if (!ParseFile(filenames[i])) + Error("Couldn't open scene file \"%s\"", filenames[i].c_str()); + } + pbrtCleanup(); + return 0; +} + + diff --git a/materials/glass.cpp b/materials/glass.cpp new file mode 100644 index 0000000..c69181d --- /dev/null +++ b/materials/glass.cpp @@ -0,0 +1,62 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// materials/glass.cpp* +#include "stdafx.h" +#include "materials/glass.h" +#include "spectrum.h" +#include "reflection.h" +#include "paramset.h" +#include "texture.h" + +// GlassMaterial Method Definitions +BSDF *GlassMaterial::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) const { + DifferentialGeometry dgs; + if (bumpMap) + Bump(bumpMap, dgGeom, dgShading, &dgs); + else + dgs = dgShading; + float ior = index->Evaluate(dgs); + BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn, ior); + Spectrum R = Kr->Evaluate(dgs).Clamp(); + Spectrum T = Kt->Evaluate(dgs).Clamp(); + if (!R.IsBlack()) + bsdf->Add(BSDF_ALLOC(arena, SpecularReflection)(R, + BSDF_ALLOC(arena, FresnelDielectric)(1., ior))); + if (!T.IsBlack()) + bsdf->Add(BSDF_ALLOC(arena, SpecularTransmission)(T, 1., ior)); + return bsdf; +} + + +GlassMaterial *CreateGlassMaterial(const Transform &xform, + const TextureParams &mp) { + Reference > Kr = mp.GetSpectrumTexture("Kr", Spectrum(1.f)); + Reference > Kt = mp.GetSpectrumTexture("Kt", Spectrum(1.f)); + Reference > index = mp.GetFloatTexture("index", 1.5f); + Reference > bumpMap = mp.GetFloatTexture("bumpmap", 0.f); + return new GlassMaterial(Kr, Kt, index, bumpMap); +} + + diff --git a/materials/glass.h b/materials/glass.h new file mode 100644 index 0000000..bbb9ccb --- /dev/null +++ b/materials/glass.h @@ -0,0 +1,58 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_MATERIALS_GLASS_H +#define PBRT_MATERIALS_GLASS_H + +// materials/glass.h* +#include "pbrt.h" +#include "material.h" + +// GlassMaterial Declarations +class GlassMaterial : public Material { +public: + // GlassMaterial Public Methods + GlassMaterial(Reference > r, Reference > t, + Reference > i, Reference > bump) { + Kr = r; + Kt = t; + index = i; + bumpMap = bump; + } + BSDF *GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) const; +private: + // GlassMaterial Private Data + Reference > Kr, Kt; + Reference > index; + Reference > bumpMap; +}; + + +GlassMaterial *CreateGlassMaterial(const Transform &xform, + const TextureParams &mp); + +#endif // PBRT_MATERIALS_GLASS_H diff --git a/materials/kdsubsurface.cpp b/materials/kdsubsurface.cpp new file mode 100644 index 0000000..cf1c896 --- /dev/null +++ b/materials/kdsubsurface.cpp @@ -0,0 +1,78 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// materials/kdsubsurface.cpp* +#include "stdafx.h" +#include "materials/kdsubsurface.h" +#include "textures/constant.h" +#include "volume.h" +#include "spectrum.h" +#include "reflection.h" +#include "texture.h" +#include "paramset.h" + +// KdSubsurfaceMaterial Method Definitions +BSDF *KdSubsurfaceMaterial::GetBSDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, + MemoryArena &arena) const { + // Allocate _BSDF_, possibly doing bump mapping with _bumpMap_ + DifferentialGeometry dgs; + if (bumpMap) + Bump(bumpMap, dgGeom, dgShading, &dgs); + else + dgs = dgShading; + BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn); + Spectrum R = Kr->Evaluate(dgs).Clamp(); + float e = eta->Evaluate(dgs); + if (!R.IsBlack()) + bsdf->Add(BSDF_ALLOC(arena, SpecularReflection)(R, + BSDF_ALLOC(arena, FresnelDielectric)(1., e))); + return bsdf; +} + + +BSSRDF *KdSubsurfaceMaterial::GetBSSRDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, + MemoryArena &arena) const { + float e = eta->Evaluate(dgShading); + float mfp = meanfreepath->Evaluate(dgShading); + Spectrum kd = Kd->Evaluate(dgShading).Clamp(); + Spectrum sigma_a, sigma_prime_s; + SubsurfaceFromDiffuse(kd, mfp, e, &sigma_a, &sigma_prime_s); + return BSDF_ALLOC(arena, BSSRDF)(sigma_a, sigma_prime_s, e); +} + + +KdSubsurfaceMaterial *CreateKdSubsurfaceMaterial(const Transform &xform, + const TextureParams &mp) { + float Kd[3] = { .5, .5, .5 }; + Reference > kd = mp.GetSpectrumTexture("Kd", Spectrum::FromRGB(Kd)); + Reference > mfp = mp.GetFloatTexture("meanfreepath", 1.f); + Reference > ior = mp.GetFloatTexture("index", 1.3f); + Reference > kr = mp.GetSpectrumTexture("Kr", Spectrum(1.f)); + Reference > bumpMap = mp.GetFloatTexture("bumpmap", 0.f); + return new KdSubsurfaceMaterial(kd, kr, mfp, ior, bumpMap); +} + + diff --git a/materials/kdsubsurface.h b/materials/kdsubsurface.h new file mode 100644 index 0000000..9be1732 --- /dev/null +++ b/materials/kdsubsurface.h @@ -0,0 +1,66 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_MATERIALS_KDSUBSURFACE_H +#define PBRT_MATERIALS_KDSUBSURFACE_H + +// materials/kdsubsurface.h* +#include "pbrt.h" +#include "material.h" + +// KdSubsurfaceMaterial Declarations +class KdSubsurfaceMaterial : public Material { +public: + // KdSubsurfaceMaterial Public Methods + KdSubsurfaceMaterial(Reference > kd, + Reference > kr, + Reference > mfp, + Reference > e, + Reference > bump) { + Kd = kd; + Kr = kr; + meanfreepath = mfp; + eta = e; + bumpMap = bump; + } + BSDF *GetBSDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, + MemoryArena &arena) const; + BSSRDF *GetBSSRDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, + MemoryArena &arena) const; +private: + // KdSubsurfaceMaterial Private Data + Reference > Kd, Kr; + Reference > meanfreepath, eta, bumpMap; +}; + + +KdSubsurfaceMaterial *CreateKdSubsurfaceMaterial(const Transform &xform, + const TextureParams &mp); + +#endif // PBRT_MATERIALS_KDSUBSURFACE_H diff --git a/materials/matte.cpp b/materials/matte.cpp new file mode 100644 index 0000000..042b711 --- /dev/null +++ b/materials/matte.cpp @@ -0,0 +1,64 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// materials/matte.cpp* +#include "stdafx.h" +#include "materials/matte.h" +#include "paramset.h" +#include "reflection.h" +#include "diffgeom.h" +#include "texture.h" + +// MatteMaterial Method Definitions +BSDF *MatteMaterial::GetBSDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, + MemoryArena &arena) const { + // Allocate _BSDF_, possibly doing bump mapping with _bumpMap_ + DifferentialGeometry dgs; + if (bumpMap) + Bump(bumpMap, dgGeom, dgShading, &dgs); + else + dgs = dgShading; + BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn); + + // Evaluate textures for _MatteMaterial_ material and allocate BRDF + Spectrum r = Kd->Evaluate(dgs).Clamp(); + float sig = Clamp(sigma->Evaluate(dgs), 0.f, 90.f); + if (sig == 0.) + bsdf->Add(BSDF_ALLOC(arena, Lambertian)(r)); + else + bsdf->Add(BSDF_ALLOC(arena, OrenNayar)(r, sig)); + return bsdf; +} + + +MatteMaterial *CreateMatteMaterial(const Transform &xform, + const TextureParams &mp) { + Reference > Kd = mp.GetSpectrumTexture("Kd", Spectrum(0.5f)); + Reference > sigma = mp.GetFloatTexture("sigma", 0.f); + Reference > bumpMap = mp.GetFloatTexture("bumpmap", 0.f); + return new MatteMaterial(Kd, sigma, bumpMap); +} + + diff --git a/materials/matte.h b/materials/matte.h new file mode 100644 index 0000000..7206582 --- /dev/null +++ b/materials/matte.h @@ -0,0 +1,57 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_MATERIALS_MATTE_H +#define PBRT_MATERIALS_MATTE_H + +// materials/matte.h* +#include "pbrt.h" +#include "material.h" + +// MatteMaterial Declarations +class MatteMaterial : public Material { +public: + // MatteMaterial Public Methods + MatteMaterial(Reference > kd, + Reference > sig, + Reference > bump) + : Kd(kd), sigma(sig), bumpMap(bump) { + } + BSDF *GetBSDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, + MemoryArena &arena) const; +private: + // MatteMaterial Private Data + Reference > Kd; + Reference > sigma, bumpMap; +}; + + +MatteMaterial *CreateMatteMaterial(const Transform &xform, + const TextureParams &mp); + +#endif // PBRT_MATERIALS_MATTE_H diff --git a/materials/measured.cpp b/materials/measured.cpp new file mode 100644 index 0000000..f8ca1e1 --- /dev/null +++ b/materials/measured.cpp @@ -0,0 +1,206 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// materials/measured.cpp* +#include "stdafx.h" +#include "materials/measured.h" +#include "paramset.h" +#include "floatfile.h" + +/* + File format descriptions: + + -- Irregularly Sampled Isotropic BRDF -- + + This is the format of the BRDFs in the scenes/brdfs/ folder of the pbrt + distribution. This is a simple text format of numbers in a particular + format; the hash character # is used to denote a comment that continues + to the end of the current line. + + The first number in the file gives the number of wavelengths at which the + reflection data was measured, numWls. This is followed by numWls values + that give the frequency in nm of these wavelengths. Each BRDF + measurement is represented by 4+numWls values. The first two give the + (theta,phi) angles of the incident illumination direction, the next two + give (theta,phi) for the measured reflection direction, and the following + numWls give the spectral coefficients for the measurement at the + wavelength specified at the start of the file. + + + -- Regular Half-Angle BRDF -- + This is the file format used in the MERL BRDF database; see http://merl.com/brdf. + + This file format is a binary format, with numbers encoded in low-endian + form. It represents a regular 3D tabularization of BRDF samples in RGB + color where the dimensions indexed over are (delta phi, delta theta, + sqrt(theta_h)). Here, theta_h is the angle between the halfangle vector + and the normal, and delta theta and delta phi are the offset in theta and + phi of one of the two directions. (Note that the offset would be the + same for the other direction, since it's from the half-angle vector.) + + The starts with three 32-bit integers, giving the resolution of the + overall table. It then containes a number of samples equal to the + product of those three integers, times 3 (for RGB). Samples are laid out + with delta phi the minor index, then delta theta, then sqrt(theta_h) as + the major index. + + In the file each sample should be scaled by RGB(1500,1500,1500/1.6) of + the original measurement. (In order words, the sample values are scaled + by the inverse of that as they are read in. +*/ + + +// MeasuredMaterial Method Definitions +static map loadedRegularHalfangle; +static map *> loadedThetaPhi; +MeasuredMaterial::MeasuredMaterial(const string &filename, + Reference > bump) { + bumpMap = bump; + const char *suffix = strrchr(filename.c_str(), '.'); + regularHalfangleData = NULL; + thetaPhiData = NULL; + if (!suffix) + Error("No suffix in measured BRDF filename \"%s\". " + "Can't determine file type (.brdf / .merl)", filename.c_str()); + if (!strcmp(suffix, ".brdf") || !strcmp(suffix, ".BRDF")) { + // Load $(\theta, \phi)$ measured BRDF data + if (loadedThetaPhi.find(filename) != loadedThetaPhi.end()) { + thetaPhiData = loadedThetaPhi[filename]; + return; + } + + vector values; + if (!ReadFloatFile(filename.c_str(), &values)) + Error("Unable to read BRDF data from file \"%s\"", filename.c_str()); + + uint32_t pos = 0; + int numWls = int(values[pos++]); + if ((values.size() - 1 - numWls) % (4 + numWls) != 0) + Error("Excess or insufficient data in theta, phi BRDF file \"%s\"", + filename.c_str()); + vector wls; + for (int i = 0; i < numWls; ++i) + wls.push_back(values[pos++]); + + BBox bbox; + vector samples; + while (pos < values.size()) { + float thetai = values[pos++]; + float phii = values[pos++]; + float thetao = values[pos++]; + float phio = values[pos++]; + Vector wo = SphericalDirection(sinf(thetao), cosf(thetao), phio); + Vector wi = SphericalDirection(sinf(thetai), cosf(thetai), phii); + Spectrum s = Spectrum::FromSampled(&wls[0], &values[pos], numWls); + pos += numWls; + Point p = BRDFRemap(wo, wi); + samples.push_back(IrregIsotropicBRDFSample(p, s)); + bbox = Union(bbox, p); + } + loadedThetaPhi[filename] = thetaPhiData = new KdTree(samples); + } + else { + // Load RegularHalfangle BRDF Data + nThetaH = 90; + nThetaD = 90; + nPhiD = 180; + + if (loadedRegularHalfangle.find(filename) != loadedRegularHalfangle.end()) { + regularHalfangleData = loadedRegularHalfangle[filename]; + return; + } + + FILE *f = fopen(filename.c_str(), "rb"); + if (!f) { + Error("Unable to open BRDF data file \"%s\"", filename.c_str()); + return; + } + int dims[3]; + if (fread(dims, sizeof(int), 3, f) != 3) { + Error("Premature end-of-file in measured BRDF data file \"%s\"", + filename.c_str()); + fclose(f); + return; + } + uint32_t n = dims[0] * dims[1] * dims[2]; + if (n != nThetaH * nThetaD * nPhiD) { + Error("Dimensions don't match\n"); + fclose(f); + return; + } + + regularHalfangleData = new float[3*n]; + const uint32_t chunkSize = 2*nPhiD; + double *tmp = ALLOCA(double, chunkSize); + uint32_t nChunks = n / chunkSize; + Assert((n % chunkSize) == 0); + float scales[3] = { 1.f/1500.f, 1.15f/1500.f, 1.66f/1500.f }; + for (int c = 0; c < 3; ++c) { + int offset = 0; + for (uint32_t i = 0; i < nChunks; ++i) { + if (fread(tmp, sizeof(double), chunkSize, f) != chunkSize) { + Error("Premature end-of-file in measured BRDF data file \"%s\"", + filename.c_str()); + delete[] regularHalfangleData; + regularHalfangleData = NULL; + fclose(f); + return; + } + for (uint32_t j = 0; j < chunkSize; ++j) + regularHalfangleData[3 * offset++ + c] = max(0., tmp[j] * scales[c]); + } + } + + loadedRegularHalfangle[filename] = regularHalfangleData; + fclose(f); + } +} + + +BSDF *MeasuredMaterial::GetBSDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, + MemoryArena &arena) const { + // Allocate _BSDF_, possibly doing bump mapping with _bumpMap_ + DifferentialGeometry dgs; + if (bumpMap) + Bump(bumpMap, dgGeom, dgShading, &dgs); + else + dgs = dgShading; + BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn); + if (regularHalfangleData) + bsdf->Add(BSDF_ALLOC(arena, RegularHalfangleBRDF) + (regularHalfangleData, nThetaH, nThetaD, nPhiD)); + else if (thetaPhiData) + bsdf->Add(BSDF_ALLOC(arena, IrregIsotropicBRDF)(thetaPhiData)); + return bsdf; +} + + +MeasuredMaterial *CreateMeasuredMaterial(const Transform &xform, + const TextureParams &mp) { + Reference > bumpMap = mp.GetFloatTexture("bumpmap", 0.f); + return new MeasuredMaterial(mp.FindFilename("filename"), bumpMap); +} + + diff --git a/materials/measured.h b/materials/measured.h new file mode 100644 index 0000000..d1db699 --- /dev/null +++ b/materials/measured.h @@ -0,0 +1,57 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_MATERIALS_MEASURED_H +#define PBRT_MATERIALS_MEASURED_H + +// materials/measured.h* +#include "pbrt.h" +#include "material.h" +#include "reflection.h" +#include "kdtree.h" + +// MeasuredMaterial Declarations +class MeasuredMaterial : public Material { +public: + // MeasuredMaterial Public Methods + MeasuredMaterial(const string &filename, Reference > bump); + BSDF *GetBSDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, + MemoryArena &arena) const; +private: + // MeasuredMaterial Private Data + KdTree *thetaPhiData; + float *regularHalfangleData; + uint32_t nThetaH, nThetaD, nPhiD; + Reference > bumpMap; +}; + + +MeasuredMaterial *CreateMeasuredMaterial(const Transform &xform, + const TextureParams &mp); + +#endif // PBRT_MATERIALS_MEASURED_H diff --git a/materials/metal.cpp b/materials/metal.cpp new file mode 100644 index 0000000..1831ce0 --- /dev/null +++ b/materials/metal.cpp @@ -0,0 +1,102 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// materials/metal.cpp* +#include "stdafx.h" +#include "materials/metal.h" +#include "reflection.h" +#include "paramset.h" +#include "texture.h" + +// MetalMaterial Method Definitions +MetalMaterial::MetalMaterial(Reference > et, + Reference > kk, Reference > rough, + Reference > bump) { + eta = et; + k = kk; + roughness = rough; + bumpMap = bump; +} + + +BSDF *MetalMaterial::GetBSDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, MemoryArena &arena) const { + // Allocate _BSDF_, possibly doing bump mapping with _bumpMap_ + DifferentialGeometry dgs; + if (bumpMap) + Bump(bumpMap, dgGeom, dgShading, &dgs); + else + dgs = dgShading; + BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn); + + float rough = roughness->Evaluate(dgs); + MicrofacetDistribution *md = BSDF_ALLOC(arena, Blinn)(1.f / rough); + + Fresnel *frMf = BSDF_ALLOC(arena, FresnelConductor)(eta->Evaluate(dgs), + k->Evaluate(dgs)); + bsdf->Add(BSDF_ALLOC(arena, Microfacet)(1., frMf, md)); + return bsdf; +} + + +const int CopperSamples = 56; +const float CopperWavelengths[CopperSamples] = { + 298.7570554, 302.4004341, 306.1337728, 309.960445, 313.8839949, 317.9081487, 322.036826, + 326.2741526, 330.6244747, 335.092373, 339.6826795, 344.4004944, 349.2512056, 354.2405086, + 359.374429, 364.6593471, 370.1020239, 375.7096303, 381.4897785, 387.4505563, 393.6005651, + 399.9489613, 406.5055016, 413.2805933, 420.2853492, 427.5316483, 435.0322035, 442.8006357, + 450.8515564, 459.2006593, 467.8648226, 476.8622231, 486.2124627, 495.936712, 506.0578694, + 516.6007417, 527.5922468, 539.0616435, 551.0407911, 563.5644455, 576.6705953, 590.4008476, + 604.8008683, 619.92089, 635.8162974, 652.5483053, 670.1847459, 688.8009889, 708.4810171, + 729.3186941, 751.4192606, 774.9011125, 799.8979226, 826.5611867, 855.0632966, 885.6012714 }; + +const float CopperN[CopperSamples] = { + 1.400313, 1.38, 1.358438, 1.34, 1.329063, 1.325, 1.3325, 1.34, 1.334375, 1.325, + 1.317812, 1.31, 1.300313, 1.29, 1.281563, 1.27, 1.249062, 1.225, 1.2, 1.18, 1.174375, 1.175, + 1.1775, 1.18, 1.178125, 1.175, 1.172812, 1.17, 1.165312, 1.16, 1.155312, 1.15, 1.142812, 1.135, + 1.131562, 1.12, 1.092437, 1.04, 0.950375, 0.826, 0.645875, 0.468, 0.35125, 0.272, 0.230813, 0.214, + 0.20925, 0.213, 0.21625, 0.223, 0.2365, 0.25, 0.254188, 0.26, 0.28, 0.3 +}; + + + +const float CopperK[CopperSamples] = { + 1.662125, 1.687, 1.703313, 1.72, 1.744563, 1.77, 1.791625, 1.81, 1.822125, 1.834, + 1.85175, 1.872, 1.89425, 1.916, 1.931688, 1.95, 1.972438, 2.015, 2.121562, 2.21, 2.177188, 2.13, + 2.160063, 2.21, 2.249938, 2.289, 2.326, 2.362, 2.397625, 2.433, 2.469187, 2.504, 2.535875, 2.564, + 2.589625, 2.605, 2.595562, 2.583, 2.5765, 2.599, 2.678062, 2.809, 3.01075, 3.24, 3.458187, 3.67, + 3.863125, 4.05, 4.239563, 4.43, 4.619563, 4.817, 5.034125, 5.26, 5.485625, 5.717 }; +MetalMaterial *CreateMetalMaterial(const Transform &xform, const TextureParams &mp) { + static Spectrum copperN = Spectrum::FromSampled(CopperWavelengths, CopperN, CopperSamples); + Reference > eta = mp.GetSpectrumTexture("eta", copperN); + + static Spectrum copperK = Spectrum::FromSampled(CopperWavelengths, CopperK, CopperSamples); + Reference > k = mp.GetSpectrumTexture("k", copperK); + + Reference > roughness = mp.GetFloatTexture("roughness", .01f); + Reference > bumpMap = mp.GetFloatTexture("bumpmap", 0.f); + return new MetalMaterial(eta, k, roughness, bumpMap); +} + + diff --git a/materials/metal.h b/materials/metal.h new file mode 100644 index 0000000..a7af725 --- /dev/null +++ b/materials/metal.h @@ -0,0 +1,56 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_MATERIALS_METAL_H +#define PBRT_MATERIALS_METAL_H + +// materials/metal.h* +#include "pbrt.h" +#include "material.h" +#include "spectrum.h" + +// MetalMaterial Declarations +class MetalMaterial : public Material { +public: + // MetalMaterial Public Methods + MetalMaterial(Reference > eta, + Reference > k, Reference > rough, + Reference > bump); + BSDF *GetBSDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, MemoryArena &arena) const; +private: + // MetalMaterial Private Data + Reference > eta, k; + Reference > roughness; + Reference > bumpMap; +}; + + +MetalMaterial *CreateMetalMaterial(const Transform &xform, + const TextureParams &mp); + +#endif // PBRT_MATERIALS_METAL_H diff --git a/materials/mirror.cpp b/materials/mirror.cpp new file mode 100644 index 0000000..52fcd61 --- /dev/null +++ b/materials/mirror.cpp @@ -0,0 +1,57 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// materials/mirror.cpp* +#include "stdafx.h" +#include "materials/mirror.h" +#include "spectrum.h" +#include "reflection.h" +#include "paramset.h" +#include "texture.h" + +// MirrorMaterial Method Definitions +BSDF *MirrorMaterial::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) const { + // Allocate _BSDF_, possibly doing bump mapping with _bumpMap_ + DifferentialGeometry dgs; + if (bumpMap) + Bump(bumpMap, dgGeom, dgShading, &dgs); + else + dgs = dgShading; + BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn); + Spectrum R = Kr->Evaluate(dgs).Clamp(); + if (!R.IsBlack()) + bsdf->Add(BSDF_ALLOC(arena, SpecularReflection)(R, + BSDF_ALLOC(arena, FresnelNoOp)())); + return bsdf; +} + + +MirrorMaterial *CreateMirrorMaterial(const Transform &xform, + const TextureParams &mp) { + Reference > Kr = mp.GetSpectrumTexture("Kr", Spectrum(0.9f)); + Reference > bumpMap = mp.GetFloatTexture("bumpmap", 0.f); + return new MirrorMaterial(Kr, bumpMap); +} + + diff --git a/materials/mirror.h b/materials/mirror.h new file mode 100644 index 0000000..19cab59 --- /dev/null +++ b/materials/mirror.h @@ -0,0 +1,54 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_MATERIALS_MIRROR_H +#define PBRT_MATERIALS_MIRROR_H + +// materials/mirror.h* +#include "pbrt.h" +#include "material.h" + +// MirrorMaterial Declarations +class MirrorMaterial : public Material { +public: + // MirrorMaterial Public Methods + MirrorMaterial(Reference > r, Reference > bump) { + Kr = r; + bumpMap = bump; + } + BSDF *GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) const; +private: + // MirrorMaterial Private Data + Reference > Kr; + Reference > bumpMap; +}; + + +MirrorMaterial *CreateMirrorMaterial(const Transform &xform, + const TextureParams &mp); + +#endif // PBRT_MATERIALS_MIRROR_H diff --git a/materials/mixmat.cpp b/materials/mixmat.cpp new file mode 100644 index 0000000..e748cf4 --- /dev/null +++ b/materials/mixmat.cpp @@ -0,0 +1,59 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// materials/mixmat.cpp* +#include "stdafx.h" +#include "materials/mixmat.h" +#include "materials/matte.h" +#include "spectrum.h" +#include "reflection.h" +#include "paramset.h" +#include "texture.h" + +// MixMaterial Method Definitions +BSDF *MixMaterial::GetBSDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, + MemoryArena &arena) const { + BSDF *b1 = m1->GetBSDF(dgGeom, dgShading, arena); + BSDF *b2 = m2->GetBSDF(dgGeom, dgShading, arena); + Spectrum s1 = scale->Evaluate(dgShading).Clamp(); + Spectrum s2 = (Spectrum(1.f) - s1).Clamp(); + int n1 = b1->NumComponents(), n2 = b2->NumComponents(); + for (int i = 0; i < n1; ++i) + b1->bxdfs[i] = BSDF_ALLOC(arena, ScaledBxDF)(b1->bxdfs[i], s1); + for (int i = 0; i < n2; ++i) + b1->Add(BSDF_ALLOC(arena, ScaledBxDF)(b2->bxdfs[i], s2)); + return b1; +} + + +MixMaterial *CreateMixMaterial(const Transform &xform, + const TextureParams &mp, const Reference &m1, + const Reference &m2) { + Reference > scale = mp.GetSpectrumTexture("amount", + Spectrum(0.5f)); + return new MixMaterial(m1, m2, scale); +} + + diff --git a/materials/mixmat.h b/materials/mixmat.h new file mode 100644 index 0000000..0b86f56 --- /dev/null +++ b/materials/mixmat.h @@ -0,0 +1,57 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_MATERIALS_MIXMAT_H +#define PBRT_MATERIALS_MIXMAT_H + +// materials/mixmat.h* +#include "pbrt.h" +#include "material.h" + +// MixMaterial Declarations +class MixMaterial : public Material { +public: + // MixMaterial Public Methods + MixMaterial(Reference mat1, Reference mat2, + Reference > sc) + : m1(mat1), m2(mat2), scale(sc) { + } + BSDF *GetBSDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, + MemoryArena &arena) const; +private: + // MixMaterial Private Data + Reference m1, m2; + Reference > scale; +}; + + +MixMaterial *CreateMixMaterial(const Transform &xform, + const TextureParams &mp, const Reference &m1, + const Reference &m2); + +#endif // PBRT_MATERIALS_MIXMAT_H diff --git a/materials/plastic.cpp b/materials/plastic.cpp new file mode 100644 index 0000000..aa764f7 --- /dev/null +++ b/materials/plastic.cpp @@ -0,0 +1,66 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// materials/plastic.cpp* +#include "stdafx.h" +#include "materials/plastic.h" +#include "spectrum.h" +#include "reflection.h" +#include "paramset.h" +#include "texture.h" + +// PlasticMaterial Method Definitions +BSDF *PlasticMaterial::GetBSDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, + MemoryArena &arena) const { + // Allocate _BSDF_, possibly doing bump mapping with _bumpMap_ + DifferentialGeometry dgs; + if (bumpMap) + Bump(bumpMap, dgGeom, dgShading, &dgs); + else + dgs = dgShading; + BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn); + Spectrum kd = Kd->Evaluate(dgs).Clamp(); + BxDF *diff = BSDF_ALLOC(arena, Lambertian)(kd); + Fresnel *fresnel = BSDF_ALLOC(arena, FresnelDielectric)(1.5f, 1.f); + Spectrum ks = Ks->Evaluate(dgs).Clamp(); + float rough = roughness->Evaluate(dgs); + BxDF *spec = BSDF_ALLOC(arena, Microfacet) + (ks, fresnel, BSDF_ALLOC(arena, Blinn)(1.f / rough)); + bsdf->Add(diff); + bsdf->Add(spec); + return bsdf; +} + + +PlasticMaterial *CreatePlasticMaterial(const Transform &xform, + const TextureParams &mp) { + Reference > Kd = mp.GetSpectrumTexture("Kd", Spectrum(0.25f)); + Reference > Ks = mp.GetSpectrumTexture("Ks", Spectrum(0.25f)); + Reference > roughness = mp.GetFloatTexture("roughness", .1f); + Reference > bumpMap = mp.GetFloatTexture("bumpmap", 0.f); + return new PlasticMaterial(Kd, Ks, roughness, bumpMap); +} + + diff --git a/materials/plastic.h b/materials/plastic.h new file mode 100644 index 0000000..1e72c6f --- /dev/null +++ b/materials/plastic.h @@ -0,0 +1,58 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_MATERIALS_PLASTIC_H +#define PBRT_MATERIALS_PLASTIC_H + +// materials/plastic.h* +#include "pbrt.h" +#include "material.h" + +// PlasticMaterial Declarations +class PlasticMaterial : public Material { +public: + // PlasticMaterial Public Methods + PlasticMaterial(Reference > kd, + Reference > ks, + Reference > rough, + Reference > bump) + : Kd(kd), Ks(ks), roughness(rough), bumpMap(bump) { + } + BSDF *GetBSDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, + MemoryArena &arena) const; +private: + // PlasticMaterial Private Data + Reference > Kd, Ks; + Reference > roughness, bumpMap; +}; + + +PlasticMaterial *CreatePlasticMaterial(const Transform &xform, + const TextureParams &mp); + +#endif // PBRT_MATERIALS_PLASTIC_H diff --git a/materials/shinymetal.cpp b/materials/shinymetal.cpp new file mode 100644 index 0000000..4a34966 --- /dev/null +++ b/materials/shinymetal.cpp @@ -0,0 +1,75 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +// shinymetal.cpp* +#include "stdafx.h" +#include "materials/shinymetal.h" +#include "spectrum.h" +#include "reflection.h" +#include "paramset.h" +#include "texture.h" + +static inline Spectrum FresnelApproxEta(const Spectrum &Fr) { + Spectrum reflectance = Fr.Clamp(0.f, .999f); + return (Spectrum(1.) + Sqrt(reflectance)) / + (Spectrum(1.) - Sqrt(reflectance)); +} + +static inline Spectrum FresnelApproxK(const Spectrum &Fr) { + Spectrum reflectance = Fr.Clamp(0.f, .999f); + return 2.f * Sqrt(reflectance / (Spectrum(1.) - reflectance)); +} + + +// ShinyMetalMaterial Method Definitions +BSDF *ShinyMetalMaterial::GetBSDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, + MemoryArena &arena) const { + // Allocate _BSDF_, possibly doing bump-mapping with _bumpMap_ + DifferentialGeometry dgs; + if (bumpMap) + Bump(bumpMap, dgGeom, dgShading, &dgs); + else + dgs = dgShading; + BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn); + Spectrum spec = Ks->Evaluate(dgs).Clamp(); + float rough = roughness->Evaluate(dgs); + Spectrum R = Kr->Evaluate(dgs).Clamp(); + + MicrofacetDistribution *md = BSDF_ALLOC(arena, Blinn)(1.f / rough); + Spectrum k = 0.; + Fresnel *frMf = BSDF_ALLOC(arena, FresnelConductor)(FresnelApproxEta(spec), k); + Fresnel *frSr = BSDF_ALLOC(arena, FresnelConductor)(FresnelApproxEta(R), k); + bsdf->Add(BSDF_ALLOC(arena, Microfacet)(1., frMf, md)); + bsdf->Add(BSDF_ALLOC(arena, SpecularReflection)(1., frSr)); + return bsdf; +} + +ShinyMetalMaterial *CreateShinyMetalMaterial(const Transform &xform, + const TextureParams &mp) { + Reference > Kr = mp.GetSpectrumTexture("Kr", Spectrum(1.f)); + Reference > Ks = mp.GetSpectrumTexture("Ks", Spectrum(1.f)); + Reference > roughness = mp.GetFloatTexture("roughness", .1f); + Reference > bumpMap = mp.GetFloatTexture("bumpmap", 0.f); + return new ShinyMetalMaterial(Ks, roughness, Kr, bumpMap); +} diff --git a/materials/shinymetal.h b/materials/shinymetal.h new file mode 100644 index 0000000..a7c79b4 --- /dev/null +++ b/materials/shinymetal.h @@ -0,0 +1,57 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_MATERIALS_SHINYMETAL_H +#define PBRT_MATERIALS_SHINYMETAL_H + +#include "pbrt.h" +#include "material.h" + +// ShinyMetalMaterial Class Declarations +class ShinyMetalMaterial : public Material { +public: + // ShinyMetalMaterial Public Methods + ShinyMetalMaterial(const Reference > &ks, + const Reference > &rough, + const Reference > &kr, + const Reference > &bump) + : Ks(ks), Kr(kr), roughness(rough), bumpMap(bump) { + } + BSDF *GetBSDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, + MemoryArena &arena) const; +private: + // ShinyMetalMaterial Private Data + Reference > Ks, Kr; + Reference > roughness; + Reference > bumpMap; +}; + +ShinyMetalMaterial *CreateShinyMetalMaterial(const Transform &xform, + const TextureParams &mp); + +#endif // PBRT_MATERIALS_SHINYMETAL_H diff --git a/materials/substrate.cpp b/materials/substrate.cpp new file mode 100644 index 0000000..dcdeec7 --- /dev/null +++ b/materials/substrate.cpp @@ -0,0 +1,62 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// materials/substrate.cpp* +#include "stdafx.h" +#include "materials/substrate.h" +#include "spectrum.h" +#include "reflection.h" +#include "paramset.h" +#include "texture.h" + +// SubstrateMaterial Method Definitions +BSDF *SubstrateMaterial::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) const { + // Allocate _BSDF_, possibly doing bump mapping with _bumpMap_ + DifferentialGeometry dgs; + if (bumpMap) + Bump(bumpMap, dgGeom, dgShading, &dgs); + else + dgs = dgShading; + BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn); + Spectrum d = Kd->Evaluate(dgs).Clamp(); + Spectrum s = Ks->Evaluate(dgs).Clamp(); + float u = nu->Evaluate(dgs); + float v = nv->Evaluate(dgs); + + bsdf->Add(BSDF_ALLOC(arena, FresnelBlend)(d, s, BSDF_ALLOC(arena, Anisotropic)(1.f/u, 1.f/v))); + return bsdf; +} + + +SubstrateMaterial *CreateSubstrateMaterial(const Transform &xform, + const TextureParams &mp) { + Reference > Kd = mp.GetSpectrumTexture("Kd", Spectrum(.5f)); + Reference > Ks = mp.GetSpectrumTexture("Ks", Spectrum(.5f)); + Reference > uroughness = mp.GetFloatTexture("uroughness", .1f); + Reference > vroughness = mp.GetFloatTexture("vroughness", .1f); + Reference > bumpMap = mp.GetFloatTexture("bumpmap", 0.f); + return new SubstrateMaterial(Kd, Ks, uroughness, vroughness, bumpMap); +} + + diff --git a/materials/substrate.h b/materials/substrate.h new file mode 100644 index 0000000..c6a5769 --- /dev/null +++ b/materials/substrate.h @@ -0,0 +1,60 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_MATERIALS_SUBSTRATE_H +#define PBRT_MATERIALS_SUBSTRATE_H + +// materials/substrate.h* +#include "pbrt.h" +#include "material.h" + +// SubstrateMaterial Declarations +class SubstrateMaterial : public Material { +public: + // SubstrateMaterial Public Methods + SubstrateMaterial(Reference > kd, Reference > ks, + Reference > u, Reference > v, + Reference > bump) { + Kd = kd; + Ks = ks; + nu = u; + nv = v; + bumpMap = bump; + } + BSDF *GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) const; +private: + // SubstrateMaterial Private Data + Reference > Kd, Ks; + Reference > nu, nv; + Reference > bumpMap; +}; + + +SubstrateMaterial *CreateSubstrateMaterial(const Transform &xform, + const TextureParams &mp); + +#endif // PBRT_MATERIALS_SUBSTRATE_H diff --git a/materials/subsurface.cpp b/materials/subsurface.cpp new file mode 100644 index 0000000..0e70db7 --- /dev/null +++ b/materials/subsurface.cpp @@ -0,0 +1,81 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// materials/subsurface.cpp* +#include "stdafx.h" +#include "materials/subsurface.h" +#include "textures/constant.h" +#include "volume.h" +#include "spectrum.h" +#include "reflection.h" +#include "texture.h" +#include "paramset.h" + +// SubsurfaceMaterial Method Definitions +BSDF *SubsurfaceMaterial::GetBSDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, MemoryArena &arena) const { + // Allocate _BSDF_, possibly doing bump mapping with _bumpMap_ + DifferentialGeometry dgs; + if (bumpMap) + Bump(bumpMap, dgGeom, dgShading, &dgs); + else + dgs = dgShading; + BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn); + Spectrum R = Kr->Evaluate(dgs).Clamp(); + float e = eta->Evaluate(dgs); + if (!R.IsBlack()) + bsdf->Add(BSDF_ALLOC(arena, SpecularReflection)(R, + BSDF_ALLOC(arena, FresnelDielectric)(1., e))); + return bsdf; +} + + +BSSRDF *SubsurfaceMaterial::GetBSSRDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, MemoryArena &arena) const { + float e = eta->Evaluate(dgShading); + return BSDF_ALLOC(arena, BSSRDF)(scale * sigma_a->Evaluate(dgShading), + scale * sigma_prime_s->Evaluate(dgShading), e); +} + + +SubsurfaceMaterial *CreateSubsurfaceMaterial(const Transform &xform, + const TextureParams &mp) { + float sa_rgb[3] = { .0011f, .0024f, .014f }, sps_rgb[3] = { 2.55f, 3.21f, 3.77f }; + Spectrum sa = Spectrum::FromRGB(sa_rgb), sps = Spectrum::FromRGB(sps_rgb); + string name = mp.FindString("name"); + bool found = GetVolumeScatteringProperties(name, &sa, &sps); + if (name != "" && !found) + Warning("Named material \"%s\" not found. Using defaults.", name.c_str()); + float scale = mp.FindFloat("scale", 1.f); + + Reference > sigma_a, sigma_prime_s; + sigma_a = mp.GetSpectrumTexture("sigma_a", sa); + sigma_prime_s = mp.GetSpectrumTexture("sigma_prime_s", sps); + Reference > ior = mp.GetFloatTexture("index", 1.3f); + Reference > Kr = mp.GetSpectrumTexture("Kr", Spectrum(1.f)); + Reference > bumpMap = mp.GetFloatTexture("bumpmap", 0.f); + return new SubsurfaceMaterial(scale, Kr, sigma_a, sigma_prime_s, ior, bumpMap); +} + + diff --git a/materials/subsurface.h b/materials/subsurface.h new file mode 100644 index 0000000..6bb4624 --- /dev/null +++ b/materials/subsurface.h @@ -0,0 +1,68 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_MATERIALS_SUBSURFACE_H +#define PBRT_MATERIALS_SUBSURFACE_H + +// materials/subsurface.h* +#include "pbrt.h" +#include "material.h" + +// SubsurfaceMaterial Declarations +class SubsurfaceMaterial : public Material { +public: + // SubsurfaceMaterial Public Methods + SubsurfaceMaterial(float sc, Reference > kr, + Reference > sa, + Reference > sps, + Reference > e, + Reference > bump) { + scale = sc; + Kr = kr; + sigma_a = sa; + sigma_prime_s = sps; + eta = e; + bumpMap = bump; + } + BSDF *GetBSDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, + MemoryArena &arena) const; + BSSRDF *GetBSSRDF(const DifferentialGeometry &dgGeom, + const DifferentialGeometry &dgShading, + MemoryArena &arena) const; +private: + // SubsurfaceMaterial Private Data + float scale; + Reference > Kr, sigma_a, sigma_prime_s; + Reference > eta, bumpMap; +}; + + +SubsurfaceMaterial *CreateSubsurfaceMaterial(const Transform &xform, + const TextureParams &mp); + +#endif // PBRT_MATERIALS_SUBSURFACE_H diff --git a/materials/translucent.cpp b/materials/translucent.cpp new file mode 100644 index 0000000..4598a87 --- /dev/null +++ b/materials/translucent.cpp @@ -0,0 +1,81 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// materials/translucent.cpp* +#include "stdafx.h" +#include "materials/translucent.h" +#include "spectrum.h" +#include "reflection.h" +#include "paramset.h" +#include "texture.h" + +// TranslucentMaterial Method Definitions +BSDF *TranslucentMaterial::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) const { + float ior = 1.5f; + DifferentialGeometry dgs; + if (bumpMap) + Bump(bumpMap, dgGeom, dgShading, &dgs); + else + dgs = dgShading; + BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn, ior); + + Spectrum r = reflect->Evaluate(dgs).Clamp(); + Spectrum t = transmit->Evaluate(dgs).Clamp(); + if (r.IsBlack() && t.IsBlack()) return bsdf; + + Spectrum kd = Kd->Evaluate(dgs).Clamp(); + if (!kd.IsBlack()) { + if (!r.IsBlack()) bsdf->Add(BSDF_ALLOC(arena, Lambertian)(r * kd)); + if (!t.IsBlack()) bsdf->Add(BSDF_ALLOC(arena, BRDFToBTDF)(BSDF_ALLOC(arena, Lambertian)(t * kd))); + } + Spectrum ks = Ks->Evaluate(dgs).Clamp(); + if (!ks.IsBlack()) { + float rough = roughness->Evaluate(dgs); + if (!r.IsBlack()) { + Fresnel *fresnel = BSDF_ALLOC(arena, FresnelDielectric)(ior, 1.f); + bsdf->Add(BSDF_ALLOC(arena, Microfacet)(r * ks, fresnel, + BSDF_ALLOC(arena, Blinn)(1.f / rough))); + } + if (!t.IsBlack()) { + Fresnel *fresnel = BSDF_ALLOC(arena, FresnelDielectric)(ior, 1.f); + bsdf->Add(BSDF_ALLOC(arena, BRDFToBTDF)(BSDF_ALLOC(arena, Microfacet)(t * ks, fresnel, + BSDF_ALLOC(arena, Blinn)(1.f / rough)))); + } + } + return bsdf; +} + + +TranslucentMaterial *CreateTranslucentMaterial(const Transform &xform, + const TextureParams &mp) { + Reference > Kd = mp.GetSpectrumTexture("Kd", Spectrum(0.25f)); + Reference > Ks = mp.GetSpectrumTexture("Ks", Spectrum(0.25f)); + Reference > reflect = mp.GetSpectrumTexture("reflect", Spectrum(0.5f)); + Reference > transmit = mp.GetSpectrumTexture("transmit", Spectrum(0.5f)); + Reference > roughness = mp.GetFloatTexture("roughness", .1f); + Reference > bumpMap = mp.GetFloatTexture("bumpmap", 0.f); + return new TranslucentMaterial(Kd, Ks, roughness, reflect, transmit, bumpMap); +} + + diff --git a/materials/translucent.h b/materials/translucent.h new file mode 100644 index 0000000..e028e1c --- /dev/null +++ b/materials/translucent.h @@ -0,0 +1,65 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_MATERIALS_TRANSLUCENT_H +#define PBRT_MATERIALS_TRANSLUCENT_H + +// materials/translucent.h* +#include "pbrt.h" +#include "material.h" + +// TranslucentMaterial Declarations +class TranslucentMaterial : public Material { +public: + // TranslucentMaterial Public Methods + TranslucentMaterial(Reference > kd, Reference > ks, + Reference > rough, + Reference > refl, + Reference > trans, + Reference > bump) { + Kd = kd; + Ks = ks; + roughness = rough; + reflect = refl; + transmit = trans; + bumpMap = bump; + } + BSDF *GetBSDF(const DifferentialGeometry &dgGeom, const + DifferentialGeometry &dgShading, MemoryArena &arena) const; +private: + // TranslucentMaterial Private Data + Reference > Kd, Ks; + Reference > roughness; + Reference > reflect, transmit; + Reference > bumpMap; +}; + + +TranslucentMaterial *CreateTranslucentMaterial(const Transform &xform, + const TextureParams &mp); + +#endif // PBRT_MATERIALS_TRANSLUCENT_H diff --git a/materials/uber.cpp b/materials/uber.cpp new file mode 100644 index 0000000..30b4720 --- /dev/null +++ b/materials/uber.cpp @@ -0,0 +1,91 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// materials/uber.cpp* +#include "stdafx.h" +#include "materials/uber.h" +#include "spectrum.h" +#include "reflection.h" +#include "texture.h" +#include "paramset.h" + +// UberMaterial Method Definitions +BSDF *UberMaterial::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) const { + // Allocate _BSDF_, possibly doing bump mapping with _bumpMap_ + DifferentialGeometry dgs; + if (bumpMap) + Bump(bumpMap, dgGeom, dgShading, &dgs); + else + dgs = dgShading; + BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn); + + Spectrum op = opacity->Evaluate(dgs).Clamp(); + if (op != Spectrum(1.)) { + BxDF *tr = BSDF_ALLOC(arena, SpecularTransmission)(-op + Spectrum(1.), 1., 1.); + bsdf->Add(tr); + } + + Spectrum kd = op * Kd->Evaluate(dgs).Clamp(); + if (!kd.IsBlack()) { + BxDF *diff = BSDF_ALLOC(arena, Lambertian)(kd); + bsdf->Add(diff); + } + + float e = eta->Evaluate(dgs); + Spectrum ks = op * Ks->Evaluate(dgs).Clamp(); + if (!ks.IsBlack()) { + Fresnel *fresnel = BSDF_ALLOC(arena, FresnelDielectric)(e, 1.f); + float rough = roughness->Evaluate(dgs); + BxDF *spec = BSDF_ALLOC(arena, Microfacet)(ks, fresnel, BSDF_ALLOC(arena, Blinn)(1.f / rough)); + bsdf->Add(spec); + } + + Spectrum kr = op * Kr->Evaluate(dgs).Clamp(); + if (!kr.IsBlack()) { + Fresnel *fresnel = BSDF_ALLOC(arena, FresnelDielectric)(e, 1.f); + bsdf->Add(BSDF_ALLOC(arena, SpecularReflection)(kr, fresnel)); + } + + Spectrum kt = op * Kt->Evaluate(dgs).Clamp(); + if (!kt.IsBlack()) + bsdf->Add(BSDF_ALLOC(arena, SpecularTransmission)(kt, e, 1.f)); + + return bsdf; +} + + +UberMaterial *CreateUberMaterial(const Transform &xform, + const TextureParams &mp) { + Reference > Kd = mp.GetSpectrumTexture("Kd", Spectrum(0.25f)); + Reference > Ks = mp.GetSpectrumTexture("Ks", Spectrum(0.25f)); + Reference > Kr = mp.GetSpectrumTexture("Kr", Spectrum(0.f)); + Reference > Kt = mp.GetSpectrumTexture("Kt", Spectrum(0.f)); + Reference > roughness = mp.GetFloatTexture("roughness", .1f); + Reference > eta = mp.GetFloatTexture("index", 1.5f); + Reference > opacity = mp.GetSpectrumTexture("opacity", 1.f); + Reference > bumpMap = mp.GetFloatTexture("bumpmap", 0.f); + return new UberMaterial(Kd, Ks, Kr, Kt, roughness, opacity, eta, bumpMap); +} + + diff --git a/materials/uber.h b/materials/uber.h new file mode 100644 index 0000000..f0c8962 --- /dev/null +++ b/materials/uber.h @@ -0,0 +1,66 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_MATERIALS_UBER_H +#define PBRT_MATERIALS_UBER_H + +// materials/uber.h* +#include "pbrt.h" +#include "material.h" + +// UberMaterial Declarations +class UberMaterial : public Material { +public: + UberMaterial(Reference > kd, + Reference > ks, + Reference > kr, + Reference > kt, + Reference > rough, + Reference > op, + Reference > e, + Reference > bump) { + Kd = kd; + Ks = ks; + Kr = kr; + Kt = kt; + roughness = rough; + opacity = op; + eta = e; + bumpMap = bump; + } + BSDF *GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) const; +private: + // UberMaterial Private Data + Reference > Kd, Ks, Kr, Kt, opacity; + Reference > roughness, eta, bumpMap; +}; + + +UberMaterial *CreateUberMaterial(const Transform &xform, + const TextureParams &mp); + +#endif // PBRT_MATERIALS_UBER_H diff --git a/pbrt.exr b/pbrt.exr new file mode 100644 index 0000000..6d957a4 Binary files /dev/null and b/pbrt.exr differ diff --git a/pbrt.xcodeproj/project.pbxproj b/pbrt.xcodeproj/project.pbxproj new file mode 100644 index 0000000..a4aa0e9 --- /dev/null +++ b/pbrt.xcodeproj/project.pbxproj @@ -0,0 +1,1121 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + B130248E1236EE5100206AC7 /* fileutil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B130248C1236EE5100206AC7 /* fileutil.cpp */; }; + B19397BB12083210008317C5 /* shinymetal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B19397B912083210008317C5 /* shinymetal.cpp */; }; + B1D8EB5A117030DE00A8A49E /* bvh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB54117030DE00A8A49E /* bvh.cpp */; }; + B1D8EB5B117030DE00A8A49E /* grid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB56117030DE00A8A49E /* grid.cpp */; }; + B1D8EB5C117030DE00A8A49E /* kdtreeaccel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB58117030DE00A8A49E /* kdtreeaccel.cpp */; }; + B1D8EB64117030E500A8A49E /* environment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB5E117030E500A8A49E /* environment.cpp */; }; + B1D8EB65117030E500A8A49E /* orthographic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB60117030E500A8A49E /* orthographic.cpp */; }; + B1D8EB66117030E500A8A49E /* perspective.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB62117030E500A8A49E /* perspective.cpp */; }; + B1D8EBB4117030F200A8A49E /* api.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB68117030F200A8A49E /* api.cpp */; }; + B1D8EBB5117030F200A8A49E /* camera.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB6A117030F200A8A49E /* camera.cpp */; }; + B1D8EBB6117030F200A8A49E /* diffgeom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB6C117030F200A8A49E /* diffgeom.cpp */; }; + B1D8EBB7117030F200A8A49E /* dtrace.d in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB6E117030F200A8A49E /* dtrace.d */; }; + B1D8EBB8117030F200A8A49E /* error.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB6F117030F200A8A49E /* error.cpp */; }; + B1D8EBB9117030F200A8A49E /* film.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB71117030F200A8A49E /* film.cpp */; }; + B1D8EBBA117030F200A8A49E /* filter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB73117030F200A8A49E /* filter.cpp */; }; + B1D8EBBB117030F200A8A49E /* floatfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB75117030F200A8A49E /* floatfile.cpp */; }; + B1D8EBBC117030F200A8A49E /* geometry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB77117030F200A8A49E /* geometry.cpp */; }; + B1D8EBBD117030F200A8A49E /* imageio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB79117030F200A8A49E /* imageio.cpp */; }; + B1D8EBBE117030F200A8A49E /* integrator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB7B117030F200A8A49E /* integrator.cpp */; }; + B1D8EBBF117030F200A8A49E /* intersection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB7D117030F200A8A49E /* intersection.cpp */; }; + B1D8EBC0117030F200A8A49E /* light.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB80117030F200A8A49E /* light.cpp */; }; + B1D8EBC1117030F200A8A49E /* material.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB82117030F200A8A49E /* material.cpp */; }; + B1D8EBC2117030F200A8A49E /* memory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB84117030F200A8A49E /* memory.cpp */; }; + B1D8EBC3117030F200A8A49E /* montecarlo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB87117030F200A8A49E /* montecarlo.cpp */; }; + B1D8EBC4117030F200A8A49E /* parallel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB8A117030F200A8A49E /* parallel.cpp */; }; + B1D8EBC5117030F200A8A49E /* paramset.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB8C117030F200A8A49E /* paramset.cpp */; }; + B1D8EBC6117030F200A8A49E /* parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB8E117030F200A8A49E /* parser.cpp */; }; + B1D8EBC7117030F200A8A49E /* pbrtlex.ll in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB91117030F200A8A49E /* pbrtlex.ll */; }; + B1D8EBC8117030F200A8A49E /* primitive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB93117030F200A8A49E /* primitive.cpp */; }; + B1D8EBC9117030F200A8A49E /* probes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB95117030F200A8A49E /* probes.cpp */; }; + B1D8EBCA117030F200A8A49E /* progressreporter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB97117030F200A8A49E /* progressreporter.cpp */; }; + B1D8EBCB117030F200A8A49E /* quaternion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB99117030F200A8A49E /* quaternion.cpp */; }; + B1D8EBCC117030F200A8A49E /* reflection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB9B117030F200A8A49E /* reflection.cpp */; }; + B1D8EBCD117030F200A8A49E /* renderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB9D117030F200A8A49E /* renderer.cpp */; }; + B1D8EBCE117030F200A8A49E /* rng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB9F117030F200A8A49E /* rng.cpp */; }; + B1D8EBCF117030F200A8A49E /* sampler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBA1117030F200A8A49E /* sampler.cpp */; }; + B1D8EBD0117030F200A8A49E /* scene.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBA3117030F200A8A49E /* scene.cpp */; }; + B1D8EBD1117030F200A8A49E /* sh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBA5117030F200A8A49E /* sh.cpp */; }; + B1D8EBD2117030F200A8A49E /* shape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBA7117030F200A8A49E /* shape.cpp */; }; + B1D8EBD3117030F200A8A49E /* shrots.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBA9117030F200A8A49E /* shrots.cpp */; }; + B1D8EBD4117030F200A8A49E /* spectrum.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBAA117030F200A8A49E /* spectrum.cpp */; }; + B1D8EBD5117030F200A8A49E /* texture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBAC117030F200A8A49E /* texture.cpp */; }; + B1D8EBD6117030F200A8A49E /* timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBAE117030F200A8A49E /* timer.cpp */; }; + B1D8EBD7117030F200A8A49E /* transform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBB0117030F200A8A49E /* transform.cpp */; }; + B1D8EBD8117030F200A8A49E /* volume.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBB2117030F200A8A49E /* volume.cpp */; }; + B1D8EC7D1170310E00A8A49E /* image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBDA1170310E00A8A49E /* image.cpp */; }; + B1D8EC7E1170310E00A8A49E /* box.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBDD1170310E00A8A49E /* box.cpp */; }; + B1D8EC7F1170310E00A8A49E /* gaussian.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBDF1170310E00A8A49E /* gaussian.cpp */; }; + B1D8EC801170310E00A8A49E /* mitchell.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBE11170310E00A8A49E /* mitchell.cpp */; }; + B1D8EC811170310E00A8A49E /* sinc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBE31170310E00A8A49E /* sinc.cpp */; }; + B1D8EC821170310E00A8A49E /* triangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBE51170310E00A8A49E /* triangle.cpp */; }; + B1D8EC831170310E00A8A49E /* ambientocclusion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBE81170310E00A8A49E /* ambientocclusion.cpp */; }; + B1D8EC841170310E00A8A49E /* diffuseprt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBEA1170310E00A8A49E /* diffuseprt.cpp */; }; + B1D8EC851170310E00A8A49E /* dipolesubsurface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBEC1170310E00A8A49E /* dipolesubsurface.cpp */; }; + B1D8EC861170310E00A8A49E /* directlighting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBEE1170310E00A8A49E /* directlighting.cpp */; }; + B1D8EC871170310E00A8A49E /* emission.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBF01170310E00A8A49E /* emission.cpp */; }; + B1D8EC881170310E00A8A49E /* glossyprt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBF21170310E00A8A49E /* glossyprt.cpp */; }; + B1D8EC891170310E00A8A49E /* igi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBF41170310E00A8A49E /* igi.cpp */; }; + B1D8EC8A1170310E00A8A49E /* irradiancecache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBF61170310E00A8A49E /* irradiancecache.cpp */; }; + B1D8EC8B1170310E00A8A49E /* path.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBF81170310E00A8A49E /* path.cpp */; }; + B1D8EC8C1170310E00A8A49E /* photonmap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBFA1170310E00A8A49E /* photonmap.cpp */; }; + B1D8EC8D1170310E00A8A49E /* single.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBFC1170310E00A8A49E /* single.cpp */; }; + B1D8EC8E1170310E00A8A49E /* useprobes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EBFE1170310E00A8A49E /* useprobes.cpp */; }; + B1D8EC8F1170310E00A8A49E /* whitted.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC001170310E00A8A49E /* whitted.cpp */; }; + B1D8EC901170310E00A8A49E /* diffuse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC031170310E00A8A49E /* diffuse.cpp */; }; + B1D8EC911170310E00A8A49E /* distant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC051170310E00A8A49E /* distant.cpp */; }; + B1D8EC931170310E00A8A49E /* goniometric.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC091170310E00A8A49E /* goniometric.cpp */; }; + B1D8EC941170310E00A8A49E /* infinite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC0B1170310E00A8A49E /* infinite.cpp */; }; + B1D8EC951170310E00A8A49E /* point.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC0D1170310E00A8A49E /* point.cpp */; }; + B1D8EC961170310E00A8A49E /* projection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC0F1170310E00A8A49E /* projection.cpp */; }; + B1D8EC971170310E00A8A49E /* spot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC111170310E00A8A49E /* spot.cpp */; }; + B1D8EC981170310E00A8A49E /* pbrt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC141170310E00A8A49E /* pbrt.cpp */; }; + B1D8EC991170310E00A8A49E /* glass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC161170310E00A8A49E /* glass.cpp */; }; + B1D8EC9A1170310E00A8A49E /* kdsubsurface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC181170310E00A8A49E /* kdsubsurface.cpp */; }; + B1D8EC9B1170310E00A8A49E /* matte.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC1A1170310E00A8A49E /* matte.cpp */; }; + B1D8EC9C1170310E00A8A49E /* measured.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC1C1170310E00A8A49E /* measured.cpp */; }; + B1D8EC9D1170310E00A8A49E /* metal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC1E1170310E00A8A49E /* metal.cpp */; }; + B1D8EC9E1170310E00A8A49E /* mirror.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC201170310E00A8A49E /* mirror.cpp */; }; + B1D8EC9F1170310E00A8A49E /* mixmat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC221170310E00A8A49E /* mixmat.cpp */; }; + B1D8ECA01170310E00A8A49E /* plastic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC241170310E00A8A49E /* plastic.cpp */; }; + B1D8ECA11170310E00A8A49E /* substrate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC261170310E00A8A49E /* substrate.cpp */; }; + B1D8ECA21170310E00A8A49E /* subsurface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC281170310E00A8A49E /* subsurface.cpp */; }; + B1D8ECA31170310E00A8A49E /* translucent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC2A1170310E00A8A49E /* translucent.cpp */; }; + B1D8ECA41170310E00A8A49E /* uber.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC2C1170310E00A8A49E /* uber.cpp */; }; + B1D8ECA51170310E00A8A49E /* aggregatetest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC301170310E00A8A49E /* aggregatetest.cpp */; }; + B1D8ECA61170310E00A8A49E /* createprobes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC321170310E00A8A49E /* createprobes.cpp */; }; + B1D8ECA71170310E00A8A49E /* metropolis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC341170310E00A8A49E /* metropolis.cpp */; }; + B1D8ECA81170310E00A8A49E /* samplerrenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC361170310E00A8A49E /* samplerrenderer.cpp */; }; + B1D8ECA91170310E00A8A49E /* surfacepoints.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC381170310E00A8A49E /* surfacepoints.cpp */; }; + B1D8ECAA1170310E00A8A49E /* adaptive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC3B1170310E00A8A49E /* adaptive.cpp */; }; + B1D8ECAB1170310E00A8A49E /* bestcandidate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC3D1170310E00A8A49E /* bestcandidate.cpp */; }; + B1D8ECAC1170310E00A8A49E /* halton.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC3F1170310E00A8A49E /* halton.cpp */; }; + B1D8ECAD1170310E00A8A49E /* lowdiscrepancy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC411170310E00A8A49E /* lowdiscrepancy.cpp */; }; + B1D8ECAE1170310E00A8A49E /* random.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC431170310E00A8A49E /* random.cpp */; }; + B1D8ECAF1170310E00A8A49E /* stratified.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC461170310E00A8A49E /* stratified.cpp */; }; + B1D8ECB01170310E00A8A49E /* cone.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC491170310E00A8A49E /* cone.cpp */; }; + B1D8ECB11170310E00A8A49E /* cylinder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC4B1170310E00A8A49E /* cylinder.cpp */; }; + B1D8ECB21170310E00A8A49E /* disk.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC4D1170310E00A8A49E /* disk.cpp */; }; + B1D8ECB31170310E00A8A49E /* heightfield.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC4F1170310E00A8A49E /* heightfield.cpp */; }; + B1D8ECB41170310E00A8A49E /* hyperboloid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC511170310E00A8A49E /* hyperboloid.cpp */; }; + B1D8ECB51170310E00A8A49E /* loopsubdiv.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC531170310E00A8A49E /* loopsubdiv.cpp */; }; + B1D8ECB61170310E00A8A49E /* nurbs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC551170310E00A8A49E /* nurbs.cpp */; }; + B1D8ECB71170310E00A8A49E /* paraboloid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC571170310E00A8A49E /* paraboloid.cpp */; }; + B1D8ECB81170310E00A8A49E /* sphere.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC591170310E00A8A49E /* sphere.cpp */; }; + B1D8ECB91170310E00A8A49E /* trianglemesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC5B1170310E00A8A49E /* trianglemesh.cpp */; }; + B1D8ECBA1170310E00A8A49E /* bilerp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC5E1170310E00A8A49E /* bilerp.cpp */; }; + B1D8ECBB1170310E00A8A49E /* checkerboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC601170310E00A8A49E /* checkerboard.cpp */; }; + B1D8ECBC1170310E00A8A49E /* constant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC621170310E00A8A49E /* constant.cpp */; }; + B1D8ECBD1170310E00A8A49E /* dots.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC641170310E00A8A49E /* dots.cpp */; }; + B1D8ECBE1170310E00A8A49E /* fbm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC661170310E00A8A49E /* fbm.cpp */; }; + B1D8ECBF1170310E00A8A49E /* imagemap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC681170310E00A8A49E /* imagemap.cpp */; }; + B1D8ECC01170310E00A8A49E /* marble.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC6A1170310E00A8A49E /* marble.cpp */; }; + B1D8ECC11170310E00A8A49E /* mix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC6C1170310E00A8A49E /* mix.cpp */; }; + B1D8ECC21170310E00A8A49E /* scale.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC6E1170310E00A8A49E /* scale.cpp */; }; + B1D8ECC31170310E00A8A49E /* uv.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC701170310E00A8A49E /* uv.cpp */; }; + B1D8ECC41170310E00A8A49E /* windy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC721170310E00A8A49E /* windy.cpp */; }; + B1D8ECC51170310E00A8A49E /* wrinkled.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC741170310E00A8A49E /* wrinkled.cpp */; }; + B1D8ECC61170310E00A8A49E /* exponential.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC771170310E00A8A49E /* exponential.cpp */; }; + B1D8ECC71170310E00A8A49E /* homogeneous.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC791170310E00A8A49E /* homogeneous.cpp */; }; + B1D8ECC81170310E00A8A49E /* volumegrid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EC7B1170310E00A8A49E /* volumegrid.cpp */; }; + B1E1BB3F1177B63E00337ECE /* pbrtparse.yy in Sources */ = {isa = PBXBuildFile; fileRef = B1D8EB92117030F200A8A49E /* pbrtparse.yy */; }; +/* End PBXBuildFile section */ + +/* Begin PBXBuildRule section */ + B1E1BB511177B8CF00337ECE /* PBXBuildRule */ = { + isa = PBXBuildRule; + compilerSpec = com.apple.compilers.proxy.script; + fileType = sourcecode.yacc; + isEditable = 1; + outputFiles = ( + "$(DERIVED_FILES_DIR)/Yacc/$(INPUT_FILE_BASE).hpp", + "$(DERIVED_FILES_DIR)/Yacc/$(INPUT_FILE_BASE).cpp", + ); + script = "cd \"$DERIVED_FILES_DIR/Yacc\" && /usr/bin/bison -d -v -t \"$INPUT_FILE_PATH\" -o \"$DERIVED_FILES_DIR/Yacc/$INPUT_FILE_BASE.cpp\" && /bin/mv \"$DERIVED_FILES_DIR/Yacc/$INPUT_FILE_BASE.hpp\" \"$DERIVED_FILES_DIR/Yacc/$INPUT_FILE_BASE.hh\""; + }; + B1E1BB7B1177BCE900337ECE /* PBXBuildRule */ = { + isa = PBXBuildRule; + compilerSpec = com.apple.compilers.proxy.script; + fileType = sourcecode.lex; + isEditable = 1; + outputFiles = ( + "$(DERIVED_FILES_DIR)/Lex/$(INPUT_FILE_BASE).cpp", + ); + script = "cd \"$DERIVED_FILES_DIR/Lex\" && /usr/bin/flex -o \"$DERIVED_FILES_DIR/Lex/$INPUT_FILE_BASE.cpp\" \"$INPUT_FILE_PATH\" "; + }; +/* End PBXBuildRule section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 8DD76F690486A84900D96B5E /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + B130248C1236EE5100206AC7 /* fileutil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fileutil.cpp; sourceTree = ""; }; + B130248D1236EE5100206AC7 /* fileutil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fileutil.h; sourceTree = ""; }; + B154B21412001D29009551FC /* stdafx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stdafx.h; sourceTree = ""; }; + B19397B912083210008317C5 /* shinymetal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = shinymetal.cpp; sourceTree = ""; }; + B19397BA12083210008317C5 /* shinymetal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shinymetal.h; sourceTree = ""; }; + B1D8EB54117030DE00A8A49E /* bvh.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bvh.cpp; path = accelerators/bvh.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB55117030DE00A8A49E /* bvh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bvh.h; path = accelerators/bvh.h; sourceTree = SOURCE_ROOT; }; + B1D8EB56117030DE00A8A49E /* grid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = grid.cpp; path = accelerators/grid.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB57117030DE00A8A49E /* grid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = grid.h; path = accelerators/grid.h; sourceTree = SOURCE_ROOT; }; + B1D8EB58117030DE00A8A49E /* kdtreeaccel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = kdtreeaccel.cpp; path = accelerators/kdtreeaccel.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB59117030DE00A8A49E /* kdtreeaccel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = kdtreeaccel.h; path = accelerators/kdtreeaccel.h; sourceTree = SOURCE_ROOT; }; + B1D8EB5E117030E500A8A49E /* environment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = environment.cpp; path = cameras/environment.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB5F117030E500A8A49E /* environment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = environment.h; path = cameras/environment.h; sourceTree = SOURCE_ROOT; }; + B1D8EB60117030E500A8A49E /* orthographic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = orthographic.cpp; path = cameras/orthographic.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB61117030E500A8A49E /* orthographic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = orthographic.h; path = cameras/orthographic.h; sourceTree = SOURCE_ROOT; }; + B1D8EB62117030E500A8A49E /* perspective.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = perspective.cpp; path = cameras/perspective.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB63117030E500A8A49E /* perspective.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = perspective.h; path = cameras/perspective.h; sourceTree = SOURCE_ROOT; }; + B1D8EB68117030F200A8A49E /* api.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = api.cpp; path = core/api.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB69117030F200A8A49E /* api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = api.h; path = core/api.h; sourceTree = SOURCE_ROOT; }; + B1D8EB6A117030F200A8A49E /* camera.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = camera.cpp; path = core/camera.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB6B117030F200A8A49E /* camera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = camera.h; path = core/camera.h; sourceTree = SOURCE_ROOT; }; + B1D8EB6C117030F200A8A49E /* diffgeom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = diffgeom.cpp; path = core/diffgeom.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB6D117030F200A8A49E /* diffgeom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = diffgeom.h; path = core/diffgeom.h; sourceTree = SOURCE_ROOT; }; + B1D8EB6E117030F200A8A49E /* dtrace.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; name = dtrace.d; path = core/dtrace.d; sourceTree = SOURCE_ROOT; }; + B1D8EB6F117030F200A8A49E /* error.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = error.cpp; path = core/error.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB70117030F200A8A49E /* error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = error.h; path = core/error.h; sourceTree = SOURCE_ROOT; }; + B1D8EB71117030F200A8A49E /* film.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = film.cpp; path = core/film.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB72117030F200A8A49E /* film.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = film.h; path = core/film.h; sourceTree = SOURCE_ROOT; }; + B1D8EB73117030F200A8A49E /* filter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = filter.cpp; path = core/filter.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB74117030F200A8A49E /* filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = filter.h; path = core/filter.h; sourceTree = SOURCE_ROOT; }; + B1D8EB75117030F200A8A49E /* floatfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = floatfile.cpp; path = core/floatfile.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB76117030F200A8A49E /* floatfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = floatfile.h; path = core/floatfile.h; sourceTree = SOURCE_ROOT; }; + B1D8EB77117030F200A8A49E /* geometry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = geometry.cpp; path = core/geometry.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB78117030F200A8A49E /* geometry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = geometry.h; path = core/geometry.h; sourceTree = SOURCE_ROOT; }; + B1D8EB79117030F200A8A49E /* imageio.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imageio.cpp; path = core/imageio.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB7A117030F200A8A49E /* imageio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imageio.h; path = core/imageio.h; sourceTree = SOURCE_ROOT; }; + B1D8EB7B117030F200A8A49E /* integrator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = integrator.cpp; path = core/integrator.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB7C117030F200A8A49E /* integrator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = integrator.h; path = core/integrator.h; sourceTree = SOURCE_ROOT; }; + B1D8EB7D117030F200A8A49E /* intersection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = intersection.cpp; path = core/intersection.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB7E117030F200A8A49E /* intersection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = intersection.h; path = core/intersection.h; sourceTree = SOURCE_ROOT; }; + B1D8EB7F117030F200A8A49E /* kdtree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = kdtree.h; path = core/kdtree.h; sourceTree = SOURCE_ROOT; }; + B1D8EB80117030F200A8A49E /* light.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = light.cpp; path = core/light.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB81117030F200A8A49E /* light.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = light.h; path = core/light.h; sourceTree = SOURCE_ROOT; }; + B1D8EB82117030F200A8A49E /* material.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = material.cpp; path = core/material.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB83117030F200A8A49E /* material.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = material.h; path = core/material.h; sourceTree = SOURCE_ROOT; }; + B1D8EB84117030F200A8A49E /* memory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = memory.cpp; path = core/memory.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB85117030F200A8A49E /* memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = memory.h; path = core/memory.h; sourceTree = SOURCE_ROOT; }; + B1D8EB86117030F200A8A49E /* mipmap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mipmap.h; path = core/mipmap.h; sourceTree = SOURCE_ROOT; }; + B1D8EB87117030F200A8A49E /* montecarlo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = montecarlo.cpp; path = core/montecarlo.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB88117030F200A8A49E /* montecarlo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = montecarlo.h; path = core/montecarlo.h; sourceTree = SOURCE_ROOT; }; + B1D8EB89117030F200A8A49E /* octree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = octree.h; path = core/octree.h; sourceTree = SOURCE_ROOT; }; + B1D8EB8A117030F200A8A49E /* parallel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = parallel.cpp; path = core/parallel.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB8B117030F200A8A49E /* parallel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = parallel.h; path = core/parallel.h; sourceTree = SOURCE_ROOT; }; + B1D8EB8C117030F200A8A49E /* paramset.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = paramset.cpp; path = core/paramset.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB8D117030F200A8A49E /* paramset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = paramset.h; path = core/paramset.h; sourceTree = SOURCE_ROOT; }; + B1D8EB8E117030F200A8A49E /* parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = parser.cpp; path = core/parser.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB8F117030F200A8A49E /* parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = parser.h; path = core/parser.h; sourceTree = SOURCE_ROOT; }; + B1D8EB90117030F200A8A49E /* pbrt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pbrt.h; path = core/pbrt.h; sourceTree = SOURCE_ROOT; }; + B1D8EB91117030F200A8A49E /* pbrtlex.ll */ = {isa = PBXFileReference; explicitFileType = sourcecode.lex; fileEncoding = 4; name = pbrtlex.ll; path = core/pbrtlex.ll; sourceTree = SOURCE_ROOT; }; + B1D8EB92117030F200A8A49E /* pbrtparse.yy */ = {isa = PBXFileReference; explicitFileType = sourcecode.yacc; fileEncoding = 4; name = pbrtparse.yy; path = core/pbrtparse.yy; sourceTree = SOURCE_ROOT; }; + B1D8EB93117030F200A8A49E /* primitive.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = primitive.cpp; path = core/primitive.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB94117030F200A8A49E /* primitive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = primitive.h; path = core/primitive.h; sourceTree = SOURCE_ROOT; }; + B1D8EB95117030F200A8A49E /* probes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = probes.cpp; path = core/probes.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB96117030F200A8A49E /* probes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = probes.h; path = core/probes.h; sourceTree = SOURCE_ROOT; }; + B1D8EB97117030F200A8A49E /* progressreporter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = progressreporter.cpp; path = core/progressreporter.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB98117030F200A8A49E /* progressreporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = progressreporter.h; path = core/progressreporter.h; sourceTree = SOURCE_ROOT; }; + B1D8EB99117030F200A8A49E /* quaternion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = quaternion.cpp; path = core/quaternion.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB9A117030F200A8A49E /* quaternion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = quaternion.h; path = core/quaternion.h; sourceTree = SOURCE_ROOT; }; + B1D8EB9B117030F200A8A49E /* reflection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = reflection.cpp; path = core/reflection.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB9C117030F200A8A49E /* reflection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = reflection.h; path = core/reflection.h; sourceTree = SOURCE_ROOT; }; + B1D8EB9D117030F200A8A49E /* renderer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = renderer.cpp; path = core/renderer.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EB9E117030F200A8A49E /* renderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = renderer.h; path = core/renderer.h; sourceTree = SOURCE_ROOT; }; + B1D8EB9F117030F200A8A49E /* rng.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = rng.cpp; path = core/rng.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBA0117030F200A8A49E /* rng.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rng.h; path = core/rng.h; sourceTree = SOURCE_ROOT; }; + B1D8EBA1117030F200A8A49E /* sampler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = sampler.cpp; path = core/sampler.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBA2117030F200A8A49E /* sampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sampler.h; path = core/sampler.h; sourceTree = SOURCE_ROOT; }; + B1D8EBA3117030F200A8A49E /* scene.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = scene.cpp; path = core/scene.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBA4117030F200A8A49E /* scene.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = scene.h; path = core/scene.h; sourceTree = SOURCE_ROOT; }; + B1D8EBA5117030F200A8A49E /* sh.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = sh.cpp; path = core/sh.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBA6117030F200A8A49E /* sh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sh.h; path = core/sh.h; sourceTree = SOURCE_ROOT; }; + B1D8EBA7117030F200A8A49E /* shape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = shape.cpp; path = core/shape.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBA8117030F200A8A49E /* shape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = shape.h; path = core/shape.h; sourceTree = SOURCE_ROOT; }; + B1D8EBA9117030F200A8A49E /* shrots.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = shrots.cpp; path = core/shrots.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBAA117030F200A8A49E /* spectrum.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = spectrum.cpp; path = core/spectrum.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBAB117030F200A8A49E /* spectrum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = spectrum.h; path = core/spectrum.h; sourceTree = SOURCE_ROOT; }; + B1D8EBAC117030F200A8A49E /* texture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = texture.cpp; path = core/texture.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBAD117030F200A8A49E /* texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = texture.h; path = core/texture.h; sourceTree = SOURCE_ROOT; }; + B1D8EBAE117030F200A8A49E /* timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = timer.cpp; path = core/timer.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBAF117030F200A8A49E /* timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = timer.h; path = core/timer.h; sourceTree = SOURCE_ROOT; }; + B1D8EBB0117030F200A8A49E /* transform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = transform.cpp; path = core/transform.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBB1117030F200A8A49E /* transform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = transform.h; path = core/transform.h; sourceTree = SOURCE_ROOT; }; + B1D8EBB2117030F200A8A49E /* volume.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = volume.cpp; path = core/volume.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBB3117030F200A8A49E /* volume.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = volume.h; path = core/volume.h; sourceTree = SOURCE_ROOT; }; + B1D8EBDA1170310E00A8A49E /* image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = image.cpp; path = film/image.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBDB1170310E00A8A49E /* image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = image.h; path = film/image.h; sourceTree = SOURCE_ROOT; }; + B1D8EBDD1170310E00A8A49E /* box.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = box.cpp; path = filters/box.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBDE1170310E00A8A49E /* box.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = box.h; path = filters/box.h; sourceTree = SOURCE_ROOT; }; + B1D8EBDF1170310E00A8A49E /* gaussian.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = gaussian.cpp; path = filters/gaussian.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBE01170310E00A8A49E /* gaussian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gaussian.h; path = filters/gaussian.h; sourceTree = SOURCE_ROOT; }; + B1D8EBE11170310E00A8A49E /* mitchell.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mitchell.cpp; path = filters/mitchell.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBE21170310E00A8A49E /* mitchell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mitchell.h; path = filters/mitchell.h; sourceTree = SOURCE_ROOT; }; + B1D8EBE31170310E00A8A49E /* sinc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = sinc.cpp; path = filters/sinc.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBE41170310E00A8A49E /* sinc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sinc.h; path = filters/sinc.h; sourceTree = SOURCE_ROOT; }; + B1D8EBE51170310E00A8A49E /* triangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = triangle.cpp; path = filters/triangle.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBE61170310E00A8A49E /* triangle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = triangle.h; path = filters/triangle.h; sourceTree = SOURCE_ROOT; }; + B1D8EBE81170310E00A8A49E /* ambientocclusion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ambientocclusion.cpp; path = integrators/ambientocclusion.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBE91170310E00A8A49E /* ambientocclusion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ambientocclusion.h; path = integrators/ambientocclusion.h; sourceTree = SOURCE_ROOT; }; + B1D8EBEA1170310E00A8A49E /* diffuseprt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = diffuseprt.cpp; path = integrators/diffuseprt.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBEB1170310E00A8A49E /* diffuseprt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = diffuseprt.h; path = integrators/diffuseprt.h; sourceTree = SOURCE_ROOT; }; + B1D8EBEC1170310E00A8A49E /* dipolesubsurface.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dipolesubsurface.cpp; path = integrators/dipolesubsurface.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBED1170310E00A8A49E /* dipolesubsurface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dipolesubsurface.h; path = integrators/dipolesubsurface.h; sourceTree = SOURCE_ROOT; }; + B1D8EBEE1170310E00A8A49E /* directlighting.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = directlighting.cpp; path = integrators/directlighting.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBEF1170310E00A8A49E /* directlighting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = directlighting.h; path = integrators/directlighting.h; sourceTree = SOURCE_ROOT; }; + B1D8EBF01170310E00A8A49E /* emission.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = emission.cpp; path = integrators/emission.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBF11170310E00A8A49E /* emission.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = emission.h; path = integrators/emission.h; sourceTree = SOURCE_ROOT; }; + B1D8EBF21170310E00A8A49E /* glossyprt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = glossyprt.cpp; path = integrators/glossyprt.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBF31170310E00A8A49E /* glossyprt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = glossyprt.h; path = integrators/glossyprt.h; sourceTree = SOURCE_ROOT; }; + B1D8EBF41170310E00A8A49E /* igi.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = igi.cpp; path = integrators/igi.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBF51170310E00A8A49E /* igi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = igi.h; path = integrators/igi.h; sourceTree = SOURCE_ROOT; }; + B1D8EBF61170310E00A8A49E /* irradiancecache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = irradiancecache.cpp; path = integrators/irradiancecache.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBF71170310E00A8A49E /* irradiancecache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = irradiancecache.h; path = integrators/irradiancecache.h; sourceTree = SOURCE_ROOT; }; + B1D8EBF81170310E00A8A49E /* path.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = path.cpp; path = integrators/path.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBF91170310E00A8A49E /* path.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = path.h; path = integrators/path.h; sourceTree = SOURCE_ROOT; }; + B1D8EBFA1170310E00A8A49E /* photonmap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = photonmap.cpp; path = integrators/photonmap.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBFB1170310E00A8A49E /* photonmap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = photonmap.h; path = integrators/photonmap.h; sourceTree = SOURCE_ROOT; }; + B1D8EBFC1170310E00A8A49E /* single.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = single.cpp; path = integrators/single.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBFD1170310E00A8A49E /* single.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = single.h; path = integrators/single.h; sourceTree = SOURCE_ROOT; }; + B1D8EBFE1170310E00A8A49E /* useprobes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = useprobes.cpp; path = integrators/useprobes.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EBFF1170310E00A8A49E /* useprobes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = useprobes.h; path = integrators/useprobes.h; sourceTree = SOURCE_ROOT; }; + B1D8EC001170310E00A8A49E /* whitted.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = whitted.cpp; path = integrators/whitted.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC011170310E00A8A49E /* whitted.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = whitted.h; path = integrators/whitted.h; sourceTree = SOURCE_ROOT; }; + B1D8EC031170310E00A8A49E /* diffuse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = diffuse.cpp; path = lights/diffuse.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC041170310E00A8A49E /* diffuse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = diffuse.h; path = lights/diffuse.h; sourceTree = SOURCE_ROOT; }; + B1D8EC051170310E00A8A49E /* distant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = distant.cpp; path = lights/distant.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC061170310E00A8A49E /* distant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = distant.h; path = lights/distant.h; sourceTree = SOURCE_ROOT; }; + B1D8EC091170310E00A8A49E /* goniometric.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = goniometric.cpp; path = lights/goniometric.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC0A1170310E00A8A49E /* goniometric.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = goniometric.h; path = lights/goniometric.h; sourceTree = SOURCE_ROOT; }; + B1D8EC0B1170310E00A8A49E /* infinite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = infinite.cpp; path = lights/infinite.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC0C1170310E00A8A49E /* infinite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = infinite.h; path = lights/infinite.h; sourceTree = SOURCE_ROOT; }; + B1D8EC0D1170310E00A8A49E /* point.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = point.cpp; path = lights/point.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC0E1170310E00A8A49E /* point.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = point.h; path = lights/point.h; sourceTree = SOURCE_ROOT; }; + B1D8EC0F1170310E00A8A49E /* projection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = projection.cpp; path = lights/projection.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC101170310E00A8A49E /* projection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = projection.h; path = lights/projection.h; sourceTree = SOURCE_ROOT; }; + B1D8EC111170310E00A8A49E /* spot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = spot.cpp; path = lights/spot.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC121170310E00A8A49E /* spot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = spot.h; path = lights/spot.h; sourceTree = SOURCE_ROOT; }; + B1D8EC141170310E00A8A49E /* pbrt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = pbrt.cpp; path = main/pbrt.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC161170310E00A8A49E /* glass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = glass.cpp; path = materials/glass.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC171170310E00A8A49E /* glass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = glass.h; path = materials/glass.h; sourceTree = SOURCE_ROOT; }; + B1D8EC181170310E00A8A49E /* kdsubsurface.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = kdsubsurface.cpp; path = materials/kdsubsurface.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC191170310E00A8A49E /* kdsubsurface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = kdsubsurface.h; path = materials/kdsubsurface.h; sourceTree = SOURCE_ROOT; }; + B1D8EC1A1170310E00A8A49E /* matte.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = matte.cpp; path = materials/matte.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC1B1170310E00A8A49E /* matte.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = matte.h; path = materials/matte.h; sourceTree = SOURCE_ROOT; }; + B1D8EC1C1170310E00A8A49E /* measured.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = measured.cpp; path = materials/measured.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC1D1170310E00A8A49E /* measured.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = measured.h; path = materials/measured.h; sourceTree = SOURCE_ROOT; }; + B1D8EC1E1170310E00A8A49E /* metal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = metal.cpp; path = materials/metal.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC1F1170310E00A8A49E /* metal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = metal.h; path = materials/metal.h; sourceTree = SOURCE_ROOT; }; + B1D8EC201170310E00A8A49E /* mirror.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mirror.cpp; path = materials/mirror.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC211170310E00A8A49E /* mirror.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mirror.h; path = materials/mirror.h; sourceTree = SOURCE_ROOT; }; + B1D8EC221170310E00A8A49E /* mixmat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mixmat.cpp; path = materials/mixmat.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC231170310E00A8A49E /* mixmat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mixmat.h; path = materials/mixmat.h; sourceTree = SOURCE_ROOT; }; + B1D8EC241170310E00A8A49E /* plastic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = plastic.cpp; path = materials/plastic.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC251170310E00A8A49E /* plastic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = plastic.h; path = materials/plastic.h; sourceTree = SOURCE_ROOT; }; + B1D8EC261170310E00A8A49E /* substrate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = substrate.cpp; path = materials/substrate.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC271170310E00A8A49E /* substrate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = substrate.h; path = materials/substrate.h; sourceTree = SOURCE_ROOT; }; + B1D8EC281170310E00A8A49E /* subsurface.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = subsurface.cpp; path = materials/subsurface.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC291170310E00A8A49E /* subsurface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = subsurface.h; path = materials/subsurface.h; sourceTree = SOURCE_ROOT; }; + B1D8EC2A1170310E00A8A49E /* translucent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = translucent.cpp; path = materials/translucent.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC2B1170310E00A8A49E /* translucent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = translucent.h; path = materials/translucent.h; sourceTree = SOURCE_ROOT; }; + B1D8EC2C1170310E00A8A49E /* uber.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = uber.cpp; path = materials/uber.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC2D1170310E00A8A49E /* uber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = uber.h; path = materials/uber.h; sourceTree = SOURCE_ROOT; }; + B1D8EC301170310E00A8A49E /* aggregatetest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = aggregatetest.cpp; path = renderers/aggregatetest.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC311170310E00A8A49E /* aggregatetest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = aggregatetest.h; path = renderers/aggregatetest.h; sourceTree = SOURCE_ROOT; }; + B1D8EC321170310E00A8A49E /* createprobes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = createprobes.cpp; path = renderers/createprobes.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC331170310E00A8A49E /* createprobes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = createprobes.h; path = renderers/createprobes.h; sourceTree = SOURCE_ROOT; }; + B1D8EC341170310E00A8A49E /* metropolis.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = metropolis.cpp; path = renderers/metropolis.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC351170310E00A8A49E /* metropolis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = metropolis.h; path = renderers/metropolis.h; sourceTree = SOURCE_ROOT; }; + B1D8EC361170310E00A8A49E /* samplerrenderer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = samplerrenderer.cpp; path = renderers/samplerrenderer.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC371170310E00A8A49E /* samplerrenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = samplerrenderer.h; path = renderers/samplerrenderer.h; sourceTree = SOURCE_ROOT; }; + B1D8EC381170310E00A8A49E /* surfacepoints.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = surfacepoints.cpp; path = renderers/surfacepoints.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC391170310E00A8A49E /* surfacepoints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = surfacepoints.h; path = renderers/surfacepoints.h; sourceTree = SOURCE_ROOT; }; + B1D8EC3B1170310E00A8A49E /* adaptive.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = adaptive.cpp; path = samplers/adaptive.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC3C1170310E00A8A49E /* adaptive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = adaptive.h; path = samplers/adaptive.h; sourceTree = SOURCE_ROOT; }; + B1D8EC3D1170310E00A8A49E /* bestcandidate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bestcandidate.cpp; path = samplers/bestcandidate.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC3E1170310E00A8A49E /* bestcandidate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bestcandidate.h; path = samplers/bestcandidate.h; sourceTree = SOURCE_ROOT; }; + B1D8EC3F1170310E00A8A49E /* halton.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = halton.cpp; path = samplers/halton.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC401170310E00A8A49E /* halton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = halton.h; path = samplers/halton.h; sourceTree = SOURCE_ROOT; }; + B1D8EC411170310E00A8A49E /* lowdiscrepancy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = lowdiscrepancy.cpp; path = samplers/lowdiscrepancy.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC421170310E00A8A49E /* lowdiscrepancy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = lowdiscrepancy.h; path = samplers/lowdiscrepancy.h; sourceTree = SOURCE_ROOT; }; + B1D8EC431170310E00A8A49E /* random.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = random.cpp; path = samplers/random.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC441170310E00A8A49E /* random.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = random.h; path = samplers/random.h; sourceTree = SOURCE_ROOT; }; + B1D8EC451170310E00A8A49E /* sampledata.out */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = sampledata.out; path = samplers/sampledata.out; sourceTree = SOURCE_ROOT; }; + B1D8EC461170310E00A8A49E /* stratified.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stratified.cpp; path = samplers/stratified.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC471170310E00A8A49E /* stratified.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stratified.h; path = samplers/stratified.h; sourceTree = SOURCE_ROOT; }; + B1D8EC491170310E00A8A49E /* cone.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cone.cpp; path = shapes/cone.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC4A1170310E00A8A49E /* cone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cone.h; path = shapes/cone.h; sourceTree = SOURCE_ROOT; }; + B1D8EC4B1170310E00A8A49E /* cylinder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cylinder.cpp; path = shapes/cylinder.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC4C1170310E00A8A49E /* cylinder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cylinder.h; path = shapes/cylinder.h; sourceTree = SOURCE_ROOT; }; + B1D8EC4D1170310E00A8A49E /* disk.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = disk.cpp; path = shapes/disk.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC4E1170310E00A8A49E /* disk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = disk.h; path = shapes/disk.h; sourceTree = SOURCE_ROOT; }; + B1D8EC4F1170310E00A8A49E /* heightfield.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = heightfield.cpp; path = shapes/heightfield.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC501170310E00A8A49E /* heightfield.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = heightfield.h; path = shapes/heightfield.h; sourceTree = SOURCE_ROOT; }; + B1D8EC511170310E00A8A49E /* hyperboloid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = hyperboloid.cpp; path = shapes/hyperboloid.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC521170310E00A8A49E /* hyperboloid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hyperboloid.h; path = shapes/hyperboloid.h; sourceTree = SOURCE_ROOT; }; + B1D8EC531170310E00A8A49E /* loopsubdiv.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = loopsubdiv.cpp; path = shapes/loopsubdiv.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC541170310E00A8A49E /* loopsubdiv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = loopsubdiv.h; path = shapes/loopsubdiv.h; sourceTree = SOURCE_ROOT; }; + B1D8EC551170310E00A8A49E /* nurbs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = nurbs.cpp; path = shapes/nurbs.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC561170310E00A8A49E /* nurbs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nurbs.h; path = shapes/nurbs.h; sourceTree = SOURCE_ROOT; }; + B1D8EC571170310E00A8A49E /* paraboloid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = paraboloid.cpp; path = shapes/paraboloid.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC581170310E00A8A49E /* paraboloid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = paraboloid.h; path = shapes/paraboloid.h; sourceTree = SOURCE_ROOT; }; + B1D8EC591170310E00A8A49E /* sphere.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = sphere.cpp; path = shapes/sphere.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC5A1170310E00A8A49E /* sphere.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sphere.h; path = shapes/sphere.h; sourceTree = SOURCE_ROOT; }; + B1D8EC5B1170310E00A8A49E /* trianglemesh.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = trianglemesh.cpp; path = shapes/trianglemesh.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC5C1170310E00A8A49E /* trianglemesh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = trianglemesh.h; path = shapes/trianglemesh.h; sourceTree = SOURCE_ROOT; }; + B1D8EC5E1170310E00A8A49E /* bilerp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bilerp.cpp; path = textures/bilerp.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC5F1170310E00A8A49E /* bilerp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bilerp.h; path = textures/bilerp.h; sourceTree = SOURCE_ROOT; }; + B1D8EC601170310E00A8A49E /* checkerboard.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = checkerboard.cpp; path = textures/checkerboard.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC611170310E00A8A49E /* checkerboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = checkerboard.h; path = textures/checkerboard.h; sourceTree = SOURCE_ROOT; }; + B1D8EC621170310E00A8A49E /* constant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = constant.cpp; path = textures/constant.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC631170310E00A8A49E /* constant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = constant.h; path = textures/constant.h; sourceTree = SOURCE_ROOT; }; + B1D8EC641170310E00A8A49E /* dots.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dots.cpp; path = textures/dots.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC651170310E00A8A49E /* dots.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dots.h; path = textures/dots.h; sourceTree = SOURCE_ROOT; }; + B1D8EC661170310E00A8A49E /* fbm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = fbm.cpp; path = textures/fbm.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC671170310E00A8A49E /* fbm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fbm.h; path = textures/fbm.h; sourceTree = SOURCE_ROOT; }; + B1D8EC681170310E00A8A49E /* imagemap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imagemap.cpp; path = textures/imagemap.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC691170310E00A8A49E /* imagemap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imagemap.h; path = textures/imagemap.h; sourceTree = SOURCE_ROOT; }; + B1D8EC6A1170310E00A8A49E /* marble.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = marble.cpp; path = textures/marble.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC6B1170310E00A8A49E /* marble.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = marble.h; path = textures/marble.h; sourceTree = SOURCE_ROOT; }; + B1D8EC6C1170310E00A8A49E /* mix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mix.cpp; path = textures/mix.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC6D1170310E00A8A49E /* mix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mix.h; path = textures/mix.h; sourceTree = SOURCE_ROOT; }; + B1D8EC6E1170310E00A8A49E /* scale.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = scale.cpp; path = textures/scale.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC6F1170310E00A8A49E /* scale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = scale.h; path = textures/scale.h; sourceTree = SOURCE_ROOT; }; + B1D8EC701170310E00A8A49E /* uv.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = uv.cpp; path = textures/uv.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC711170310E00A8A49E /* uv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = uv.h; path = textures/uv.h; sourceTree = SOURCE_ROOT; }; + B1D8EC721170310E00A8A49E /* windy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = windy.cpp; path = textures/windy.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC731170310E00A8A49E /* windy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = windy.h; path = textures/windy.h; sourceTree = SOURCE_ROOT; }; + B1D8EC741170310E00A8A49E /* wrinkled.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = wrinkled.cpp; path = textures/wrinkled.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC751170310E00A8A49E /* wrinkled.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wrinkled.h; path = textures/wrinkled.h; sourceTree = SOURCE_ROOT; }; + B1D8EC771170310E00A8A49E /* exponential.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exponential.cpp; path = volumes/exponential.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC781170310E00A8A49E /* exponential.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = exponential.h; path = volumes/exponential.h; sourceTree = SOURCE_ROOT; }; + B1D8EC791170310E00A8A49E /* homogeneous.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = homogeneous.cpp; path = volumes/homogeneous.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC7A1170310E00A8A49E /* homogeneous.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = homogeneous.h; path = volumes/homogeneous.h; sourceTree = SOURCE_ROOT; }; + B1D8EC7B1170310E00A8A49E /* volumegrid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = volumegrid.cpp; path = volumes/volumegrid.cpp; sourceTree = SOURCE_ROOT; }; + B1D8EC7C1170310E00A8A49E /* volumegrid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = volumegrid.h; path = volumes/volumegrid.h; sourceTree = SOURCE_ROOT; }; + B1D8ECE2117032E500A8A49E /* pbrt */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pbrt; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8DD76F660486A84900D96B5E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* pbrt */ = { + isa = PBXGroup; + children = ( + 08FB7795FE84155DC02AAC07 /* Source */, + C6859E8C029090F304C91782 /* Documentation */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = pbrt; + sourceTree = ""; + }; + 08FB7795FE84155DC02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + B1D8EBD91170310E00A8A49E /* film */, + B1D8EBDC1170310E00A8A49E /* filters */, + B1D8EBE71170310E00A8A49E /* integrators */, + B1D8EC021170310E00A8A49E /* lights */, + B1D8EC131170310E00A8A49E /* main */, + B1D8EC151170310E00A8A49E /* materials */, + B1D8EC2E1170310E00A8A49E /* renderers */, + B1D8EC3A1170310E00A8A49E /* samplers */, + B1D8EC481170310E00A8A49E /* shapes */, + B1D8EC5D1170310E00A8A49E /* textures */, + B1D8EC761170310E00A8A49E /* volumes */, + B1D8EB67117030F200A8A49E /* core */, + B1D8EB5D117030E500A8A49E /* cameras */, + B1D8EB53117030DE00A8A49E /* accelerators */, + ); + name = Source; + sourceTree = ""; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + B1D8ECE2117032E500A8A49E /* pbrt */, + ); + name = Products; + sourceTree = ""; + }; + B1D8EB53117030DE00A8A49E /* accelerators */ = { + isa = PBXGroup; + children = ( + B1D8EB54117030DE00A8A49E /* bvh.cpp */, + B1D8EB55117030DE00A8A49E /* bvh.h */, + B1D8EB56117030DE00A8A49E /* grid.cpp */, + B1D8EB57117030DE00A8A49E /* grid.h */, + B1D8EB58117030DE00A8A49E /* kdtreeaccel.cpp */, + B1D8EB59117030DE00A8A49E /* kdtreeaccel.h */, + ); + path = accelerators; + sourceTree = SOURCE_ROOT; + }; + B1D8EB5D117030E500A8A49E /* cameras */ = { + isa = PBXGroup; + children = ( + B1D8EB5E117030E500A8A49E /* environment.cpp */, + B1D8EB5F117030E500A8A49E /* environment.h */, + B1D8EB60117030E500A8A49E /* orthographic.cpp */, + B1D8EB61117030E500A8A49E /* orthographic.h */, + B1D8EB62117030E500A8A49E /* perspective.cpp */, + B1D8EB63117030E500A8A49E /* perspective.h */, + ); + path = cameras; + sourceTree = SOURCE_ROOT; + }; + B1D8EB67117030F200A8A49E /* core */ = { + isa = PBXGroup; + children = ( + B130248C1236EE5100206AC7 /* fileutil.cpp */, + B130248D1236EE5100206AC7 /* fileutil.h */, + B154B21412001D29009551FC /* stdafx.h */, + B1D8EB68117030F200A8A49E /* api.cpp */, + B1D8EB69117030F200A8A49E /* api.h */, + B1D8EB6A117030F200A8A49E /* camera.cpp */, + B1D8EB6B117030F200A8A49E /* camera.h */, + B1D8EB6C117030F200A8A49E /* diffgeom.cpp */, + B1D8EB6D117030F200A8A49E /* diffgeom.h */, + B1D8EB6E117030F200A8A49E /* dtrace.d */, + B1D8EB6F117030F200A8A49E /* error.cpp */, + B1D8EB70117030F200A8A49E /* error.h */, + B1D8EB71117030F200A8A49E /* film.cpp */, + B1D8EB72117030F200A8A49E /* film.h */, + B1D8EB73117030F200A8A49E /* filter.cpp */, + B1D8EB74117030F200A8A49E /* filter.h */, + B1D8EB75117030F200A8A49E /* floatfile.cpp */, + B1D8EB76117030F200A8A49E /* floatfile.h */, + B1D8EB77117030F200A8A49E /* geometry.cpp */, + B1D8EB78117030F200A8A49E /* geometry.h */, + B1D8EB79117030F200A8A49E /* imageio.cpp */, + B1D8EB7A117030F200A8A49E /* imageio.h */, + B1D8EB7B117030F200A8A49E /* integrator.cpp */, + B1D8EB7C117030F200A8A49E /* integrator.h */, + B1D8EB7D117030F200A8A49E /* intersection.cpp */, + B1D8EB7E117030F200A8A49E /* intersection.h */, + B1D8EB7F117030F200A8A49E /* kdtree.h */, + B1D8EB80117030F200A8A49E /* light.cpp */, + B1D8EB81117030F200A8A49E /* light.h */, + B1D8EB82117030F200A8A49E /* material.cpp */, + B1D8EB83117030F200A8A49E /* material.h */, + B1D8EB84117030F200A8A49E /* memory.cpp */, + B1D8EB85117030F200A8A49E /* memory.h */, + B1D8EB86117030F200A8A49E /* mipmap.h */, + B1D8EB87117030F200A8A49E /* montecarlo.cpp */, + B1D8EB88117030F200A8A49E /* montecarlo.h */, + B1D8EB89117030F200A8A49E /* octree.h */, + B1D8EB8A117030F200A8A49E /* parallel.cpp */, + B1D8EB8B117030F200A8A49E /* parallel.h */, + B1D8EB8C117030F200A8A49E /* paramset.cpp */, + B1D8EB8D117030F200A8A49E /* paramset.h */, + B1D8EB8E117030F200A8A49E /* parser.cpp */, + B1D8EB8F117030F200A8A49E /* parser.h */, + B1D8EB90117030F200A8A49E /* pbrt.h */, + B1D8EB91117030F200A8A49E /* pbrtlex.ll */, + B1D8EB92117030F200A8A49E /* pbrtparse.yy */, + B1D8EB93117030F200A8A49E /* primitive.cpp */, + B1D8EB94117030F200A8A49E /* primitive.h */, + B1D8EB95117030F200A8A49E /* probes.cpp */, + B1D8EB96117030F200A8A49E /* probes.h */, + B1D8EB97117030F200A8A49E /* progressreporter.cpp */, + B1D8EB98117030F200A8A49E /* progressreporter.h */, + B1D8EB99117030F200A8A49E /* quaternion.cpp */, + B1D8EB9A117030F200A8A49E /* quaternion.h */, + B1D8EB9B117030F200A8A49E /* reflection.cpp */, + B1D8EB9C117030F200A8A49E /* reflection.h */, + B1D8EB9D117030F200A8A49E /* renderer.cpp */, + B1D8EB9E117030F200A8A49E /* renderer.h */, + B1D8EB9F117030F200A8A49E /* rng.cpp */, + B1D8EBA0117030F200A8A49E /* rng.h */, + B1D8EBA1117030F200A8A49E /* sampler.cpp */, + B1D8EBA2117030F200A8A49E /* sampler.h */, + B1D8EBA3117030F200A8A49E /* scene.cpp */, + B1D8EBA4117030F200A8A49E /* scene.h */, + B1D8EBA5117030F200A8A49E /* sh.cpp */, + B1D8EBA6117030F200A8A49E /* sh.h */, + B1D8EBA7117030F200A8A49E /* shape.cpp */, + B1D8EBA8117030F200A8A49E /* shape.h */, + B1D8EBA9117030F200A8A49E /* shrots.cpp */, + B1D8EBAA117030F200A8A49E /* spectrum.cpp */, + B1D8EBAB117030F200A8A49E /* spectrum.h */, + B1D8EBAC117030F200A8A49E /* texture.cpp */, + B1D8EBAD117030F200A8A49E /* texture.h */, + B1D8EBAE117030F200A8A49E /* timer.cpp */, + B1D8EBAF117030F200A8A49E /* timer.h */, + B1D8EBB0117030F200A8A49E /* transform.cpp */, + B1D8EBB1117030F200A8A49E /* transform.h */, + B1D8EBB2117030F200A8A49E /* volume.cpp */, + B1D8EBB3117030F200A8A49E /* volume.h */, + ); + path = core; + sourceTree = SOURCE_ROOT; + }; + B1D8EBD91170310E00A8A49E /* film */ = { + isa = PBXGroup; + children = ( + B1D8EBDA1170310E00A8A49E /* image.cpp */, + B1D8EBDB1170310E00A8A49E /* image.h */, + ); + path = film; + sourceTree = SOURCE_ROOT; + }; + B1D8EBDC1170310E00A8A49E /* filters */ = { + isa = PBXGroup; + children = ( + B1D8EBDD1170310E00A8A49E /* box.cpp */, + B1D8EBDE1170310E00A8A49E /* box.h */, + B1D8EBDF1170310E00A8A49E /* gaussian.cpp */, + B1D8EBE01170310E00A8A49E /* gaussian.h */, + B1D8EBE11170310E00A8A49E /* mitchell.cpp */, + B1D8EBE21170310E00A8A49E /* mitchell.h */, + B1D8EBE31170310E00A8A49E /* sinc.cpp */, + B1D8EBE41170310E00A8A49E /* sinc.h */, + B1D8EBE51170310E00A8A49E /* triangle.cpp */, + B1D8EBE61170310E00A8A49E /* triangle.h */, + ); + path = filters; + sourceTree = SOURCE_ROOT; + }; + B1D8EBE71170310E00A8A49E /* integrators */ = { + isa = PBXGroup; + children = ( + B1D8EBE81170310E00A8A49E /* ambientocclusion.cpp */, + B1D8EBE91170310E00A8A49E /* ambientocclusion.h */, + B1D8EBEA1170310E00A8A49E /* diffuseprt.cpp */, + B1D8EBEB1170310E00A8A49E /* diffuseprt.h */, + B1D8EBEC1170310E00A8A49E /* dipolesubsurface.cpp */, + B1D8EBED1170310E00A8A49E /* dipolesubsurface.h */, + B1D8EBEE1170310E00A8A49E /* directlighting.cpp */, + B1D8EBEF1170310E00A8A49E /* directlighting.h */, + B1D8EBF01170310E00A8A49E /* emission.cpp */, + B1D8EBF11170310E00A8A49E /* emission.h */, + B1D8EBF21170310E00A8A49E /* glossyprt.cpp */, + B1D8EBF31170310E00A8A49E /* glossyprt.h */, + B1D8EBF41170310E00A8A49E /* igi.cpp */, + B1D8EBF51170310E00A8A49E /* igi.h */, + B1D8EBF61170310E00A8A49E /* irradiancecache.cpp */, + B1D8EBF71170310E00A8A49E /* irradiancecache.h */, + B1D8EBF81170310E00A8A49E /* path.cpp */, + B1D8EBF91170310E00A8A49E /* path.h */, + B1D8EBFA1170310E00A8A49E /* photonmap.cpp */, + B1D8EBFB1170310E00A8A49E /* photonmap.h */, + B1D8EBFC1170310E00A8A49E /* single.cpp */, + B1D8EBFD1170310E00A8A49E /* single.h */, + B1D8EBFE1170310E00A8A49E /* useprobes.cpp */, + B1D8EBFF1170310E00A8A49E /* useprobes.h */, + B1D8EC001170310E00A8A49E /* whitted.cpp */, + B1D8EC011170310E00A8A49E /* whitted.h */, + ); + path = integrators; + sourceTree = SOURCE_ROOT; + }; + B1D8EC021170310E00A8A49E /* lights */ = { + isa = PBXGroup; + children = ( + B1D8EC031170310E00A8A49E /* diffuse.cpp */, + B1D8EC041170310E00A8A49E /* diffuse.h */, + B1D8EC051170310E00A8A49E /* distant.cpp */, + B1D8EC061170310E00A8A49E /* distant.h */, + B1D8EC091170310E00A8A49E /* goniometric.cpp */, + B1D8EC0A1170310E00A8A49E /* goniometric.h */, + B1D8EC0B1170310E00A8A49E /* infinite.cpp */, + B1D8EC0C1170310E00A8A49E /* infinite.h */, + B1D8EC0D1170310E00A8A49E /* point.cpp */, + B1D8EC0E1170310E00A8A49E /* point.h */, + B1D8EC0F1170310E00A8A49E /* projection.cpp */, + B1D8EC101170310E00A8A49E /* projection.h */, + B1D8EC111170310E00A8A49E /* spot.cpp */, + B1D8EC121170310E00A8A49E /* spot.h */, + ); + path = lights; + sourceTree = SOURCE_ROOT; + }; + B1D8EC131170310E00A8A49E /* main */ = { + isa = PBXGroup; + children = ( + B1D8EC141170310E00A8A49E /* pbrt.cpp */, + ); + path = main; + sourceTree = SOURCE_ROOT; + }; + B1D8EC151170310E00A8A49E /* materials */ = { + isa = PBXGroup; + children = ( + B19397B912083210008317C5 /* shinymetal.cpp */, + B19397BA12083210008317C5 /* shinymetal.h */, + B1D8EC161170310E00A8A49E /* glass.cpp */, + B1D8EC171170310E00A8A49E /* glass.h */, + B1D8EC181170310E00A8A49E /* kdsubsurface.cpp */, + B1D8EC191170310E00A8A49E /* kdsubsurface.h */, + B1D8EC1A1170310E00A8A49E /* matte.cpp */, + B1D8EC1B1170310E00A8A49E /* matte.h */, + B1D8EC1C1170310E00A8A49E /* measured.cpp */, + B1D8EC1D1170310E00A8A49E /* measured.h */, + B1D8EC1E1170310E00A8A49E /* metal.cpp */, + B1D8EC1F1170310E00A8A49E /* metal.h */, + B1D8EC201170310E00A8A49E /* mirror.cpp */, + B1D8EC211170310E00A8A49E /* mirror.h */, + B1D8EC221170310E00A8A49E /* mixmat.cpp */, + B1D8EC231170310E00A8A49E /* mixmat.h */, + B1D8EC241170310E00A8A49E /* plastic.cpp */, + B1D8EC251170310E00A8A49E /* plastic.h */, + B1D8EC261170310E00A8A49E /* substrate.cpp */, + B1D8EC271170310E00A8A49E /* substrate.h */, + B1D8EC281170310E00A8A49E /* subsurface.cpp */, + B1D8EC291170310E00A8A49E /* subsurface.h */, + B1D8EC2A1170310E00A8A49E /* translucent.cpp */, + B1D8EC2B1170310E00A8A49E /* translucent.h */, + B1D8EC2C1170310E00A8A49E /* uber.cpp */, + B1D8EC2D1170310E00A8A49E /* uber.h */, + ); + path = materials; + sourceTree = SOURCE_ROOT; + }; + B1D8EC2E1170310E00A8A49E /* renderers */ = { + isa = PBXGroup; + children = ( + B1D8EC301170310E00A8A49E /* aggregatetest.cpp */, + B1D8EC311170310E00A8A49E /* aggregatetest.h */, + B1D8EC321170310E00A8A49E /* createprobes.cpp */, + B1D8EC331170310E00A8A49E /* createprobes.h */, + B1D8EC341170310E00A8A49E /* metropolis.cpp */, + B1D8EC351170310E00A8A49E /* metropolis.h */, + B1D8EC361170310E00A8A49E /* samplerrenderer.cpp */, + B1D8EC371170310E00A8A49E /* samplerrenderer.h */, + B1D8EC381170310E00A8A49E /* surfacepoints.cpp */, + B1D8EC391170310E00A8A49E /* surfacepoints.h */, + ); + path = renderers; + sourceTree = SOURCE_ROOT; + }; + B1D8EC3A1170310E00A8A49E /* samplers */ = { + isa = PBXGroup; + children = ( + B1D8EC3B1170310E00A8A49E /* adaptive.cpp */, + B1D8EC3C1170310E00A8A49E /* adaptive.h */, + B1D8EC3D1170310E00A8A49E /* bestcandidate.cpp */, + B1D8EC3E1170310E00A8A49E /* bestcandidate.h */, + B1D8EC3F1170310E00A8A49E /* halton.cpp */, + B1D8EC401170310E00A8A49E /* halton.h */, + B1D8EC411170310E00A8A49E /* lowdiscrepancy.cpp */, + B1D8EC421170310E00A8A49E /* lowdiscrepancy.h */, + B1D8EC431170310E00A8A49E /* random.cpp */, + B1D8EC441170310E00A8A49E /* random.h */, + B1D8EC451170310E00A8A49E /* sampledata.out */, + B1D8EC461170310E00A8A49E /* stratified.cpp */, + B1D8EC471170310E00A8A49E /* stratified.h */, + ); + path = samplers; + sourceTree = SOURCE_ROOT; + }; + B1D8EC481170310E00A8A49E /* shapes */ = { + isa = PBXGroup; + children = ( + B1D8EC491170310E00A8A49E /* cone.cpp */, + B1D8EC4A1170310E00A8A49E /* cone.h */, + B1D8EC4B1170310E00A8A49E /* cylinder.cpp */, + B1D8EC4C1170310E00A8A49E /* cylinder.h */, + B1D8EC4D1170310E00A8A49E /* disk.cpp */, + B1D8EC4E1170310E00A8A49E /* disk.h */, + B1D8EC4F1170310E00A8A49E /* heightfield.cpp */, + B1D8EC501170310E00A8A49E /* heightfield.h */, + B1D8EC511170310E00A8A49E /* hyperboloid.cpp */, + B1D8EC521170310E00A8A49E /* hyperboloid.h */, + B1D8EC531170310E00A8A49E /* loopsubdiv.cpp */, + B1D8EC541170310E00A8A49E /* loopsubdiv.h */, + B1D8EC551170310E00A8A49E /* nurbs.cpp */, + B1D8EC561170310E00A8A49E /* nurbs.h */, + B1D8EC571170310E00A8A49E /* paraboloid.cpp */, + B1D8EC581170310E00A8A49E /* paraboloid.h */, + B1D8EC591170310E00A8A49E /* sphere.cpp */, + B1D8EC5A1170310E00A8A49E /* sphere.h */, + B1D8EC5B1170310E00A8A49E /* trianglemesh.cpp */, + B1D8EC5C1170310E00A8A49E /* trianglemesh.h */, + ); + path = shapes; + sourceTree = SOURCE_ROOT; + }; + B1D8EC5D1170310E00A8A49E /* textures */ = { + isa = PBXGroup; + children = ( + B1D8EC5E1170310E00A8A49E /* bilerp.cpp */, + B1D8EC5F1170310E00A8A49E /* bilerp.h */, + B1D8EC601170310E00A8A49E /* checkerboard.cpp */, + B1D8EC611170310E00A8A49E /* checkerboard.h */, + B1D8EC621170310E00A8A49E /* constant.cpp */, + B1D8EC631170310E00A8A49E /* constant.h */, + B1D8EC641170310E00A8A49E /* dots.cpp */, + B1D8EC651170310E00A8A49E /* dots.h */, + B1D8EC661170310E00A8A49E /* fbm.cpp */, + B1D8EC671170310E00A8A49E /* fbm.h */, + B1D8EC681170310E00A8A49E /* imagemap.cpp */, + B1D8EC691170310E00A8A49E /* imagemap.h */, + B1D8EC6A1170310E00A8A49E /* marble.cpp */, + B1D8EC6B1170310E00A8A49E /* marble.h */, + B1D8EC6C1170310E00A8A49E /* mix.cpp */, + B1D8EC6D1170310E00A8A49E /* mix.h */, + B1D8EC6E1170310E00A8A49E /* scale.cpp */, + B1D8EC6F1170310E00A8A49E /* scale.h */, + B1D8EC701170310E00A8A49E /* uv.cpp */, + B1D8EC711170310E00A8A49E /* uv.h */, + B1D8EC721170310E00A8A49E /* windy.cpp */, + B1D8EC731170310E00A8A49E /* windy.h */, + B1D8EC741170310E00A8A49E /* wrinkled.cpp */, + B1D8EC751170310E00A8A49E /* wrinkled.h */, + ); + path = textures; + sourceTree = SOURCE_ROOT; + }; + B1D8EC761170310E00A8A49E /* volumes */ = { + isa = PBXGroup; + children = ( + B1D8EC771170310E00A8A49E /* exponential.cpp */, + B1D8EC781170310E00A8A49E /* exponential.h */, + B1D8EC791170310E00A8A49E /* homogeneous.cpp */, + B1D8EC7A1170310E00A8A49E /* homogeneous.h */, + B1D8EC7B1170310E00A8A49E /* volumegrid.cpp */, + B1D8EC7C1170310E00A8A49E /* volumegrid.h */, + ); + path = volumes; + sourceTree = SOURCE_ROOT; + }; + C6859E8C029090F304C91782 /* Documentation */ = { + isa = PBXGroup; + children = ( + ); + name = Documentation; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8DD76F620486A84900D96B5E /* pbrt */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "pbrt" */; + buildPhases = ( + 8DD76F640486A84900D96B5E /* Sources */, + 8DD76F660486A84900D96B5E /* Frameworks */, + 8DD76F690486A84900D96B5E /* CopyFiles */, + ); + buildRules = ( + B1E1BB7B1177BCE900337ECE /* PBXBuildRule */, + B1E1BB511177B8CF00337ECE /* PBXBuildRule */, + ); + dependencies = ( + ); + name = pbrt; + productInstallPath = "$(HOME)/bin"; + productName = pbrt; + productReference = B1D8ECE2117032E500A8A49E /* pbrt */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "pbrt" */; + compatibilityVersion = "Xcode 3.1"; + hasScannedForEncodings = 1; + mainGroup = 08FB7794FE84155DC02AAC07 /* pbrt */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8DD76F620486A84900D96B5E /* pbrt */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 8DD76F640486A84900D96B5E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B1D8EB5A117030DE00A8A49E /* bvh.cpp in Sources */, + B1D8EB5B117030DE00A8A49E /* grid.cpp in Sources */, + B1D8EB5C117030DE00A8A49E /* kdtreeaccel.cpp in Sources */, + B1D8EB64117030E500A8A49E /* environment.cpp in Sources */, + B1D8EB65117030E500A8A49E /* orthographic.cpp in Sources */, + B1D8EB66117030E500A8A49E /* perspective.cpp in Sources */, + B1D8EBB4117030F200A8A49E /* api.cpp in Sources */, + B1D8EBB5117030F200A8A49E /* camera.cpp in Sources */, + B1D8EBB6117030F200A8A49E /* diffgeom.cpp in Sources */, + B1D8EBB7117030F200A8A49E /* dtrace.d in Sources */, + B1D8EBB8117030F200A8A49E /* error.cpp in Sources */, + B1D8EBB9117030F200A8A49E /* film.cpp in Sources */, + B1D8EBBA117030F200A8A49E /* filter.cpp in Sources */, + B1D8EBBB117030F200A8A49E /* floatfile.cpp in Sources */, + B1D8EBBC117030F200A8A49E /* geometry.cpp in Sources */, + B1D8EBBD117030F200A8A49E /* imageio.cpp in Sources */, + B1D8EBBE117030F200A8A49E /* integrator.cpp in Sources */, + B1D8EBBF117030F200A8A49E /* intersection.cpp in Sources */, + B1D8EBC0117030F200A8A49E /* light.cpp in Sources */, + B1D8EBC1117030F200A8A49E /* material.cpp in Sources */, + B1D8EBC2117030F200A8A49E /* memory.cpp in Sources */, + B1D8EBC3117030F200A8A49E /* montecarlo.cpp in Sources */, + B1D8EBC4117030F200A8A49E /* parallel.cpp in Sources */, + B1D8EBC5117030F200A8A49E /* paramset.cpp in Sources */, + B1D8EBC6117030F200A8A49E /* parser.cpp in Sources */, + B1D8EBC7117030F200A8A49E /* pbrtlex.ll in Sources */, + B1D8EBC8117030F200A8A49E /* primitive.cpp in Sources */, + B1D8EBC9117030F200A8A49E /* probes.cpp in Sources */, + B1D8EBCA117030F200A8A49E /* progressreporter.cpp in Sources */, + B1D8EBCB117030F200A8A49E /* quaternion.cpp in Sources */, + B1D8EBCC117030F200A8A49E /* reflection.cpp in Sources */, + B1D8EBCD117030F200A8A49E /* renderer.cpp in Sources */, + B1D8EBCE117030F200A8A49E /* rng.cpp in Sources */, + B1D8EBCF117030F200A8A49E /* sampler.cpp in Sources */, + B1D8EBD0117030F200A8A49E /* scene.cpp in Sources */, + B1D8EBD1117030F200A8A49E /* sh.cpp in Sources */, + B1D8EBD2117030F200A8A49E /* shape.cpp in Sources */, + B1D8EBD3117030F200A8A49E /* shrots.cpp in Sources */, + B1D8EBD4117030F200A8A49E /* spectrum.cpp in Sources */, + B1D8EBD5117030F200A8A49E /* texture.cpp in Sources */, + B1D8EBD6117030F200A8A49E /* timer.cpp in Sources */, + B1D8EBD7117030F200A8A49E /* transform.cpp in Sources */, + B1D8EBD8117030F200A8A49E /* volume.cpp in Sources */, + B1D8EC7D1170310E00A8A49E /* image.cpp in Sources */, + B1D8EC7E1170310E00A8A49E /* box.cpp in Sources */, + B1D8EC7F1170310E00A8A49E /* gaussian.cpp in Sources */, + B1D8EC801170310E00A8A49E /* mitchell.cpp in Sources */, + B1D8EC811170310E00A8A49E /* sinc.cpp in Sources */, + B1D8EC821170310E00A8A49E /* triangle.cpp in Sources */, + B1D8EC831170310E00A8A49E /* ambientocclusion.cpp in Sources */, + B1D8EC841170310E00A8A49E /* diffuseprt.cpp in Sources */, + B1D8EC851170310E00A8A49E /* dipolesubsurface.cpp in Sources */, + B1D8EC861170310E00A8A49E /* directlighting.cpp in Sources */, + B1D8EC871170310E00A8A49E /* emission.cpp in Sources */, + B1D8EC881170310E00A8A49E /* glossyprt.cpp in Sources */, + B1D8EC891170310E00A8A49E /* igi.cpp in Sources */, + B1D8EC8A1170310E00A8A49E /* irradiancecache.cpp in Sources */, + B1D8EC8B1170310E00A8A49E /* path.cpp in Sources */, + B1D8EC8C1170310E00A8A49E /* photonmap.cpp in Sources */, + B1D8EC8D1170310E00A8A49E /* single.cpp in Sources */, + B1D8EC8E1170310E00A8A49E /* useprobes.cpp in Sources */, + B1D8EC8F1170310E00A8A49E /* whitted.cpp in Sources */, + B1D8EC901170310E00A8A49E /* diffuse.cpp in Sources */, + B1D8EC911170310E00A8A49E /* distant.cpp in Sources */, + B1D8EC931170310E00A8A49E /* goniometric.cpp in Sources */, + B1D8EC941170310E00A8A49E /* infinite.cpp in Sources */, + B1D8EC951170310E00A8A49E /* point.cpp in Sources */, + B1D8EC961170310E00A8A49E /* projection.cpp in Sources */, + B1D8EC971170310E00A8A49E /* spot.cpp in Sources */, + B1D8EC981170310E00A8A49E /* pbrt.cpp in Sources */, + B1D8EC991170310E00A8A49E /* glass.cpp in Sources */, + B1D8EC9A1170310E00A8A49E /* kdsubsurface.cpp in Sources */, + B1D8EC9B1170310E00A8A49E /* matte.cpp in Sources */, + B1D8EC9C1170310E00A8A49E /* measured.cpp in Sources */, + B1D8EC9D1170310E00A8A49E /* metal.cpp in Sources */, + B1D8EC9E1170310E00A8A49E /* mirror.cpp in Sources */, + B1D8EC9F1170310E00A8A49E /* mixmat.cpp in Sources */, + B1D8ECA01170310E00A8A49E /* plastic.cpp in Sources */, + B1D8ECA11170310E00A8A49E /* substrate.cpp in Sources */, + B1D8ECA21170310E00A8A49E /* subsurface.cpp in Sources */, + B1D8ECA31170310E00A8A49E /* translucent.cpp in Sources */, + B1D8ECA41170310E00A8A49E /* uber.cpp in Sources */, + B1D8ECA51170310E00A8A49E /* aggregatetest.cpp in Sources */, + B1D8ECA61170310E00A8A49E /* createprobes.cpp in Sources */, + B1D8ECA71170310E00A8A49E /* metropolis.cpp in Sources */, + B1D8ECA81170310E00A8A49E /* samplerrenderer.cpp in Sources */, + B1D8ECA91170310E00A8A49E /* surfacepoints.cpp in Sources */, + B1D8ECAA1170310E00A8A49E /* adaptive.cpp in Sources */, + B1D8ECAB1170310E00A8A49E /* bestcandidate.cpp in Sources */, + B1D8ECAC1170310E00A8A49E /* halton.cpp in Sources */, + B1D8ECAD1170310E00A8A49E /* lowdiscrepancy.cpp in Sources */, + B1D8ECAE1170310E00A8A49E /* random.cpp in Sources */, + B1D8ECAF1170310E00A8A49E /* stratified.cpp in Sources */, + B1D8ECB01170310E00A8A49E /* cone.cpp in Sources */, + B1D8ECB11170310E00A8A49E /* cylinder.cpp in Sources */, + B1D8ECB21170310E00A8A49E /* disk.cpp in Sources */, + B1D8ECB31170310E00A8A49E /* heightfield.cpp in Sources */, + B1D8ECB41170310E00A8A49E /* hyperboloid.cpp in Sources */, + B1D8ECB51170310E00A8A49E /* loopsubdiv.cpp in Sources */, + B1D8ECB61170310E00A8A49E /* nurbs.cpp in Sources */, + B1D8ECB71170310E00A8A49E /* paraboloid.cpp in Sources */, + B1D8ECB81170310E00A8A49E /* sphere.cpp in Sources */, + B1D8ECB91170310E00A8A49E /* trianglemesh.cpp in Sources */, + B1D8ECBA1170310E00A8A49E /* bilerp.cpp in Sources */, + B1D8ECBB1170310E00A8A49E /* checkerboard.cpp in Sources */, + B1D8ECBC1170310E00A8A49E /* constant.cpp in Sources */, + B1D8ECBD1170310E00A8A49E /* dots.cpp in Sources */, + B1D8ECBE1170310E00A8A49E /* fbm.cpp in Sources */, + B1D8ECBF1170310E00A8A49E /* imagemap.cpp in Sources */, + B1D8ECC01170310E00A8A49E /* marble.cpp in Sources */, + B1D8ECC11170310E00A8A49E /* mix.cpp in Sources */, + B1D8ECC21170310E00A8A49E /* scale.cpp in Sources */, + B1D8ECC31170310E00A8A49E /* uv.cpp in Sources */, + B1D8ECC41170310E00A8A49E /* windy.cpp in Sources */, + B1D8ECC51170310E00A8A49E /* wrinkled.cpp in Sources */, + B1D8ECC61170310E00A8A49E /* exponential.cpp in Sources */, + B1D8ECC71170310E00A8A49E /* homogeneous.cpp in Sources */, + B1D8ECC81170310E00A8A49E /* volumegrid.cpp in Sources */, + B1E1BB3F1177B63E00337ECE /* pbrtparse.yy in Sources */, + B19397BB12083210008317C5 /* shinymetal.cpp in Sources */, + B130248E1236EE5100206AC7 /* fileutil.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB923208733DC60010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = PBRT_PROBES_NONE; + HEADER_SEARCH_PATHS = ( + "$(DERIVED_FILES_DIR)/Yacc", + ., + ); + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = pbrt; + }; + name = Debug; + }; + 1DEB923308733DC60010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_MODEL_TUNING = G5; + GCC_PREPROCESSOR_DEFINITIONS = PBRT_PROBES_NONE; + HEADER_SEARCH_PATHS = ( + "$(DERIVED_FILES_DIR)/Yacc", + ., + ); + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = pbrt; + }; + name = Release; + }; + 1DEB923608733DC60010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + PBRT_STATS_NONE, + PBRT_HAS_PTHREADS, + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ..; + ONLY_ACTIVE_ARCH = YES; + PREBINDING = NO; + RUN_CLANG_STATIC_ANALYZER = YES; + SDKROOT = macosx10.6; + }; + name = Debug; + }; + 1DEB923708733DC60010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_PREPROCESSOR_DEFINITIONS = ( + NDEBUG, + PBRT_STATS_NONE, + PBRT_HAS_PTHREADS, + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ..; + PREBINDING = NO; + RUN_CLANG_STATIC_ANALYZER = YES; + SDKROOT = macosx10.6; + }; + name = Release; + }; + B18C76E91189CC6400AEF213 /* dtrace */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_PREPROCESSOR_DEFINITIONS = ( + NDEBUG, + PBRT_STATS_DTRACE, + PBRT_HAS_PTHREADS, + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ..; + PREBINDING = NO; + RUN_CLANG_STATIC_ANALYZER = YES; + SDKROOT = macosx10.6; + }; + name = dtrace; + }; + B18C76EA1189CC6400AEF213 /* dtrace */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_MODEL_TUNING = G5; + GCC_PREPROCESSOR_DEFINITIONS = PBRT_PROBES_NONE; + HEADER_SEARCH_PATHS = ( + "$(DERIVED_FILES_DIR)/Yacc", + ., + ); + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = pbrt; + }; + name = dtrace; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "pbrt" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB923208733DC60010E9CD /* Debug */, + 1DEB923308733DC60010E9CD /* Release */, + B18C76EA1189CC6400AEF213 /* dtrace */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "pbrt" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB923608733DC60010E9CD /* Debug */, + 1DEB923708733DC60010E9CD /* Release */, + B18C76E91189CC6400AEF213 /* dtrace */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/renderers/#metropolis.cpp# b/renderers/#metropolis.cpp# new file mode 100644 index 0000000..30582e2 --- /dev/null +++ b/renderers/#metropolis.cpp# @@ -0,0 +1,808 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// renderers/metropolis.cpp* +#include "renderers/metropolis.h" +#include "renderers/samplerrenderer.h" +#include "scene.h" +#include "imageio.h" +#include "spectrum.h" +#include "camera.h" +#include "film.h" +#include "rng.h" +#include "progressreporter.h" +#include "paramset.h" +#include "parallel.h" +#include "probes.h" +#include "intersection.h" +#include "montecarlo.h" +#include "samplers/lowdiscrepancy.h" +#include "integrators/directlighting.h" + +// Metropolis Local Declarations +struct PathSample { + BSDFSample bsdfSample; + float rrSample; +}; + + +struct LightingSample { + BSDFSample bsdfSample; + float lightNum; + LightSample lightSample; +}; + + +struct MLTSample { + MLTSample(int maxLength) { + cameraPathSamples.resize(maxLength); + lightPathSamples.resize(maxLength); + lightingSamples.resize(maxLength); + } + CameraSample cameraSample; + float lightNumSample, lightRaySamples[5]; + vector cameraPathSamples, lightPathSamples; + vector lightingSamples; +}; + + +static void LargeStep(RNG &rng, MLTSample *sample, int maxDepth, + float x, float y, float t0, float t1, bool bidirectional) { + // Do large step mutation of _cameraSample_ + sample->cameraSample.imageX = x; + sample->cameraSample.imageY = y; + sample->cameraSample.time = Lerp(rng.RandomFloat(), t0, t1); + sample->cameraSample.lensU = rng.RandomFloat(); + sample->cameraSample.lensV = rng.RandomFloat(); + for (int i = 0; i < maxDepth; ++i) { + // Apply large step to $i$th camera _PathSample_ + PathSample &cps = sample->cameraPathSamples[i]; + cps.bsdfSample.uComponent = rng.RandomFloat(); + cps.bsdfSample.uDir[0] = rng.RandomFloat(); + cps.bsdfSample.uDir[1] = rng.RandomFloat(); + cps.rrSample = rng.RandomFloat(); + + // Apply large step to $i$th _LightingSample_ + LightingSample &ls = sample->lightingSamples[i]; + ls.bsdfSample.uComponent = rng.RandomFloat(); + ls.bsdfSample.uDir[0] = rng.RandomFloat(); + ls.bsdfSample.uDir[1] = rng.RandomFloat(); + ls.lightNum = rng.RandomFloat(); + ls.lightSample.uComponent = rng.RandomFloat(); + ls.lightSample.uPos[0] = rng.RandomFloat(); + ls.lightSample.uPos[1] = rng.RandomFloat(); + } + if (bidirectional) { + // Apply large step to bidirectional light samples + sample->lightNumSample = rng.RandomFloat(); + for (int i = 0; i < 5; ++i) + sample->lightRaySamples[i] = rng.RandomFloat(); + for (int i = 0; i < maxDepth; ++i) { + // Apply large step to $i$th light _PathSample_ + PathSample &lps = sample->lightPathSamples[i]; + lps.bsdfSample.uComponent = rng.RandomFloat(); + lps.bsdfSample.uDir[0] = rng.RandomFloat(); + lps.bsdfSample.uDir[1] = rng.RandomFloat(); + lps.rrSample = rng.RandomFloat(); + } + } +} + + +static inline void mutate(RNG &rng, float *v, float min = 0.f, + float max = 1.f) { + if (min == max) { *v = min; return; } + Assert(min < max); + float a = 1.f / 1024.f, b = 1.f / 64.f; + static const float logRatio = -logf(b/a); + float delta = (max - min) * b * expf(logRatio * rng.RandomFloat()); + float orig = *v; + bool low = false; + if (rng.RandomFloat() < 0.5f) { + low = true; + *v += delta; + if (*v >= max) *v = min + (*v - max); + if (*v < min) v = min; + } + else { + *v -= delta; + if (*v < min) *v = max - (min - *v); + } + Assert(*v >= min && *v < max); +} + + +static void SmallStep(RNG &rng, MLTSample *sample, int maxDepth, + int x0, int x1, int y0, int y1, float t0, float t1, + bool bidirectional) { + mutate(rng, &sample->cameraSample.imageX, x0, x1); + mutate(rng, &sample->cameraSample.imageY, y0, y1); + mutate(rng, &sample->cameraSample.time, t0, t1); + mutate(rng, &sample->cameraSample.lensU); + mutate(rng, &sample->cameraSample.lensV); + // Apply small step mutation to camera, lighting, and light samples + for (int i = 0; i < maxDepth; ++i) { + // Apply small step to $i$th camera _PathSample_ + PathSample &eps = sample->cameraPathSamples[i]; + mutate(rng, &eps.bsdfSample.uComponent); + mutate(rng, &eps.bsdfSample.uDir[0]); + mutate(rng, &eps.bsdfSample.uDir[1]); + mutate(rng, &eps.rrSample); + + // Apply small step to $i$th _LightingSample_ + LightingSample &ls = sample->lightingSamples[i]; + mutate(rng, &ls.bsdfSample.uComponent); + mutate(rng, &ls.bsdfSample.uDir[0]); + mutate(rng, &ls.bsdfSample.uDir[1]); + mutate(rng, &ls.lightNum); + mutate(rng, &ls.lightSample.uComponent); + mutate(rng, &ls.lightSample.uPos[0]); + mutate(rng, &ls.lightSample.uPos[1]); + } + + if (bidirectional) { + mutate(rng, &sample->lightNumSample); + for (int i = 0; i < 5; ++i) + mutate(rng, &sample->lightRaySamples[i]); + for (int i = 0; i < maxDepth; ++i) { + // Apply small step to $i$th light _PathSample_ + PathSample &lps = sample->lightPathSamples[i]; + mutate(rng, &lps.bsdfSample.uComponent); + mutate(rng, &lps.bsdfSample.uDir[0]); + mutate(rng, &lps.bsdfSample.uDir[1]); + mutate(rng, &lps.rrSample); + } + } +} + + +struct PathVertex { + Intersection isect; + Vector wPrev, wNext; + BSDF *bsdf; + bool specularBounce; + int nSpecularComponents; + Spectrum alpha; +}; + + +static uint32_t GeneratePath(const RayDifferential &r, const Spectrum &alpha, + const Scene *scene, MemoryArena &arena, const vector &samples, + PathVertex *path, RayDifferential *escapedRay, + Spectrum *escapedAlpha); +inline float I(const Spectrum &L); +class MLTTask : public Task { +public: + MLTTask(ProgressReporter &prog, uint32_t pfreq, uint32_t taskNum, + float dx, float dy, int xx0, int xx1, int yy0, int yy1, float tt0, float tt1, + float bb, const MLTSample &is, const Scene *sc, const Camera *c, + MetropolisRenderer *renderer, Mutex *filmMutex, + Distribution1D *lightDistribution); + void Run(); + +private: + ProgressReporter &progress; + uint32_t progressUpdateFrequency, taskNum; + float dx, dy; + int currentPixelSample; + int x0, x1, y0, y1; + float t0, t1; + float b; + const MLTSample &initialSample; + const Scene *scene; + const Camera *camera; + MetropolisRenderer *renderer; + Mutex *filmMutex; + Distribution1D *lightDistribution; +}; + + + +// Metropolis Method Definitions +static uint32_t GeneratePath(const RayDifferential &r, + const Spectrum &a, const Scene *scene, MemoryArena &arena, + const vector &samples, PathVertex *path, + RayDifferential *escapedRay, Spectrum *escapedAlpha) { + PBRT_MLT_STARTED_GENERATE_PATH(); + RayDifferential ray = r; + Spectrum alpha = a; + if (escapedAlpha) *escapedAlpha = 0.f; + uint32_t length = 0; + for (; length < samples.size(); ++length) { + // Try to generate next vertex of ray path + PathVertex &v = path[length]; + if (!scene->Intersect(ray, &v.isect)) { + // Handle ray that leaves the scene during path generation + if (escapedAlpha) *escapedAlpha = alpha; + if (escapedRay) *escapedRay = ray; + break; + } + + // Record information for current path vertex + v.alpha = alpha; + BSDF *bsdf = v.isect.GetBSDF(ray, arena); + v.bsdf = bsdf; + v.wPrev = -ray.d; + + // Sample direction for outgoing Metropolis path direction + float pdf; + BxDFType flags; + Spectrum f = bsdf->Sample_f(-ray.d, &v.wNext, samples[length].bsdfSample, + &pdf, BSDF_ALL, &flags); + v.specularBounce = (flags & BSDF_SPECULAR) != 0; + v.nSpecularComponents = bsdf->NumComponents(BxDFType(BSDF_SPECULAR | + BSDF_REFLECTION | BSDF_TRANSMISSION)); + if (f.IsBlack() || pdf == 0.f) + { + PBRT_MLT_FINISHED_GENERATE_PATH(); + return length+1; + } + + // Terminate path with RR or prepare for finding next vertex + const Point &p = bsdf->dgShading.p; + const Normal &n = bsdf->dgShading.nn; + Spectrum pathScale = f * AbsDot(v.wNext, n) / pdf; + float rrSurviveProb = min(1.f, pathScale.y()); + if (samples[length].rrSample > rrSurviveProb) + { + PBRT_MLT_FINISHED_GENERATE_PATH(); + return length+1; + } + alpha *= pathScale / rrSurviveProb; + //alpha *= renderer->Transmittance(scene, ray, NULL, rng, arena); + ray = RayDifferential(p, v.wNext, ray, v.isect.rayEpsilon); + } + PBRT_MLT_FINISHED_GENERATE_PATH(); + return length; +} + + +Spectrum MetropolisRenderer::PathL(const MLTSample &sample, + const Scene *scene, MemoryArena &arena, const Camera *camera, + const Distribution1D *lightDistribution, + PathVertex *cameraPath, PathVertex *lightPath, + RNG &rng) const { + // Generate camera path from camera path samples + PBRT_STARTED_GENERATING_CAMERA_RAY((CameraSample *)(&sample.cameraSample)); + RayDifferential cameraRay; + float cameraWt = camera->GenerateRayDifferential(sample.cameraSample, + &cameraRay); + cameraRay.ScaleDifferentials(1.f / sqrtf(nPixelSamples)); + PBRT_FINISHED_GENERATING_CAMERA_RAY((CameraSample *)(&sample.cameraSample), &cameraRay, cameraWt); + RayDifferential escapedRay; + Spectrum escapedAlpha; + uint32_t cameraLength = GeneratePath(cameraRay, cameraWt, scene, arena, + sample.cameraPathSamples, cameraPath, &escapedRay, &escapedAlpha); + if (!bidirectional) { + // Compute radiance along path using path tracing + return Lpath(scene, cameraPath, cameraLength, arena, + sample.lightingSamples, rng, sample.cameraSample.time, + lightDistribution, escapedRay, escapedAlpha); + } + else { + // Sample light ray and apply bidirectional path tracing + + // Choose light and sample ray to start light path + PBRT_MLT_STARTED_SAMPLE_LIGHT_FOR_BIDIR(); + float lightPdf, lightRayPdf; + uint32_t lightNum = lightDistribution->SampleDiscrete(sample.lightNumSample, + &lightPdf); + const Light *light = scene->lights[lightNum]; + Ray lightRay; + Normal Nl; + LightSample lrs(sample.lightRaySamples[0], sample.lightRaySamples[1], + sample.lightRaySamples[2]); + Spectrum lightWt = light->Sample_L(scene, lrs, sample.lightRaySamples[3], + sample.lightRaySamples[4], sample.cameraSample.time, &lightRay, + &Nl, &lightRayPdf); + PBRT_MLT_FINISHED_SAMPLE_LIGHT_FOR_BIDIR(); + if (lightWt.IsBlack() || lightRayPdf == 0.f) { + // Compute radiance along path using path tracing + return Lpath(scene, cameraPath, cameraLength, arena, + sample.lightingSamples, rng, sample.cameraSample.time, + lightDistribution, escapedRay, escapedAlpha); + } + else { + // Compute radiance along paths using bidirectional path tracing + lightWt *= AbsDot(Normalize(Nl), lightRay.d) / (lightPdf * lightRayPdf); + uint32_t lightLength = GeneratePath(RayDifferential(lightRay), lightWt, + scene, arena, sample.lightPathSamples, lightPath, NULL, NULL); + return Lbidir(scene, cameraPath, cameraLength, lightPath, lightLength, + arena, sample.lightingSamples, rng, sample.cameraSample.time, + lightDistribution, escapedRay, escapedAlpha); + } + } +} + + +Spectrum MetropolisRenderer::Lpath(const Scene *scene, + const PathVertex *cameraPath, int cameraPathLength, + MemoryArena &arena, const vector &samples, + RNG &rng, float time, const Distribution1D *lightDistribution, + const RayDifferential &eRay, const Spectrum &eAlpha) const { + PBRT_MLT_STARTED_LPATH(); + Spectrum L = 0.; + bool previousSpecular = true, allSpecular = true; + for (int i = 0; i < cameraPathLength; ++i) { + // Initialize basic variables for camera path vertex + const PathVertex &vc = cameraPath[i]; + const Point &pc = vc.bsdf->dgShading.p; + const Normal &nc = vc.bsdf->dgShading.nn; + + // Add emitted light from vertex if appropriate + if (previousSpecular && (directLighting == NULL || !allSpecular)) + L += vc.alpha * vc.isect.Le(vc.wPrev); + + // Compute direct illumination for Metropolis path vertex + Spectrum Ld(0.f); + if (directLighting == NULL || !allSpecular) { + // Choose light and call _EstimateDirect()_ for Metropolis vertex + const LightingSample &ls = samples[i]; + float lightPdf; + uint32_t lightNum = lightDistribution->SampleDiscrete(ls.lightNum, + &lightPdf); + const Light *light = scene->lights[lightNum]; + PBRT_MLT_STARTED_ESTIMATE_DIRECT(); + Ld = vc.alpha * + EstimateDirect(scene, this, arena, light, pc, nc, vc.wPrev, + vc.isect.rayEpsilon, time, vc.bsdf, rng, + ls.lightSample, ls.bsdfSample, + BxDFType(BSDF_ALL & ~BSDF_SPECULAR)) / lightPdf; + PBRT_MLT_FINISHED_ESTIMATE_DIRECT(); + } + previousSpecular = vc.specularBounce; + allSpecular &= previousSpecular; + L += Ld; + } + // Add contribution of escaped ray, if any + if (!eAlpha.IsBlack() && previousSpecular && + (directLighting == NULL || !allSpecular)) + for (uint32_t i = 0; i < scene->lights.size(); ++i) + L += eAlpha * scene->lights[i]->Le(eRay); + PBRT_MLT_FINISHED_LPATH(); + return L; +} + + +Spectrum MetropolisRenderer::Lbidir(const Scene *scene, + const PathVertex *cameraPath, int cameraPathLength, + const PathVertex *lightPath, int lightPathLength, + MemoryArena &arena, const vector &samples, + RNG &rng, float time, const Distribution1D *lightDistribution, + const RayDifferential &eRay, const Spectrum &eAlpha) const { + PBRT_MLT_STARTED_LBIDIR(); + Spectrum L = 0.; + bool previousSpecular = true, allSpecular = true; + // Compute number of specular vertices for each path length + int nVerts = cameraPathLength + lightPathLength + 2; + int *nSpecularVertices = ALLOCA(int, nVerts); + memset(nSpecularVertices, 0, nVerts * sizeof(int)); + for (int i = 0; i < cameraPathLength; ++i) + for (int j = 0; j < lightPathLength; ++j) + if (cameraPath[i].specularBounce || lightPath[j].specularBounce) + ++nSpecularVertices[i+j+2]; + for (int i = 0; i < cameraPathLength; ++i) { + // Initialize basic variables for camera path vertex + const PathVertex &vc = cameraPath[i]; + const Point &pc = vc.bsdf->dgShading.p; + const Normal &nc = vc.bsdf->dgShading.nn; + + // Compute reflected light at camera path vertex + + // Add emitted light from vertex if appropriate + if (previousSpecular && (directLighting == NULL || !allSpecular)) + L += vc.alpha * vc.isect.Le(vc.wPrev); + + // Compute direct illumination for Metropolis path vertex + Spectrum Ld(0.f); + if (directLighting == NULL || !allSpecular) { + // Choose light and call _EstimateDirect()_ for Metropolis vertex + const LightingSample &ls = samples[i]; + float lightPdf; + uint32_t lightNum = lightDistribution->SampleDiscrete(ls.lightNum, + &lightPdf); + const Light *light = scene->lights[lightNum]; + PBRT_MLT_STARTED_ESTIMATE_DIRECT(); + Ld = vc.alpha * + EstimateDirect(scene, this, arena, light, pc, nc, vc.wPrev, + vc.isect.rayEpsilon, time, vc.bsdf, rng, + ls.lightSample, ls.bsdfSample, + BxDFType(BSDF_ALL & ~BSDF_SPECULAR)) / lightPdf; + PBRT_MLT_FINISHED_ESTIMATE_DIRECT(); + } + previousSpecular = vc.specularBounce; + allSpecular &= previousSpecular; + L += Ld / (i + 1 - nSpecularVertices[i+1]); + if (!vc.specularBounce) { + // Loop over light path vertices and connect to camera vertex + for (int j = 0; j < lightPathLength; ++j) { + const PathVertex &vl = lightPath[j]; + const Point &pl = vl.bsdf->dgShading.p; + const Normal &nl = vl.bsdf->dgShading.nn; + if (!vl.specularBounce) { + // Compute contribution between camera and light vertices + Vector w = Normalize(pl - pc); + Spectrum fc = vc.bsdf->f(vc.wPrev, w) * (1 + vc.nSpecularComponents); + Spectrum fl = vl.bsdf->f(-w, vl.wPrev) * (1 + vl.nSpecularComponents); + if (fc.IsBlack() || fl.IsBlack()) continue; + Ray r(pc, pl - pc, 1e-3f, .999f, time); + if (!scene->IntersectP(r)) { + // Compute weight for bidirectional path, _pathWt_ + float pathWt = 1.f / (i + j + 2 - nSpecularVertices[i+j+2]); + float G = AbsDot(nc, w) * AbsDot(nl, w) / DistanceSquared(pl, pc); + L += (vc.alpha * fc * G * fl * vl.alpha) * pathWt; + } + } + } + } + } + // Add contribution of escaped ray, if any + if (!eAlpha.IsBlack() && previousSpecular && + (directLighting == NULL || !allSpecular)) + for (uint32_t i = 0; i < scene->lights.size(); ++i) + L += eAlpha * scene->lights[i]->Le(eRay); + PBRT_MLT_FINISHED_LBIDIR(); + return L; +} + + +MetropolisRenderer::MetropolisRenderer(int perPixelSamples, + int nboot, int dps, float lsp, bool dds, int mr, int md, + Camera *c, bool db) { + camera = c; + + nPixelSamples = perPixelSamples; + float largeStepProbability = lsp; + largeStepsPerPixel = max(1u, RoundUpPow2(largeStepProbability * nPixelSamples)); + if (largeStepsPerPixel >= nPixelSamples) largeStepsPerPixel /= 2; + Assert(largeStepsPerPixel >= 1 && largeStepsPerPixel < nPixelSamples); + if ((nPixelSamples % largeStepsPerPixel) != 0) { + int origPixelSamples = nPixelSamples; + nPixelSamples += largeStepsPerPixel - (nPixelSamples % largeStepsPerPixel); + Warning("Rounding up to %d Metropolis samples per pixel (from %d)", + nPixelSamples, origPixelSamples); + } + + nBootstrap = nboot; + nDirectPixelSamples = dps; + + maxDepth = md; + maxConsecutiveRejects = mr; + nTasksFinished = 0; + directLighting = dds ? new DirectLightingIntegrator(SAMPLE_ALL_UNIFORM, maxDepth) : NULL; + bidirectional = db; +} + + +MetropolisRenderer::~MetropolisRenderer() { + delete camera; + delete directLighting; +} + + +MetropolisRenderer *CreateMetropolisRenderer(const ParamSet ¶ms, + Camera *camera) { + float largeStepProbability = params.FindOneFloat("largestepprobability", .25f); + int perPixelSamples = params.FindOneInt("samplesperpixel", 100); + int nBootstrap = params.FindOneInt("bootstrapsamples", 100000); + int nDirectPixelSamples = params.FindOneInt("directsamples", 4); + bool doDirectSeparately = params.FindOneBool("dodirectseparately", true); + int mr = params.FindOneInt("maxconsecutiverejects", 512); + int md = params.FindOneInt("maxdepth", 7); + bool doBidirectional = params.FindOneBool("bidirectional", true); + + if (PbrtOptions.quickRender) { + perPixelSamples = max(1, perPixelSamples / 4); + nBootstrap = max(1, nBootstrap / 4); + nDirectPixelSamples = max(1, nDirectPixelSamples / 4); + } + + return new MetropolisRenderer(perPixelSamples, nBootstrap, + nDirectPixelSamples, largeStepProbability, doDirectSeparately, + mr, md, camera, doBidirectional); +} + + +void MetropolisRenderer::Render(const Scene *scene) { + PBRT_MLT_STARTED_RENDERING(); + if (scene->lights.size() > 0) { + int x0, x1, y0, y1; + camera->film->GetPixelExtent(&x0, &x1, &y0, &y1); + float t0 = camera->shutterOpen, t1 = camera->shutterClose; + Distribution1D *lightDistribution = ComputeLightSamplingCDF(scene); + + if (directLighting != NULL) { + PBRT_MLT_STARTED_DIRECTLIGHTING(); + // Compute direct lighting before Metropolis light transport + if (nDirectPixelSamples > 0) { + LDSampler sampler(x0, x1, y0, y1, nDirectPixelSamples, t0, t1); + Sample *sample = new Sample(&sampler, directLighting, NULL, scene); + vector directTasks; + int nDirectTasks = max(32 * NumSystemCores(), + (camera->film->xResolution * camera->film->yResolution) / (16*16)); + nDirectTasks = RoundUpPow2(nDirectTasks); + ProgressReporter directProgress(nDirectTasks, "Direct Lighting"); + for (int i = 0; i < nDirectTasks; ++i) + directTasks.push_back(new SamplerRendererTask(scene, this, camera, directProgress, + &sampler, sample, i, nDirectTasks)); + std::reverse(directTasks.begin(), directTasks.end()); + EnqueueTasks(directTasks); + WaitForAllTasks(); + for (uint32_t i = 0; i < directTasks.size(); ++i) + delete directTasks[i]; + delete sample; + directProgress.Done(); + } + camera->film->WriteImage(); + PBRT_MLT_FINISHED_DIRECTLIGHTING(); + } + // Take initial set of samples to compute $b$ + PBRT_MLT_STARTED_BOOTSTRAPPING(nBootstrap); + RNG rng(0); + MemoryArena arena; + vector bootstrapI; + vector cameraPath(maxDepth, PathVertex()); + vector lightPath(maxDepth, PathVertex()); + float sumI = 0.f; + bootstrapI.reserve(nBootstrap); + MLTSample sample(maxDepth); + for (uint32_t i = 0; i < nBootstrap; ++i) { + // Generate random sample and path radiance for MLT bootstrapping + float x = Lerp(rng.RandomFloat(), x0, x1); + float y = Lerp(rng.RandomFloat(), y0, y1); + LargeStep(rng, &sample, maxDepth, x, y, t0, t1, bidirectional); + Spectrum L = PathL(sample, scene, arena, camera, lightDistribution, + &cameraPath[0], &lightPath[0], rng); + + // Compute contribution for random sample for MLT bootstrapping + float I = ::I(L); + sumI += I; + bootstrapI.push_back(I); + arena.FreeAll(); + } + float b = sumI / nBootstrap; + PBRT_MLT_FINISHED_BOOTSTRAPPING(b); + Info("MLT computed b = %f", b); + + // Select initial sample from bootstrap samples + float contribOffset = rng.RandomFloat() * sumI; + rng.Seed(0); + sumI = 0.f; + MLTSample initialSample(maxDepth); + for (uint32_t i = 0; i < nBootstrap; ++i) { + float x = Lerp(rng.RandomFloat(), x0, x1); + float y = Lerp(rng.RandomFloat(), y0, y1); + LargeStep(rng, &initialSample, maxDepth, x, y, t0, t1, + bidirectional); + sumI += bootstrapI[i]; + if (sumI > contribOffset) + break; + } + + // Launch tasks to generate Metropolis samples + uint32_t nTasks = largeStepsPerPixel; + uint32_t largeStepRate = nPixelSamples / largeStepsPerPixel; + Info("MLT running %d tasks, large step rate %d", nTasks, largeStepRate); + ProgressReporter progress(nTasks * largeStepRate, "Metropolis"); + vector tasks; + Mutex *filmMutex = Mutex::Create(); + Assert(IsPowerOf2(nTasks)); + uint32_t scramble[2] = { rng.RandomUInt(), rng.RandomUInt() }; + uint32_t pfreq = (x1-x0) * (y1-y0); + for (uint32_t i = 0; i < nTasks; ++i) { + float d[2]; + Sample02(i, scramble, d); + tasks.push_back(new MLTTask(progress, pfreq, i, + d[0], d[1], x0, x1, y0, y1, t0, t1, b, initialSample, + scene, camera, this, filmMutex, lightDistribution)); + } + EnqueueTasks(tasks); + WaitForAllTasks(); + for (uint32_t i = 0; i < tasks.size(); ++i) + delete tasks[i]; + progress.Done(); + Mutex::Destroy(filmMutex); + } + camera->film->WriteImage(); + PBRT_MLT_FINISHED_RENDERING(); +} + + +inline float I(const Spectrum &L) { + return L.y(); +} + + +MLTTask::MLTTask(ProgressReporter &prog, uint32_t pfreq, uint32_t tn, + float ddx, float ddy, int xx0, int xx1, int yy0, int yy1, float tt0, float tt1, + float bb, const MLTSample &is, const Scene *sc, const Camera *c, + MetropolisRenderer *ren, Mutex *fm, Distribution1D *ld) + : progress(prog), initialSample(is) { + progressUpdateFrequency = pfreq; + taskNum = tn; + dx = ddx; + dy = ddy; + x0 = xx0; + x1 = xx1; + y0 = yy0; + y1 = yy1; + t0 = tt0; + t1 = tt1; + currentPixelSample = 0; + b = bb; + scene = sc; + camera = c; + renderer = ren; + filmMutex = fm; + lightDistribution = ld; +} + + +void MLTTask::Run() { + PBRT_MLT_STARTED_MLT_TASK(this); + // Declare basic _MLTTask_ variables and prepare for sampling + PBRT_MLT_STARTED_TASK_INIT(); + uint32_t nPixels = (x1-x0) * (y1-y0); + uint32_t nPixelSamples = renderer->nPixelSamples; + uint32_t largeStepRate = nPixelSamples / renderer->largeStepsPerPixel; + Assert(largeStepRate > 1); + uint64_t nTaskSamples = uint64_t(nPixels) * uint64_t(largeStepRate); + uint32_t consecutiveRejects = 0; + uint32_t progressCounter = progressUpdateFrequency; + + // Declare variables for storing and computing MLT samples + MemoryArena arena; + RNG rng(taskNum); + vector cameraPath(renderer->maxDepth, PathVertex()); + vector lightPath(renderer->maxDepth, PathVertex()); + vector samples(2, MLTSample(renderer->maxDepth)); + Spectrum L[2]; + float I[2]; + Spectrum currentSumContrib(0.f); + uint32_t current = 0, proposed = 1; + + // Compute _L[current]_ for initial sample + samples[current] = initialSample; + L[current] = renderer->PathL(initialSample, scene, arena, camera, + lightDistribution, &cameraPath[0], &lightPath[0], rng); + I[current] = ::I(L[current]); + arena.FreeAll(); + + // Compute randomly permuted table of pixel indices for large steps + uint32_t pixelNumOffset = 0; + vector largeStepPixelNum; + largeStepPixelNum.reserve(nPixels); + for (uint32_t i = 0; i < nPixels; ++i) largeStepPixelNum.push_back(i); + Shuffle(&largeStepPixelNum[0], nPixels, 1, rng); + PBRT_MLT_FINISHED_TASK_INIT(); + for (uint64_t s = 0; s < nTaskSamples; ++s) { + // Compute proposed mutation to current sample + PBRT_MLT_STARTED_MUTATION(); + samples[proposed] = samples[current]; + bool largeStep = ((s % largeStepRate) == 0); + if (largeStep) { + int x = x0 + largeStepPixelNum[pixelNumOffset] % (x1 - x0); + int y = y0 + largeStepPixelNum[pixelNumOffset] / (x1 - x0); + LargeStep(rng, &samples[proposed], renderer->maxDepth, + x + dx, y + dy, t0, t1, renderer->bidirectional); + ++pixelNumOffset; + } + else + SmallStep(rng, &samples[proposed], renderer->maxDepth, + x0, x1, y0, y1, t0, t1, renderer->bidirectional); + PBRT_MLT_FINISHED_MUTATION(); + + // Compute contribution of proposed sample + L[proposed] = renderer->PathL(samples[proposed], scene, arena, camera, + lightDistribution, &cameraPath[0], &lightPath[0], rng); + I[proposed] = ::I(L[proposed]); + arena.FreeAll(); + + // Compute acceptance probability for proposed sample + float a = min(1.f, I[proposed] / I[current]); + + // Randomly accept proposed path mutation (or not) + if (a < 1.f && I[current] > 0.f) { + float invI = 1.f / I[current]; + if (!isinf(invI)) + currentSumContrib += ((1.f - a) * (invI * b / nPixelSamples)) * L[current]; + } + Spectrum proposedContrib = 0.f; + if (a > 0.f && I[proposed] > 0.f) { + float invI = 1.f / I[proposed]; + if (!isinf(invI)) + proposedContrib = (a * invI * b / nPixelSamples) * L[proposed]; + } + + if (consecutiveRejects >= renderer->maxConsecutiveRejects || + rng.RandomFloat() < a) { + PBRT_MLT_STARTED_SAMPLE_SPLAT(); + camera->film->Splat(samples[current].cameraSample, currentSumContrib); + PBRT_MLT_FINISHED_SAMPLE_SPLAT(); + + currentSumContrib = proposedContrib; + + PBRT_MLT_ACCEPTED_MUTATION(a, &samples[current], &samples[proposed]); + current ^= 1; + proposed ^= 1; + consecutiveRejects = 0; + } + else + { + PBRT_MLT_REJECTED_MUTATION(a, &samples[current], &samples[proposed]); + ++consecutiveRejects; + + if (I[proposed] > 0.f) { + PBRT_MLT_STARTED_SAMPLE_SPLAT(); + camera->film->Splat(samples[proposed].cameraSample, proposedContrib); + PBRT_MLT_FINISHED_SAMPLE_SPLAT(); + } + } + if (--progressCounter == 0) { + progress.Update(); + progressCounter = progressUpdateFrequency; + } + } + Assert(pixelNumOffset == nPixels); + // Update display for recently computed Metropolis samples + PBRT_MLT_STARTED_DISPLAY_UPDATE(); + int ntf = AtomicAdd(&renderer->nTasksFinished, 1); + int64_t totalSamples = int64_t(nPixels) * int64_t(nPixelSamples); + float splatScale = float(double(totalSamples) / double(ntf * nTaskSamples)); + camera->film->UpdateDisplay(x0, y0, x1, y1, splatScale); + if ((taskNum % 8) == 0) { + MutexLock lock(*filmMutex); + camera->film->WriteImage(splatScale); + } + PBRT_MLT_FINISHED_DISPLAY_UPDATE(); + PBRT_MLT_FINISHED_MLT_TASK(this); +} + + +Spectrum MetropolisRenderer::Li(const Scene *scene, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena, Intersection *isect, + Spectrum *T) const { + Spectrum localT; + if (!T) T = &localT; + Intersection localIsect; + if (!isect) isect = &localIsect; + Spectrum Lo = 0.f; + if (scene->Intersect(ray, isect)) + Lo = directLighting->Li(scene, this, ray, *isect, sample, + rng, arena); + else { + // Handle ray that doesn't intersect any geometry + for (uint32_t i = 0; i < scene->lights.size(); ++i) + Lo += scene->lights[i]->Le(ray); + } + return Lo; +} + + +Spectrum MetropolisRenderer::Transmittance(const Scene *scene, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena) const { + return 1.f; +} + + diff --git a/renderers/aggregatetest.cpp b/renderers/aggregatetest.cpp new file mode 100644 index 0000000..559a9c4 --- /dev/null +++ b/renderers/aggregatetest.cpp @@ -0,0 +1,127 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// renderers/aggregatetest.cpp* +#include "stdafx.h" +#include "renderers/aggregatetest.h" +#include "progressreporter.h" +#include "scene.h" +#include "paramset.h" +#include "montecarlo.h" +#include "primitive.h" +#include "intersection.h" + +// AggregateTest Method Definitions +AggregateTest::AggregateTest(int niters, + const vector > &p) { + nIterations = niters; + for (uint32_t i = 0; i < p.size(); ++i) + p[i]->FullyRefine(primitives); + for (uint32_t i = 0; i < primitives.size(); ++i) + bboxes.push_back(primitives[i]->WorldBound()); +} + + +AggregateTest *CreateAggregateTestRenderer(const ParamSet ¶ms, + const vector > &primitives) { + int niters = params.FindOneInt("niters", 100000); + return new AggregateTest(niters, primitives); +} + + +void AggregateTest::Render(const Scene *scene) { + RNG rng; + ProgressReporter prog(nIterations, "Aggregate Test"); + // Compute bounding box of region used to generate random rays + BBox bbox = scene->WorldBound(); + bbox.Expand(bbox.pMax[bbox.MaximumExtent()] - + bbox.pMin[bbox.MaximumExtent()]); + Point lastHit; + float lastEps = 0.f; + for (int i = 0; i < nIterations; ++i) { + // Choose random rays, _rayAccel_ and _rayAll_ for testing + + // Choose ray origin for testing accelerator + Point org(Lerp(rng.RandomFloat(), bbox.pMin.x, bbox.pMax.x), + Lerp(rng.RandomFloat(), bbox.pMin.y, bbox.pMax.y), + Lerp(rng.RandomFloat(), bbox.pMin.z, bbox.pMax.z)); + if ((rng.RandomUInt() % 4) == 0) org = lastHit; + + // Choose ray direction for testing accelerator + Vector dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat()); + if ((rng.RandomUInt() % 32) == 0) dir.x = dir.y = 0.f; + else if ((rng.RandomUInt() % 32) == 0) dir.x = dir.z = 0.f; + else if ((rng.RandomUInt() % 32) == 0) dir.y = dir.z = 0.f; + + // Choose ray epsilon for testing accelerator + float eps = 0.f; + if (rng.RandomFloat() < .25) eps = lastEps; + else if (rng.RandomFloat() < .25) eps = 1e-3f; + Ray rayAccel(org, dir, eps); + Ray rayAll = rayAccel; + + // Compute intersections using accelerator and exhaustive testing + Intersection isectAccel, isectAll; + bool hitAccel = scene->Intersect(rayAccel, &isectAccel); + bool hitAll = false; + bool inconsistentBounds = false; + for (uint32_t j = 0; j < primitives.size(); ++j) { + if (bboxes[j].IntersectP(rayAll)) + hitAll |= primitives[j]->Intersect(rayAll, &isectAll); + else if (primitives[j]->Intersect(rayAll, &isectAll)) + inconsistentBounds = true; + } + + // Report any inconsistencies between intersections + if (!inconsistentBounds && + ((hitAccel != hitAll) || (rayAccel.maxt != rayAll.maxt))) + Warning("Disagreement: t accel %.16g [%a] t exhaustive %.16g [%a]\n" + "Ray: org [%a, %a, %a], dir [%a, %a, %a], mint = %a", + rayAccel.maxt, rayAll.maxt, rayAccel.maxt, rayAll.maxt, + rayAll.o.x, rayAll.o.y, rayAll.o.z, + rayAll.d.x, rayAll.d.y, rayAll.d.z, rayAll.mint); + if (hitAll) { + lastHit = rayAll(rayAll.maxt); + lastEps = isectAll.rayEpsilon; + } + prog.Update(); + } + prog.Done(); +} + + +Spectrum AggregateTest::Li(const Scene *scene, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena, Intersection *isect, + Spectrum *T) const { + return 0.f; +} + + +Spectrum AggregateTest::Transmittance(const Scene *scene, + const RayDifferential &ray, const Sample *sample, RNG &rng, + MemoryArena &arena) const { + return 0.f; +} + + diff --git a/renderers/aggregatetest.h b/renderers/aggregatetest.h new file mode 100644 index 0000000..2156cbe --- /dev/null +++ b/renderers/aggregatetest.h @@ -0,0 +1,58 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_RENDERERS_AGGREGATETEST_H +#define PBRT_RENDERERS_AGGREGATETEST_H + +// renderers/aggregatetest.h* +#include "pbrt.h" +#include "renderer.h" +#include "memory.h" + +// AggregateTest Declarations +class AggregateTest : public Renderer { +public: + // AggregateTest Public Methods + AggregateTest(int nIters, const vector > &primitives); + void Render(const Scene *scene); + Spectrum Li(const Scene *scene, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena, Intersection *isect = NULL, + Spectrum *T = NULL) const; + Spectrum Transmittance(const Scene *scene, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena) const; +private: + // AggregateTest Private Data + int nIterations; + vector > primitives; + vector bboxes; +}; + + +AggregateTest *CreateAggregateTestRenderer(const ParamSet ¶ms, + const vector > &primitives); + +#endif // PBRT_RENDERERS_AGGREGATETEST_H diff --git a/renderers/createprobes.cpp b/renderers/createprobes.cpp new file mode 100644 index 0000000..01b80cc --- /dev/null +++ b/renderers/createprobes.cpp @@ -0,0 +1,336 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// renderers/createprobes.cpp* +#include "stdafx.h" +#include "renderers/createprobes.h" +#include "shapes/sphere.h" +#include "sh.h" +#include "parallel.h" +#include "scene.h" +#include "progressreporter.h" +#include "camera.h" +#include "intersection.h" +#include "integrator.h" +#include "volume.h" +#include "paramset.h" +#include "montecarlo.h" + +// CreateRadianceProbes Local Declarations +class CreateRadProbeTask : public Task { +public: + CreateRadProbeTask(int i, int nProbes[3], float t, const BBox &b, int lmax, bool id, + bool ii, int nindir, ProgressReporter &p, Sample *sample, + const vector &sp, const Scene *sc, const Renderer *ren, Spectrum *c); + void Run(); +private: + int pointNum, nProbes[3]; + const BBox &bbox; + int lmax, nIndirSamples; + float time; + ProgressReporter &prog; + bool includeDirectInProbes, includeIndirectInProbes; + Sample *origSample; + const Renderer *renderer; + const Scene *scene; + const vector &surfacePoints; + Spectrum *c_in; +}; + + + +// CreateRadianceProbes Method Definitions +CreateRadianceProbes::CreateRadianceProbes(SurfaceIntegrator *surf, + VolumeIntegrator *vol, const Camera *cam, int lm, float ps, const BBox &b, + int nindir, bool id, bool ii, float t, const string &fn) { + lmax = lm; + probeSpacing = ps; + bbox = b; + filename = fn; + includeDirectInProbes = id; + includeIndirectInProbes = ii; + time = t; + nIndirSamples = nindir; + surfaceIntegrator = surf; + volumeIntegrator = vol; + camera = cam; +} + + +CreateRadianceProbes::~CreateRadianceProbes() { + delete surfaceIntegrator; + delete volumeIntegrator; +} + + +Spectrum CreateRadianceProbes::Li(const Scene *scene, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena, Intersection *isect, + Spectrum *T) const { + Assert(ray.time == sample->time); + Spectrum localT; + if (!T) T = &localT; + Intersection localIsect; + if (!isect) isect = &localIsect; + Assert(!ray.HasNaNs()); + Spectrum Lo = 0.f; + if (scene->Intersect(ray, isect)) + Lo = surfaceIntegrator->Li(scene, this, ray, *isect, sample, rng, arena); + else { + for (uint32_t i = 0; i < scene->lights.size(); ++i) + Lo += scene->lights[i]->Le(ray); + } + Spectrum Lv = volumeIntegrator->Li(scene, this, ray, sample, rng, T, arena); + return *T * Lo + Lv; +} + + +Spectrum CreateRadianceProbes::Transmittance(const Scene *scene, + const RayDifferential &ray, const Sample *sample, RNG &rng, + MemoryArena &arena) const { + return volumeIntegrator->Transmittance(scene, this, ray, sample, rng, arena); +} + + +void CreateRadianceProbes::Render(const Scene *scene) { + // Compute scene bounds and initialize probe integrators + if (bbox.pMin.x > bbox.pMax.x) + bbox = scene->WorldBound(); + surfaceIntegrator->Preprocess(scene, camera, this); + volumeIntegrator->Preprocess(scene, camera, this); + Sample *origSample = new Sample(NULL, surfaceIntegrator, volumeIntegrator, + scene); + + // Compute sampling rate in each dimension + Vector delta = bbox.pMax - bbox.pMin; + int nProbes[3]; + for (int i = 0; i < 3; ++i) + nProbes[i] = max(1, Ceil2Int(delta[i] / probeSpacing)); + + // Allocate SH coefficient vector pointers for sample points + int count = nProbes[0] * nProbes[1] * nProbes[2]; + Spectrum **c_in = new Spectrum *[count]; + for (int i = 0; i < count; ++i) + c_in[i] = new Spectrum[SHTerms(lmax)]; + + // Compute random points on surfaces of scene + + // Create scene bounding sphere to catch rays that leave the scene + Point sceneCenter; + float sceneRadius; + scene->WorldBound().BoundingSphere(&sceneCenter, &sceneRadius); + Transform ObjectToWorld(Translate(sceneCenter - Point(0,0,0))); + Transform WorldToObject(Inverse(ObjectToWorld)); + Reference sph = new Sphere(&ObjectToWorld, &WorldToObject, + true, sceneRadius, -sceneRadius, sceneRadius, 360.f); + Reference nullMaterial = Reference(NULL); + GeometricPrimitive sphere(sph, nullMaterial, NULL); + vector surfacePoints; + uint32_t nPoints = 32768, maxDepth = 32; + surfacePoints.reserve(nPoints + maxDepth); + Point pCamera = camera->CameraToWorld(camera->shutterOpen, + Point(0, 0, 0)); + surfacePoints.push_back(pCamera); + RNG rng; + while (surfacePoints.size() < nPoints) { + // Generate random path from camera and deposit surface points + Point pray = pCamera; + Vector dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat()); + float rayEpsilon = 0.f; + for (uint32_t i = 0; i < maxDepth; ++i) { + Ray ray(pray, dir, rayEpsilon, INFINITY, time); + + Intersection isect; + if (!scene->Intersect(ray, &isect) && + !sphere.Intersect(ray, &isect)) + break; + + surfacePoints.push_back(ray(ray.maxt)); + + DifferentialGeometry &hitGeometry = isect.dg; + pray = isect.dg.p; + rayEpsilon = isect.rayEpsilon; + hitGeometry.nn = Faceforward(hitGeometry.nn, -ray.d); + + dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat()); + dir = Faceforward(dir, hitGeometry.nn); + } + } + + // Launch tasks to compute radiance probes at sample points + vector tasks; + ProgressReporter prog(count, "Radiance Probes"); + for (int i = 0; i < count; ++i) + tasks.push_back(new CreateRadProbeTask(i, nProbes, time, + bbox, lmax, includeDirectInProbes, + includeIndirectInProbes, nIndirSamples, + prog, origSample, surfacePoints, + scene, this, c_in[i])); + EnqueueTasks(tasks); + WaitForAllTasks(); + for (uint32_t i = 0; i < tasks.size(); ++i) + delete tasks[i]; + prog.Done(); + + // Write radiance probe coefficients to file + FILE *f = fopen(filename.c_str(), "w"); + if (f) { + if (fprintf(f, "%d %d %d\n", lmax, includeDirectInProbes?1:0, includeIndirectInProbes?1:0) < 0 || + fprintf(f, "%d %d %d\n", nProbes[0], nProbes[1], nProbes[2]) < 0 || + fprintf(f, "%f %f %f %f %f %f\n", bbox.pMin.x, bbox.pMin.y, bbox.pMin.z, + bbox.pMax.x, bbox.pMax.y, bbox.pMax.z) < 0) + Severe("Error writing radiance file \"%s\"", filename.c_str()); + for (int i = 0; i < nProbes[0] * nProbes[1] * nProbes[2]; ++i) { + for (int j = 0; j < SHTerms(lmax); ++j) { + fprintf(f, " "); + if (c_in[i][j].Write(f) == false) + Severe("Error writing radiance file \"%s\"", filename.c_str()); + fprintf(f, "\n"); + } + fprintf(f, "\n"); + } + fclose(f); + } + for (int i = 0; i < nProbes[0] * nProbes[1] * nProbes[2]; ++i) + delete[] c_in[i]; + delete[] c_in; + delete origSample; +} + + +CreateRadProbeTask::CreateRadProbeTask(int pn, int d[3], float t, + const BBox &b, int lm, bool id, + bool ii, int nindir, ProgressReporter &p, Sample *samp, + const vector &sp, const Scene *sc, const Renderer *ren, Spectrum *c) + : bbox(b), prog(p), surfacePoints(sp) { + pointNum = pn; + lmax = lm; + nIndirSamples = nindir; + time = t; + for (int i = 0; i < 3; ++i) nProbes[i] = d[i]; + origSample = samp; + c_in = c; + includeDirectInProbes = id; + includeIndirectInProbes = ii; + scene = sc; + renderer = ren; +} + + +void CreateRadProbeTask::Run() { + // Compute region in which to compute incident radiance probes + int sx = pointNum % nProbes[0]; + int sy = (pointNum / nProbes[0]) % nProbes[1]; + int sz = pointNum / (nProbes[0] * nProbes[1]); + Assert(sx >= 0 && sx < nProbes[0]); + Assert(sy >= 0 && sy < nProbes[1]); + Assert(sz >= 0 && sz < nProbes[2]); + float tx0 = float(sx) / nProbes[0], tx1 = float(sx+1) / nProbes[0]; + float ty0 = float(sy) / nProbes[1], ty1 = float(sy+1) / nProbes[1]; + float tz0 = float(sz) / nProbes[2], tz1 = float(sz+1) / nProbes[2]; + BBox b(bbox.Lerp(tx0, ty0, tz0), bbox.Lerp(tx1, ty1, tz1)); + + // Initialize common variables for _CreateRadProbeTask::Run()_ + RNG rng(pointNum); + Spectrum *c_probe = new Spectrum[SHTerms(lmax)]; + MemoryArena arena; + uint32_t nFound = 0, lastVisibleOffset = 0; + for (int i = 0; i < 256; ++i) { + if (nFound == 32) break; + // Try to compute radiance probe contribution at _i_th sample point + + // Compute _i_th candidate point _p_ in cell's bounding box + float dx = RadicalInverse(i+1, 2); + float dy = RadicalInverse(i+1, 3); + float dz = RadicalInverse(i+1, 5); + Point p = b.Lerp(dx, dy, dz); + + // Skip point _p_ if not indirectly visible from camera + if (scene->IntersectP(Ray(surfacePoints[lastVisibleOffset], + p - surfacePoints[lastVisibleOffset], + 1e-4f, 1.f, time))) { + uint32_t j; + // See if point is visible to any element of _surfacePoints_ + for (j = 0; j < surfacePoints.size(); ++j) + if (!scene->IntersectP(Ray(surfacePoints[j], p - surfacePoints[j], + 1e-4f, 1.f, time))) { + lastVisibleOffset = j; + break; + } + if (j == surfacePoints.size()) + continue; + } + ++nFound; + + // Compute SH coefficients of incident radiance at point _p_ + if (includeDirectInProbes) { + for (int i = 0; i < SHTerms(lmax); ++i) + c_probe[i] = 0.f; + SHProjectIncidentDirectRadiance(p, 0.f, time, arena, scene, + true, lmax, rng, c_probe); + for (int i = 0; i < SHTerms(lmax); ++i) + c_in[i] += c_probe[i]; + } + + if (includeIndirectInProbes) { + for (int i = 0; i < SHTerms(lmax); ++i) + c_probe[i] = 0.f; + SHProjectIncidentIndirectRadiance(p, 0.f, time, renderer, + origSample, scene, lmax, rng, nIndirSamples, c_probe); + for (int i = 0; i < SHTerms(lmax); ++i) + c_in[i] += c_probe[i]; + } + arena.FreeAll(); + } + // Compute final average value for probe and cleanup + if (nFound > 0) + for (int i = 0; i < SHTerms(lmax); ++i) + c_in[i] /= nFound; + delete[] c_probe; + prog.Update(); +} + + +CreateRadianceProbes *CreateRadianceProbesRenderer(const Camera *camera, + SurfaceIntegrator *surf, VolumeIntegrator *vol, + const ParamSet ¶ms) { + bool includeDirect = params.FindOneBool("directlighting", true); + bool includeIndirect = params.FindOneBool("indirectlighting", true); + int lmax = params.FindOneInt("lmax", 4); + int nindir = params.FindOneInt("indirectsamples", 512); + int nbbox; + BBox bounds; + const float *b = params.FindFloat("bounds", &nbbox); + if (b) { + if (nbbox != 6) Warning("Expecting six values [x0 y0 z0 x1 y1 z1] for bounds"); + else bounds = BBox(Point(b[0], b[1], b[2]), Point(b[3], b[4], b[5])); + } + float probeSpacing = params.FindOneFloat("samplespacing", 1.f); + float time = params.FindOneFloat("time", 0.f); + string filename = params.FindOneFilename("filename", "probes.out"); + + return new CreateRadianceProbes(surf, vol, camera, lmax, probeSpacing, + bounds, nindir, includeDirect, includeIndirect, time, filename); +} + + diff --git a/renderers/createprobes.h b/renderers/createprobes.h new file mode 100644 index 0000000..42d21d9 --- /dev/null +++ b/renderers/createprobes.h @@ -0,0 +1,67 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_RENDERERS_CREATEPROBES_H +#define PBRT_RENDERERS_CREATEPROBES_H + +// renderers/createprobes.h* +#include "pbrt.h" +#include "renderer.h" +#include "geometry.h" + +// CreateRadianceProbes Declarations +class CreateRadianceProbes : public Renderer { +public: + // CreateRadianceProbes Public Methods + CreateRadianceProbes(SurfaceIntegrator *surf, VolumeIntegrator *vol, + const Camera *camera, int lmax, float probeSpacing, const BBox &bbox, + int nIndirSamples, bool includeDirect, bool includeIndirect, + float time, const string &filename); + ~CreateRadianceProbes(); + void Render(const Scene *scene); + Spectrum Li(const Scene *scene, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena, Intersection *isect, + Spectrum *T) const; + Spectrum Transmittance(const Scene *scene, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena) const; +private: + // CreateRadianceProbes Private Data + SurfaceIntegrator *surfaceIntegrator; + VolumeIntegrator *volumeIntegrator; + const Camera *camera; + int lmax, nIndirSamples; + BBox bbox; + bool includeDirectInProbes, includeIndirectInProbes; + float time, probeSpacing; + string filename; +}; + + +CreateRadianceProbes *CreateRadianceProbesRenderer(const Camera *camera, + SurfaceIntegrator *surf, VolumeIntegrator *vol, const ParamSet ¶ms); + +#endif // PBRT_RENDERERS_CREATEPROBES_H diff --git a/renderers/metropolis.cpp b/renderers/metropolis.cpp new file mode 100644 index 0000000..5446e62 --- /dev/null +++ b/renderers/metropolis.cpp @@ -0,0 +1,802 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// renderers/metropolis.cpp* +#include "stdafx.h" +#include "renderers/metropolis.h" +#include "renderers/samplerrenderer.h" +#include "scene.h" +#include "imageio.h" +#include "spectrum.h" +#include "camera.h" +#include "film.h" +#include "rng.h" +#include "progressreporter.h" +#include "paramset.h" +#include "parallel.h" +#include "probes.h" +#include "intersection.h" +#include "montecarlo.h" +#include "samplers/lowdiscrepancy.h" +#include "integrators/directlighting.h" + +// Metropolis Local Declarations +struct PathSample { + BSDFSample bsdfSample; + float rrSample; +}; + + +struct LightingSample { + BSDFSample bsdfSample; + float lightNum; + LightSample lightSample; +}; + + +struct MLTSample { + MLTSample(int maxLength) { + cameraPathSamples.resize(maxLength); + lightPathSamples.resize(maxLength); + lightingSamples.resize(maxLength); + } + CameraSample cameraSample; + float lightNumSample, lightRaySamples[5]; + vector cameraPathSamples, lightPathSamples; + vector lightingSamples; +}; + + +static void LargeStep(RNG &rng, MLTSample *sample, int maxDepth, + float x, float y, float t0, float t1, bool bidirectional) { + // Do large step mutation of _cameraSample_ + sample->cameraSample.imageX = x; + sample->cameraSample.imageY = y; + sample->cameraSample.time = Lerp(rng.RandomFloat(), t0, t1); + sample->cameraSample.lensU = rng.RandomFloat(); + sample->cameraSample.lensV = rng.RandomFloat(); + for (int i = 0; i < maxDepth; ++i) { + // Apply large step to $i$th camera _PathSample_ + PathSample &cps = sample->cameraPathSamples[i]; + cps.bsdfSample.uComponent = rng.RandomFloat(); + cps.bsdfSample.uDir[0] = rng.RandomFloat(); + cps.bsdfSample.uDir[1] = rng.RandomFloat(); + cps.rrSample = rng.RandomFloat(); + + // Apply large step to $i$th _LightingSample_ + LightingSample &ls = sample->lightingSamples[i]; + ls.bsdfSample.uComponent = rng.RandomFloat(); + ls.bsdfSample.uDir[0] = rng.RandomFloat(); + ls.bsdfSample.uDir[1] = rng.RandomFloat(); + ls.lightNum = rng.RandomFloat(); + ls.lightSample.uComponent = rng.RandomFloat(); + ls.lightSample.uPos[0] = rng.RandomFloat(); + ls.lightSample.uPos[1] = rng.RandomFloat(); + } + if (bidirectional) { + // Apply large step to bidirectional light samples + sample->lightNumSample = rng.RandomFloat(); + for (int i = 0; i < 5; ++i) + sample->lightRaySamples[i] = rng.RandomFloat(); + for (int i = 0; i < maxDepth; ++i) { + // Apply large step to $i$th light _PathSample_ + PathSample &lps = sample->lightPathSamples[i]; + lps.bsdfSample.uComponent = rng.RandomFloat(); + lps.bsdfSample.uDir[0] = rng.RandomFloat(); + lps.bsdfSample.uDir[1] = rng.RandomFloat(); + lps.rrSample = rng.RandomFloat(); + } + } +} + + +static inline void mutate(RNG &rng, float *v, float min = 0.f, + float max = 1.f) { + if (min == max) { *v = min; return; } + Assert(min < max); + float a = 1.f / 1024.f, b = 1.f / 64.f; + static const float logRatio = -logf(b/a); + float delta = (max - min) * b * expf(logRatio * rng.RandomFloat()); + if (rng.RandomFloat() < 0.5f) { + *v += delta; + if (*v >= max) *v = min + (*v - max); + } + else { + *v -= delta; + if (*v < min) *v = max - (min - *v); + } + if (*v < min || *v >= max) *v = min; +} + + +static void SmallStep(RNG &rng, MLTSample *sample, int maxDepth, + int x0, int x1, int y0, int y1, float t0, float t1, + bool bidirectional) { + mutate(rng, &sample->cameraSample.imageX, x0, x1); + mutate(rng, &sample->cameraSample.imageY, y0, y1); + mutate(rng, &sample->cameraSample.time, t0, t1); + mutate(rng, &sample->cameraSample.lensU); + mutate(rng, &sample->cameraSample.lensV); + // Apply small step mutation to camera, lighting, and light samples + for (int i = 0; i < maxDepth; ++i) { + // Apply small step to $i$th camera _PathSample_ + PathSample &eps = sample->cameraPathSamples[i]; + mutate(rng, &eps.bsdfSample.uComponent); + mutate(rng, &eps.bsdfSample.uDir[0]); + mutate(rng, &eps.bsdfSample.uDir[1]); + mutate(rng, &eps.rrSample); + + // Apply small step to $i$th _LightingSample_ + LightingSample &ls = sample->lightingSamples[i]; + mutate(rng, &ls.bsdfSample.uComponent); + mutate(rng, &ls.bsdfSample.uDir[0]); + mutate(rng, &ls.bsdfSample.uDir[1]); + mutate(rng, &ls.lightNum); + mutate(rng, &ls.lightSample.uComponent); + mutate(rng, &ls.lightSample.uPos[0]); + mutate(rng, &ls.lightSample.uPos[1]); + } + + if (bidirectional) { + mutate(rng, &sample->lightNumSample); + for (int i = 0; i < 5; ++i) + mutate(rng, &sample->lightRaySamples[i]); + for (int i = 0; i < maxDepth; ++i) { + // Apply small step to $i$th light _PathSample_ + PathSample &lps = sample->lightPathSamples[i]; + mutate(rng, &lps.bsdfSample.uComponent); + mutate(rng, &lps.bsdfSample.uDir[0]); + mutate(rng, &lps.bsdfSample.uDir[1]); + mutate(rng, &lps.rrSample); + } + } +} + + +struct PathVertex { + Intersection isect; + Vector wPrev, wNext; + BSDF *bsdf; + bool specularBounce; + int nSpecularComponents; + Spectrum alpha; +}; + + +static uint32_t GeneratePath(const RayDifferential &r, const Spectrum &alpha, + const Scene *scene, MemoryArena &arena, const vector &samples, + PathVertex *path, RayDifferential *escapedRay, + Spectrum *escapedAlpha); +inline float I(const Spectrum &L); +class MLTTask : public Task { +public: + MLTTask(ProgressReporter &prog, uint32_t pfreq, uint32_t taskNum, + float dx, float dy, int xx0, int xx1, int yy0, int yy1, float tt0, float tt1, + float bb, const MLTSample &is, const Scene *sc, const Camera *c, + MetropolisRenderer *renderer, Mutex *filmMutex, + Distribution1D *lightDistribution); + void Run(); + +private: + ProgressReporter &progress; + uint32_t progressUpdateFrequency, taskNum; + float dx, dy; + int currentPixelSample; + int x0, x1, y0, y1; + float t0, t1; + float b; + const MLTSample &initialSample; + const Scene *scene; + const Camera *camera; + MetropolisRenderer *renderer; + Mutex *filmMutex; + Distribution1D *lightDistribution; +}; + + + +// Metropolis Method Definitions +static uint32_t GeneratePath(const RayDifferential &r, + const Spectrum &a, const Scene *scene, MemoryArena &arena, + const vector &samples, PathVertex *path, + RayDifferential *escapedRay, Spectrum *escapedAlpha) { + PBRT_MLT_STARTED_GENERATE_PATH(); + RayDifferential ray = r; + Spectrum alpha = a; + if (escapedAlpha) *escapedAlpha = 0.f; + uint32_t length = 0; + for (; length < samples.size(); ++length) { + // Try to generate next vertex of ray path + PathVertex &v = path[length]; + if (!scene->Intersect(ray, &v.isect)) { + // Handle ray that leaves the scene during path generation + if (escapedAlpha) *escapedAlpha = alpha; + if (escapedRay) *escapedRay = ray; + break; + } + + // Record information for current path vertex + v.alpha = alpha; + BSDF *bsdf = v.isect.GetBSDF(ray, arena); + v.bsdf = bsdf; + v.wPrev = -ray.d; + + // Sample direction for outgoing Metropolis path direction + float pdf; + BxDFType flags; + Spectrum f = bsdf->Sample_f(-ray.d, &v.wNext, samples[length].bsdfSample, + &pdf, BSDF_ALL, &flags); + v.specularBounce = (flags & BSDF_SPECULAR) != 0; + v.nSpecularComponents = bsdf->NumComponents(BxDFType(BSDF_SPECULAR | + BSDF_REFLECTION | BSDF_TRANSMISSION)); + if (f.IsBlack() || pdf == 0.f) + { + PBRT_MLT_FINISHED_GENERATE_PATH(); + return length+1; + } + + // Terminate path with RR or prepare for finding next vertex + const Point &p = bsdf->dgShading.p; + const Normal &n = bsdf->dgShading.nn; + Spectrum pathScale = f * AbsDot(v.wNext, n) / pdf; + float rrSurviveProb = min(1.f, pathScale.y()); + if (samples[length].rrSample > rrSurviveProb) + { + PBRT_MLT_FINISHED_GENERATE_PATH(); + return length+1; + } + alpha *= pathScale / rrSurviveProb; + //alpha *= renderer->Transmittance(scene, ray, NULL, rng, arena); + ray = RayDifferential(p, v.wNext, ray, v.isect.rayEpsilon); + } + PBRT_MLT_FINISHED_GENERATE_PATH(); + return length; +} + + +Spectrum MetropolisRenderer::PathL(const MLTSample &sample, + const Scene *scene, MemoryArena &arena, const Camera *camera, + const Distribution1D *lightDistribution, + PathVertex *cameraPath, PathVertex *lightPath, + RNG &rng) const { + // Generate camera path from camera path samples + PBRT_STARTED_GENERATING_CAMERA_RAY((CameraSample *)(&sample.cameraSample)); + RayDifferential cameraRay; + float cameraWt = camera->GenerateRayDifferential(sample.cameraSample, + &cameraRay); + cameraRay.ScaleDifferentials(1.f / sqrtf(nPixelSamples)); + PBRT_FINISHED_GENERATING_CAMERA_RAY((CameraSample *)(&sample.cameraSample), &cameraRay, cameraWt); + RayDifferential escapedRay; + Spectrum escapedAlpha; + uint32_t cameraLength = GeneratePath(cameraRay, cameraWt, scene, arena, + sample.cameraPathSamples, cameraPath, &escapedRay, &escapedAlpha); + if (!bidirectional) { + // Compute radiance along path using path tracing + return Lpath(scene, cameraPath, cameraLength, arena, + sample.lightingSamples, rng, sample.cameraSample.time, + lightDistribution, escapedRay, escapedAlpha); + } + else { + // Sample light ray and apply bidirectional path tracing + + // Choose light and sample ray to start light path + PBRT_MLT_STARTED_SAMPLE_LIGHT_FOR_BIDIR(); + float lightPdf, lightRayPdf; + uint32_t lightNum = lightDistribution->SampleDiscrete(sample.lightNumSample, + &lightPdf); + const Light *light = scene->lights[lightNum]; + Ray lightRay; + Normal Nl; + LightSample lrs(sample.lightRaySamples[0], sample.lightRaySamples[1], + sample.lightRaySamples[2]); + Spectrum lightWt = light->Sample_L(scene, lrs, sample.lightRaySamples[3], + sample.lightRaySamples[4], sample.cameraSample.time, &lightRay, + &Nl, &lightRayPdf); + PBRT_MLT_FINISHED_SAMPLE_LIGHT_FOR_BIDIR(); + if (lightWt.IsBlack() || lightRayPdf == 0.f) { + // Compute radiance along path using path tracing + return Lpath(scene, cameraPath, cameraLength, arena, + sample.lightingSamples, rng, sample.cameraSample.time, + lightDistribution, escapedRay, escapedAlpha); + } + else { + // Compute radiance along paths using bidirectional path tracing + lightWt *= AbsDot(Normalize(Nl), lightRay.d) / (lightPdf * lightRayPdf); + uint32_t lightLength = GeneratePath(RayDifferential(lightRay), lightWt, + scene, arena, sample.lightPathSamples, lightPath, NULL, NULL); + + return Lbidir(scene, cameraPath, cameraLength, lightPath, lightLength, + arena, sample.lightingSamples, rng, sample.cameraSample.time, + lightDistribution, escapedRay, escapedAlpha); + } + } +} + + +Spectrum MetropolisRenderer::Lpath(const Scene *scene, + const PathVertex *cameraPath, int cameraPathLength, + MemoryArena &arena, const vector &samples, + RNG &rng, float time, const Distribution1D *lightDistribution, + const RayDifferential &eRay, const Spectrum &eAlpha) const { + PBRT_MLT_STARTED_LPATH(); + Spectrum L = 0.; + bool previousSpecular = true, allSpecular = true; + for (int i = 0; i < cameraPathLength; ++i) { + // Initialize basic variables for camera path vertex + const PathVertex &vc = cameraPath[i]; + const Point &pc = vc.bsdf->dgShading.p; + const Normal &nc = vc.bsdf->dgShading.nn; + + // Add emitted light from vertex if appropriate + if (previousSpecular && (directLighting == NULL || !allSpecular)) + L += vc.alpha * vc.isect.Le(vc.wPrev); + + // Compute direct illumination for Metropolis path vertex + Spectrum Ld(0.f); + if (directLighting == NULL || !allSpecular) { + // Choose light and call _EstimateDirect()_ for Metropolis vertex + const LightingSample &ls = samples[i]; + float lightPdf; + uint32_t lightNum = lightDistribution->SampleDiscrete(ls.lightNum, + &lightPdf); + const Light *light = scene->lights[lightNum]; + PBRT_MLT_STARTED_ESTIMATE_DIRECT(); + + Ld = vc.alpha * + EstimateDirect(scene, this, arena, light, pc, nc, vc.wPrev, + vc.isect.rayEpsilon, time, vc.bsdf, rng, + ls.lightSample, ls.bsdfSample, + BxDFType(BSDF_ALL & ~BSDF_SPECULAR)) / lightPdf; + PBRT_MLT_FINISHED_ESTIMATE_DIRECT(); + } + previousSpecular = vc.specularBounce; + allSpecular &= previousSpecular; + L += Ld; + } + // Add contribution of escaped ray, if any + if (!eAlpha.IsBlack() && previousSpecular && + (directLighting == NULL || !allSpecular)) + for (uint32_t i = 0; i < scene->lights.size(); ++i) + L += eAlpha * scene->lights[i]->Le(eRay); + PBRT_MLT_FINISHED_LPATH(); + return L; +} + + +Spectrum MetropolisRenderer::Lbidir(const Scene *scene, + const PathVertex *cameraPath, int cameraPathLength, + const PathVertex *lightPath, int lightPathLength, + MemoryArena &arena, const vector &samples, + RNG &rng, float time, const Distribution1D *lightDistribution, + const RayDifferential &eRay, const Spectrum &eAlpha) const { + PBRT_MLT_STARTED_LBIDIR(); + Spectrum L = 0.; + bool previousSpecular = true, allSpecular = true; + // Compute number of specular vertices for each path length + int nVerts = cameraPathLength + lightPathLength + 2; + int *nSpecularVertices = ALLOCA(int, nVerts); + memset(nSpecularVertices, 0, nVerts * sizeof(int)); + for (int i = 0; i < cameraPathLength; ++i) + for (int j = 0; j < lightPathLength; ++j) + if (cameraPath[i].specularBounce || lightPath[j].specularBounce) + ++nSpecularVertices[i+j+2]; + for (int i = 0; i < cameraPathLength; ++i) { + // Initialize basic variables for camera path vertex + const PathVertex &vc = cameraPath[i]; + const Point &pc = vc.bsdf->dgShading.p; + const Normal &nc = vc.bsdf->dgShading.nn; + + // Compute reflected light at camera path vertex + + // Add emitted light from vertex if appropriate + if (previousSpecular && (directLighting == NULL || !allSpecular)) + L += vc.alpha * vc.isect.Le(vc.wPrev); + + // Compute direct illumination for Metropolis path vertex + Spectrum Ld(0.f); + if (directLighting == NULL || !allSpecular) { + // Choose light and call _EstimateDirect()_ for Metropolis vertex + const LightingSample &ls = samples[i]; + float lightPdf; + uint32_t lightNum = lightDistribution->SampleDiscrete(ls.lightNum, + &lightPdf); + const Light *light = scene->lights[lightNum]; + PBRT_MLT_STARTED_ESTIMATE_DIRECT(); + + Ld = vc.alpha * + EstimateDirect(scene, this, arena, light, pc, nc, vc.wPrev, + vc.isect.rayEpsilon, time, vc.bsdf, rng, + ls.lightSample, ls.bsdfSample, + BxDFType(BSDF_ALL & ~BSDF_SPECULAR)) / lightPdf; + PBRT_MLT_FINISHED_ESTIMATE_DIRECT(); + } + previousSpecular = vc.specularBounce; + allSpecular &= previousSpecular; + L += Ld / (i + 1 - nSpecularVertices[i+1]); + if (!vc.specularBounce) { + // Loop over light path vertices and connect to camera vertex + for (int j = 0; j < lightPathLength; ++j) { + const PathVertex &vl = lightPath[j]; + const Point &pl = vl.bsdf->dgShading.p; + const Normal &nl = vl.bsdf->dgShading.nn; + if (!vl.specularBounce) { + // Compute contribution between camera and light vertices + Vector w = Normalize(pl - pc); + Spectrum fc = vc.bsdf->f(vc.wPrev, w) * (1 + vc.nSpecularComponents); + Spectrum fl = vl.bsdf->f(-w, vl.wPrev) * (1 + vl.nSpecularComponents); + if (fc.IsBlack() || fl.IsBlack()) continue; + Ray r(pc, pl - pc, 1e-3f, .999f, time); + if (!scene->IntersectP(r)) { + // Compute weight for bidirectional path, _pathWt_ + float pathWt = 1.f / (i + j + 2 - nSpecularVertices[i+j+2]); + float G = AbsDot(nc, w) * AbsDot(nl, w) / DistanceSquared(pl, pc); + L += (vc.alpha * fc * G * fl * vl.alpha) * pathWt; + } + } + } + } + } + // Add contribution of escaped ray, if any + if (!eAlpha.IsBlack() && previousSpecular && + (directLighting == NULL || !allSpecular)) + for (uint32_t i = 0; i < scene->lights.size(); ++i) + L += eAlpha * scene->lights[i]->Le(eRay); + PBRT_MLT_FINISHED_LBIDIR(); + return L; +} + + +MetropolisRenderer::MetropolisRenderer(int perPixelSamples, + int nboot, int dps, float lsp, bool dds, int mr, int md, + Camera *c, bool db) { + camera = c; + + nPixelSamples = perPixelSamples; + float largeStepProbability = lsp; + largeStepsPerPixel = max(1u, RoundUpPow2(largeStepProbability * nPixelSamples)); + if (largeStepsPerPixel >= nPixelSamples) largeStepsPerPixel /= 2; + Assert(largeStepsPerPixel >= 1 && largeStepsPerPixel < nPixelSamples); + if ((nPixelSamples % largeStepsPerPixel) != 0) { + int origPixelSamples = nPixelSamples; + nPixelSamples += largeStepsPerPixel - (nPixelSamples % largeStepsPerPixel); + Warning("Rounding up to %d Metropolis samples per pixel (from %d)", + nPixelSamples, origPixelSamples); + } + + nBootstrap = nboot; + nDirectPixelSamples = dps; + + maxDepth = md; + maxConsecutiveRejects = mr; + nTasksFinished = 0; + directLighting = dds ? new DirectLightingIntegrator(SAMPLE_ALL_UNIFORM, maxDepth) : NULL; + bidirectional = db; +} + + +MetropolisRenderer::~MetropolisRenderer() { + delete camera; + delete directLighting; +} + + +MetropolisRenderer *CreateMetropolisRenderer(const ParamSet ¶ms, + Camera *camera) { + float largeStepProbability = params.FindOneFloat("largestepprobability", .25f); + int perPixelSamples = params.FindOneInt("samplesperpixel", 100); + int nBootstrap = params.FindOneInt("bootstrapsamples", 100000); + int nDirectPixelSamples = params.FindOneInt("directsamples", 4); + bool doDirectSeparately = params.FindOneBool("dodirectseparately", true); + int mr = params.FindOneInt("maxconsecutiverejects", 512); + int md = params.FindOneInt("maxdepth", 7); + bool doBidirectional = params.FindOneBool("bidirectional", true); + + if (PbrtOptions.quickRender) { + perPixelSamples = max(1, perPixelSamples / 4); + nBootstrap = max(1, nBootstrap / 4); + nDirectPixelSamples = max(1, nDirectPixelSamples / 4); + } + + return new MetropolisRenderer(perPixelSamples, nBootstrap, + nDirectPixelSamples, largeStepProbability, doDirectSeparately, + mr, md, camera, doBidirectional); +} + + +void MetropolisRenderer::Render(const Scene *scene) { + PBRT_MLT_STARTED_RENDERING(); + if (scene->lights.size() > 0) { + int x0, x1, y0, y1; + camera->film->GetPixelExtent(&x0, &x1, &y0, &y1); + float t0 = camera->shutterOpen, t1 = camera->shutterClose; + Distribution1D *lightDistribution = ComputeLightSamplingCDF(scene); + + if (directLighting != NULL) { + PBRT_MLT_STARTED_DIRECTLIGHTING(); + // Compute direct lighting before Metropolis light transport + if (nDirectPixelSamples > 0) { + LDSampler sampler(x0, x1, y0, y1, nDirectPixelSamples, t0, t1); + Sample *sample = new Sample(&sampler, directLighting, NULL, scene); + vector directTasks; + int nDirectTasks = max(32 * NumSystemCores(), + (camera->film->xResolution * camera->film->yResolution) / (16*16)); + nDirectTasks = RoundUpPow2(nDirectTasks); + ProgressReporter directProgress(nDirectTasks, "Direct Lighting"); + for (int i = 0; i < nDirectTasks; ++i) + directTasks.push_back(new SamplerRendererTask(scene, this, camera, directProgress, + &sampler, sample, false, i, nDirectTasks)); + std::reverse(directTasks.begin(), directTasks.end()); + EnqueueTasks(directTasks); + WaitForAllTasks(); + for (uint32_t i = 0; i < directTasks.size(); ++i) + delete directTasks[i]; + delete sample; + directProgress.Done(); + } + camera->film->WriteImage(); + PBRT_MLT_FINISHED_DIRECTLIGHTING(); + } + // Take initial set of samples to compute $b$ + PBRT_MLT_STARTED_BOOTSTRAPPING(nBootstrap); + RNG rng(0); + MemoryArena arena; + vector bootstrapI; + vector cameraPath(maxDepth, PathVertex()); + vector lightPath(maxDepth, PathVertex()); + float sumI = 0.f; + bootstrapI.reserve(nBootstrap); + MLTSample sample(maxDepth); + for (uint32_t i = 0; i < nBootstrap; ++i) { + // Generate random sample and path radiance for MLT bootstrapping + float x = Lerp(rng.RandomFloat(), x0, x1); + float y = Lerp(rng.RandomFloat(), y0, y1); + LargeStep(rng, &sample, maxDepth, x, y, t0, t1, bidirectional); + Spectrum L = PathL(sample, scene, arena, camera, lightDistribution, + &cameraPath[0], &lightPath[0], rng); + + // Compute contribution for random sample for MLT bootstrapping + float I = ::I(L); + sumI += I; + bootstrapI.push_back(I); + arena.FreeAll(); + } + float b = sumI / nBootstrap; + PBRT_MLT_FINISHED_BOOTSTRAPPING(b); + Info("MLT computed b = %f", b); + + // Select initial sample from bootstrap samples + float contribOffset = rng.RandomFloat() * sumI; + rng.Seed(0); + sumI = 0.f; + MLTSample initialSample(maxDepth); + for (uint32_t i = 0; i < nBootstrap; ++i) { + float x = Lerp(rng.RandomFloat(), x0, x1); + float y = Lerp(rng.RandomFloat(), y0, y1); + LargeStep(rng, &initialSample, maxDepth, x, y, t0, t1, + bidirectional); + sumI += bootstrapI[i]; + if (sumI > contribOffset) + break; + } + + // Launch tasks to generate Metropolis samples + uint32_t nTasks = largeStepsPerPixel; + uint32_t largeStepRate = nPixelSamples / largeStepsPerPixel; + Info("MLT running %d tasks, large step rate %d", nTasks, largeStepRate); + ProgressReporter progress(nTasks * largeStepRate, "Metropolis"); + vector tasks; + Mutex *filmMutex = Mutex::Create(); + Assert(IsPowerOf2(nTasks)); + uint32_t scramble[2] = { rng.RandomUInt(), rng.RandomUInt() }; + uint32_t pfreq = (x1-x0) * (y1-y0); + for (uint32_t i = 0; i < nTasks; ++i) { + float d[2]; + Sample02(i, scramble, d); + tasks.push_back(new MLTTask(progress, pfreq, i, + d[0], d[1], x0, x1, y0, y1, t0, t1, b, initialSample, + scene, camera, this, filmMutex, lightDistribution)); + } + EnqueueTasks(tasks); + WaitForAllTasks(); + for (uint32_t i = 0; i < tasks.size(); ++i) + delete tasks[i]; + progress.Done(); + Mutex::Destroy(filmMutex); + delete lightDistribution; + } + camera->film->WriteImage(); + PBRT_MLT_FINISHED_RENDERING(); +} + + +inline float I(const Spectrum &L) { + return L.y(); +} + + +MLTTask::MLTTask(ProgressReporter &prog, uint32_t pfreq, uint32_t tn, + float ddx, float ddy, int xx0, int xx1, int yy0, int yy1, float tt0, float tt1, + float bb, const MLTSample &is, const Scene *sc, const Camera *c, + MetropolisRenderer *ren, Mutex *fm, Distribution1D *ld) + : progress(prog), initialSample(is) { + progressUpdateFrequency = pfreq; + taskNum = tn; + dx = ddx; + dy = ddy; + x0 = xx0; + x1 = xx1; + y0 = yy0; + y1 = yy1; + t0 = tt0; + t1 = tt1; + currentPixelSample = 0; + b = bb; + scene = sc; + camera = c; + renderer = ren; + filmMutex = fm; + lightDistribution = ld; +} + + +void MLTTask::Run() { + PBRT_MLT_STARTED_MLT_TASK(this); + // Declare basic _MLTTask_ variables and prepare for sampling + PBRT_MLT_STARTED_TASK_INIT(); + uint32_t nPixels = (x1-x0) * (y1-y0); + uint32_t nPixelSamples = renderer->nPixelSamples; + uint32_t largeStepRate = nPixelSamples / renderer->largeStepsPerPixel; + Assert(largeStepRate > 1); + uint64_t nTaskSamples = uint64_t(nPixels) * uint64_t(largeStepRate); + uint32_t consecutiveRejects = 0; + uint32_t progressCounter = progressUpdateFrequency; + + // Declare variables for storing and computing MLT samples + MemoryArena arena; + RNG rng(taskNum); + vector cameraPath(renderer->maxDepth, PathVertex()); + vector lightPath(renderer->maxDepth, PathVertex()); + vector samples(2, MLTSample(renderer->maxDepth)); + Spectrum L[2]; + float I[2]; + uint32_t current = 0, proposed = 1; + + // Compute _L[current]_ for initial sample + samples[current] = initialSample; + L[current] = renderer->PathL(initialSample, scene, arena, camera, + lightDistribution, &cameraPath[0], &lightPath[0], rng); + I[current] = ::I(L[current]); + arena.FreeAll(); + + // Compute randomly permuted table of pixel indices for large steps + uint32_t pixelNumOffset = 0; + vector largeStepPixelNum; + largeStepPixelNum.reserve(nPixels); + for (uint32_t i = 0; i < nPixels; ++i) largeStepPixelNum.push_back(i); + Shuffle(&largeStepPixelNum[0], nPixels, 1, rng); + PBRT_MLT_FINISHED_TASK_INIT(); + for (uint64_t s = 0; s < nTaskSamples; ++s) { + // Compute proposed mutation to current sample + PBRT_MLT_STARTED_MUTATION(); + samples[proposed] = samples[current]; + bool largeStep = ((s % largeStepRate) == 0); + if (largeStep) { + int x = x0 + largeStepPixelNum[pixelNumOffset] % (x1 - x0); + int y = y0 + largeStepPixelNum[pixelNumOffset] / (x1 - x0); + LargeStep(rng, &samples[proposed], renderer->maxDepth, + x + dx, y + dy, t0, t1, renderer->bidirectional); + ++pixelNumOffset; + } + else + SmallStep(rng, &samples[proposed], renderer->maxDepth, + x0, x1, y0, y1, t0, t1, renderer->bidirectional); + PBRT_MLT_FINISHED_MUTATION(); + + // Compute contribution of proposed sample + L[proposed] = renderer->PathL(samples[proposed], scene, arena, camera, + lightDistribution, &cameraPath[0], &lightPath[0], rng); + I[proposed] = ::I(L[proposed]); + arena.FreeAll(); + + // Compute acceptance probability for proposed sample + float a = min(1.f, I[proposed] / I[current]); + + // Splat current and proposed samples to _Film_ + PBRT_MLT_STARTED_SAMPLE_SPLAT(); + if (I[current] > 0.f) { + if (!isinf(1.f / I[current])) { + Spectrum contrib = (b / nPixelSamples) * L[current] / I[current]; + camera->film->Splat(samples[current].cameraSample, + (1.f - a) * contrib); + } + } + if (I[proposed] > 0.f) { + if (!isinf(1.f / I[proposed])) { + Spectrum contrib = (b / nPixelSamples) * L[proposed] / I[proposed]; + camera->film->Splat(samples[proposed].cameraSample, + a * contrib); + } + } + PBRT_MLT_FINISHED_SAMPLE_SPLAT(); + + // Randomly accept proposed path mutation (or not) + if (consecutiveRejects >= renderer->maxConsecutiveRejects || + rng.RandomFloat() < a) { + PBRT_MLT_ACCEPTED_MUTATION(a, &samples[current], &samples[proposed]); + current ^= 1; + proposed ^= 1; + consecutiveRejects = 0; + } + else + { + PBRT_MLT_REJECTED_MUTATION(a, &samples[current], &samples[proposed]); + ++consecutiveRejects; + } + if (--progressCounter == 0) { + progress.Update(); + progressCounter = progressUpdateFrequency; + } + } + Assert(pixelNumOffset == nPixels); + // Update display for recently computed Metropolis samples + PBRT_MLT_STARTED_DISPLAY_UPDATE(); + int ntf = AtomicAdd(&renderer->nTasksFinished, 1); + int64_t totalSamples = int64_t(nPixels) * int64_t(nPixelSamples); + float splatScale = float(double(totalSamples) / double(ntf * nTaskSamples)); + camera->film->UpdateDisplay(x0, y0, x1, y1, splatScale); + if ((taskNum % 8) == 0) { + MutexLock lock(*filmMutex); + camera->film->WriteImage(splatScale); + } + PBRT_MLT_FINISHED_DISPLAY_UPDATE(); + PBRT_MLT_FINISHED_MLT_TASK(this); +} + + +Spectrum MetropolisRenderer::Li(const Scene *scene, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena, Intersection *isect, + Spectrum *T) const { + Spectrum localT; + if (!T) T = &localT; + Intersection localIsect; + if (!isect) isect = &localIsect; + Spectrum Lo = 0.f; + if (scene->Intersect(ray, isect)) + Lo = directLighting->Li(scene, this, ray, *isect, sample, + rng, arena); + else { + // Handle ray that doesn't intersect any geometry + for (uint32_t i = 0; i < scene->lights.size(); ++i) + Lo += scene->lights[i]->Le(ray); + } + return Lo; +} + + +Spectrum MetropolisRenderer::Transmittance(const Scene *scene, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena) const { + return 1.f; +} + + diff --git a/renderers/metropolis.h b/renderers/metropolis.h new file mode 100644 index 0000000..68dfbc5 --- /dev/null +++ b/renderers/metropolis.h @@ -0,0 +1,87 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_RENDERERS_METROPOLIS_H +#define PBRT_RENDERERS_METROPOLIS_H + +// renderers/metropolis.h* +#include "pbrt.h" +#include "renderer.h" +#include "parallel.h" +struct MLTSample; +class DirectLightingIntegrator; +struct LightingSample; + +// Metropolis Declarations +struct PathVertex; + +class MetropolisRenderer : public Renderer { +public: + // MetropolisRenderer Public Methods + MetropolisRenderer(int perPixelSamples, int nBootstrap, + int directPixelSamples, float largeStepProbability, + bool doDirectSeparately, int maxConsecutiveRejects, int maxDepth, + Camera *camera, bool doBidirectional); + ~MetropolisRenderer(); + void Render(const Scene *scene); + Spectrum Li(const Scene *scene, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena, + Intersection *isect = NULL, Spectrum *T = NULL) const; + Spectrum Transmittance(const Scene *scene, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena) const; +private: + // MetropolisRenderer Private Methods + Spectrum PathL(const MLTSample &sample, const Scene *scene, + MemoryArena &arena, const Camera *camera, + const Distribution1D *lightDistribution, PathVertex *cameraPath, + PathVertex *lightPath, RNG &rng) const; + Spectrum Lpath(const Scene *scene, const PathVertex *path, int pathLength, + MemoryArena &arena, const vector &samples, + RNG &rng, float time, const Distribution1D *lightDistribution, + const RayDifferential &escapedRay, const Spectrum &escapedAlpha) const; + Spectrum Lbidir(const Scene *scene, + const PathVertex *cameraPath, int cameraPathLength, + const PathVertex *lightPath, int lightPathLength, + MemoryArena &arena, const vector &samples, + RNG &rng, float time, const Distribution1D *lightDistribution, + const RayDifferential &escapedRay, const Spectrum &escapedAlpha) const; + + // MetropolisRenderer Private Data + Camera *camera; + bool bidirectional; + uint32_t nDirectPixelSamples, nPixelSamples, maxDepth; + uint32_t largeStepsPerPixel, nBootstrap, maxConsecutiveRejects; + DirectLightingIntegrator *directLighting; + AtomicInt32 nTasksFinished; + friend class MLTTask; +}; + + +MetropolisRenderer *CreateMetropolisRenderer(const ParamSet ¶ms, + Camera *camera); + +#endif // PBRT_RENDERERS_METROPOLIS_H diff --git a/renderers/samplerrenderer.cpp b/renderers/samplerrenderer.cpp new file mode 100644 index 0000000..1761410 --- /dev/null +++ b/renderers/samplerrenderer.cpp @@ -0,0 +1,248 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// renderers/samplerrenderer.cpp* +#include "stdafx.h" +#include "renderers/samplerrenderer.h" +#include "scene.h" +#include "film.h" +#include "volume.h" +#include "sampler.h" +#include "integrator.h" +#include "progressreporter.h" +#include "camera.h" +#include "intersection.h" + +static uint32_t hash(char *key, uint32_t len) +{ + uint32_t hash, i; + for (hash=0, i=0; i> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash; +} + +// SamplerRendererTask Definitions +void SamplerRendererTask::Run() { + PBRT_STARTED_RENDERTASK(taskNum); + // Get sub-_Sampler_ for _SamplerRendererTask_ + Sampler *sampler = mainSampler->GetSubSampler(taskNum, taskCount); + if (!sampler) + { + reporter.Update(); + PBRT_FINISHED_RENDERTASK(taskNum); + return; + } + + // Declare local variables used for rendering loop + MemoryArena arena; + RNG rng(taskNum); + + // Allocate space for samples and intersections + int maxSamples = sampler->MaximumSampleCount(); + Sample *samples = origSample->Duplicate(maxSamples); + RayDifferential *rays = new RayDifferential[maxSamples]; + Spectrum *Ls = new Spectrum[maxSamples]; + Spectrum *Ts = new Spectrum[maxSamples]; + Intersection *isects = new Intersection[maxSamples]; + + // Get samples from _Sampler_ and update image + int sampleCount; + while ((sampleCount = sampler->GetMoreSamples(samples, rng)) > 0) { + // Generate camera rays and compute radiance along rays + for (int i = 0; i < sampleCount; ++i) { + // Find camera ray for _sample[i]_ + PBRT_STARTED_GENERATING_CAMERA_RAY(&samples[i]); + float rayWeight = camera->GenerateRayDifferential(samples[i], &rays[i]); + rays[i].ScaleDifferentials(1.f / sqrtf(sampler->samplesPerPixel)); + PBRT_FINISHED_GENERATING_CAMERA_RAY(&samples[i], &rays[i], rayWeight); + + // Evaluate radiance along camera ray + PBRT_STARTED_CAMERA_RAY_INTEGRATION(&rays[i], &samples[i]); + if (visualizeObjectIds) { + if (rayWeight > 0.f && scene->Intersect(rays[i], &isects[i])) { + // random shading based on shape id... + uint32_t ids[2] = { isects[i].shapeId, isects[i].primitiveId }; + uint32_t h = hash((char *)ids, sizeof(ids)); + float rgb[3] = { (h & 0xff), (h >> 8) & 0xff, (h >> 16) & 0xff }; + Ls[i] = Spectrum::FromRGB(rgb); + Ls[i] /= 255.f; + } + else + Ls[i] = 0.f; + } + else { + if (rayWeight > 0.f) + Ls[i] = rayWeight * renderer->Li(scene, rays[i], &samples[i], rng, + arena, &isects[i], &Ts[i]); + else { + Ls[i] = 0.f; + Ts[i] = 1.f; + } + + // Issue warning if unexpected radiance value returned + if (Ls[i].HasNaNs()) { + Error("Not-a-number radiance value returned " + "for image sample. Setting to black."); + Ls[i] = Spectrum(0.f); + } + else if (Ls[i].y() < -1e-5) { + Error("Negative luminance value, %f, returned" + "for image sample. Setting to black.", Ls[i].y()); + Ls[i] = Spectrum(0.f); + } + else if (isinf(Ls[i].y())) { + Error("Infinite luminance value returned" + "for image sample. Setting to black."); + Ls[i] = Spectrum(0.f); + } + } + PBRT_FINISHED_CAMERA_RAY_INTEGRATION(&rays[i], &samples[i], &Ls[i]); + } + + // Report sample results to _Sampler_, add contributions to image + if (sampler->ReportResults(samples, rays, Ls, isects, sampleCount)) + { + for (int i = 0; i < sampleCount; ++i) + { + PBRT_STARTED_ADDING_IMAGE_SAMPLE(&samples[i], &rays[i], &Ls[i], &Ts[i]); + camera->film->AddSample(samples[i], Ls[i]); + PBRT_FINISHED_ADDING_IMAGE_SAMPLE(); + } + } + + // Free _MemoryArena_ memory from computing image sample values + arena.FreeAll(); + } + + // Clean up after _SamplerRendererTask_ is done with its image region + camera->film->UpdateDisplay(sampler->xPixelStart, + sampler->yPixelStart, sampler->xPixelEnd+1, sampler->yPixelEnd+1); + delete sampler; + delete[] samples; + delete[] rays; + delete[] Ls; + delete[] Ts; + delete[] isects; + reporter.Update(); + PBRT_FINISHED_RENDERTASK(taskNum); +} + + + +// SamplerRenderer Method Definitions +SamplerRenderer::SamplerRenderer(Sampler *s, Camera *c, + SurfaceIntegrator *si, VolumeIntegrator *vi, + bool visIds) { + sampler = s; + camera = c; + surfaceIntegrator = si; + volumeIntegrator = vi; + visualizeObjectIds = visIds; +} + + +SamplerRenderer::~SamplerRenderer() { + delete sampler; + delete camera; + delete surfaceIntegrator; + delete volumeIntegrator; +} + + +void SamplerRenderer::Render(const Scene *scene) { + PBRT_FINISHED_PARSING(); + // Allow integrators to do preprocessing for the scene + PBRT_STARTED_PREPROCESSING(); + surfaceIntegrator->Preprocess(scene, camera, this); + volumeIntegrator->Preprocess(scene, camera, this); + PBRT_FINISHED_PREPROCESSING(); + PBRT_STARTED_RENDERING(); + // Allocate and initialize _sample_ + Sample *sample = new Sample(sampler, surfaceIntegrator, + volumeIntegrator, scene); + + // Create and launch _SamplerRendererTask_s for rendering image + + // Compute number of _SamplerRendererTask_s to create for rendering + int nPixels = camera->film->xResolution * camera->film->yResolution; + int nTasks = max(32 * NumSystemCores(), nPixels / (16*16)); + nTasks = RoundUpPow2(nTasks); + ProgressReporter reporter(nTasks, "Rendering"); + vector renderTasks; + for (int i = 0; i < nTasks; ++i) + renderTasks.push_back(new SamplerRendererTask(scene, this, camera, + reporter, sampler, sample, + visualizeObjectIds, + nTasks-1-i, nTasks)); + EnqueueTasks(renderTasks); + WaitForAllTasks(); + for (uint32_t i = 0; i < renderTasks.size(); ++i) + delete renderTasks[i]; + reporter.Done(); + PBRT_FINISHED_RENDERING(); + // Clean up after rendering and store final image + delete sample; + camera->film->WriteImage(); +} + + +Spectrum SamplerRenderer::Li(const Scene *scene, + const RayDifferential &ray, const Sample *sample, RNG &rng, + MemoryArena &arena, Intersection *isect, Spectrum *T) const { + Assert(ray.time == sample->time); + Assert(!ray.HasNaNs()); + // Allocate local variables for _isect_ and _T_ if needed + Spectrum localT; + if (!T) T = &localT; + Intersection localIsect; + if (!isect) isect = &localIsect; + Spectrum Li = 0.f; + if (scene->Intersect(ray, isect)) + Li = surfaceIntegrator->Li(scene, this, ray, *isect, sample, + rng, arena); + else { + // Handle ray that doesn't intersect any geometry + for (uint32_t i = 0; i < scene->lights.size(); ++i) + Li += scene->lights[i]->Le(ray); + } + Spectrum Lvi = volumeIntegrator->Li(scene, this, ray, sample, rng, + T, arena); + return *T * Li + Lvi; +} + + +Spectrum SamplerRenderer::Transmittance(const Scene *scene, + const RayDifferential &ray, const Sample *sample, RNG &rng, + MemoryArena &arena) const { + return volumeIntegrator->Transmittance(scene, this, ray, sample, + rng, arena); +} + + diff --git a/renderers/samplerrenderer.h b/renderers/samplerrenderer.h new file mode 100644 index 0000000..461eccd --- /dev/null +++ b/renderers/samplerrenderer.h @@ -0,0 +1,87 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_RENDERERS_SAMPLERRENDERER_H +#define PBRT_RENDERERS_SAMPLERRENDERER_H + +// renderers/samplerrenderer.h* +#include "pbrt.h" +#include "renderer.h" +#include "parallel.h" + +// SamplerRenderer Declarations +class SamplerRenderer : public Renderer { +public: + // SamplerRenderer Public Methods + SamplerRenderer(Sampler *s, Camera *c, SurfaceIntegrator *si, + VolumeIntegrator *vi, bool visIds); + ~SamplerRenderer(); + void Render(const Scene *scene); + Spectrum Li(const Scene *scene, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena, + Intersection *isect = NULL, Spectrum *T = NULL) const; + Spectrum Transmittance(const Scene *scene, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena) const; +private: + // SamplerRenderer Private Data + bool visualizeObjectIds; + Sampler *sampler; + Camera *camera; + SurfaceIntegrator *surfaceIntegrator; + VolumeIntegrator *volumeIntegrator; +}; + + + +// SamplerRendererTask Declarations +class SamplerRendererTask : public Task { +public: + // SamplerRendererTask Public Methods + SamplerRendererTask(const Scene *sc, Renderer *ren, Camera *c, + ProgressReporter &pr, Sampler *ms, Sample *sam, + bool visIds, int tn, int tc) + : reporter(pr) + { + scene = sc; renderer = ren; camera = c; mainSampler = ms; + origSample = sam; visualizeObjectIds = visIds; taskNum = tn; taskCount = tc; + } + void Run(); +private: + // SamplerRendererTask Private Data + const Scene *scene; + const Renderer *renderer; + Camera *camera; + Sampler *mainSampler; + ProgressReporter &reporter; + Sample *origSample; + bool visualizeObjectIds; + int taskNum, taskCount; +}; + + + +#endif // PBRT_RENDERERS_SAMPLERRENDERER_H diff --git a/renderers/surfacepoints.cpp b/renderers/surfacepoints.cpp new file mode 100644 index 0000000..41dedd2 --- /dev/null +++ b/renderers/surfacepoints.cpp @@ -0,0 +1,272 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// renderers/surfacepoints.cpp* +#include "stdafx.h" +#include "renderers/surfacepoints.h" +#include "paramset.h" +#include "octree.h" +#include "camera.h" +#include "probes.h" +#include "parallel.h" +#include "progressreporter.h" +#include "scene.h" +#include "intersection.h" +#include "montecarlo.h" +#include "shapes/sphere.h" + +// SurfacePointsRenderer Local Declarations +class SurfacePointTask : public Task { +public: + SurfacePointTask(const Scene *sc, const Point &org, float ti, int tn, + float msd, int mf, RWMutex &m, int &rf, int &mrf, + int &tpt, int &trt, int &npa, GeometricPrimitive &sph, + Octree &oct, vector &sps, + ProgressReporter &pr) + : taskNum(tn), scene(sc), origin(org), time(ti), + minSampleDist(msd), maxFails(mf), mutex(m), + repeatedFails(rf), maxRepeatedFails(mrf), totalPathsTraced(tpt), + totalRaysTraced(trt), numPointsAdded(npa), sphere(sph), + octree(oct), surfacePoints(sps), prog(pr) { } + void Run(); + + int taskNum; + const Scene *scene; + Point origin; + float time; + float minSampleDist; + int maxFails; + + RWMutex &mutex; + int &repeatedFails, &maxRepeatedFails; + int &totalPathsTraced, &totalRaysTraced, &numPointsAdded; + GeometricPrimitive &sphere; + Octree &octree; + vector &surfacePoints; + ProgressReporter &prog; +}; + + +struct PoissonCheck { + PoissonCheck(float md, const Point &pt) + { maxDist2 = md * md; failed = false; p = pt; } + float maxDist2; + bool failed; + Point p; + bool operator()(const SurfacePoint &sp) { + if (DistanceSquared(sp.p, p) < maxDist2) { + failed = true; return false; + } + return true; + } +}; + + + +// SurfacePointsRenderer Method Definitions +Spectrum SurfacePointsRenderer::Li(const Scene *scene, + const RayDifferential &ray, const Sample *sample, RNG &rng, MemoryArena &arena, + Intersection *isect, Spectrum *T) const { + return 0.f; +} + + +Spectrum SurfacePointsRenderer::Transmittance(const Scene *scene, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena) const { + return 0.f; +} + + +void SurfacePointsRenderer::Render(const Scene *scene) { + // Declare shared variables for Poisson point generation + BBox octBounds = scene->WorldBound(); + octBounds.Expand(.001f * powf(octBounds.Volume(), 1.f/3.f)); + Octree pointOctree(octBounds); + + // Create scene bounding sphere to catch rays that leave the scene + Point sceneCenter; + float sceneRadius; + scene->WorldBound().BoundingSphere(&sceneCenter, &sceneRadius); + Transform ObjectToWorld(Translate(sceneCenter - Point(0,0,0))); + Transform WorldToObject(Inverse(ObjectToWorld)); + Reference sph = new Sphere(&ObjectToWorld, &WorldToObject, + true, sceneRadius, -sceneRadius, sceneRadius, 360.f); + Reference nullMaterial = Reference(NULL); + GeometricPrimitive sphere(sph, nullMaterial, NULL); + int maxFails = 2000, repeatedFails = 0, maxRepeatedFails = 0; + if (PbrtOptions.quickRender) maxFails = max(10, maxFails / 10); + int totalPathsTraced = 0, totalRaysTraced = 0, numPointsAdded = 0; + ProgressReporter prog(maxFails, "Depositing samples"); + // Launch tasks to trace rays to find Poisson points + PBRT_SUBSURFACE_STARTED_RAYS_FOR_POINTS(); + vector tasks; + RWMutex *mutex = RWMutex::Create(); + int nTasks = NumSystemCores(); + for (int i = 0; i < nTasks; ++i) + tasks.push_back(new SurfacePointTask(scene, pCamera, time, i, + minDist, maxFails, *mutex, repeatedFails, maxRepeatedFails, + totalPathsTraced, totalRaysTraced, numPointsAdded, sphere, pointOctree, + points, prog)); + EnqueueTasks(tasks); + WaitForAllTasks(); + for (uint32_t i = 0; i < tasks.size(); ++i) + delete tasks[i]; + RWMutex::Destroy(mutex); + prog.Done(); + PBRT_SUBSURFACE_FINISHED_RAYS_FOR_POINTS(totalRaysTraced, numPointsAdded); + if (filename != "") { + // Write surface points to file + FILE *f = fopen(filename.c_str(), "w"); + if (!f) Severe("Unable to open output file \"%s\"", filename.c_str()); + fprintf(f, "# points generated by SurfacePointsRenderer\n"); + fprintf(f, "# position (x,y,z), normal (x,y,z), area, rayEpsilon\n"); + for (u_int i = 0; i < points.size(); ++i) { + const SurfacePoint &sp = points[i]; + fprintf(f, "%g %g %g %g %g %g %g %g\n", sp.p.x, sp.p.y, sp.p.z, + sp.n.x, sp.n.y, sp.n.z, sp.area, sp.rayEpsilon); + } + fclose(f); + } +} + + +void SurfacePointTask::Run() { + // Declare common variables for _SurfacePointTask::Run()_ + RNG rng(37 * taskNum); + MemoryArena arena; + vector candidates; + while (true) { + int pathsTraced, raysTraced = 0; + for (pathsTraced = 0; pathsTraced < 20000; ++pathsTraced) { + // Follow ray path and attempt to deposit candidate sample points + Vector dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat()); + Ray ray(origin, dir, 0.f, INFINITY, time); + while (ray.depth < 30) { + // Find ray intersection with scene geometry or bounding sphere + ++raysTraced; + Intersection isect; + bool hitOnSphere = false; + if (!scene->Intersect(ray, &isect)) { + if (!sphere.Intersect(ray, &isect)) + break; + hitOnSphere = true; + } + DifferentialGeometry &hitGeometry = isect.dg; + hitGeometry.nn = Faceforward(hitGeometry.nn, -ray.d); + + // Store candidate sample point at ray intersection if appropriate + if (!hitOnSphere && ray.depth >= 3 && + isect.GetBSSRDF(RayDifferential(ray), arena) != NULL) { + float area = M_PI * (minSampleDist / 2.f) * (minSampleDist / 2.f); + candidates.push_back(SurfacePoint(hitGeometry.p, hitGeometry.nn, + area, isect.rayEpsilon)); + } + + // Generate random ray from intersection point + Vector dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat()); + dir = Faceforward(dir, hitGeometry.nn); + ray = Ray(hitGeometry.p, dir, ray, isect.rayEpsilon); + } + arena.FreeAll(); + } + // Make first pass through candidate points with reader lock + vector candidateRejected; + candidateRejected.reserve(candidates.size()); + RWMutexLock lock(mutex, READ); + for (uint32_t i = 0; i < candidates.size(); ++i) { + PoissonCheck check(minSampleDist, candidates[i].p); + octree.Lookup(candidates[i].p, check); + candidateRejected.push_back(check.failed); + } + + // Make second pass through points with writer lock and update octree + lock.UpgradeToWrite(); + if (repeatedFails >= maxFails) + return; + totalPathsTraced += pathsTraced; + totalRaysTraced += raysTraced; + int oldMaxRepeatedFails = maxRepeatedFails; + for (uint32_t i = 0; i < candidates.size(); ++i) { + if (candidateRejected[i]) { + // Update for rejected candidate point + ++repeatedFails; + maxRepeatedFails = max(maxRepeatedFails, repeatedFails); + if (repeatedFails >= maxFails) + return; + } + else { + // Recheck candidate point and possibly add to octree + SurfacePoint &sp = candidates[i]; + PoissonCheck check(minSampleDist, sp.p); + octree.Lookup(sp.p, check); + if (check.failed) { + // Update for rejected candidate point + ++repeatedFails; + maxRepeatedFails = max(maxRepeatedFails, repeatedFails); + if (repeatedFails >= maxFails) + return; + } + else { + ++numPointsAdded; + repeatedFails = 0; + Vector delta(minSampleDist, minSampleDist, minSampleDist); + octree.Add(sp, BBox(sp.p-delta, sp.p+delta)); + PBRT_SUBSURFACE_ADDED_POINT_TO_OCTREE(&sp, minSampleDist); + surfacePoints.push_back(sp); + } + } + } + + // Stop following paths if not finding new points + if (repeatedFails > oldMaxRepeatedFails) { + int delta = repeatedFails - oldMaxRepeatedFails; + prog.Update(delta); + } + if (totalPathsTraced > 50000 && numPointsAdded == 0) { + Warning("There don't seem to be any objects with BSSRDFs " + "in this scene. Giving up."); + return; + } + candidates.erase(candidates.begin(), candidates.end()); + } +} + + +void FindPoissonPointDistribution(const Point &pCamera, float time, + float minDist, const Scene *scene, vector *points) { + SurfacePointsRenderer sp(minDist, pCamera, time, ""); + sp.Render(scene); + points->swap(sp.points); +} + + +SurfacePointsRenderer *CreateSurfacePointsRenderer(const ParamSet ¶ms, + const Point &pCamera, float time) { + float minDist = params.FindOneFloat("minsampledistance", .25f); + string filename = params.FindOneFilename("filename", ""); + if (PbrtOptions.quickRender) { minDist *= 4.f; } + return new SurfacePointsRenderer(minDist, pCamera, time, filename); +} + + diff --git a/renderers/surfacepoints.h b/renderers/surfacepoints.h new file mode 100644 index 0000000..9f740ad --- /dev/null +++ b/renderers/surfacepoints.h @@ -0,0 +1,76 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_RENDERERS_SURFACEPOINTS_H +#define PBRT_RENDERERS_SURFACEPOINTS_H + +// renderers/surfacepoints.h* +#include "pbrt.h" +#include "geometry.h" +#include "renderer.h" + +// SurfacePointsRenderer Declarations +struct SurfacePoint { + SurfacePoint() { } + SurfacePoint(const Point &pp, const Normal &nn, float a, float eps) + : p(pp), n(nn), area(a), rayEpsilon(eps) { } + // SurfacePoint Data + Point p; + Normal n; + float area, rayEpsilon; +}; + + +class SurfacePointsRenderer : public Renderer { +public: + // SurfacePointsRenderer Public Methods + SurfacePointsRenderer(float md, const Point &pc, float t, + const string &fn) + : minDist(md), time(t), pCamera(pc), filename(fn) { } + void Render(const Scene *scene); + Spectrum Li(const Scene *scene, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena, + Intersection *isect, Spectrum *T) const; + Spectrum Transmittance(const Scene *scene, const RayDifferential &ray, + const Sample *sample, RNG &rng, MemoryArena &arena) const; +private: + // SurfacePointsRenderer Private Data + float minDist, time; + Point pCamera; + string filename; + friend void FindPoissonPointDistribution(const Point &pCamera, float time, + float minDist, const Scene *scene, vector *points); + vector points; +}; + + +void FindPoissonPointDistribution(const Point &pCamera, float time, float minDist, + const Scene *scene, vector *points); +SurfacePointsRenderer *CreateSurfacePointsRenderer(const ParamSet ¶ms, + const Point &pCamera, float time); + +#endif // PBRT_RENDERERS_SURFACEPOINTS_H diff --git a/samplers/adaptive.cpp b/samplers/adaptive.cpp new file mode 100644 index 0000000..98b6f1d --- /dev/null +++ b/samplers/adaptive.cpp @@ -0,0 +1,182 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// samplers/adaptive.cpp* +#include "stdafx.h" +#include "samplers/adaptive.h" +#include "paramset.h" +#include "film.h" +#include "primitive.h" +#include "intersection.h" +#include "camera.h" +#include "montecarlo.h" + +// AdaptiveSampler Method Definitions +AdaptiveSampler::AdaptiveSampler(int xstart, int xend, + int ystart, int yend, int mins, int maxs, const string &m, + float sopen, float sclose) + : Sampler(xstart, xend, ystart, yend, RoundUpPow2(max(mins, maxs)), + sopen, sclose) { + xPos = xPixelStart; + yPos = yPixelStart; + supersamplePixel = false; + if (mins > maxs) std::swap(mins, maxs); + + if (!IsPowerOf2(mins)) { + Warning("Minimum pixel samples being rounded up to power of 2"); + minSamples = RoundUpPow2(mins); + } + else + minSamples = mins; + if (!IsPowerOf2(maxs)) { + Warning("Maximum pixel samples being rounded up to power of 2"); + maxSamples = RoundUpPow2(maxs); + } + else + maxSamples = maxs; + + if (minSamples < 2) { + Warning("Adaptive sampler needs at least two initial pixel samples. Using two."); + minSamples = 2; + } + if (minSamples == maxSamples) { + maxSamples *= 2; + Warning("Adaptive sampler must have more maximum samples than minimum. Using %d - %d", + minSamples, maxSamples); + } + if (m == "contrast") method = ADAPTIVE_CONTRAST_THRESHOLD; + else if (m == "shapeid") method = ADAPTIVE_COMPARE_SHAPE_ID; + else { + Warning("Adaptive sampling metric \"%s\" unknown. Using \"contrast\".", + m.c_str()); + method = ADAPTIVE_CONTRAST_THRESHOLD; + } + sampleBuf = NULL; +} + + +AdaptiveSampler::~AdaptiveSampler() { + delete[] sampleBuf; +} + + +Sampler *AdaptiveSampler::GetSubSampler(int num, int count) { + int x0, x1, y0, y1; + ComputeSubWindow(num, count, &x0, &x1, &y0, &y1); + if (x0 == x1 || y0 == y1) return NULL; + return new AdaptiveSampler(x0, x1, y0, y1, minSamples, maxSamples, + method == ADAPTIVE_CONTRAST_THRESHOLD ? "contrast" : "shapeid", + shutterOpen, shutterClose); +} + + +int AdaptiveSampler::GetMoreSamples(Sample *samples, RNG &rng) { + if (!sampleBuf) + sampleBuf = new float[LDPixelSampleFloatsNeeded(samples, + maxSamples)]; + if (supersamplePixel) { + LDPixelSample(xPos, yPos, shutterOpen, shutterClose, maxSamples, + samples, sampleBuf, rng); + return maxSamples; + } + else { + if (yPos == yPixelEnd) return 0; + LDPixelSample(xPos, yPos, shutterOpen, shutterClose, minSamples, + samples, sampleBuf, rng); + return minSamples; + } +} + + +bool AdaptiveSampler::ReportResults(Sample *samples, + const RayDifferential *rays, const Spectrum *Ls, + const Intersection *isects, int count) { + if (supersamplePixel) { + supersamplePixel = false; + // Advance to next pixel for sampling for _AdaptiveSampler_ + if (++xPos == xPixelEnd) { + xPos = xPixelStart; + ++yPos; + } + return true; + } + else if (needsSupersampling(samples, rays, Ls, isects, count)) { + PBRT_SUPERSAMPLE_PIXEL_YES(xPos, yPos); + supersamplePixel = true; + return false; + } + + else { + PBRT_SUPERSAMPLE_PIXEL_NO(xPos, yPos); + // Advance to next pixel for sampling for _AdaptiveSampler_ + if (++xPos == xPixelEnd) { + xPos = xPixelStart; + ++yPos; + } + return true; + } +} + + +bool AdaptiveSampler::needsSupersampling(Sample *samples, + const RayDifferential *rays, const Spectrum *Ls, + const Intersection *isects, int count) { + switch (method) { + case ADAPTIVE_COMPARE_SHAPE_ID: + // See if any shape ids differ within samples + for (int i = 0; i < count-1; ++i) + if (isects[i].shapeId != isects[i+1].shapeId || + isects[i].primitiveId != isects[i+1].primitiveId) + return true; + return false; + case ADAPTIVE_CONTRAST_THRESHOLD: + // Compare contrast of sample differences to threshold + float Lavg = 0.f; + for (int i = 0; i < count; ++i) + Lavg += Ls[i].y(); + Lavg /= count; + const float maxContrast = 0.5f; + for (int i = 0; i < count; ++i) + if (fabsf(Ls[i].y() - Lavg) / Lavg > maxContrast) + return true; + return false; + } + return false; +} + + +AdaptiveSampler *CreateAdaptiveSampler(const ParamSet ¶ms, const Film *film, + const Camera *camera) { + // Initialize common sampler parameters + int xstart, xend, ystart, yend; + film->GetSampleExtent(&xstart, &xend, &ystart, ¥d); + int minsamp = params.FindOneInt("minsamples", 4); + int maxsamp = params.FindOneInt("maxsamples", 32); + if (PbrtOptions.quickRender) { minsamp = 2; maxsamp = 4; } + string method = params.FindOneString("method", "contrast"); + return new AdaptiveSampler(xstart, xend, ystart, yend, minsamp, maxsamp, method, + camera->shutterOpen, camera->shutterClose); +} + + diff --git a/samplers/adaptive.h b/samplers/adaptive.h new file mode 100644 index 0000000..96eb660 --- /dev/null +++ b/samplers/adaptive.h @@ -0,0 +1,70 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_SAMPLERS_ADAPTIVE_H +#define PBRT_SAMPLERS_ADAPTIVE_H + +// samplers/adaptive.h* +#include "pbrt.h" +#include "sampler.h" + +// AdaptiveSampler Declarations +class AdaptiveSampler : public Sampler { +public: + // AdaptiveSampler Public Methods + AdaptiveSampler(int xstart, int xend, int ystart, int yend, + int minSamples, int maxSamples, const string &method, + float sopen, float sclose); + Sampler *GetSubSampler(int num, int count); + ~AdaptiveSampler(); + int RoundSize(int size) const { + return RoundUpPow2(size); + } + int MaximumSampleCount() { return maxSamples; } + int GetMoreSamples(Sample *sample, RNG &rng); + bool ReportResults(Sample *samples, const RayDifferential *rays, + const Spectrum *Ls, const Intersection *isects, int count); +private: + // AdaptiveSampler Private Methods + bool needsSupersampling(Sample *samples, const RayDifferential *rays, + const Spectrum *Ls, const Intersection *isects, int count); + + // AdaptiveSampler Private Data + int xPos, yPos; + int minSamples, maxSamples; + float *sampleBuf; + enum AdaptiveTest { ADAPTIVE_COMPARE_SHAPE_ID, + ADAPTIVE_CONTRAST_THRESHOLD }; + AdaptiveTest method; + bool supersamplePixel; +}; + + +AdaptiveSampler *CreateAdaptiveSampler(const ParamSet ¶ms, const Film *film, + const Camera *camera); + +#endif // PBRT_SAMPLERS_ADAPTIVE_H diff --git a/samplers/bestcandidate.cpp b/samplers/bestcandidate.cpp new file mode 100644 index 0000000..c233a3b --- /dev/null +++ b/samplers/bestcandidate.cpp @@ -0,0 +1,97 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// samplers/bestcandidate.cpp* +#include "stdafx.h" +#include "samplers/bestcandidate.h" +#include "camera.h" +#include "montecarlo.h" + +// BestCandidateSampler Method Definitions +#include "samplers/bestcandidate.out" +Sampler *BestCandidateSampler::GetSubSampler(int num, int count) { + int x0, x1, y0, y1; + ComputeSubWindow(num, count, &x0, &x1, &y0, &y1); + if (x0 == x1 || y0 == y1) return NULL; + return new BestCandidateSampler(x0, x1, y0, y1, samplesPerPixel, + shutterOpen, shutterClose); +} + + +int BestCandidateSampler::GetMoreSamples(Sample *sample, RNG &rng) { +again: + if (tableOffset == SAMPLE_TABLE_SIZE) { + // Advance to next best-candidate sample table position + tableOffset = 0; + if (++xTile > xTileEnd) { + xTile = xTileStart; + if (++yTile > yTileEnd) + return 0; + } + + // Update sample shifts + RNG tileRng(xTile + (yTile<<8)); + for (int i = 0; i < 3; ++i) + sampleOffsets[i] = tileRng.RandomFloat(); + } + // Compute raster sample from table +#define WRAP(x) ((x) > 1 ? ((x)-1) : (x)) + sample->imageX = (xTile + sampleTable[tableOffset][0]) * tableWidth; + sample->imageY = (yTile + sampleTable[tableOffset][1]) * tableWidth; + sample->time = Lerp(WRAP(sampleOffsets[0] + sampleTable[tableOffset][2]), + shutterOpen, shutterClose); + sample->lensU = WRAP(sampleOffsets[1] + + sampleTable[tableOffset][3]); + sample->lensV = WRAP(sampleOffsets[2] + + sampleTable[tableOffset][4]); + + // Check sample against crop window, goto _again_ if outside + if (sample->imageX < xPixelStart || sample->imageX >= xPixelEnd || + sample->imageY < yPixelStart || sample->imageY >= yPixelEnd) { + ++tableOffset; + goto again; + } + + // Compute integrator samples for best-candidate sample + for (uint32_t i = 0; i < sample->n1D.size(); ++i) + LDShuffleScrambled1D(sample->n1D[i], 1, sample->oneD[i], rng); + for (uint32_t i = 0; i < sample->n2D.size(); ++i) + LDShuffleScrambled2D(sample->n2D[i], 1, sample->twoD[i], rng); + ++tableOffset; + return 1; +} + + +BestCandidateSampler *CreateBestCandidateSampler(const ParamSet ¶ms, const Film *film, + const Camera *camera) { + // Initialize common sampler parameters + int xstart, xend, ystart, yend; + film->GetSampleExtent(&xstart, &xend, &ystart, ¥d); + int nsamp = params.FindOneInt("pixelsamples", 4); + if (PbrtOptions.quickRender) nsamp = 1; + return new BestCandidateSampler(xstart, xend, ystart, yend, nsamp, + camera->shutterOpen, camera->shutterClose); +} + + diff --git a/samplers/bestcandidate.h b/samplers/bestcandidate.h new file mode 100644 index 0000000..d52f076 --- /dev/null +++ b/samplers/bestcandidate.h @@ -0,0 +1,82 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_SAMPLERS_BESTCANDIDATE_H +#define PBRT_SAMPLERS_BESTCANDIDATE_H + +// samplers/bestcandidate.h* +#include "sampler.h" +#include "paramset.h" +#include "film.h" + +// BestCandidate Sampling Constants +#define SQRT_SAMPLE_TABLE_SIZE 64 +#define SAMPLE_TABLE_SIZE (SQRT_SAMPLE_TABLE_SIZE * \ + SQRT_SAMPLE_TABLE_SIZE) + +// BestCandidateSampler Declarations +class BestCandidateSampler : public Sampler { +public: + // BestCandidateSampler Public Methods + BestCandidateSampler(int xstart, int xend, int ystart, int yend, + int nPixelSamples, float sopen, float sclose) + : Sampler(xstart, xend, ystart, yend, nPixelSamples, sopen, sclose) { + tableWidth = (float)SQRT_SAMPLE_TABLE_SIZE / + (float)sqrtf(nPixelSamples); + xTileStart = Floor2Int(xstart / tableWidth); + xTileEnd = Floor2Int(xend / tableWidth); + yTileStart = Floor2Int(ystart / tableWidth); + yTileEnd = Floor2Int(yend / tableWidth); + xTile = xTileStart; + yTile = yTileStart; + tableOffset = 0; + // Update sample shifts + RNG tileRng(xTile + (yTile<<8)); + for (int i = 0; i < 3; ++i) + sampleOffsets[i] = tileRng.RandomFloat(); + } + Sampler *GetSubSampler(int num, int count); + int RoundSize(int size) const { + return RoundUpPow2(size); + } + int MaximumSampleCount() { return 1; } + int GetMoreSamples(Sample *sample, RNG &rng); +private: + // BestCandidateSampler Private Data + float tableWidth; + int tableOffset; + int xTileStart, xTileEnd, yTileStart, yTileEnd; + int xTile, yTile; + static const float sampleTable[SAMPLE_TABLE_SIZE][5]; + float sampleOffsets[3]; +}; + + +BestCandidateSampler *CreateBestCandidateSampler(const ParamSet ¶ms, const Film *film, + const Camera *camera); + +#endif // PBRT_SAMPLERS_BESTCANDIDATE_H diff --git a/samplers/bestcandidate.out b/samplers/bestcandidate.out new file mode 100644 index 0000000..a2305ec --- /dev/null +++ b/samplers/bestcandidate.out @@ -0,0 +1,4101 @@ + +/* Automatically generated 64x64 sample table (Mar 11 2003 @ 18:26:01) */ + +const float BestCandidateSampler::sampleTable[4096][5] = { + { 0.8147236705f, 0.1354770064f, 0.0000925521f, 0.4019474089f, 0.6087165475f, }, + { 0.9057919383f, 0.8350085616f, 0.0003553750f, 0.0861424059f, 0.0100619597f, }, + { 0.5407393575f, 0.2690643370f, 0.0006090801f, 0.6007867455f, 0.8780308366f, }, + { 0.2601301968f, 0.6379706860f, 0.0009086037f, 0.7664164901f, 0.8738085628f, }, + { 0.3190678060f, 0.9074092507f, 0.0011911630f, 0.9212453961f, 0.6868487597f, }, + { 0.7451665998f, 0.5743905902f, 0.0013162681f, 0.9683164358f, 0.5127110481f, }, + { 0.4001524150f, 0.5284244418f, 0.0016778698f, 0.6921809912f, 0.4125681221f, }, + { 0.1100450456f, 0.1057574451f, 0.0018501711f, 0.0146250632f, 0.8812126517f, }, + { 0.8948429227f, 0.2533296347f, 0.0020738356f, 0.4565072358f, 0.5722977519f, }, + { 0.2674683630f, 0.5533290505f, 0.0023895311f, 0.1681169569f, 0.2947981060f, }, + { 0.3942572773f, 0.2532950938f, 0.0026231781f, 0.2203403264f, 0.3363176882f, }, + { 0.4852786958f, 0.3545391560f, 0.0028830934f, 0.3188484907f, 0.9074358344f, }, + { 0.6586979032f, 0.8418058157f, 0.0030069787f, 0.7844486237f, 0.6568627954f, }, + { 0.9411987066f, 0.5897576213f, 0.0033880144f, 0.8060938716f, 0.4992469847f, }, + { 0.5399997830f, 0.9201279879f, 0.0034516300f, 0.7110665441f, 0.9379280806f, }, + { 0.7044532299f, 0.3615645170f, 0.0038146735f, 0.3312333524f, 0.7043340802f, }, + { 0.2236744910f, 0.6983554363f, 0.0040313010f, 0.9803896546f, 0.0122512933f, }, + { 0.9424012303f, 0.3758843243f, 0.0043811370f, 0.1272166520f, 0.7057249546f, }, + { 0.7769014239f, 0.5007985234f, 0.0045080204f, 0.4891040921f, 0.6144846678f, }, + { 0.3352120221f, 0.4250096679f, 0.0048495578f, 0.1398096681f, 0.4732225239f, }, + { 0.2864905894f, 0.3687916994f, 0.0050996765f, 0.5154488683f, 0.7148888111f, }, + { 0.4302304387f, 0.7953287363f, 0.0053384029f, 0.3845077455f, 0.4471219778f, }, + { 0.7122719884f, 0.6312747002f, 0.0053886301f, 0.2098473012f, 0.0359315202f, }, + { 0.2255856991f, 0.8242244124f, 0.0057056206f, 0.0154700223f, 0.7429744601f, }, + { 0.4062927365f, 0.1937931925f, 0.0059459647f, 0.7694647908f, 0.8217784762f, }, + { 0.3468713462f, 0.6767925024f, 0.0062678517f, 0.8330464959f, 0.2177158743f, }, + { 0.9666144252f, 0.2009279728f, 0.0064939880f, 0.8835488558f, 0.7352885008f, }, + { 0.3542139530f, 0.1368083954f, 0.0068113748f, 0.7127271891f, 0.7369572520f, }, + { 0.0730623454f, 0.9186591506f, 0.0070059323f, 0.8506008983f, 0.2909074426f, }, + { 0.0576261431f, 0.6444487572f, 0.0072751464f, 0.1983753592f, 0.6282710433f, }, + { 0.8324630857f, 0.0756615698f, 0.0074814279f, 0.8288900852f, 0.9258258343f, }, + { 0.6643590927f, 0.7455400229f, 0.0078120320f, 0.2949022353f, 0.0725637302f, }, + { 0.7771928906f, 0.0457091779f, 0.0079298988f, 0.3379514217f, 0.3358463049f, }, + { 0.7178720832f, 0.0836343467f, 0.0081919432f, 0.0248849336f, 0.2305759937f, }, + { 0.3458726108f, 0.0467313565f, 0.0085327048f, 0.0916037932f, 0.5246021152f, }, + { 0.3535799682f, 0.9239047170f, 0.0086721992f, 0.2325491011f, 0.1278568357f, }, + { 0.4694392085f, 0.1728783846f, 0.0088718766f, 0.2934763730f, 0.6021974683f, }, + { 0.4273798168f, 0.0501741581f, 0.0092035085f, 0.7160296440f, 0.3402471542f, }, + { 0.9108628631f, 0.2238015085f, 0.0093548680f, 0.8826734424f, 0.7824344039f, }, + { 0.6898998618f, 0.4835795760f, 0.0097168721f, 0.0895984694f, 0.6975994706f, }, + { 0.7868241072f, 0.8537104726f, 0.0097885933f, 0.1676693857f, 0.8658806682f, }, + { 0.5064531565f, 0.1874002069f, 0.0101869470f, 0.2452387512f, 0.5405161977f, }, + { 0.7579895854f, 0.7569690943f, 0.0103190392f, 0.1678106338f, 0.5750533342f, }, + { 0.4616447687f, 0.2728512287f, 0.0106443241f, 0.5919349790f, 0.2881401181f, }, + { 0.4405889809f, 0.4591084123f, 0.0109313000f, 0.7328998446f, 0.6630277634f, }, + { 0.5048032403f, 0.1451848596f, 0.0110682091f, 0.9092653394f, 0.1455762088f, }, + { 0.5176716447f, 0.8154572845f, 0.0114612412f, 0.0788091794f, 0.1426269263f, }, + { 0.0507072657f, 0.2023273557f, 0.0115570212f, 0.5186483860f, 0.1527025849f, }, + { 0.0960686132f, 0.9986093640f, 0.0118583171f, 0.0184947345f, 0.5494630933f, }, + { 0.3829126060f, 0.3327288330f, 0.0121809021f, 0.0219344981f, 0.6127645969f, }, + { 0.3661476672f, 0.1958540827f, 0.0123146856f, 0.4433521628f, 0.7052192092f, }, + { 0.2274705768f, 0.3423889875f, 0.0124962647f, 0.3325358033f, 0.6719499826f, }, + { 0.8564140797f, 0.8799827099f, 0.0128203863f, 0.4616371095f, 0.4424869716f, }, + { 0.0257591251f, 0.9929412603f, 0.0129602877f, 0.4425229132f, 0.8805189133f, }, + { 0.0189489890f, 0.8733308315f, 0.0133971358f, 0.4266490340f, 0.7925782204f, }, + { 0.9364752769f, 0.1634215117f, 0.0136603368f, 0.6092597246f, 0.5063406229f, }, + { 0.7860327363f, 0.2605836987f, 0.0137975588f, 0.8142901659f, 0.0293884389f, }, + { 0.9804726243f, 0.0265780203f, 0.0140897799f, 0.8962855339f, 0.3561876714f, }, + { 0.1831031144f, 0.1188247874f, 0.0143356901f, 0.7261373997f, 0.6238805056f, }, + { 0.7739988565f, 0.6843484640f, 0.0145266177f, 0.0040075476f, 0.6703180671f, }, + { 0.8973402977f, 0.9881284833f, 0.0147383977f, 0.1109874770f, 0.2047449797f, }, + { 0.1769492477f, 0.8110610247f, 0.0150778210f, 0.5277686119f, 0.2967748046f, }, + { 0.4921269119f, 0.3022507429f, 0.0152802048f, 0.6041954756f, 0.4695280492f, }, + { 0.0783381686f, 0.7078509927f, 0.0154551705f, 0.1806261986f, 0.4749867320f, }, + { 0.4441930950f, 0.3144947588f, 0.0158082489f, 0.6334674358f, 0.0843452588f, }, + { 0.4833642840f, 0.0819099694f, 0.0159649383f, 0.3896810114f, 0.7832011580f, }, + { 0.9700933099f, 0.9633082151f, 0.0162235647f, 0.0769674554f, 0.5728059411f, }, + { 0.4663167298f, 0.6109359860f, 0.0165467877f, 0.3170534968f, 0.5696546435f, }, + { 0.6208630800f, 0.1367374957f, 0.0167269148f, 0.0137705170f, 0.1829838008f, }, + { 0.8400792480f, 0.4905676842f, 0.0169972964f, 0.7087520361f, 0.5272886157f, }, + { 0.4622295201f, 0.9965586662f, 0.0173130222f, 0.9431533217f, 0.9666104317f, }, + { 0.0206090696f, 0.6428968310f, 0.0175194405f, 0.8819432855f, 0.0703618452f, }, + { 0.9498320222f, 0.0117056081f, 0.0177698825f, 0.3387356699f, 0.2081270069f, }, + { 0.5681881309f, 0.7464584708f, 0.0179468580f, 0.8252582550f, 0.0903981924f, }, + { 0.2801332176f, 0.4389587045f, 0.0182940979f, 0.2809591591f, 0.3265851736f, }, + { 0.7442450523f, 0.9018602371f, 0.0183938816f, 0.5043178201f, 0.5288457870f, }, + { 0.9010351896f, 0.9257849455f, 0.0185957365f, 0.0032330919f, 0.7852386832f, }, + { 0.2091527432f, 0.4226507545f, 0.0189210195f, 0.1409777850f, 0.0846762210f, }, + { 0.8047815561f, 0.5894420147f, 0.0190771352f, 0.2615225613f, 0.4571531117f, }, + { 0.1401103735f, 0.0175967962f, 0.0195146669f, 0.6312081814f, 0.7898635864f, }, + { 0.0271497797f, 0.3446519375f, 0.0195794944f, 0.9772230983f, 0.3104098737f, }, + { 0.3501657248f, 0.7712000608f, 0.0198350661f, 0.7422171831f, 0.0328862183f, }, + { 0.2244993448f, 0.9878500700f, 0.0200550221f, 0.9384350777f, 0.4154943228f, }, + { 0.4029869437f, 0.7474737763f, 0.0204645973f, 0.2761213779f, 0.7616214752f, }, + { 0.2186425477f, 0.5974915624f, 0.0205609128f, 0.1831181645f, 0.7619341016f, }, + { 0.9248407483f, 0.8833535314f, 0.0209227093f, 0.1526287049f, 0.1579527855f, }, + { 0.3336008787f, 0.3455565572f, 0.0211345553f, 0.1134738997f, 0.8607695103f, }, + { 0.9732974768f, 0.4391311109f, 0.0214559622f, 0.6812891960f, 0.9797594547f, }, + { 0.7273365855f, 0.0127240587f, 0.0215192456f, 0.9041584730f, 0.2457261384f, }, + { 0.4251326621f, 0.4004603624f, 0.0218490809f, 0.4733976722f, 0.2654740512f, }, + { 0.4099306166f, 0.5888402462f, 0.0220631715f, 0.4979542196f, 0.2041166872f, }, + { 0.6102679968f, 0.8612695336f, 0.0223458037f, 0.5463936925f, 0.4322631061f, }, + { 0.5966469049f, 0.4805867374f, 0.0226596743f, 0.1803955585f, 0.5317785740f, }, + { 0.0489680506f, 0.7191831470f, 0.0228388328f, 0.4975504875f, 0.0379846580f, }, + { 0.7716502547f, 0.8034937382f, 0.0230321046f, 0.3578487337f, 0.8847640157f, }, + { 0.1918073297f, 0.6402989030f, 0.0233804137f, 0.7596606612f, 0.9317308664f, }, + { 0.3741894662f, 0.8122962117f, 0.0234890021f, 0.1669710577f, 0.3774351478f, }, + { 0.5275450945f, 0.6425983310f, 0.0238353070f, 0.9419788718f, 0.8392260671f, }, + { 0.6433275342f, 0.9961528778f, 0.0241268668f, 0.2342460603f, 0.8907893300f, }, + { 0.6144811511f, 0.3709629476f, 0.0243708324f, 0.0782319084f, 0.6190319657f, }, + { 0.6816558838f, 0.9993784428f, 0.0244583730f, 0.6334012747f, 0.4117903709f, }, + { 0.4726617336f, 0.5447264314f, 0.0247860309f, 0.8789321780f, 0.4223836660f, }, + { 0.5717362165f, 0.6817410588f, 0.0249806046f, 0.6160323620f, 0.1728063822f, }, + { 0.6919798851f, 0.4180691838f, 0.0252522565f, 0.8133153915f, 0.3570474982f, }, + { 0.8461546898f, 0.2650289536f, 0.0254083686f, 0.4229061604f, 0.0914310142f, }, + { 0.0176351219f, 0.3986770809f, 0.0258302372f, 0.7590498328f, 0.7672837973f, }, + { 0.0286485460f, 0.5403446555f, 0.0259606503f, 0.6974081993f, 0.6889986396f, }, + { 0.6547404528f, 0.2553975582f, 0.0261899736f, 0.2342714965f, 0.6719627380f, }, + { 0.3202907443f, 0.7651812434f, 0.0265327375f, 0.3210408688f, 0.2570245862f, }, + { 0.6180875897f, 0.0858205631f, 0.0266514737f, 0.5866110921f, 0.9739878178f, }, + { 0.2358479500f, 0.4541831017f, 0.0270466581f, 0.9057922959f, 0.4995442629f, }, + { 0.3066716790f, 0.8568725586f, 0.0272267722f, 0.9903813004f, 0.3697066009f, }, + { 0.2215915173f, 0.0363276117f, 0.0274902955f, 0.7752750516f, 0.5667720437f, }, + { 0.1476514637f, 0.8328262568f, 0.0278153662f, 0.5921120048f, 0.0397551768f, }, + { 0.0322317481f, 0.4823409021f, 0.0280717947f, 0.1926080883f, 0.9854156375f, }, + { 0.1801132709f, 0.4977526367f, 0.0282866769f, 0.6680429578f, 0.6038916707f, }, + { 0.6371629238f, 0.2046487629f, 0.0284619182f, 0.6822410822f, 0.1335783750f, }, + { 0.0786340758f, 0.5616105199f, 0.0286622979f, 0.4424726069f, 0.3179470003f, }, + { 0.2680398226f, 0.0542958677f, 0.0288912673f, 0.1232327446f, 0.3603746593f, }, + { 0.5928773284f, 0.6370098591f, 0.0292382184f, 0.5372427106f, 0.0153745608f, }, + { 0.6602200270f, 0.5478175282f, 0.0294613056f, 0.7959799767f, 0.2727995217f, }, + { 0.1012622416f, 0.5150785446f, 0.0295804180f, 0.4599424005f, 0.1007173210f, }, + { 0.9175854325f, 0.3132068515f, 0.0299239308f, 0.6730643511f, 0.3301970065f, }, + { 0.1607560366f, 0.4457321465f, 0.0302418936f, 0.8026931286f, 0.8473737240f, }, + { 0.1940494776f, 0.9447404742f, 0.0304444674f, 0.9928097129f, 0.1495564878f, }, + { 0.6413668394f, 0.6585265398f, 0.0305533614f, 0.3597672582f, 0.9672973156f, }, + { 0.1912067384f, 0.1551680863f, 0.0309032984f, 0.2989568710f, 0.9990157485f, }, + { 0.9998430014f, 0.5238247514f, 0.0310248416f, 0.0835820511f, 0.3182901144f, }, + { 0.5861057043f, 0.5752487183f, 0.0314886495f, 0.4995223880f, 0.3906169236f, }, + { 0.1257322431f, 0.7310088277f, 0.0315883681f, 0.2163365036f, 0.8022968173f, }, + { 0.7773286104f, 0.9719676375f, 0.0318491347f, 0.5086533427f, 0.7980102301f, }, + { 0.7954028845f, 0.4589500129f, 0.0320912041f, 0.7803107500f, 0.1435992569f, }, + { 0.8501529694f, 0.1994784325f, 0.0323931947f, 0.3305530250f, 0.0982837230f, }, + { 0.1773519367f, 0.3744114041f, 0.0326150246f, 0.7939080596f, 0.3190090358f, }, + { 0.9700883627f, 0.1067062318f, 0.0327795967f, 0.1210447699f, 0.4231351316f, }, + { 0.4946098328f, 0.8558630347f, 0.0330642574f, 0.9935570359f, 0.0574124344f, }, + { 0.0295954887f, 0.5919592977f, 0.0333239101f, 0.2452888042f, 0.9840896130f, }, + { 0.8895401359f, 0.1269200742f, 0.0334943980f, 0.2818838954f, 0.1574520916f, }, + { 0.3841145635f, 0.0482447408f, 0.0337872729f, 0.9579399228f, 0.7551828623f, }, + { 0.5663750172f, 0.1356172413f, 0.0340032168f, 0.5419430137f, 0.9085814953f, }, + { 0.6406635046f, 0.4919643104f, 0.0341934077f, 0.7170193791f, 0.1857164800f, }, + { 0.3853508234f, 0.9630408883f, 0.0345966704f, 0.2728398442f, 0.2342964560f, }, + { 0.4968118668f, 0.6725898385f, 0.0348359607f, 0.8808291554f, 0.5868647695f, }, + { 0.7742865682f, 0.1744856536f, 0.0350137204f, 0.4174623787f, 0.5443277359f, }, + { 0.6669078469f, 0.3683382273f, 0.0351756066f, 0.1893181503f, 0.0768967420f, }, + { 0.6054267883f, 0.7039074898f, 0.0355220959f, 0.1502123773f, 0.3435633183f, }, + { 0.4638076425f, 0.7313242555f, 0.0357781947f, 0.4730790555f, 0.9558206797f, }, + { 0.8493852615f, 0.8290187716f, 0.0359090529f, 0.5293825865f, 0.5766800046f, }, + { 0.0524612069f, 0.2923840582f, 0.0361595266f, 0.1765686423f, 0.2269783914f, }, + { 0.7580386400f, 0.3284719288f, 0.0365415998f, 0.1755308509f, 0.7086476684f, }, + { 0.5718393326f, 0.3993137777f, 0.0366347097f, 0.1346118152f, 0.9723603725f, }, + { 0.7347082496f, 0.4644138813f, 0.0369054228f, 0.7713994980f, 0.4232122302f, }, + { 0.1327264458f, 0.6681285501f, 0.0373436734f, 0.0478908755f, 0.4894922972f, }, + { 0.4221930206f, 0.8320023417f, 0.0375452377f, 0.5311310291f, 0.6686213017f, }, + { 0.5427172780f, 0.5945629478f, 0.0377456769f, 0.5970438123f, 0.1244033352f, }, + { 0.2341895550f, 0.9043307304f, 0.0380652733f, 0.7040627599f, 0.8816208243f, }, + { 0.8437633514f, 0.7053799629f, 0.0381792784f, 0.1664177179f, 0.9150137305f, }, + { 0.6732702255f, 0.9473659992f, 0.0384328924f, 0.6328683496f, 0.2354076356f, }, + { 0.0066912696f, 0.8097978830f, 0.0386478044f, 0.2113407850f, 0.5908805728f, }, + { 0.8053469658f, 0.6347839832f, 0.0388571545f, 0.5441893935f, 0.0701473728f, }, + { 0.3133361340f, 0.0957893953f, 0.0391662419f, 0.4492388070f, 0.2216103524f, }, + { 0.8475818634f, 0.4353236854f, 0.0393983871f, 0.2861022055f, 0.3857587278f, }, + { 0.7463465929f, 0.2790216506f, 0.0396046303f, 0.4482796788f, 0.8284660578f, }, + { 0.8919641972f, 0.4985580146f, 0.0398458429f, 0.4852329195f, 0.3255411386f, }, + { 0.7066060305f, 0.7637109756f, 0.0401278362f, 0.3290512860f, 0.0209563412f, }, + { 0.6722646952f, 0.6053004861f, 0.0403660908f, 0.9424302578f, 0.6016924381f, }, + { 0.1458182931f, 0.9545296431f, 0.0405431092f, 0.9870889783f, 0.4168865085f, }, + { 0.1059840694f, 0.1887766868f, 0.0408416353f, 0.8587096334f, 0.4811220467f, }, + { 0.1891167164f, 0.2009778321f, 0.0411720984f, 0.4343391359f, 0.3975535333f, }, + { 0.2666101158f, 0.2967492640f, 0.0413284376f, 0.5330547690f, 0.2441772074f, }, + { 0.0448957682f, 0.0480144769f, 0.0415939093f, 0.4865770340f, 0.6698746085f, }, + { 0.2736288011f, 0.1566580087f, 0.0419333726f, 0.5710110068f, 0.7737393975f, }, + { 0.3498518169f, 0.5168098807f, 0.0421938039f, 0.8241609335f, 0.4251399636f, }, + { 0.1353416890f, 0.9153692126f, 0.0422598906f, 0.6755535007f, 0.4900777042f, }, + { 0.2125526518f, 0.8644635677f, 0.0425663441f, 0.9716135263f, 0.2004876435f, }, + { 0.5886977911f, 0.2198120207f, 0.0427719690f, 0.5127003193f, 0.4849517047f, }, + { 0.0703917071f, 0.1007515416f, 0.0431488492f, 0.8210902214f, 0.7899536490f, }, + { 0.0767651945f, 0.7511868477f, 0.0434283242f, 0.3574953377f, 0.1649470329f, }, + { 0.0008240642f, 0.2334658504f, 0.0436701924f, 0.5398108363f, 0.9711065292f, }, + { 0.5569124222f, 0.8739325404f, 0.0438596345f, 0.7377768159f, 0.2424974740f, }, + { 0.6102737784f, 0.0294529982f, 0.0439805835f, 0.5558157563f, 0.5363591909f, }, + { 0.9640653133f, 0.6786074042f, 0.0443023629f, 0.9775245786f, 0.9434307814f, }, + { 0.8117011786f, 0.9116708040f, 0.0445028320f, 0.7437243462f, 0.9962877035f, }, + { 0.6231177449f, 0.7698760033f, 0.0448828004f, 0.0271507986f, 0.1094925180f, }, + { 0.3188054264f, 0.6217828393f, 0.0449406356f, 0.0679292083f, 0.9222252369f, }, + { 0.9124069214f, 0.0696860999f, 0.0452763513f, 0.5776777864f, 0.3616185188f, }, + { 0.8492888808f, 0.3641744852f, 0.0456503965f, 0.3848410845f, 0.8302230239f, }, + { 0.2618224919f, 0.7441193461f, 0.0457888357f, 0.0650434867f, 0.0608354285f, }, + { 0.7182237506f, 0.8124958277f, 0.0461096242f, 0.8289935589f, 0.9926660657f, }, + { 0.5042542219f, 0.9527418613f, 0.0461843312f, 0.7309857011f, 0.4532707930f, }, + { 0.6644627452f, 0.1013275832f, 0.0464992747f, 0.4423924983f, 0.0438876860f, }, + { 0.4284345508f, 0.9272229671f, 0.0468358286f, 0.5433413982f, 0.8430919647f, }, + { 0.7193606496f, 0.2038395852f, 0.0469797514f, 0.0623772219f, 0.9706354141f, }, + { 0.2190305591f, 0.5460209846f, 0.0471397638f, 0.0781095698f, 0.2526320517f, }, + { 0.9172998071f, 0.7936462760f, 0.0474723727f, 0.3083115816f, 0.4762945473f, }, + { 0.6551039815f, 0.1564930826f, 0.0476199314f, 0.5133156180f, 0.1036999971f, }, + { 0.1053718179f, 0.3743568361f, 0.0480879769f, 0.6821129322f, 0.0415123999f, }, + { 0.3984370828f, 0.4426503181f, 0.0482615903f, 0.4567431808f, 0.5151667595f, }, + { 0.1474771947f, 0.6189020276f, 0.0485207476f, 0.8494740129f, 0.1338191330f, }, + { 0.5166945457f, 0.7381197214f, 0.0487401374f, 0.3090821505f, 0.8510544300f, }, + { 0.5631777644f, 0.7910258174f, 0.0490162447f, 0.6591098905f, 0.2866385877f, }, + { 0.1495835781f, 0.2930206060f, 0.0491319709f, 0.7515223026f, 0.1923044026f, }, + { 0.0222943667f, 0.1526654065f, 0.0494016558f, 0.7231612802f, 0.2935799956f, }, + { 0.6939067245f, 0.8788351417f, 0.0495812930f, 0.5617181063f, 0.1850942671f, }, + { 0.0742898807f, 0.8189433813f, 0.0498057455f, 0.0719347149f, 0.7690908909f, }, + { 0.3843702376f, 0.0856694505f, 0.0502408892f, 0.0632688701f, 0.1883670837f, }, + { 0.8471630216f, 0.9770510197f, 0.0505254567f, 0.9435009360f, 0.0184909068f, }, + { 0.4755743742f, 0.4956137240f, 0.0505534820f, 0.2663745284f, 0.2870857418f, }, + { 0.5003576279f, 0.0493856855f, 0.0507818721f, 0.4078702033f, 0.9913962483f, }, + { 0.0634744540f, 0.3819875121f, 0.0511389747f, 0.6562582850f, 0.8385023475f, }, + { 0.9663436413f, 0.8378800154f, 0.0514060855f, 0.8269785047f, 0.6928087473f, }, + { 0.6748873591f, 0.0387051813f, 0.0516586639f, 0.6970779300f, 0.2274947166f, }, + { 0.3471541703f, 0.2694189250f, 0.0518629141f, 0.7180790305f, 0.0973428786f, }, + { 0.5997167826f, 0.2987565398f, 0.0520669073f, 0.9336352348f, 0.2970329821f, }, + { 0.0647970438f, 0.4367446005f, 0.0524305478f, 0.4101348519f, 0.1639807820f, }, + { 0.3169389367f, 0.9983556867f, 0.0525224581f, 0.9353601336f, 0.9077124000f, }, + { 0.7611338496f, 0.0960676968f, 0.0529565662f, 0.2388710082f, 0.3941167891f, }, + { 0.0540681593f, 0.8735795021f, 0.0531926192f, 0.3957832754f, 0.2782140374f, }, + { 0.3029129207f, 0.1325840801f, 0.0532588921f, 0.8127061725f, 0.8821395636f, }, + { 0.8986012936f, 0.6072000861f, 0.0534798093f, 0.3593181670f, 0.3983343840f, }, + { 0.9129838943f, 0.7453516126f, 0.0537796691f, 0.8607261181f, 0.5410499573f, }, + { 0.9417704344f, 0.2610845864f, 0.0539830700f, 0.0257038940f, 0.3592725992f, }, + { 0.2048562467f, 0.7651212811f, 0.0543002672f, 0.1183954701f, 0.8158272505f, }, + { 0.3784966767f, 0.3854971230f, 0.0544520915f, 0.6006575227f, 0.5854203105f, }, + { 0.1654667109f, 0.5481364727f, 0.0549034104f, 0.5382045507f, 0.3623740673f, }, + { 0.1889458746f, 0.3205667436f, 0.0549550392f, 0.5858517289f, 0.8370037675f, }, + { 0.2994317412f, 0.8076255918f, 0.0553018488f, 0.3067924678f, 0.8248385191f, }, + { 0.9775391817f, 0.5781039000f, 0.0555876419f, 0.9463933110f, 0.3657433689f, }, + { 0.5661306381f, 0.0790204853f, 0.0558209904f, 0.5954768062f, 0.6424548030f, }, + { 0.0183017049f, 0.4401574433f, 0.0560885035f, 0.2119552642f, 0.1980753243f, }, + { 0.5380973220f, 0.5193555355f, 0.0563860424f, 0.7689244151f, 0.0808177143f, }, + { 0.8255710006f, 0.7867128253f, 0.0564623103f, 0.8930397034f, 0.8562948108f, }, + { 0.5752024055f, 0.5284490585f, 0.0566996634f, 0.9966987371f, 0.4685010314f, }, + { 0.9589093924f, 0.7410116196f, 0.0570079796f, 0.6101198196f, 0.7272050977f, }, + { 0.0123756276f, 0.1013899222f, 0.0571777858f, 0.4160855412f, 0.6536789536f, }, + { 0.4474143386f, 0.6530405283f, 0.0575506836f, 0.6438226104f, 0.9699420929f, }, + { 0.5423610806f, 0.3267042339f, 0.0577740297f, 0.1104684919f, 0.7613546252f, }, + { 0.9706943035f, 0.6447551847f, 0.0578642637f, 0.8414371610f, 0.5892925262f, }, + { 0.9663971066f, 0.3403144777f, 0.0581630543f, 0.1323272884f, 0.5152189732f, }, + { 0.0107964240f, 0.9275842309f, 0.0584492274f, 0.2931319773f, 0.7148856521f, }, + { 0.5555430055f, 0.4287147522f, 0.0587269962f, 0.7511355877f, 0.3629468977f, }, + { 0.9218703508f, 0.5341714025f, 0.0588651560f, 0.2927557528f, 0.1145779639f, }, + { 0.8722203970f, 0.6732161641f, 0.0592366867f, 0.3445213139f, 0.4443978667f, }, + { 0.6457434297f, 0.3153223097f, 0.0595620386f, 0.1724845469f, 0.0341088809f, }, + { 0.7613945603f, 0.6155192852f, 0.0596458130f, 0.4148417711f, 0.9365081191f, }, + { 0.6043331623f, 0.4050677121f, 0.0599584319f, 0.1357058436f, 0.6250661016f, }, + { 0.2862799466f, 0.4940985739f, 0.0602868572f, 0.0855147615f, 0.4534803033f, }, + { 0.9881494641f, 0.2781268954f, 0.0603672117f, 0.9720658660f, 0.7081292868f, }, + { 0.8715701699f, 0.5466591716f, 0.0606565997f, 0.0285781454f, 0.8393635750f, }, + { 0.8387814760f, 0.0395718664f, 0.0609819628f, 0.3718280494f, 0.5818833709f, }, + { 0.4345148802f, 0.8815767765f, 0.0611360371f, 0.9440345764f, 0.0952378213f, }, + { 0.1069847941f, 0.4628326893f, 0.0615231432f, 0.2101773173f, 0.9288322926f, }, + { 0.5075126886f, 0.4000643194f, 0.0616699941f, 0.0308158733f, 0.4320195913f, }, + { 0.8162390590f, 0.3211650252f, 0.0619850792f, 0.7479447722f, 0.1394517124f, }, + { 0.9539483786f, 0.9044382572f, 0.0622508638f, 0.5755401254f, 0.6758915782f, }, + { 0.7120071650f, 0.6868788600f, 0.0622641221f, 0.7057911158f, 0.7800344229f, }, + { 0.5653573275f, 0.9720668197f, 0.0626811981f, 0.3935459554f, 0.2007560879f, }, + { 0.2615462542f, 0.1205192506f, 0.0628411695f, 0.6551766992f, 0.1969967037f, }, + { 0.7768732309f, 0.4172841311f, 0.0630410910f, 0.3674635291f, 0.4925908446f, }, + { 0.6667024493f, 0.7920866609f, 0.0634110644f, 0.8996462822f, 0.9083211422f, }, + { 0.7094047070f, 0.1457012445f, 0.0635015145f, 0.3562548161f, 0.5322344303f, }, + { 0.6049612164f, 0.9375944734f, 0.0637211204f, 0.4981285334f, 0.9198222160f, }, + { 0.7252311110f, 0.5214147568f, 0.0640635043f, 0.7540050745f, 0.7136243582f, }, + { 0.9189988375f, 0.6631800532f, 0.0642608404f, 0.1623289287f, 0.8097453117f, }, + { 0.2993314564f, 0.6986395121f, 0.0644821525f, 0.5717529655f, 0.4875931144f, }, + { 0.7453587651f, 0.4093028903f, 0.0647298992f, 0.6292716265f, 0.0229672510f, }, + { 0.2319925427f, 0.2401632965f, 0.0651091859f, 0.8973861337f, 0.9965874553f, }, + { 0.8872523308f, 0.3972734213f, 0.0653588995f, 0.9181726575f, 0.1807984114f, }, + { 0.3786160052f, 0.6723023057f, 0.0656563044f, 0.5863515139f, 0.4089870155f, }, + { 0.2557370067f, 0.9578768015f, 0.0658259541f, 0.9881767631f, 0.8308966756f, }, + { 0.8790580630f, 0.4285563231f, 0.0661118031f, 0.4060144722f, 0.4772524834f, }, + { 0.2992962301f, 0.2059165388f, 0.0663643777f, 0.4671196342f, 0.1619008482f, }, + { 0.0289979875f, 0.7550174594f, 0.0665974542f, 0.0359000526f, 0.3192620575f, }, + { 0.3674427867f, 0.5780120492f, 0.0667555034f, 0.6541302204f, 0.8969657421f, }, + { 0.4474572539f, 0.1086908430f, 0.0669978186f, 0.0417408682f, 0.0230331719f, }, + { 0.3625333309f, 0.8655498028f, 0.0673053190f, 0.2341199815f, 0.0855290517f, }, + { 0.3467016518f, 0.3802669048f, 0.0674490258f, 0.2344822884f, 0.7505428791f, }, + { 0.6175200343f, 0.8083914518f, 0.0676408187f, 0.8380948901f, 0.6287975311f, }, + { 0.4477202594f, 0.3626734614f, 0.0680689439f, 0.6547611356f, 0.5478475094f, }, + { 0.8220201135f, 0.2012880147f, 0.0683359578f, 0.3885985017f, 0.7240751386f, }, + { 0.1448843628f, 0.2296859622f, 0.0684017390f, 0.7839163542f, 0.9860430360f, }, + { 0.9685826302f, 0.7999537587f, 0.0688472837f, 0.7031974792f, 0.8250049353f, }, + { 0.2662183940f, 0.8745645881f, 0.0689502209f, 0.3876169324f, 0.0347653963f, }, + { 0.2576650381f, 0.0209626518f, 0.0692833588f, 0.3917622268f, 0.3390086591f, }, + { 0.1257773340f, 0.7977453470f, 0.0693983063f, 0.1064087823f, 0.9067006707f, }, + { 0.1288160235f, 0.0601612851f, 0.0696804002f, 0.4825960398f, 0.8466435075f, }, + { 0.4570294023f, 0.2116647512f, 0.0698961839f, 0.9510145187f, 0.6506526470f, }, + { 0.3929893970f, 0.4847156405f, 0.0702058151f, 0.2872371674f, 0.6579374671f, }, + { 0.7387816906f, 0.9707887769f, 0.0703754127f, 0.5938100219f, 0.2366212904f, }, + { 0.5601204038f, 0.0343928337f, 0.0707908198f, 0.2606928349f, 0.9264442325f, }, + { 0.0774890482f, 0.0626507029f, 0.0709281787f, 0.6520555019f, 0.7433550954f, }, + { 0.1146918684f, 0.4213481247f, 0.0711388066f, 0.2502732575f, 0.8452306390f, }, + { 0.0544719659f, 0.1501971781f, 0.0715257749f, 0.7733664513f, 0.5148495436f, }, + { 0.3153182268f, 0.5712278485f, 0.0715651736f, 0.9528820515f, 0.5524266958f, }, + { 0.9439774156f, 0.4815790355f, 0.0718785897f, 0.8494734168f, 0.7470275164f, }, + { 0.4937552810f, 0.9147025943f, 0.0721168965f, 0.2468672395f, 0.7171310186f, }, + { 0.1757197976f, 0.2605859637f, 0.0724579245f, 0.9079783559f, 0.5483204126f, }, + { 0.7733299136f, 0.2041899413f, 0.0725474730f, 0.7994664311f, 0.6117724180f, }, + { 0.7291424274f, 0.8528920412f, 0.0727805421f, 0.3395567536f, 0.7672840953f, }, + { 0.8544574976f, 0.9431186914f, 0.0731034353f, 0.6349754333f, 0.6721323729f, }, + { 0.6962663531f, 0.3192598224f, 0.0734091923f, 0.8889439702f, 0.6281045079f, }, + { 0.8659900427f, 0.3132424057f, 0.0736058876f, 0.2243998945f, 0.2960400283f, }, + { 0.0999320522f, 0.2499219179f, 0.5115166903f, 0.0204182714f, 0.6631027460f, }, + { 0.8230811954f, 0.5496843457f, 0.5046294928f, 0.9811518192f, 0.1133715957f, }, + { 0.2259661108f, 0.1999054700f, 0.5419001579f, 0.0715354383f, 0.2745304704f, }, + { 0.1484488994f, 0.3254649937f, 0.5480608344f, 0.1789485812f, 0.5548414588f, }, + { 0.0015056671f, 0.6750273705f, 0.5227317810f, 0.0008752898f, 0.5411751866f, }, + { 0.5249070525f, 0.4570088685f, 0.5505707264f, 0.7655183077f, 0.7792156339f, }, + { 0.6483680606f, 0.4496525824f, 0.5599683523f, 0.6312948465f, 0.1278442740f, }, + { 0.4247913659f, 0.0007082918f, 0.5338511467f, 0.4571608603f, 0.2620616853f, }, + { 0.1010501832f, 0.8749824166f, 0.5277982950f, 0.0978882238f, 0.5404268503f, }, + { 0.4003234804f, 0.1471461952f, 0.5669991374f, 0.5410963893f, 0.5188904405f, }, + { 0.7992156148f, 0.3746570647f, 0.5364877582f, 0.6718787551f, 0.2058310509f, }, + { 0.2480937093f, 0.3753580451f, 0.5190321207f, 0.6394835711f, 0.5764335990f, }, + { 0.5001162887f, 0.5508361459f, 0.5376195908f, 0.1067471281f, 0.6241273284f, }, + { 0.8019540310f, 0.7488102913f, 0.5381161571f, 0.6607485414f, 0.4171015918f, }, + { 0.2246898711f, 0.0752501786f, 0.5143418908f, 0.2288838625f, 0.1156424880f, }, + { 0.0999287590f, 0.6014629006f, 0.5073698759f, 0.6983845830f, 0.1368516386f, }, + { 0.8736896515f, 0.7525588870f, 0.5565645099f, 0.4013375938f, 0.3540355265f, }, + { 0.5754721761f, 0.3261488676f, 0.5243055224f, 0.5820555091f, 0.1185304895f, }, + { 0.5007212162f, 0.2262357920f, 0.5005226135f, 0.0950565264f, 0.3787706792f, }, + { 0.1740462631f, 0.7624011040f, 0.5504430532f, 0.6341329813f, 0.3289246559f, }, + { 0.8504666686f, 0.5751883388f, 0.5534842014f, 0.8555600643f, 0.9008951187f, }, + { 0.1483384818f, 0.1497145593f, 0.5018998981f, 0.5148512721f, 0.3895414472f, }, + { 0.1749736965f, 0.7005600333f, 0.5315646529f, 0.7238113284f, 0.3066526055f, }, + { 0.8754833937f, 0.0253881328f, 0.5453944206f, 0.0735144466f, 0.8595376015f, }, + { 0.8770704269f, 0.7007963061f, 0.5539349914f, 0.3620923758f, 0.0416149981f, }, + { 0.5511590242f, 0.1753898561f, 0.5428982377f, 0.0061305529f, 0.9809518456f, }, + { 0.9500498176f, 0.0746196732f, 0.5140426159f, 0.3935596943f, 0.8545308113f, }, + { 0.0751440227f, 0.3258487582f, 0.5482404232f, 0.1663255543f, 0.5424755216f, }, + { 0.4755449295f, 0.7762312889f, 0.5112431049f, 0.5744220614f, 0.6382409930f, }, + { 0.0658878610f, 0.9506678581f, 0.5125494003f, 0.9269253016f, 0.0504866913f, }, + { 0.2994566560f, 0.2502886951f, 0.5413233042f, 0.0337529555f, 0.7528452277f, }, + { 0.2519438267f, 0.7750726938f, 0.5304656625f, 0.7146564126f, 0.2432672977f, }, + { 0.3496539295f, 0.9512079358f, 0.5524450541f, 0.4369109869f, 0.4125491977f, }, + { 0.3010438979f, 0.3001830280f, 0.5212009549f, 0.6104905605f, 0.3683334589f, }, + { 0.9504808784f, 0.5489679575f, 0.5309481621f, 0.5791496038f, 0.8105304241f, }, + { 0.1749460250f, 0.8758938313f, 0.5421879888f, 0.1758835167f, 0.9822794795f, }, + { 0.6258250475f, 0.5763518214f, 0.5404347181f, 0.4388094842f, 0.1073131636f, }, + { 0.3750612736f, 0.7005741596f, 0.5204791427f, 0.7674415112f, 0.2598839402f, }, + { 0.7001037002f, 0.2501595616f, 0.5395210981f, 0.9401791096f, 0.3307978809f, }, + { 0.6495859623f, 0.8989270329f, 0.5222621560f, 0.0505006835f, 0.9291836023f, }, + { 0.4744192362f, 0.4241538048f, 0.5217758417f, 0.9684359431f, 0.7657282948f, }, + { 0.7503231168f, 0.1255191863f, 0.5349799395f, 0.9138517976f, 0.0479166918f, }, + { 0.2491602898f, 0.5001539588f, 0.5472148061f, 0.5830619335f, 0.7588519454f, }, + { 0.3500490189f, 0.6250315309f, 0.5657589436f, 0.0816372111f, 0.9144294262f, }, + { 0.2504021227f, 0.6756541729f, 0.5644892454f, 0.0794547722f, 0.9875050783f, }, + { 0.5760949254f, 0.2500765324f, 0.5521107912f, 0.4363875091f, 0.8016386032f, }, + { 0.5240598917f, 0.0005014921f, 0.5508316159f, 0.9080847502f, 0.4784570336f, }, + { 0.1754235327f, 0.0088394545f, 0.5237308741f, 0.2941185832f, 0.9301610589f, }, + { 0.9761223197f, 0.4750322104f, 0.5312444568f, 0.5898828506f, 0.8245856762f, }, + { 0.6249823570f, 0.5482255816f, 0.5568055511f, 0.4910352826f, 0.9700344205f, }, + { 0.7003957033f, 0.9335463643f, 0.5442412496f, 0.0020940867f, 0.8252884150f, }, + { 0.4500236213f, 0.8267934918f, 0.5330046415f, 0.4907908440f, 0.5618960857f, }, + { 0.6736150384f, 0.6998431087f, 0.5307450294f, 0.8588863015f, 0.4643555880f, }, + { 0.4020885229f, 0.6251436472f, 0.5615539551f, 0.1339508742f, 0.7263863683f, }, + { 0.0744914934f, 0.5144289732f, 0.5268847942f, 0.6987854838f, 0.1880896091f, }, + { 0.4735207260f, 0.0254445318f, 0.5090574622f, 0.2160100937f, 0.8461467028f, }, + { 0.1498632431f, 0.4940408468f, 0.5455294847f, 0.7461754084f, 0.6037412286f, }, + { 0.8002347350f, 0.6767628789f, 0.5379282236f, 0.6735312343f, 0.4157984555f, }, + { 0.2249268442f, 0.2818438113f, 0.5636990666f, 0.1006637216f, 0.0505338572f, }, + { 0.4440321028f, 0.5000624061f, 0.5133524537f, 0.2775644362f, 0.9255630970f, }, + { 0.1001772732f, 0.2768403292f, 0.5492872596f, 0.2484582216f, 0.6870269179f, }, + { 0.0997253805f, 0.6744239926f, 0.5071257353f, 0.6931677461f, 0.1206636950f, }, + { 0.7003175020f, 0.5999883413f, 0.5014630556f, 0.4683262408f, 0.0254596770f, }, + { 0.3272641003f, 0.7245584726f, 0.5063111782f, 0.3319536150f, 0.7235289216f, }, + { 0.8011968136f, 0.0001621095f, 0.5345208049f, 0.8668708801f, 0.5254281759f, }, + { 0.3491019607f, 0.4749787748f, 0.5048764348f, 0.6250700355f, 0.9735502005f, }, + { 0.0001044485f, 0.0749504790f, 0.5278743505f, 0.0092061460f, 0.8523430824f, }, + { 0.3668426275f, 0.0002808082f, 0.5214610696f, 0.4607114196f, 0.0699647814f, }, + { 0.0019413906f, 0.1997381002f, 0.5493205786f, 0.2258501500f, 0.7851875424f, }, + { 0.1752269715f, 0.0598003455f, 0.7709927559f, 0.7297613621f, 0.0649805665f, }, + { 0.4251952767f, 0.6993083358f, 0.5573977828f, 0.1529742479f, 0.4662842453f, }, + { 0.5745397210f, 0.8259099722f, 0.5438179970f, 0.2359199971f, 0.7312087417f, }, + { 0.1745049804f, 0.5756510496f, 0.5485115051f, 0.3477488458f, 0.6228222847f, }, + { 0.3994095325f, 0.9007194638f, 0.5086779594f, 0.7389538288f, 0.6282545328f, }, + { 0.8500962853f, 0.6250864267f, 0.5561627746f, 0.8481809497f, 0.9112290740f, }, + { 0.8962005377f, 0.1752026826f, 0.5207901001f, 0.3835842609f, 0.5991029739f, }, + { 0.3251191080f, 0.8248625994f, 0.5234875083f, 0.6679962277f, 0.8833323121f, }, + { 0.9251210690f, 0.4268980026f, 0.5215517879f, 0.1819206476f, 0.4930852056f, }, + { 0.5272848606f, 0.3749874234f, 0.5470319390f, 0.6138436198f, 0.3826188147f, }, + { 0.3000193536f, 0.0254025068f, 0.5083312392f, 0.5883831382f, 0.0250427239f, }, + { 0.5253503919f, 0.6984312534f, 0.5249617696f, 0.1148199067f, 0.6741824746f, }, + { 0.7499855757f, 0.2483469546f, 0.7933039665f, 0.4377368391f, 0.2851114273f, }, + { 0.2500551641f, 0.5995117426f, 0.5023117065f, 0.6605564356f, 0.7936561704f, }, + { 0.3750658035f, 0.2997975647f, 0.5025106072f, 0.7166559100f, 0.8406170607f, }, + { 0.2251778096f, 0.1504408717f, 0.2918845415f, 0.5752936006f, 0.2793307304f, }, + { 0.7007563710f, 0.5500325561f, 0.2513979077f, 0.9613408446f, 0.0115701305f, }, + { 0.7441768050f, 0.7239213586f, 0.5385182500f, 0.2844346166f, 0.1727228463f, }, + { 0.3000291586f, 0.9515274167f, 0.8023766279f, 0.9329535365f, 0.4029352665f, }, + { 0.3253384531f, 0.2250669003f, 0.5517534018f, 0.2216116488f, 0.6016576886f, }, + { 0.6249484420f, 0.2536979020f, 0.3020848632f, 0.4296074212f, 0.2982615232f, }, + { 0.3002781570f, 0.6501519084f, 0.5354457498f, 0.3292373717f, 0.9856880903f, }, + { 0.1259277612f, 0.5750076175f, 0.7985692024f, 0.8530553579f, 0.6365734339f, }, + { 0.9006658196f, 0.3501928747f, 0.5347179174f, 0.6244384050f, 0.5994596481f, }, + { 0.3002256453f, 0.5259074569f, 0.5570207238f, 0.4524676800f, 0.9247552752f, }, + { 0.0003350284f, 0.7242047787f, 0.7728614807f, 0.0018703928f, 0.0442872606f, }, + { 0.8747982383f, 0.0996252671f, 0.5078073740f, 0.3267765045f, 0.4316724539f, }, + { 0.6261390448f, 0.6247706413f, 0.2904641330f, 0.4472540915f, 0.6074808240f, }, + { 0.5492273569f, 0.2247809023f, 0.2553791404f, 0.5050001144f, 0.0748781487f, }, + { 0.4740642905f, 0.9500795007f, 0.5319891572f, 0.3242605627f, 0.3491915762f, }, + { 0.1001721472f, 0.8254614472f, 0.7777736187f, 0.6033853889f, 0.5377215743f, }, + { 0.7752010226f, 0.5498775244f, 0.2544977665f, 0.4832017720f, 0.1113383546f, }, + { 0.9252296686f, 0.1228583753f, 0.5328768492f, 0.6208903790f, 0.9137431383f, }, + { 0.0465656333f, 0.2499735206f, 0.5273821950f, 0.0361996554f, 0.5778218508f, }, + { 0.6004186869f, 0.9757286310f, 0.5239554048f, 0.7314612269f, 0.3885940313f, }, + { 0.6759005785f, 0.2239830643f, 0.5468668938f, 0.5622667074f, 0.4704272747f, }, + { 0.8742733002f, 0.7999920845f, 0.3064700365f, 0.3837772608f, 0.8443513513f, }, + { 0.9754860401f, 0.1605509520f, 0.7994903922f, 0.2277876586f, 0.2809434533f, }, + { 0.9752686024f, 0.3751614392f, 0.5258629322f, 0.2629101574f, 0.2701103985f, }, + { 0.1748678833f, 0.4005971849f, 0.5301225781f, 0.3054472804f, 0.3499853015f, }, + { 0.3498946428f, 0.3000138998f, 0.7711179256f, 0.6126044989f, 0.8665628433f, }, + { 0.3245068491f, 0.1747387946f, 0.5532488227f, 0.3132550418f, 0.3812983930f, }, + { 0.5758796930f, 0.9011237025f, 0.5639500022f, 0.9989155531f, 0.4252488017f, }, + { 0.5264706612f, 0.1039549336f, 0.5333061218f, 0.0940899178f, 0.6125734448f, }, + { 0.7496387362f, 0.3744670749f, 0.5200789571f, 0.7560089827f, 0.2080084532f, }, + { 0.1001026705f, 0.9458412528f, 0.5415499806f, 0.3668878973f, 0.9828520417f, }, + { 0.9995611310f, 0.7638900280f, 0.5627825260f, 0.1718402356f, 0.2598179877f, }, + { 0.9996442199f, 0.9997321963f, 0.5161181092f, 0.5751026273f, 0.0757289082f, }, + { 0.9247543812f, 0.7006901503f, 0.3038231730f, 0.8562679291f, 0.0440575555f, }, + { 0.8500502706f, 0.1521456838f, 0.7765128613f, 0.8845826387f, 0.7974487543f, }, + { 0.2751914263f, 0.9235986471f, 0.5010297894f, 0.4152250290f, 0.1891870201f, }, + { 0.7493785024f, 0.0502499864f, 0.5299572349f, 0.5484668016f, 0.8940036297f, }, + { 0.5997685194f, 0.1751283556f, 0.2929151058f, 0.5094879270f, 0.9900570512f, }, + { 0.2730788291f, 0.3252712786f, 0.5088200569f, 0.9107674956f, 0.2064258009f, }, + { 0.9254841805f, 0.9736527801f, 0.5173871517f, 0.5805056691f, 0.2224412262f, }, + { 0.4251921177f, 0.2448307574f, 0.5402419567f, 0.0911679268f, 0.1550231129f, }, + { 0.1503494382f, 0.1772428006f, 0.5361026525f, 0.9279728532f, 0.6084936857f, }, + { 0.7732584476f, 0.0000354978f, 0.5147289634f, 0.6864467859f, 0.7499171495f, }, + { 0.6498963237f, 0.4004913867f, 0.8100335598f, 0.1245280132f, 0.1258932203f, }, + { 0.5502613187f, 0.4755345285f, 0.5397840738f, 0.6746035814f, 0.5899897218f, }, + { 0.4761830568f, 0.4503525496f, 0.3006536961f, 0.2664533257f, 0.7806874514f, }, + { 0.5977367759f, 0.4497195184f, 0.5591698289f, 0.6015981436f, 0.8595799804f, }, + { 0.3999920785f, 0.7755410671f, 0.5221899748f, 0.6598505378f, 0.5304762721f, }, + { 0.7009853125f, 0.0497843474f, 0.2758545280f, 0.0503295958f, 0.7405276895f, }, + { 0.5497202277f, 0.5502256155f, 0.7878061533f, 0.1018271223f, 0.1266049147f, }, + { 0.8005627990f, 0.8237455487f, 0.5462722182f, 0.3760555983f, 0.0753159896f, }, + { 0.1035231426f, 0.1497556567f, 0.7518115640f, 0.5082446337f, 0.8875021935f, }, + { 0.8202154636f, 0.4002920389f, 0.5513230562f, 0.8215457201f, 0.9464796782f, }, + { 0.1498018503f, 0.3711400032f, 0.7981531024f, 0.6742455959f, 0.5438446999f, }, + { 0.4257688820f, 0.9712520838f, 0.7746434808f, 0.8302544951f, 0.4448617995f, }, + { 0.9000604749f, 0.5749567151f, 0.5313487053f, 0.3104019463f, 0.6124757528f, }, + { 0.2243317217f, 0.7251231074f, 0.5542970896f, 0.6156340837f, 0.3250629902f, }, + { 0.0455734171f, 0.6751070619f, 0.2728859782f, 0.5120468736f, 0.5437161326f, }, + { 0.5001484156f, 0.6025904417f, 0.5296363235f, 0.1155260205f, 0.3393405974f, }, + { 0.6501275897f, 0.0747039318f, 0.5519939661f, 0.1888348460f, 0.7275009155f, }, + { 0.4955745339f, 0.7000873089f, 0.5423910618f, 0.9416359067f, 0.3536934853f, }, + { 0.6755961776f, 0.6561246514f, 0.7678679824f, 0.3357191682f, 0.4943229258f, }, + { 0.7998280525f, 0.0751963630f, 0.5529671907f, 0.7376633286f, 0.8999725580f, }, + { 0.0996982306f, 0.0253865514f, 0.5709270239f, 0.1597508341f, 0.2412546128f, }, + { 0.8247569799f, 0.8734449148f, 0.5225820541f, 0.6883258820f, 0.0724279657f, }, + { 0.2996210754f, 0.4001732767f, 0.5182953477f, 0.7831487656f, 0.8166896105f, }, + { 0.0233779121f, 0.3021736741f, 0.5398937464f, 0.4776594043f, 0.0058054971f, }, + { 0.8610946536f, 0.2251330763f, 0.5136775374f, 0.9498023391f, 0.8130799532f, }, + { 0.8136752248f, 0.9504834414f, 0.5410513878f, 0.3925128579f, 0.2980484068f, }, + { 0.9516111016f, 0.3005914092f, 0.5590465665f, 0.6285298467f, 0.1961681694f, }, + { 0.7489117980f, 0.6507989764f, 0.5339702368f, 0.6700567007f, 0.2800427377f, }, + { 0.6983140707f, 0.5249677300f, 0.5195064545f, 0.2980390489f, 0.1606786400f, }, + { 0.2987805009f, 0.7251967788f, 0.5361614227f, 0.7935696244f, 0.5575941205f, }, + { 0.7740447521f, 0.9302762151f, 0.5445288420f, 0.0952188447f, 0.1136509851f, }, + { 0.2246903181f, 0.1248656958f, 0.2643775940f, 0.2228783816f, 0.6161629558f, }, + { 0.6998116374f, 0.8493226767f, 0.5245594382f, 0.2978401184f, 0.3333850503f, }, + { 0.3490571976f, 0.0750670508f, 0.5391489267f, 0.9486908317f, 0.7237961888f, }, + { 0.0997513980f, 0.7861223817f, 0.5464121103f, 0.8507101536f, 0.3045574427f, }, + { 0.5250537992f, 0.7750696540f, 0.5293450952f, 0.4792307317f, 0.7873080373f, }, + { 0.4325400293f, 0.5537790060f, 0.5130739212f, 0.0449095294f, 0.9175116420f, }, + { 0.1997812688f, 0.4596541226f, 0.5292966962f, 0.1815126389f, 0.2876657248f, }, + { 0.2660025358f, 0.8318057060f, 0.5373314619f, 0.8614996076f, 0.2404779047f, }, + { 0.1249781027f, 0.5496615171f, 0.5288793445f, 0.9512536526f, 0.7106238604f, }, + { 0.2499334365f, 0.4168019295f, 0.2690057755f, 0.1374810934f, 0.5880811214f, }, + { 0.1499096006f, 0.0976217687f, 0.5357709527f, 0.7261719108f, 0.3562320471f, }, + { 0.8003937006f, 0.1736645848f, 0.5000972152f, 0.9106252789f, 0.1092447415f, }, + { 0.9346538782f, 0.6255768538f, 0.5611312985f, 0.3750639260f, 0.3079939485f, }, + { 0.3747005463f, 0.5494291782f, 0.5426376462f, 0.3295607567f, 0.9194047451f, }, + { 0.6838009357f, 0.1845372915f, 0.7969882488f, 0.0567502901f, 0.4751828611f, }, + { 0.5001500249f, 0.2690117657f, 0.7505946755f, 0.1000960097f, 0.8821128607f, }, + { 0.3651940227f, 0.2250199467f, 0.3017239273f, 0.7274194360f, 0.5936693549f, }, + { 0.7753910422f, 0.8929878473f, 0.7661802173f, 0.2630929947f, 0.3632211089f, }, + { 0.0372290835f, 0.8369566798f, 0.5336752534f, 0.8983758688f, 0.2219576985f, }, + { 0.0444791801f, 0.7921099067f, 0.5526638031f, 0.5702645183f, 0.0122680143f, }, + { 0.7757485509f, 0.2998821437f, 0.5375289917f, 0.2801386118f, 0.5837280154f, }, + { 0.5242258906f, 0.8832383156f, 0.5370056033f, 0.6608048081f, 0.4363793731f, }, + { 0.7999209762f, 0.7750952840f, 0.2846296728f, 0.8795508146f, 0.1608684063f, }, + { 0.4233184755f, 0.2804969549f, 0.7526665926f, 0.2038259506f, 0.8353402615f, }, + { 0.9511299729f, 0.8747844100f, 0.5510716438f, 0.3206585050f, 0.1963020414f, }, + { 0.0725258663f, 0.4753859341f, 0.7775045633f, 0.7826504111f, 0.6878070235f, }, + { 0.1721748561f, 0.6749533415f, 0.5287784338f, 0.5452747941f, 0.3972863555f, }, + { 0.7004129291f, 0.7248691916f, 0.8003051877f, 0.2005801052f, 0.6780173182f, }, + { 0.9035027623f, 0.4600081444f, 0.7805774808f, 0.2603481114f, 0.9447153807f, }, + { 0.6034649611f, 0.6747562289f, 0.5285315514f, 0.9772263765f, 0.4650842845f, }, + { 0.3115386069f, 0.4627543688f, 0.7548241019f, 0.0751347989f, 0.9338189960f, }, + { 0.7353200316f, 0.1745953262f, 0.7850107551f, 0.4074598849f, 0.0395092294f, }, + { 0.3747457266f, 0.7407103181f, 0.7702561021f, 0.2608159781f, 0.2204758972f, }, + { 0.9142432809f, 0.0300660655f, 0.2951912582f, 0.6118893027f, 0.8346792459f, }, + { 0.9975226521f, 0.6114969254f, 0.5368096828f, 0.3778877556f, 0.8608812690f, }, + { 0.1997035146f, 0.9059427381f, 0.2862283587f, 0.6603853106f, 0.6420208216f, }, + { 0.4752921164f, 0.1196575463f, 0.5135126114f, 0.9023658037f, 0.6486666799f, }, + { 0.2795032263f, 0.9888322949f, 0.4357944131f, 0.4658937752f, 0.8178166747f, }, + { 0.4086343050f, 0.3612650335f, 0.5406261086f, 0.3329614401f, 0.0831623450f, }, + { 0.4390114248f, 0.1488649845f, 0.3171105981f, 0.5422522426f, 0.0328068510f, }, + { 0.8897623420f, 0.8997618556f, 0.5169444084f, 0.6603409648f, 0.9383791089f, }, + { 0.9743193388f, 0.2395078838f, 0.5319483280f, 0.5203607678f, 0.1380842030f, }, + { 0.2619803250f, 0.2162847072f, 0.8036819696f, 0.4048399329f, 0.6602196693f, }, + { 0.8711836338f, 0.4661754370f, 0.5409150720f, 0.0809135213f, 0.8984272480f, }, + { 0.0596349053f, 0.0117377304f, 0.3062259555f, 0.6711297035f, 0.2673375010f, }, + { 0.8356544971f, 0.6613228321f, 0.7973790765f, 0.2280260473f, 0.8149731755f, }, + { 0.0408365093f, 0.0750936046f, 0.7854781747f, 0.4383783937f, 0.1533345282f, }, + { 0.1119991168f, 0.3134014308f, 0.7992256880f, 0.7203811407f, 0.7091453671f, }, + { 0.1755617410f, 0.8496134877f, 0.5280808806f, 0.3259921372f, 0.7993033528f, }, + { 0.6418301463f, 0.9250168204f, 0.5502291322f, 0.1222573742f, 0.5057234764f, }, + { 0.1000155732f, 0.9000147581f, 0.7919905782f, 0.8671909571f, 0.0284288563f, }, + { 0.6801979542f, 0.2846042514f, 0.7828821540f, 0.4448051751f, 0.1685207933f, }, + { 0.4005309045f, 0.8637186289f, 0.5495784283f, 0.0345784724f, 0.6030176878f, }, + { 0.8173489571f, 0.2388448864f, 0.5430321097f, 0.9160596728f, 0.5306850672f, }, + { 0.0388270207f, 0.9002864361f, 0.5325637460f, 0.7880895138f, 0.7949716449f, }, + { 0.2880385220f, 0.5987402797f, 0.7523050308f, 0.6136860847f, 0.2506010234f, }, + { 0.5284342766f, 0.0743304119f, 0.5607281327f, 0.0826105773f, 0.4342528880f, }, + { 0.9920173287f, 0.8997177482f, 0.3068070412f, 0.8243589401f, 0.1300874949f, }, + { 0.2239975929f, 0.6597993970f, 0.5129216313f, 0.4075867236f, 0.4422813058f, }, + { 0.6123604774f, 0.3333697319f, 0.7742974162f, 0.5759977102f, 0.6168429852f, }, + { 0.7250822783f, 0.3105677962f, 0.5385826826f, 0.7408080697f, 0.3263380826f, }, + { 0.5629963279f, 0.3624468744f, 0.7915677428f, 0.2120130956f, 0.3663682640f, }, + { 0.9386667013f, 0.9385758042f, 0.7667163014f, 0.1570772976f, 0.1708049625f, }, + { 0.1093291715f, 0.6379883885f, 0.7723137140f, 0.5497030020f, 0.6244307160f, }, + { 0.5008698702f, 0.5245783329f, 0.5530485511f, 0.6864647865f, 0.5826882720f, }, + { 0.4386887848f, 0.7588463426f, 0.5207459927f, 0.8803467751f, 0.2860114872f, }, + { 0.7752911448f, 0.7224058509f, 0.2763405144f, 0.1926852316f, 0.1651296169f, }, + { 0.8698518872f, 0.0626572743f, 0.7763509154f, 0.8382780552f, 0.4174584746f, }, + { 0.4605165422f, 0.6877903938f, 0.3001142740f, 0.1704382151f, 0.9506057501f, }, + { 0.0413748622f, 0.1246928498f, 0.4211828113f, 0.9457256198f, 0.2883197963f, }, + { 0.5626202226f, 0.2997952104f, 0.3019315600f, 0.4052161276f, 0.3289777935f, }, + { 0.1378460377f, 0.8693628907f, 0.2777343690f, 0.8913806081f, 0.2451933920f, }, + { 0.6290415525f, 0.7323547602f, 0.5262699127f, 0.6497017741f, 0.6197906137f, }, + { 0.6127650142f, 0.9004053473f, 0.8138029575f, 0.5513033271f, 0.3798373640f, }, + { 0.9634651542f, 0.5130774975f, 0.7811911106f, 0.5899270773f, 0.3152047694f, }, + { 0.5744165182f, 0.0001871195f, 0.5706067681f, 0.7560129762f, 0.4177090228f, }, + { 0.8113030791f, 0.5146631598f, 0.7545950413f, 0.0771946386f, 0.7100368142f, }, + { 0.0633007288f, 0.6079054475f, 0.7574558258f, 0.7035510540f, 0.6323798299f, }, + { 0.2636410594f, 0.2591147423f, 0.7913017273f, 0.5046302080f, 0.7218750715f, }, + { 0.4110842943f, 0.1116999313f, 0.8085526228f, 0.9592315555f, 0.6070178747f, }, + { 0.2127826959f, 0.3852916658f, 0.7689697742f, 0.5475053191f, 0.9814865589f, }, + { 0.4718229175f, 0.8848004341f, 0.5540108085f, 0.7498770356f, 0.5739431381f, }, + { 0.1898969859f, 0.9750541449f, 0.2718774974f, 0.4377221763f, 0.4282991588f, }, + { 0.0034452199f, 0.9634109735f, 0.7646242976f, 0.0675212964f, 0.2389044762f, }, + { 0.6095223427f, 0.5148304701f, 0.3070017993f, 0.0609804951f, 0.9367491603f, }, + { 0.8380074501f, 0.7437092066f, 0.2881639302f, 0.6731401086f, 0.9257479310f, }, + { 0.6335731745f, 0.9605197310f, 0.7872013450f, 0.8635986447f, 0.7912477255f, }, + { 0.1252378970f, 0.9844140410f, 0.5324501991f, 0.1294085979f, 0.9112638235f, }, + { 0.8145045042f, 0.2843495309f, 0.7757657170f, 0.7959787846f, 0.5845375061f, }, + { 0.4706402719f, 0.5751262307f, 0.7647804022f, 0.8158777952f, 0.3960022926f, }, + { 0.3003020585f, 0.0616735183f, 0.7738249898f, 0.5302147865f, 0.6218560934f, }, + { 0.5896311402f, 0.1081295907f, 0.5352211595f, 0.1017315537f, 0.6753742695f, }, + { 0.7027110457f, 0.9697492719f, 0.7844030261f, 0.1171118990f, 0.3106798232f, }, + { 0.2504562140f, 0.0859673023f, 0.5458080173f, 0.5280211568f, 0.6978164315f, }, + { 0.5276758671f, 0.8499944210f, 0.2938606143f, 0.7426661849f, 0.7418406606f, }, + { 0.5153419971f, 0.4916026592f, 0.8018440008f, 0.0307825450f, 0.5341912508f, }, + { 0.0836942196f, 0.2176079899f, 0.7615510821f, 0.4808616340f, 0.7122395039f, }, + { 0.2144380808f, 0.5090511441f, 0.2972461581f, 0.1086695045f, 0.7769420147f, }, + { 0.5746155381f, 0.9374994040f, 0.3132429719f, 0.2976965904f, 0.7660832405f, }, + { 0.6761261821f, 0.4500373602f, 0.5095434189f, 0.5840551257f, 0.2035022974f, }, + { 0.4737493396f, 0.3882605433f, 0.7622998953f, 0.0092825871f, 0.2572658658f, }, + { 0.4130029976f, 0.6621555090f, 0.8094986677f, 0.2627421319f, 0.0946138427f, }, + { 0.4902606010f, 0.6374538541f, 0.2821718752f, 0.6151838303f, 0.0784768164f, }, + { 0.0167285688f, 0.0250962991f, 0.2846912742f, 0.4282787442f, 0.1700391173f, }, + { 0.8876488805f, 0.6409283876f, 0.8048554063f, 0.8539528251f, 0.4121233225f, }, + { 0.2251935303f, 0.9394209981f, 0.5498843193f, 0.3765726388f, 0.3822593093f, }, + { 0.1384685785f, 0.7643449903f, 0.7909381390f, 0.0896739662f, 0.3571909964f, }, + { 0.4823709726f, 0.8112801909f, 0.2614620328f, 0.6088703275f, 0.1068607867f, }, + { 0.8092662096f, 0.7131049037f, 0.7882003188f, 0.0500102006f, 0.5385617614f, }, + { 0.2635365427f, 0.7084999084f, 0.8051757216f, 0.5753301978f, 0.0005160624f, }, + { 0.8489185572f, 0.1240955219f, 0.2577161491f, 0.8503218889f, 0.4499092698f, }, + { 0.9996731281f, 0.5500799417f, 0.7929956913f, 0.4484986961f, 0.2998239696f, }, + { 0.8912776709f, 0.2883389592f, 0.5388507247f, 0.9632484913f, 0.8112907410f, }, + { 0.8502166867f, 0.3997798264f, 0.5555904508f, 0.4219462276f, 0.3296247125f, }, + { 0.9898644686f, 0.3138978481f, 0.8086916804f, 0.0744073465f, 0.1059252173f, }, + { 0.3706417382f, 0.4202817976f, 0.5342596173f, 0.7810452580f, 0.0852209106f, }, + { 0.5590644479f, 0.6252070069f, 0.5264827013f, 0.3523439169f, 0.5098841190f, }, + { 0.9554960728f, 0.4086942375f, 0.2714860737f, 0.6909407377f, 0.4901607335f, }, + { 0.6392166615f, 0.6937839389f, 0.7804899216f, 0.8526608348f, 0.9516466260f, }, + { 0.1991148293f, 0.2340947986f, 0.5572512150f, 0.0562805459f, 0.0453243330f, }, + { 0.6750744581f, 0.9095993042f, 0.2970505059f, 0.4754351974f, 0.7000186443f, }, + { 0.1316584945f, 0.2620893419f, 0.7990656495f, 0.2484972477f, 0.1811031550f, }, + { 0.6253730059f, 0.1748585850f, 0.5273047090f, 0.3286120594f, 0.6072568893f, }, + { 0.7362372279f, 0.9358738065f, 0.3073558509f, 0.4165186286f, 0.8981802464f, }, + { 0.3001219034f, 0.3351886868f, 0.2710070312f, 0.1095422283f, 0.3549511433f, }, + { 0.6977123022f, 0.1124026850f, 0.5433037281f, 0.8624612093f, 0.7299483418f, }, + { 0.5569099784f, 0.7132778764f, 0.2751158774f, 0.6061931252f, 0.6541576982f, }, + { 0.0001218671f, 0.8438360691f, 0.2859224677f, 0.4624030888f, 0.2270945013f, }, + { 0.7498405576f, 0.4957655370f, 0.5488407016f, 0.2605675459f, 0.0614596605f, }, + { 0.9457700253f, 0.7732230425f, 0.5581467748f, 0.1797589958f, 0.9994236827f, }, + { 0.2865118086f, 0.7720754743f, 0.7814735174f, 0.3624053895f, 0.7065202594f, }, + { 0.2256019861f, 0.6252601743f, 0.2569191754f, 0.9069035053f, 0.3790998161f, }, + { 0.3208078444f, 0.4973346889f, 0.2825217545f, 0.4639153481f, 0.6000622511f, }, + { 0.9945076108f, 0.1314353794f, 0.4284003675f, 0.9500859380f, 0.8687666059f, }, + { 0.4296155274f, 0.7254772186f, 0.7706710100f, 0.8460306525f, 0.7345523238f, }, + { 0.9994496107f, 0.3506086767f, 0.7760996819f, 0.7378966808f, 0.2598538697f, }, + { 0.8751109242f, 0.8503549695f, 0.2687365115f, 0.9418107271f, 0.5758903623f, }, + { 0.5956566334f, 0.0602373593f, 0.5487769246f, 0.0542028658f, 0.4060555696f, }, + { 0.0226368401f, 0.2745754123f, 0.7857446074f, 0.5217471123f, 0.4758980870f, }, + { 0.1905053407f, 0.7318531871f, 0.8043738008f, 0.6248359680f, 0.8252434731f, }, + { 0.7414038181f, 0.7869729996f, 0.5266615152f, 0.6692519188f, 0.4764635563f, }, + { 0.4744595289f, 0.2408789396f, 0.7754648924f, 0.4600417316f, 0.7893798351f, }, + { 0.5392030478f, 0.9501198530f, 0.6797338128f, 0.8395846486f, 0.9590820670f, }, + { 0.1691662073f, 0.9207706451f, 0.7862272859f, 0.2203316838f, 0.5409872532f, }, + { 0.1763838232f, 0.6097521782f, 0.2858668864f, 0.8091250658f, 0.4302299321f, }, + { 0.7918794751f, 0.1101478338f, 0.2941585779f, 0.8141484857f, 0.4729580283f, }, + { 0.4355879724f, 0.1765970439f, 0.5436180234f, 0.2081685960f, 0.0995367989f, }, + { 0.4089168310f, 0.3111028373f, 0.2592484355f, 0.4544049203f, 0.4789769351f, }, + { 0.5260415077f, 0.2998954356f, 0.5259347558f, 0.9072730541f, 0.4073594809f, }, + { 0.1410185099f, 0.7003865838f, 0.2815932930f, 0.7142217755f, 0.8033013940f, }, + { 0.8457406163f, 0.5240047574f, 0.2827538252f, 0.4805533290f, 0.0624564886f, }, + { 0.9768877625f, 0.9293188453f, 0.4134830534f, 0.5720592141f, 0.1760986447f, }, + { 0.9329249263f, 0.1977111250f, 0.5100764036f, 0.3891465664f, 0.0091627166f, }, + { 0.6256566644f, 0.2875197232f, 0.6641430855f, 0.7309313416f, 0.7672879100f, }, + { 0.8860545754f, 0.9564353824f, 0.5440785885f, 0.6018192172f, 0.1687208861f, }, + { 0.0745749623f, 0.1774723679f, 0.4165121317f, 0.0244933479f, 0.9739898443f, }, + { 0.7893202305f, 0.3419615924f, 0.7864072919f, 0.6683464646f, 0.6738077998f, }, + { 0.7579115033f, 0.8344991803f, 0.5448824167f, 0.7964057922f, 0.3579272926f, }, + { 0.6661602855f, 0.5143686533f, 0.7644002438f, 0.5755745173f, 0.7065804005f, }, + { 0.4502511919f, 0.0750880912f, 0.7614418864f, 0.2898681462f, 0.3729478717f, }, + { 0.6439507008f, 0.0250395555f, 0.3022561967f, 0.1900106966f, 0.2208629847f, }, + { 0.9743952155f, 0.7110337019f, 0.5477516651f, 0.4334086776f, 0.2265555561f, }, + { 0.9340953231f, 0.3495745957f, 0.2966069579f, 0.1040182561f, 0.0153717613f, }, + { 0.7753479481f, 0.6503980160f, 0.2883664668f, 0.0782936737f, 0.1556585431f, }, + { 0.9369826913f, 0.8211395741f, 0.5255106688f, 0.7216694951f, 0.2655977309f, }, + { 0.4939062595f, 0.9850761890f, 0.2891822755f, 0.4406910837f, 0.8576093316f, }, + { 0.3409891725f, 0.5496462584f, 0.7996324301f, 0.3746490479f, 0.3689315617f, }, + { 0.7155318260f, 0.3934908509f, 0.7617766261f, 0.2502561510f, 0.2582918108f, }, + { 0.2725115716f, 0.5246615410f, 0.8038206697f, 0.1215173379f, 0.9531595111f, }, + { 0.3749415576f, 0.1633504033f, 0.5093793869f, 0.0775244907f, 0.2248118222f, }, + { 0.4619115591f, 0.9243010283f, 0.8006494641f, 0.3813991249f, 0.2723599970f, }, + { 0.7801956534f, 0.1414201558f, 0.7675882578f, 0.3985167444f, 0.0777013674f, }, + { 0.0832739323f, 0.4089244902f, 0.5608979464f, 0.9120648503f, 0.3564301431f, }, + { 0.4358764291f, 0.6246863008f, 0.2917339802f, 0.6748359203f, 0.8100230098f, }, + { 0.7214345336f, 0.4336005151f, 0.7674770951f, 0.1289839298f, 0.8295099139f, }, + { 0.1411042064f, 0.4006635547f, 0.7801882625f, 0.8009476662f, 0.3393412828f, }, + { 0.3386042118f, 0.5950755477f, 0.5583661795f, 0.4575778842f, 0.3825599551f, }, + { 0.5092595220f, 0.3311366737f, 0.3025851250f, 0.0787324086f, 0.2990106940f, }, + { 0.1220708191f, 0.3456930816f, 0.2981326282f, 0.1732985675f, 0.0506457649f, }, + { 0.8253732324f, 0.4598790705f, 0.2902397215f, 0.6003482938f, 0.0133542782f, }, + { 0.6858534217f, 0.0750145540f, 0.2948904932f, 0.5293439627f, 0.4628251493f, }, + { 0.7639911175f, 0.4484609962f, 0.5474563241f, 0.1789518744f, 0.9198279977f, }, + { 0.1933730245f, 0.0871127918f, 0.6426331997f, 0.9601479173f, 0.3560474515f, }, + { 0.3957444727f, 0.0169553291f, 0.7837250829f, 0.9497953057f, 0.2531274259f, }, + { 0.0782000795f, 0.8508540392f, 0.2906319499f, 0.8910681009f, 0.0400970206f, }, + { 0.9442071319f, 0.2259038985f, 0.2931440175f, 0.4078338146f, 0.6724775434f, }, + { 0.8335361481f, 0.0069740796f, 0.7926688790f, 0.4450193048f, 0.0904317498f, }, + { 0.8448672891f, 0.9108209610f, 0.5449882150f, 0.2355297804f, 0.9682732821f, }, + { 0.6588913798f, 0.5752074122f, 0.7905238271f, 0.9339547753f, 0.1112099066f, }, + { 0.5902088284f, 0.7717949748f, 0.5253858566f, 0.2382190526f, 0.6141679883f, }, + { 0.6852118969f, 0.8193714023f, 0.7637542486f, 0.3638478518f, 0.8715277910f, }, + { 0.6003316045f, 0.6048004031f, 0.7847290635f, 0.9498142600f, 0.6895409822f, }, + { 0.0497272238f, 0.5658306479f, 0.5247703195f, 0.1598428339f, 0.4795340300f, }, + { 0.7133460045f, 0.2800622582f, 0.3059506714f, 0.0821619332f, 0.9653497934f, }, + { 0.2650574744f, 0.4688487649f, 0.5459523201f, 0.7050676346f, 0.9935357571f, }, + { 0.5994047523f, 0.7361437678f, 0.7716812491f, 0.4253230095f, 0.0386153422f, }, + { 0.2245454937f, 0.7913112640f, 0.5232684016f, 0.0133250756f, 0.2724117637f, }, + { 0.2549408078f, 0.1838333160f, 0.6727284193f, 0.0073994482f, 0.8394752145f, }, + { 0.9202122688f, 0.3998846710f, 0.7695948482f, 0.4187813401f, 0.1450325996f, }, + { 0.1993959546f, 0.3500203788f, 0.4006854594f, 0.0414465889f, 0.7870039940f, }, + { 0.6396826506f, 0.3506583869f, 0.4046313763f, 0.6890106797f, 0.1043194309f, }, + { 0.9647856355f, 0.6123890877f, 0.2973951697f, 0.7624385953f, 0.9991747737f, }, + { 0.9002122283f, 0.0998907015f, 0.7890358567f, 0.0819713324f, 0.6053829193f, }, + { 0.5372489691f, 0.1499465853f, 0.2835902870f, 0.5306325555f, 0.4334580600f, }, + { 0.3860293329f, 0.9300792217f, 0.7587786317f, 0.7449499965f, 0.1269662082f, }, + { 0.7750867009f, 0.5759402514f, 0.5544554591f, 0.9125486612f, 0.0779895484f, }, + { 0.0228035692f, 0.7002257109f, 0.6478238702f, 0.2508028746f, 0.2992904782f, }, + { 0.5029975176f, 0.4323965907f, 0.8060838580f, 0.5273122191f, 0.2564524412f, }, + { 0.1581190675f, 0.7286189795f, 0.1566729099f, 0.3622593284f, 0.1165340096f, }, + { 0.9549772739f, 0.1355334967f, 0.2306627780f, 0.2894310057f, 0.7520320415f, }, + { 0.1920721531f, 0.2880801558f, 0.3180584013f, 0.4580792487f, 0.3651930392f, }, + { 0.0336011872f, 0.9515703917f, 0.2855015397f, 0.5509393811f, 0.3329965174f, }, + { 0.8071669936f, 0.0343504399f, 0.2977145612f, 0.9450189471f, 0.0395925194f, }, + { 0.7499812841f, 0.5422456861f, 0.6263286471f, 0.4647623003f, 0.2473599166f, }, + { 0.3326048255f, 0.8780121803f, 0.5231653452f, 0.4300028682f, 0.6038040519f, }, + { 0.5393199921f, 0.4013643563f, 0.4338366687f, 0.5753194094f, 0.7920855284f, }, + { 0.2375757396f, 0.3116320968f, 0.2751671374f, 0.8140007257f, 0.6709600091f, }, + { 0.4242839515f, 0.0822508037f, 0.4377377331f, 0.5109994411f, 0.8381221890f, }, + { 0.7325818539f, 0.6000300050f, 0.7534617186f, 0.8508836031f, 0.5186093450f, }, + { 0.8201930523f, 0.3503412306f, 0.2912582457f, 0.1698331535f, 0.3433961272f, }, + { 0.8749606609f, 0.3452144861f, 0.5596762300f, 0.8859229088f, 0.6866813302f, }, + { 0.4001246989f, 0.8080029488f, 0.2799992263f, 0.0225006696f, 0.9885226488f, }, + { 0.0745726526f, 0.2693292797f, 0.7819388509f, 0.6689161658f, 0.0571094677f, }, + { 0.5274602175f, 0.0322797894f, 0.8106626868f, 0.8286591172f, 0.9012759328f, }, + { 0.3437840044f, 0.1065286398f, 0.2962122262f, 0.9999867678f, 0.2837511003f, }, + { 0.4418636858f, 0.5903841853f, 0.1568869501f, 0.1432511508f, 0.2637755871f, }, + { 0.9879755974f, 0.4104428589f, 0.7735606432f, 0.2709191144f, 0.7334169745f, }, + { 0.2811683416f, 0.0954814851f, 0.3043693006f, 0.0461132452f, 0.8634625673f, }, + { 0.0475427881f, 0.4099179804f, 0.5548568964f, 0.2144707888f, 0.6792877316f, }, + { 0.8108834624f, 0.4308766127f, 0.7912250161f, 0.9003937244f, 0.5373287201f, }, + { 0.3971642256f, 0.2246182263f, 0.6540088654f, 0.1797845364f, 0.2128595561f, }, + { 0.6696526408f, 0.3364855051f, 0.7198640704f, 0.3886204660f, 0.5648565292f, }, + { 0.9445192814f, 0.0433134884f, 0.7659504414f, 0.0136004789f, 0.5625730753f, }, + { 0.3796073496f, 0.1178845093f, 0.2440009862f, 0.6823272109f, 0.1710589379f, }, + { 0.4426908791f, 0.4274550080f, 0.2721720040f, 0.9906947017f, 0.2536124289f, }, + { 0.7432353497f, 0.6915289164f, 0.2979070246f, 0.9431248903f, 0.0567763224f, }, + { 0.8850826025f, 0.2047438473f, 0.7649860978f, 0.7903056145f, 0.2861865163f, }, + { 0.1094466895f, 0.7007045150f, 0.6484944820f, 0.6500830650f, 0.2995134294f, }, + { 0.7315405607f, 0.3454598486f, 0.2782539129f, 0.2504938841f, 0.1994613260f, }, + { 0.2425443232f, 0.8532289863f, 0.7899130583f, 0.3757571876f, 0.5348195434f, }, + { 0.6415081024f, 0.8681899905f, 0.2723032534f, 0.4902763665f, 0.9859597087f, }, + { 0.7578067183f, 0.8665660620f, 0.3088432848f, 0.7342776060f, 0.9250809550f, }, + { 0.2001357079f, 0.5717392564f, 0.5198030472f, 0.6827158928f, 0.6138558388f, }, + { 0.5705425739f, 0.4998483658f, 0.2985683978f, 0.2754984796f, 0.0385792106f, }, + { 0.5412657857f, 0.6709792614f, 0.2747735679f, 0.0215833541f, 0.2621179521f, }, + { 0.6292054057f, 0.4245176017f, 0.3098716438f, 0.6401355267f, 0.6350391507f, }, + { 0.3451481462f, 0.8001451492f, 0.2736293972f, 0.6688865423f, 0.3832850754f, }, + { 0.0026290112f, 0.4926379919f, 0.2810564935f, 0.5791549683f, 0.3252087831f, }, + { 0.0431423411f, 0.5124416947f, 0.1546229720f, 0.1480508000f, 0.4282864630f, }, + { 0.7129493952f, 0.9046078324f, 0.7815018892f, 0.0465084948f, 0.3294332922f, }, + { 0.1153969169f, 0.2188278437f, 0.2898322940f, 0.3131091893f, 0.2157217115f, }, + { 0.2949057519f, 0.8871413469f, 0.7510847449f, 0.4598563313f, 0.6131973267f, }, + { 0.0551494882f, 0.9805501699f, 0.7621988654f, 0.2043998092f, 0.2610918283f, }, + { 0.2401759624f, 0.5694934130f, 0.7611207366f, 0.6130263209f, 0.2001665235f, }, + { 0.1906743795f, 0.5295569897f, 0.7834599018f, 0.7504947186f, 0.0149052497f, }, + { 0.4556769729f, 0.8574418426f, 0.7936969995f, 0.4731632173f, 0.0743378848f, }, + { 0.9822815657f, 0.8694450855f, 0.7822141051f, 0.1557161659f, 0.5248658061f, }, + { 0.3995839357f, 0.4086642265f, 0.7906468511f, 0.2836396396f, 0.9961770773f, }, + { 0.1578908861f, 0.9831036925f, 0.7753174305f, 0.7032369971f, 0.1702057719f, }, + { 0.1432473660f, 0.5245524645f, 0.7873648405f, 0.9909790754f, 0.1941808164f, }, + { 0.0496347249f, 0.3230103552f, 0.2880098224f, 0.9254404306f, 0.7993409634f, }, + { 0.3677969873f, 0.4502792656f, 0.7550968528f, 0.0685292333f, 0.0322126560f, }, + { 0.3681726754f, 0.8964610696f, 0.7657590508f, 0.7328995466f, 0.1225480959f, }, + { 0.8237461448f, 0.1054824442f, 0.4235413671f, 0.0693489239f, 0.1772005558f, }, + { 0.1072291210f, 0.7561171651f, 0.3078683913f, 0.6704639196f, 0.7376510501f, }, + { 0.3759997189f, 0.6078967452f, 0.3140520155f, 0.9231520891f, 0.3376911283f, }, + { 0.5178962350f, 0.5762365460f, 0.2839297652f, 0.6083318591f, 0.6300873756f, }, + { 0.6741157174f, 0.1322117001f, 0.7947505713f, 0.9863089919f, 0.2355235219f, }, + { 0.8684127927f, 0.9994758964f, 0.2966772914f, 0.3675712347f, 0.6119997501f, }, + { 0.2690464854f, 0.8008992076f, 0.2926762700f, 0.2993549407f, 0.3847996891f, }, + { 0.0799442455f, 0.1301993132f, 0.4116391838f, 0.2668008506f, 0.3495041728f, }, + { 0.3540006578f, 0.8356643319f, 0.7733381987f, 0.0168998744f, 0.7282013893f, }, + { 0.4001987875f, 0.5594797134f, 0.7570883632f, 0.4522481859f, 0.7742182016f, }, + { 0.9329667687f, 0.8500671983f, 0.3011783361f, 0.3768123090f, 0.6565785408f, }, + { 0.3168726861f, 0.3728050888f, 0.6381832957f, 0.6217818856f, 0.2103196532f, }, + { 0.0577781945f, 0.3512331843f, 0.2998010516f, 0.5259774923f, 0.2699679136f, }, + { 0.3751579523f, 0.5097513199f, 0.3058879375f, 0.8346223235f, 0.9135133624f, }, + { 0.3425334692f, 0.9813879728f, 0.2871009409f, 0.2774653733f, 0.7453799844f, }, + { 0.3311858475f, 0.6496451497f, 0.2896683514f, 0.6599283814f, 0.4855679870f, }, + { 0.8686040640f, 0.6005551815f, 0.3034152985f, 0.3422373831f, 0.9028821588f, }, + { 0.9752067327f, 0.0568868406f, 0.7712969780f, 0.2428506464f, 0.4984464943f, }, + { 0.4726563990f, 0.3266831934f, 0.5197536349f, 0.1191676483f, 0.3807988167f, }, + { 0.6258342266f, 0.0560569949f, 0.7892054319f, 0.9146646857f, 0.5138988495f, }, + { 0.1590599418f, 0.6471906900f, 0.7767966390f, 0.2798080444f, 0.9099245071f, }, + { 0.1376058757f, 0.4660386443f, 0.7878762484f, 0.2609682083f, 0.4249886572f, }, + { 0.3760030568f, 0.6414309144f, 0.9376666546f, 0.6352919936f, 0.8449454308f, }, + { 0.9226124883f, 0.5036137104f, 0.5559523106f, 0.9124451876f, 0.3199864924f, }, + { 0.8545216322f, 0.7763401866f, 0.8065479398f, 0.9042024016f, 0.3665791154f, }, + { 0.4878125489f, 0.7499691248f, 0.2955771983f, 0.4796212614f, 0.4156348705f, }, + { 0.6559888124f, 0.6315625906f, 0.5192046165f, 0.8499541879f, 0.1051700935f, }, + { 0.9450867772f, 0.4511101842f, 0.2961124480f, 0.5963520408f, 0.3973363340f, }, + { 0.7462157011f, 0.2181172967f, 0.4330155253f, 0.3855430186f, 0.6997043490f, }, + { 0.2809849977f, 0.6741006374f, 0.2998252511f, 0.0636042878f, 0.4877717197f, }, + { 0.7193673849f, 0.4908526838f, 0.7790867686f, 0.4130373001f, 0.5244644284f, }, + { 0.0297955684f, 0.2241734713f, 0.7799593210f, 0.6138396263f, 0.5591472387f, }, + { 0.5931682587f, 0.1496370882f, 0.2843722999f, 0.5422986746f, 0.4124817550f, }, + { 0.1552470773f, 0.7898083925f, 0.3097908497f, 0.6143966317f, 0.8178458214f, }, + { 0.4004067481f, 0.7174136639f, 0.2705074549f, 0.3836323619f, 0.1506795883f, }, + { 0.3407859504f, 0.0169898923f, 0.7652972937f, 0.6428847313f, 0.4794446826f, }, + { 0.6281296611f, 0.8367557526f, 0.6374989748f, 0.9902649522f, 0.1328423768f, }, + { 0.1195605472f, 0.4906466901f, 0.3036482930f, 0.7694002986f, 0.9438231587f, }, + { 0.9209344387f, 0.2833660543f, 0.2958782911f, 0.3583146632f, 0.0124914162f, }, + { 0.0271478444f, 0.1830938458f, 0.2442035973f, 0.1633568406f, 0.3582551479f, }, + { 0.8930487633f, 0.5255863667f, 0.8074785471f, 0.6203823686f, 0.8806639314f, }, + { 0.2001634985f, 0.6789721847f, 0.2585816979f, 0.4858850539f, 0.9488404989f, }, + { 0.3169507384f, 0.2749398351f, 0.8015854955f, 0.2543512881f, 0.1484814733f, }, + { 0.1998170912f, 0.8312829137f, 0.7717654705f, 0.8164418936f, 0.7098048925f, }, + { 0.7556194067f, 0.0246483423f, 0.2681226730f, 0.1920210570f, 0.8246628046f, }, + { 0.8932147026f, 0.7755023241f, 0.1769630313f, 0.8796217442f, 0.8670396209f, }, + { 0.5000835657f, 0.0189713724f, 0.4199432731f, 0.3441577852f, 0.4229801595f, }, + { 0.4427429438f, 0.0248884745f, 0.2632511556f, 0.9104922414f, 0.4624014497f, }, + { 0.7883923054f, 0.2305282801f, 0.7785071135f, 0.3134030998f, 0.2291310728f, }, + { 0.8975443244f, 0.8703170419f, 0.7589570880f, 0.3501161635f, 0.7770552635f, }, + { 0.9095908403f, 0.1499762684f, 0.2830392122f, 0.1100165471f, 0.6619458199f, }, + { 0.8309295774f, 0.1749436557f, 0.2662031651f, 0.0523720607f, 0.4569765925f, }, + { 0.6357772350f, 0.1103235036f, 0.4204445481f, 0.3873434067f, 0.5234110951f, }, + { 0.1915344000f, 0.0344007909f, 0.2755983770f, 0.2998128831f, 0.4259296954f, }, + { 0.6235763431f, 0.4671169519f, 0.2951315641f, 0.1621862650f, 0.0188597385f, }, + { 0.8248400688f, 0.6117950678f, 0.2987766862f, 0.7614855766f, 0.5666823983f, }, + { 0.5245591998f, 0.2441071421f, 0.1280356497f, 0.6743686199f, 0.4623979926f, }, + { 0.5807595253f, 0.8561789393f, 0.2936735153f, 0.1840087622f, 0.1762438715f, }, + { 0.5563666224f, 0.1075055376f, 0.7844430208f, 0.9785437584f, 0.1414445788f, }, + { 0.3631467223f, 0.3552234471f, 0.5550847650f, 0.6623201966f, 0.0853134543f, }, + { 0.0339226574f, 0.3735741973f, 0.6598557234f, 0.1995836496f, 0.9044551253f, }, + { 0.8097031116f, 0.4850362241f, 0.5187754631f, 0.1562733650f, 0.3030130565f, }, + { 0.1345720589f, 0.1231942996f, 0.2517258823f, 0.1202225164f, 0.4748232067f, }, + { 0.4270858169f, 0.2148948759f, 0.3049951792f, 0.6375580430f, 0.2902436256f, }, + { 0.8424873948f, 0.2945866585f, 0.4247700870f, 0.2093853354f, 0.7201608419f, }, + { 0.8232980967f, 0.8431973457f, 0.2790549099f, 0.0113046262f, 0.4176355004f, }, + { 0.1039084941f, 0.0762564987f, 0.7687200904f, 0.3767068684f, 0.2080375701f, }, + { 0.5334433317f, 0.1993771642f, 0.7769105434f, 0.7445071936f, 0.5376464128f, }, + { 0.5751659274f, 0.1928819120f, 0.7927742004f, 0.0072807316f, 0.4824122190f, }, + { 0.2706641555f, 0.3944533765f, 0.7626729608f, 0.1882020086f, 0.0971265957f, }, + { 0.5991012454f, 0.2689918578f, 0.8020467758f, 0.9417535067f, 0.7980589867f, }, + { 0.6967203021f, 0.7917937636f, 0.4136724174f, 0.6591844559f, 0.4597135484f, }, + { 0.8457469344f, 0.3348135352f, 0.8026527166f, 0.5511280298f, 0.4867303371f, }, + { 0.6642525792f, 0.9755018950f, 0.4057386816f, 0.1340638846f, 0.3767580688f, }, + { 0.1703029424f, 0.3458243012f, 0.2280157655f, 0.2941951752f, 0.1464271843f, }, + { 0.2568213940f, 0.3496943712f, 0.7570667863f, 0.4027655125f, 0.1918564886f, }, + { 0.2208168209f, 0.4802232385f, 0.7869040370f, 0.6237490177f, 0.1836518049f, }, + { 0.7052675486f, 0.4582273960f, 0.2731816173f, 0.6869538426f, 0.8212174177f, }, + { 0.0819405094f, 0.2999734282f, 0.2923023105f, 0.5043700933f, 0.4098616540f, }, + { 0.3174582422f, 0.6751154661f, 0.7704699636f, 0.8110410571f, 0.8169452548f, }, + { 0.2432855666f, 0.5290631652f, 0.1721301377f, 0.3494029939f, 0.5463349819f, }, + { 0.4247282147f, 0.3365479112f, 0.7773292661f, 0.9833340645f, 0.2161256075f, }, + { 0.2500047982f, 0.9927572012f, 0.7508751154f, 0.8931486607f, 0.3399498165f, }, + { 0.8889269233f, 0.7275561690f, 0.8053399324f, 0.2233743221f, 0.6903525591f, }, + { 0.3913807869f, 0.8359543085f, 0.4148309231f, 0.6523172855f, 0.2315561920f, }, + { 0.6431411505f, 0.6001188159f, 0.1654544473f, 0.1936159134f, 0.3616076112f, }, + { 0.6380267143f, 0.5220745206f, 0.1704850197f, 0.2427753210f, 0.3764709532f, }, + { 0.6472204328f, 0.8142141700f, 0.3527438939f, 0.4917648435f, 0.2372246832f, }, + { 0.5952277780f, 0.5499820113f, 0.8068155050f, 0.4955188632f, 0.4707650244f, }, + { 0.2944735289f, 0.1771762520f, 0.3095451593f, 0.8617234826f, 0.3881261647f, }, + { 0.3247082829f, 0.3174749315f, 0.3960589468f, 0.8632043004f, 0.6118923426f, }, + { 0.5451740026f, 0.8264210224f, 0.7780685425f, 0.3865961730f, 0.3740692735f, }, + { 0.0710423440f, 0.7798178196f, 0.7979660630f, 0.5147284865f, 0.5785826445f, }, + { 0.3499533832f, 0.7061065435f, 0.2562947571f, 0.0197522454f, 0.5232437849f, }, + { 0.1162245199f, 0.8499556184f, 0.9027334452f, 0.2406211197f, 0.9040595889f, }, + { 0.4712712765f, 0.0545752756f, 0.2625442445f, 0.8004454374f, 0.9199656844f, }, + { 0.5907141566f, 0.3528652191f, 0.2805064619f, 0.8477231264f, 0.3509507775f, }, + { 0.7206040025f, 0.6591496468f, 0.8865054250f, 0.9694709778f, 0.4983907044f, }, + { 0.1598182172f, 0.2047161758f, 0.7987730503f, 0.3996876478f, 0.8058558702f, }, + { 0.0989774689f, 0.7282789946f, 0.8318630457f, 0.9660419822f, 0.0363835655f, }, + { 0.8671738505f, 0.1756909341f, 0.9045026302f, 0.5637825727f, 0.8663815260f, }, + { 0.2319063693f, 0.7536413074f, 0.8000506759f, 0.5863604546f, 0.7992135882f, }, + { 0.4219932258f, 0.4814367890f, 0.7629017234f, 0.0260796417f, 0.3073845506f, }, + { 0.5232524276f, 0.9749398828f, 0.4844135642f, 0.2303099632f, 0.3507592678f, }, + { 0.9227046371f, 0.0019649405f, 0.1564766616f, 0.7261878848f, 0.2516813278f, }, + { 0.7154665589f, 0.5749522448f, 0.8140199184f, 0.3457842469f, 0.6453396082f, }, + { 0.6868181825f, 0.3892825544f, 0.3984824121f, 0.7887382507f, 0.8365982771f, }, + { 0.3248549104f, 0.9360063076f, 0.2509986460f, 0.5284421444f, 0.7992022038f, }, + { 0.0579416603f, 0.5381578803f, 0.7750003934f, 0.1343874484f, 0.9581940770f, }, + { 0.6147286892f, 0.0008553811f, 0.7740504742f, 0.7823941112f, 0.9342224598f, }, + { 0.5669473410f, 0.6531718969f, 0.7747102976f, 0.7425286174f, 0.5242463946f, }, + { 0.2042782456f, 0.0084363222f, 0.7720063329f, 0.7291170359f, 0.0140062124f, }, + { 0.4290650189f, 0.5248267651f, 0.2691887319f, 0.7684779763f, 0.8913392425f, }, + { 0.2861766219f, 0.6251768470f, 0.7682936788f, 0.5762428045f, 0.4206987023f, }, + { 0.9714790583f, 0.9922801852f, 0.7669212222f, 0.5052084923f, 0.6450518370f, }, + { 0.4985497594f, 0.4682227671f, 0.6760318875f, 0.8983184099f, 0.1391719133f, }, + { 0.6179335713f, 0.2258358598f, 0.1724694967f, 0.0220160931f, 0.3808035553f, }, + { 0.9283209443f, 0.0941520035f, 0.2797054648f, 0.0121329706f, 0.0326453708f, }, + { 0.0866272449f, 0.9710868597f, 0.2622629702f, 0.5545566678f, 0.5643898845f, }, + { 0.5713929534f, 0.5999991894f, 0.4126140773f, 0.9695659876f, 0.6285355687f, }, + { 0.5692995787f, 0.4541948140f, 0.7901089787f, 0.9660837054f, 0.8277012706f, }, + { 0.0928914025f, 0.3484353125f, 0.6736137867f, 0.8765351772f, 0.3386749029f, }, + { 0.7252441049f, 0.1114370301f, 0.2990854383f, 0.4538967013f, 0.9787045121f, }, + { 0.3990883231f, 0.9882399440f, 0.2779621780f, 0.0663654953f, 0.7550785542f, }, + { 0.9265934825f, 0.5644822121f, 0.7671328783f, 0.8755191565f, 0.1012659818f, }, + { 0.5898082852f, 0.8015443087f, 0.7964060307f, 0.1627581716f, 0.2277553678f, }, + { 0.9264091253f, 0.9120311737f, 0.4145444632f, 0.6489874721f, 0.1752695739f, }, + { 0.0027178240f, 0.4640338421f, 0.7796453238f, 0.9751948118f, 0.5849672556f, }, + { 0.3068727255f, 0.4288714826f, 0.2617074847f, 0.7182069421f, 0.3882696331f, }, + { 0.0427591577f, 0.4549653530f, 0.5183761716f, 0.3918886781f, 0.6594117284f, }, + { 0.6001002192f, 0.8340002894f, 0.4951757193f, 0.2365927100f, 0.6956700087f, }, + { 0.1497204900f, 0.5904799104f, 0.2989979088f, 0.3457302153f, 0.1163193360f, }, + { 0.3254196644f, 0.3999947309f, 0.3009833395f, 0.7907041907f, 0.6257662773f, }, + { 0.2113198787f, 0.1751640886f, 0.7867451906f, 0.8027440906f, 0.7817027569f, }, + { 0.6641870737f, 0.4249112606f, 0.1674920321f, 0.1883893609f, 0.6185988188f, }, + { 0.0362182185f, 0.6194028854f, 0.3953706324f, 0.5091269612f, 0.2814692259f, }, + { 0.2867180109f, 0.2754775286f, 0.2186837494f, 0.8755689263f, 0.0850193575f, }, + { 0.0821465775f, 0.6301913857f, 0.2572468817f, 0.1999669373f, 0.1279871762f, }, + { 0.4453506172f, 0.9502550364f, 0.2893290818f, 0.1907250434f, 0.6880247593f, }, + { 0.3379973471f, 0.1998294890f, 0.2608736753f, 0.9429882169f, 0.7425290346f, }, + { 0.9008249044f, 0.6850529313f, 0.8091363907f, 0.6383458972f, 0.5397336483f, }, + { 0.4999698997f, 0.1050286591f, 0.2648521960f, 0.5500307083f, 0.1077635065f, }, + { 0.7545816302f, 0.1537678540f, 0.2850513756f, 0.9255035520f, 0.5411737561f, }, + { 0.1518809497f, 0.0433206260f, 0.8952417970f, 0.8873193860f, 0.4580318034f, }, + { 0.3276327550f, 0.1463776231f, 0.7795293331f, 0.2669896483f, 0.8222080469f, }, + { 0.2039921284f, 0.2620699406f, 0.8143118024f, 0.4861954451f, 0.8213962913f, }, + { 0.5840394497f, 0.4247839153f, 0.3092982173f, 0.3642277718f, 0.2982022166f, }, + { 0.7004087567f, 0.0212051533f, 0.6487102509f, 0.5274438262f, 0.9092481732f, }, + { 0.7303841710f, 0.7487973571f, 0.2889667749f, 0.7865768671f, 0.2437812686f, }, + { 0.7743490934f, 0.3881141245f, 0.7998576164f, 0.1551619917f, 0.9330435991f, }, + { 0.6870658994f, 0.5746767521f, 0.6458526254f, 0.7466739416f, 0.6684733629f, }, + { 0.5012472272f, 0.7902867198f, 0.7698841095f, 0.0425139926f, 0.6290299892f, }, + { 0.7240006328f, 0.2354215831f, 0.2400828749f, 0.6598005891f, 0.9678072333f, }, + { 0.4088793397f, 0.9475491047f, 0.9047468901f, 0.0505281314f, 0.9838845730f, }, + { 0.1737497002f, 0.4704473317f, 0.2794604301f, 0.3008873165f, 0.8608435988f, }, + { 0.3551756144f, 0.3274177611f, 0.2876883149f, 0.4380708635f, 0.4668641388f, }, + { 0.6630249619f, 0.4752038717f, 0.3399631381f, 0.0004695649f, 0.0158080906f, }, + { 0.1541123688f, 0.8944799900f, 0.9143199921f, 0.5618377328f, 0.0265781935f, }, + { 0.0014133439f, 0.1717019975f, 0.6744863391f, 0.6051113009f, 0.6700525284f, }, + { 0.8717252612f, 0.9211322069f, 0.7788960338f, 0.9970455766f, 0.3824445307f, }, + { 0.6535704732f, 0.7191313505f, 0.2670966089f, 0.2343741208f, 0.6560382843f, }, + { 0.8189513683f, 0.9779990911f, 0.2920952141f, 0.1606268585f, 0.7335300446f, }, + { 0.1817885339f, 0.4276250899f, 0.7730876207f, 0.7524567842f, 0.4017331004f, }, + { 0.8607296944f, 0.7277715206f, 0.4210158288f, 0.8780418038f, 0.3567401469f, }, + { 0.1249847785f, 0.1677636951f, 0.2262524515f, 0.9928002954f, 0.9429923296f, }, + { 0.0928178728f, 0.4386635423f, 0.8069884777f, 0.7290409207f, 0.8104345202f, }, + { 0.6501662135f, 0.7694789171f, 0.7665093541f, 0.1464402676f, 0.5142594576f, }, + { 0.0059239352f, 0.5772430897f, 0.2253716886f, 0.8281903267f, 0.8057222366f, }, + { 0.7727349401f, 0.4749777913f, 0.2912753820f, 0.3198481798f, 0.5055068731f, }, + { 0.4836567044f, 0.2031805664f, 0.3143343329f, 0.7941797376f, 0.0478825159f, }, + { 0.0725190639f, 0.6679832339f, 0.7568237185f, 0.8410646915f, 0.7609511614f, }, + { 0.9343419671f, 0.7267388701f, 0.8061711192f, 0.2502336502f, 0.5761574507f, }, + { 0.5408820510f, 0.7522531748f, 0.2887668312f, 0.2322072834f, 0.2661544383f, }, + { 0.6527605057f, 0.2828822732f, 0.3687557876f, 0.8335109949f, 0.2332811803f, }, + { 0.4580220282f, 0.7980357409f, 0.7631003261f, 0.0570261180f, 0.8262161613f, }, + { 0.6558441520f, 0.1842970848f, 0.2874549031f, 0.0934311897f, 0.9872899652f, }, + { 0.0171927176f, 0.0529784523f, 0.6494998932f, 0.6903494596f, 0.9372444153f, }, + { 0.8937577605f, 0.0486983582f, 0.9107431173f, 0.1919635534f, 0.2335986793f, }, + { 0.2497835904f, 0.9269321561f, 0.7939439416f, 0.8614564538f, 0.3511635363f, }, + { 0.9440903664f, 0.6518594623f, 0.3127450645f, 0.5599846840f, 0.9434761405f, }, + { 0.8918107152f, 0.3233214617f, 0.7946133614f, 0.4216216207f, 0.6283529401f, }, + { 0.0179141425f, 0.7844362259f, 0.3101776242f, 0.6566930413f, 0.5672486424f, }, + { 0.7889158726f, 0.6126962304f, 0.7859390974f, 0.0923882723f, 0.7710054517f, }, + { 0.0468924157f, 0.9273314476f, 0.8858300447f, 0.3495823741f, 0.0502963737f, }, + { 0.7265440822f, 0.8806681633f, 0.5553485155f, 0.4007360041f, 0.1497067511f, }, + { 0.1965579838f, 0.7914781570f, 0.7826305628f, 0.2658583522f, 0.5140508413f, }, + { 0.6845291853f, 0.6299976110f, 0.2801485360f, 0.5622635484f, 0.8259903789f, }, + { 0.5244660378f, 0.6150796413f, 0.7782981396f, 0.3102792501f, 0.8696761727f, }, + { 0.3956299722f, 0.2814948559f, 0.1310305297f, 0.8118636608f, 0.2594062388f, }, + { 0.8649273515f, 0.5036535263f, 0.5557423234f, 0.0601539686f, 0.2848358750f, }, + { 0.0737424418f, 0.0352903791f, 0.8056985736f, 0.0751454905f, 0.8200211525f, }, + { 0.4664432406f, 0.1455803216f, 0.7607629895f, 0.6063881516f, 0.4569575191f, }, + { 0.0977691114f, 0.5421596169f, 0.2784540951f, 0.5368484259f, 0.7131535411f, }, + { 0.9732908607f, 0.7721309066f, 0.3137148321f, 0.7179317474f, 0.2797978520f, }, + { 0.1720841527f, 0.2310317606f, 0.3149380684f, 0.7369439006f, 0.2979010940f, }, + { 0.3471178412f, 0.7441020608f, 0.6383051872f, 0.6432772279f, 0.4653419554f, }, + { 0.2948729694f, 0.5528818369f, 0.2871345282f, 0.0375724137f, 0.9314796329f, }, + { 0.3659904301f, 0.0274818614f, 0.2774145305f, 0.3779206276f, 0.7330094576f, }, + { 0.6690718532f, 0.8675441742f, 0.8203707337f, 0.3039523363f, 0.6855219007f, }, + { 0.3739557564f, 0.7847412229f, 0.7726964951f, 0.1901528984f, 0.8707709908f, }, + { 0.8261426687f, 0.8141835332f, 0.6765087247f, 0.7053523064f, 0.1085284501f, }, + { 0.0744494647f, 0.8915129304f, 0.7695001364f, 0.3059226274f, 0.7864413261f, }, + { 0.6495617032f, 0.2287500948f, 0.6643590927f, 0.6807377338f, 0.6854281425f, }, + { 0.1251755953f, 0.6021833420f, 0.1738262922f, 0.1027485281f, 0.3681707382f, }, + { 0.8752848506f, 0.3725059032f, 0.3002985120f, 0.2861676812f, 0.7838917971f, }, + { 0.9753560424f, 0.5377818942f, 0.2808679640f, 0.0948558152f, 0.8135243654f, }, + { 0.2024883628f, 0.0596460216f, 0.8992331624f, 0.4445746839f, 0.7883340120f, }, + { 0.7991656661f, 0.5622891784f, 0.7851824760f, 0.7671946883f, 0.5833725333f, }, + { 0.9053542614f, 0.3771561086f, 0.8870622516f, 0.7011025548f, 0.9261990786f, }, + { 0.1318989843f, 0.1970869601f, 0.6673611403f, 0.6814309359f, 0.1583046764f, }, + { 0.4001388550f, 0.6895772815f, 0.6834002137f, 0.9913667440f, 0.8109951615f, }, + { 0.3501563370f, 0.1740820706f, 0.6443064213f, 0.5699039698f, 0.2332659215f, }, + { 0.6794521809f, 0.7680356503f, 0.5901951790f, 0.9282895327f, 0.2421162277f, }, + { 0.7080360055f, 0.1728440672f, 0.4241924286f, 0.9003916979f, 0.9509291649f, }, + { 0.0724767447f, 0.2422906607f, 0.2617212534f, 0.0941282958f, 0.1398678869f, }, + { 0.2615314722f, 0.9000369906f, 0.2696160972f, 0.1269131750f, 0.8667003512f, }, + { 0.6100115180f, 0.1999786347f, 0.6599969268f, 0.0733514354f, 0.9472167492f, }, + { 0.7983407378f, 0.8789130449f, 0.1767313331f, 0.8358648419f, 0.4992512167f, }, + { 0.8810734153f, 0.1525073349f, 0.6489398479f, 0.7800874710f, 0.3111728430f, }, + { 0.6840517521f, 0.1576130092f, 0.6094434857f, 0.7155513763f, 0.6123347282f, }, + { 0.1409282237f, 0.4274391234f, 0.4048481286f, 0.5570979714f, 0.0876027569f, }, + { 0.8727819920f, 0.2688118815f, 0.7690741420f, 0.8936365843f, 0.3085227311f, }, + { 0.4744861424f, 0.8377560973f, 0.3973178864f, 0.9845040441f, 0.5582486391f, }, + { 0.4626818001f, 0.5196817517f, 0.7685114741f, 0.5016750693f, 0.6052305698f, }, + { 0.7585555315f, 0.9520831704f, 0.7883883119f, 0.9973391891f, 0.6165248752f, }, + { 0.4734658003f, 0.6585551500f, 0.7961063385f, 0.5074180365f, 0.6195576191f, }, + { 0.2928566635f, 0.8339151740f, 0.7823464274f, 0.7758680582f, 0.7892392874f, }, + { 0.9123880863f, 0.9501414299f, 0.2680390179f, 0.5070078969f, 0.7021949887f, }, + { 0.2686080337f, 0.5800030828f, 0.1445639879f, 0.3041823208f, 0.6666110158f, }, + { 0.5487381816f, 0.0103626810f, 0.2453777939f, 0.5664753318f, 0.6912289858f, }, + { 0.0022607930f, 0.3771244586f, 0.2759346068f, 0.5143600702f, 0.5078810453f, }, + { 0.3671621978f, 0.2517361045f, 0.7787028551f, 0.3381624818f, 0.9658800364f, }, + { 0.8251711726f, 0.6861642003f, 0.2994127870f, 0.6960675120f, 0.8954024315f, }, + { 0.2410800159f, 0.0543312579f, 0.2713386416f, 0.7497317195f, 0.1073124930f, }, + { 0.7433992624f, 0.0763910487f, 0.7654787302f, 0.9832741022f, 0.7660050392f, }, + { 0.7869641781f, 0.5255016685f, 0.3794865310f, 0.2267197818f, 0.3679463863f, }, + { 0.2114219069f, 0.3062874675f, 0.7886129022f, 0.8245838284f, 0.2977400422f, }, + { 0.3356454670f, 0.4515637755f, 0.1333121061f, 0.3818921745f, 0.2204141170f, }, + { 0.7715404630f, 0.0715401918f, 0.2907829285f, 0.7844450474f, 0.3635170162f, }, + { 0.3178709447f, 0.9713793993f, 0.9272905588f, 0.2381104082f, 0.1068030596f, }, + { 0.7252637744f, 0.0393355526f, 0.8350849152f, 0.3327754438f, 0.3939851224f, }, + { 0.5291517973f, 0.4294093847f, 0.2476225793f, 0.1966315061f, 0.1115974709f, }, + { 0.6157343984f, 0.6511664987f, 0.2789514065f, 0.4601100683f, 0.4930445254f, }, + { 0.4983032346f, 0.8884671926f, 0.3046303689f, 0.0650740638f, 0.4252627790f, }, + { 0.5891890526f, 0.3792130053f, 0.5577308536f, 0.6345244646f, 0.8666893840f, }, + { 0.5378469825f, 0.7984157205f, 0.8907515407f, 0.8150723577f, 0.8964385986f, }, + { 0.3197961450f, 0.0434126519f, 0.2583546340f, 0.0901802927f, 0.0315441154f, }, + { 0.8600371480f, 0.6499691010f, 0.4297827482f, 0.6067852974f, 0.1548785567f, }, + { 0.1768916547f, 0.1774273813f, 0.2866801918f, 0.8928667903f, 0.1905252934f, }, + { 0.4660939574f, 0.2989724576f, 0.5122604966f, 0.1267326325f, 0.7915951610f, }, + { 0.5922329426f, 0.8804706931f, 0.4289196432f, 0.4957201183f, 0.8686517477f, }, + { 0.4514048100f, 0.4022825658f, 0.8919409513f, 0.4644826949f, 0.7638366222f, }, + { 0.2141635716f, 0.9635137320f, 0.4108440578f, 0.5553762317f, 0.9142369628f, }, + { 0.4031233788f, 0.0664307624f, 0.7233988047f, 0.3373790681f, 0.4812686443f, }, + { 0.6600075960f, 0.6775253415f, 0.3990524411f, 0.1097663045f, 0.2192985564f, }, + { 0.8470165133f, 0.8552631140f, 0.7640679479f, 0.1831330806f, 0.9465493560f, }, + { 0.3323849440f, 0.8508573174f, 0.2944486439f, 0.6928911209f, 0.7978152633f, }, + { 0.7658269405f, 0.3536170125f, 0.6615781784f, 0.9547168612f, 0.4701850712f, }, + { 0.5496520400f, 0.0584536009f, 0.3157524765f, 0.6936239004f, 0.2673313320f, }, + { 0.5845058560f, 0.0244565476f, 0.2943458855f, 0.1873316169f, 0.3394116461f, }, + { 0.1235968247f, 0.2895309627f, 0.4208563864f, 0.9907463193f, 0.4523299932f, }, + { 0.8486821055f, 0.0960422605f, 0.6420364976f, 0.3939413726f, 0.8774323463f, }, + { 0.6714023352f, 0.3098714352f, 0.2211168855f, 0.1400515735f, 0.3537302017f, }, + { 0.2504135072f, 0.1442802697f, 0.6670401692f, 0.0758291036f, 0.5461344719f, }, + { 0.3282198906f, 0.2514461279f, 0.9266825318f, 0.9895117283f, 0.8716566563f, }, + { 0.7472376823f, 0.9956616163f, 0.3915591240f, 0.3979108632f, 0.5343204737f, }, + { 0.5599702597f, 0.5746458769f, 0.6002621055f, 0.3463972807f, 0.8279570937f, }, + { 0.2360358536f, 0.8784773946f, 0.5179415941f, 0.7606269717f, 0.5087393522f, }, + { 0.3202143312f, 0.7918854952f, 0.6523981094f, 0.9877961874f, 0.6059661508f, }, + { 0.9434994459f, 0.3252754211f, 0.7943350077f, 0.4317415059f, 0.8919587731f, }, + { 0.9502399564f, 0.7011834383f, 0.3029349148f, 0.8641203642f, 0.3685676455f, }, + { 0.2850028276f, 0.2284352183f, 0.3039897978f, 0.8638410568f, 0.3296080232f, }, + { 0.2160910070f, 0.1000289619f, 0.8285583258f, 0.6495391130f, 0.0505601168f, }, + { 0.2328470200f, 0.0129147898f, 0.4100807309f, 0.2322385162f, 0.8453789353f, }, + { 0.5249089003f, 0.5421145558f, 0.2933630943f, 0.4185113013f, 0.8834992647f, }, + { 0.7073133588f, 0.9953604341f, 0.2309181988f, 0.9861024022f, 0.7863622308f, }, + { 0.5735582113f, 0.2762266099f, 0.6771513224f, 0.1898045987f, 0.0519864261f, }, + { 0.3260851800f, 0.5279992223f, 0.3073732853f, 0.8896305561f, 0.9859982133f, }, + { 0.8819665313f, 0.8249764442f, 0.5579964519f, 0.5823746920f, 0.1648006439f, }, + { 0.0936817676f, 0.4903237224f, 0.9035113454f, 0.1783384979f, 0.4548709989f, }, + { 0.5290838480f, 0.3491431475f, 0.9245797992f, 0.5866407752f, 0.8879506588f, }, + { 0.7381102443f, 0.6270953417f, 0.3013087511f, 0.8165183663f, 0.9136554003f, }, + { 0.4437074661f, 0.9058420062f, 0.3077934682f, 0.1481266022f, 0.5974704027f, }, + { 0.4117953777f, 0.5051417351f, 0.6378746629f, 0.3662781417f, 0.2752190530f, }, + { 0.4622029066f, 0.4735332727f, 0.4884818196f, 0.5640743375f, 0.9933480024f, }, + { 0.7740606666f, 0.7776194215f, 0.7635287046f, 0.3643266261f, 0.2588997483f, }, + { 0.5159329176f, 0.9296320677f, 0.2787033319f, 0.3738671839f, 0.0344980955f, }, + { 0.4350320101f, 0.6755834818f, 0.4286924899f, 0.7871493101f, 0.3364413679f, }, + { 0.5013414025f, 0.3748833239f, 0.7356345654f, 0.8916242123f, 0.0117606986f, }, + { 0.1521019638f, 0.0712500066f, 0.4059727788f, 0.0710976794f, 0.8347967863f, }, + { 0.6400067806f, 0.3765201569f, 0.6073310971f, 0.4271332026f, 0.3422194719f, }, + { 0.1249704808f, 0.8915776610f, 0.6594917774f, 0.3747678697f, 0.9558723569f, }, + { 0.7219854593f, 0.7106966376f, 0.9313089848f, 0.4832553566f, 0.4667213559f, }, + { 0.5824468136f, 0.7162278295f, 0.5177717209f, 0.0977057889f, 0.7590029836f, }, + { 0.1714690924f, 0.9571123123f, 0.4020383954f, 0.7261196971f, 0.7496134043f, }, + { 0.7017532587f, 0.2225391120f, 0.9218833447f, 0.8255798817f, 0.2500174940f, }, + { 0.9624128938f, 0.2770902216f, 0.3105332255f, 0.4734436870f, 0.6705613136f, }, + { 0.1048703417f, 0.0505746193f, 0.3031838834f, 0.0764986053f, 0.6700251698f, }, + { 0.1248878166f, 0.9387741685f, 0.4017695785f, 0.1040696278f, 0.7459066510f, }, + { 0.6877798438f, 0.6785060167f, 0.6491712332f, 0.4595741928f, 0.0832384899f, }, + { 0.7447783947f, 0.8123399615f, 0.2865788639f, 0.1072481871f, 0.5880768299f, }, + { 0.2012768984f, 0.6164584756f, 0.6531744599f, 0.3689600825f, 0.2244419754f, }, + { 0.8485900164f, 0.8012405634f, 0.4264014959f, 0.0631803498f, 0.1144074276f, }, + { 0.9198651910f, 0.2477776110f, 0.5172892809f, 0.3793236613f, 0.1089572832f, }, + { 0.9954030514f, 0.6386104226f, 0.7809863687f, 0.2934077680f, 0.3600515127f, }, + { 0.8255298734f, 0.3752827644f, 0.8009788990f, 0.7946528792f, 0.5165820718f, }, + { 0.1997372955f, 0.7077269554f, 0.3950786293f, 0.1632033885f, 0.5593788624f, }, + { 0.4266054332f, 0.8571543097f, 0.2293199748f, 0.2288575917f, 0.3166252375f, }, + { 0.0253840014f, 0.7290859818f, 0.3571533263f, 0.6263707876f, 0.5841494799f, }, + { 0.3236172795f, 0.0720305741f, 0.8912050724f, 0.7814262509f, 0.3493556380f, }, + { 0.1000752002f, 0.5756855607f, 0.6530312896f, 0.3211900294f, 0.7120269537f, }, + { 0.4889923334f, 0.7246489525f, 0.7894634604f, 0.8173778057f, 0.7406228185f, }, + { 0.0533824638f, 0.7616798282f, 0.2118356079f, 0.1358659267f, 0.6915708780f, }, + { 0.3010347188f, 0.9254361987f, 0.6774628758f, 0.8114458919f, 0.0461394414f, }, + { 0.4491851926f, 0.2361025512f, 0.6578386426f, 0.2781579494f, 0.4753561616f, }, + { 0.7263519764f, 0.5516431332f, 0.3764113784f, 0.7071894407f, 0.7581717372f, }, + { 0.7504419684f, 0.3041412830f, 0.4077625573f, 0.9041445851f, 0.9798993468f, }, + { 0.3132814467f, 0.5969519019f, 0.8985749483f, 0.5371615887f, 0.8166791201f, }, + { 0.9128910303f, 0.6386086345f, 0.9291878939f, 0.9010465741f, 0.0515856557f, }, + { 0.8312644362f, 0.9322059155f, 0.3082694411f, 0.2631652951f, 0.6171346903f, }, + { 0.3248440325f, 0.6994132400f, 0.8882280588f, 0.3161205649f, 0.2990267575f, }, + { 0.0209084526f, 0.2487299591f, 0.2852843404f, 0.0490375198f, 0.0792967454f, }, + { 0.1343887150f, 0.6421871185f, 0.3512936831f, 0.9005096555f, 0.7998893261f, }, + { 0.1272028685f, 0.0864170641f, 0.8854416609f, 0.4485999346f, 0.5290466547f, }, + { 0.4596441090f, 0.9713689089f, 0.8959669471f, 0.6499913335f, 0.1614189446f, }, + { 0.6365318894f, 0.7912567258f, 0.5595306158f, 0.4526388943f, 0.8158668280f, }, + { 0.9839783311f, 0.7433025241f, 0.9149154425f, 0.2130972743f, 0.7002832294f, }, + { 0.9018979073f, 0.5495696068f, 0.3047397137f, 0.9602315426f, 0.7303099036f, }, + { 0.6514343619f, 0.0494217165f, 0.9204797745f, 0.5995004773f, 0.7999229431f, }, + { 0.2446528822f, 0.8066373467f, 0.7633868456f, 0.4997910857f, 0.8171027303f, }, + { 0.2998119891f, 0.7505546212f, 0.2840596735f, 0.6801810265f, 0.8937376142f, }, + { 0.9920930266f, 0.7891113758f, 0.8012133241f, 0.3600580096f, 0.9439568520f, }, + { 0.5752746463f, 0.1673168838f, 0.1591576487f, 0.2836316526f, 0.6767866015f, }, + { 0.9760351777f, 0.0820318013f, 0.2834108174f, 0.7059906125f, 0.3513303399f, }, + { 0.6475701332f, 0.1324364245f, 0.2339693159f, 0.8474177718f, 0.7218640447f, }, + { 0.4495049715f, 0.7103233933f, 0.8957070708f, 0.4991365373f, 0.5135029554f, }, + { 0.9469348788f, 0.9865314960f, 0.6421780586f, 0.0111757731f, 0.9658465385f, }, + { 0.0449516922f, 0.0997762382f, 0.2393062860f, 0.6519269347f, 0.4265230596f, }, + { 0.1593539566f, 0.1272390336f, 0.7581902146f, 0.8494831920f, 0.0624137856f, }, + { 0.5568189621f, 0.8487882018f, 0.4189198315f, 0.4743472636f, 0.9843426943f, }, + { 0.8362607360f, 0.2222026736f, 0.2823732793f, 0.7828052044f, 0.1755781770f, }, + { 0.4174544513f, 0.4262937307f, 0.5167069435f, 0.1060983315f, 0.6379290819f, }, + { 0.9572992325f, 0.1776689142f, 0.2620716393f, 0.8248003125f, 0.1567030102f, }, + { 0.6008511782f, 0.2440356314f, 0.4270541966f, 0.1630697548f, 0.0636614934f, }, + { 0.3432453871f, 0.9009386301f, 0.3871859610f, 0.9745897055f, 0.3582904339f, }, + { 0.0773086995f, 0.5866941214f, 0.2677324414f, 0.0387942530f, 0.3836332858f, }, + { 0.8752986193f, 0.5724390745f, 0.6805091500f, 0.7012855411f, 0.3378408253f, }, + { 0.8861531019f, 0.2298797965f, 0.2611677945f, 0.1331158578f, 0.5366979241f, }, + { 0.7606591582f, 0.5197066665f, 0.8155182004f, 0.8734754324f, 0.1757362485f, }, + { 0.8255903125f, 0.5745301843f, 0.7841017842f, 0.4302405417f, 0.0268313363f, }, + { 0.9966588020f, 0.6995847821f, 0.9084725380f, 0.5139925480f, 0.7311407924f, }, + { 0.9382262826f, 0.6791692972f, 0.6785366535f, 0.1941221654f, 0.4609523714f, }, + { 0.3504243493f, 0.4049642384f, 0.6625856757f, 0.5049493313f, 0.2176340818f, }, + { 0.2272735685f, 0.4055925608f, 0.1439441442f, 0.7996239066f, 0.2481847256f, }, + { 0.7855584621f, 0.0217855163f, 0.7607150078f, 0.5862695575f, 0.0883487016f, }, + { 0.1676670462f, 0.5200256109f, 0.3054049313f, 0.2125623375f, 0.7533867359f, }, + { 0.2767126858f, 0.1956664324f, 0.4313074648f, 0.7840225697f, 0.0665216669f, }, + { 0.9838973880f, 0.8195846081f, 0.5587249994f, 0.9586064816f, 0.2105056942f, }, + { 0.4114686549f, 0.1693456471f, 0.7834180593f, 0.0783827752f, 0.5129904747f, }, + { 0.5240935087f, 0.1287233979f, 0.7831305861f, 0.2181428373f, 0.9620638490f, }, + { 0.9016481638f, 0.4185965955f, 0.3055139482f, 0.7837233543f, 0.5465862155f, }, + { 0.7979394197f, 0.2068720907f, 0.3083855808f, 0.7539358139f, 0.0757107139f, }, + { 0.9212577343f, 0.7691110373f, 0.3675687313f, 0.6103746295f, 0.1860474497f, }, + { 0.7511492968f, 0.1935962141f, 0.6090257168f, 0.0654017106f, 0.8881178498f, }, + { 0.4985419214f, 0.8312378526f, 0.6632387042f, 0.2347040772f, 0.7991008162f, }, + { 0.7281176448f, 0.2602107823f, 0.6662689447f, 0.1679297984f, 0.6103778481f, }, + { 0.1163734198f, 0.3966202736f, 0.3159880936f, 0.3280013800f, 0.2707208991f, }, + { 0.9195216894f, 0.4787626565f, 0.4261068702f, 0.1933896691f, 0.5727409720f, }, + { 0.5263438821f, 0.1722705066f, 0.4131948650f, 0.3029941022f, 0.2509804070f, }, + { 0.5455015302f, 0.8958268762f, 0.2819412351f, 0.1629379690f, 0.6425027847f, }, + { 0.0120480489f, 0.3251642585f, 0.1538381279f, 0.3856068552f, 0.5091619492f, }, + { 0.2493483424f, 0.2791167498f, 0.4195877314f, 0.1697363257f, 0.4883224368f, }, + { 0.1246340126f, 0.8237965703f, 0.3087759316f, 0.2666756511f, 0.3167749643f, }, + { 0.4507784247f, 0.3383319676f, 0.7603561878f, 0.9380596876f, 0.8256477118f, }, + { 0.7961603999f, 0.7992694378f, 0.4155633748f, 0.7002693415f, 0.5806440711f, }, + { 0.4182555079f, 0.0275410898f, 0.3987272382f, 0.5506650805f, 0.8613790870f, }, + { 0.7958818078f, 0.4013074934f, 0.3107832372f, 0.4954425097f, 0.1367432624f, }, + { 0.1233286485f, 0.4443088472f, 0.2378848493f, 0.5388411880f, 0.5641937852f, }, + { 0.8892932534f, 0.0776660889f, 0.2765585482f, 0.5762675405f, 0.8628262281f, }, + { 0.7891501784f, 0.9504091144f, 0.1619831175f, 0.7198655605f, 0.1133061275f, }, + { 0.1723057777f, 0.3025299907f, 0.7976503968f, 0.0072937668f, 0.8960158825f, }, + { 0.0315585323f, 0.8132331967f, 0.6752576828f, 0.1808201671f, 0.0632313415f, }, + { 0.8969068527f, 0.0126592619f, 0.7279679179f, 0.9549113512f, 0.5302991867f, }, + { 0.9083233476f, 0.1969243586f, 0.2628656924f, 0.1486128867f, 0.3155753016f, }, + { 0.4649995863f, 0.6356135607f, 0.5602090955f, 0.1236990616f, 0.1019494906f, }, + { 0.5449941754f, 0.9861999154f, 0.8628482819f, 0.1814590693f, 0.7753313184f, }, + { 0.8170027137f, 0.0565828048f, 0.8246735930f, 0.8248749375f, 0.4647269845f, }, + { 0.0503409542f, 0.1745345891f, 0.7440862656f, 0.5324017406f, 0.9395241141f, }, + { 0.9426752925f, 0.7974939346f, 0.8027789593f, 0.9593043923f, 0.5680775642f, }, + { 0.2788208425f, 0.8538242579f, 0.3109075129f, 0.1325492114f, 0.7572354078f, }, + { 0.3708338439f, 0.2757935226f, 0.3168342710f, 0.5410025716f, 0.5047875643f, }, + { 0.4934052527f, 0.1667081267f, 0.3859228194f, 0.6246893406f, 0.8557038903f, }, + { 0.8220987320f, 0.7622995973f, 0.7972608209f, 0.1990088075f, 0.5000911355f, }, + { 0.1486209333f, 0.5659176111f, 0.9267964363f, 0.9206584692f, 0.1615228206f, }, + { 0.3245853186f, 0.1215075403f, 0.9093947411f, 0.5747628212f, 0.5843873620f, }, + { 0.8471792340f, 0.5482380986f, 0.9225259423f, 0.6037865281f, 0.5505496860f, }, + { 0.2792744637f, 0.9645184278f, 0.5603542328f, 0.4866510332f, 0.4041455984f, }, + { 0.4026151597f, 0.3846546412f, 0.3112013340f, 0.1198368594f, 0.5647251606f, }, + { 0.8492454886f, 0.6815847158f, 0.6630335450f, 0.9351033568f, 0.1822353601f, }, + { 0.0542719588f, 0.2261167914f, 0.1366736442f, 0.3123262823f, 0.4076761305f, }, + { 0.1226021498f, 0.0342418142f, 0.7951807976f, 0.6466630101f, 0.2780374885f, }, + { 0.2562767267f, 0.4415720701f, 0.7895520926f, 0.3055075705f, 0.9376997352f, }, + { 0.5907462239f, 0.0839731321f, 0.2812598646f, 0.4252110124f, 0.3137876689f, }, + { 0.5340557098f, 0.7213253379f, 0.7600395679f, 0.2145395130f, 0.2726213932f, }, + { 0.4629644156f, 0.7556714416f, 0.1657276750f, 0.1947537810f, 0.1462160945f, }, + { 0.4306474030f, 0.1258661151f, 0.1921306700f, 0.2863297760f, 0.2456044555f, }, + { 0.4276483953f, 0.3762872815f, 0.1896154583f, 0.7289283872f, 0.0281404834f, }, + { 0.0572299622f, 0.6962128282f, 0.8861011863f, 0.1007233784f, 0.0842091218f, }, + { 0.3553883433f, 0.6536983848f, 0.7516837120f, 0.1639147550f, 0.5001323819f, }, + { 0.9223991036f, 0.6045851707f, 0.3113570809f, 0.4550888240f, 0.8555629849f, }, + { 0.8712018728f, 0.9753783345f, 0.4203636050f, 0.6919427514f, 0.7681412697f, }, + { 0.9369074106f, 0.7508563399f, 0.1912885755f, 0.0488978103f, 0.2743213475f, }, + { 0.8294526935f, 0.6378447413f, 0.9181020856f, 0.0207253229f, 0.2460011095f, }, + { 0.9463785887f, 0.1102090627f, 0.6609685421f, 0.6241750717f, 0.3926430941f, }, + { 0.2022247612f, 0.1335944831f, 0.5613848567f, 0.9954510331f, 0.2715858817f, }, + { 0.6894689202f, 0.7462707758f, 0.4290166795f, 0.7576712370f, 0.8266029954f, }, + { 0.7332335711f, 0.1426250041f, 0.9101426601f, 0.6721584797f, 0.2937390506f, }, + { 0.7919439077f, 0.3180099428f, 0.2347182333f, 0.3101541102f, 0.1496052593f, }, + { 0.6221362948f, 0.3111922741f, 0.2805654109f, 0.1779901832f, 0.6279724240f, }, + { 0.6781911850f, 0.2603260577f, 0.6612037420f, 0.6178060770f, 0.5715984106f, }, + { 0.1071078628f, 0.9229523540f, 0.2220921516f, 0.1412636340f, 0.3300559819f, }, + { 0.0548924245f, 0.4914132357f, 0.3363906443f, 0.5005406141f, 0.9501827955f, }, + { 0.1177470461f, 0.9617888927f, 0.7922086716f, 0.7557209134f, 0.0914994776f, }, + { 0.0798678845f, 0.1541324258f, 0.5801106095f, 0.2038975805f, 0.6908184886f, }, + { 0.4942097068f, 0.5793737173f, 0.1503309906f, 0.8724965453f, 0.9717769623f, }, + { 0.7213614583f, 0.9545400739f, 0.9041411877f, 0.6803680062f, 0.7212558985f, }, + { 0.5946334004f, 0.9160152078f, 0.9386318922f, 0.9252097607f, 0.9924756289f, }, + { 0.8972641230f, 0.8065363765f, 0.4323031604f, 0.6466017962f, 0.5974913239f, }, + { 0.2889424562f, 0.4705303907f, 0.4141258597f, 0.8581247330f, 0.6880973577f, }, + { 0.6264872551f, 0.3961832225f, 0.9171339273f, 0.8472799063f, 0.3797605038f, }, + { 0.1174795404f, 0.0094451653f, 0.2767684460f, 0.3742263317f, 0.5159526467f, }, + { 0.1536156237f, 0.2517654598f, 0.9240382314f, 0.4080337584f, 0.7883666754f, }, + { 0.0191498268f, 0.5097766519f, 0.7922783494f, 0.8297792673f, 0.0704369396f, }, + { 0.5159924626f, 0.9056462049f, 0.7600080967f, 0.0250729267f, 0.0746496320f, }, + { 0.8448827863f, 0.5982452035f, 0.1587237418f, 0.9601131082f, 0.2660181820f, }, + { 0.9463102818f, 0.9610263705f, 0.3926327229f, 0.8793945312f, 0.3192653358f, }, + { 0.7450480461f, 0.4337556958f, 0.9021731615f, 0.0920987800f, 0.2523356378f, }, + { 0.0258540474f, 0.5639489889f, 0.3752073944f, 0.6409106851f, 0.2234590799f, }, + { 0.9407078624f, 0.5197525620f, 0.9200838804f, 0.7753949761f, 0.0485823080f, }, + { 0.7261092663f, 0.3716974854f, 0.1573868096f, 0.7386546135f, 0.7995461226f, }, + { 0.9846478701f, 0.2161029279f, 0.7940491438f, 0.5405111909f, 0.5354738832f, }, + { 0.0175896753f, 0.1258732080f, 0.2390264273f, 0.4795934558f, 0.0188046489f, }, + { 0.6767147779f, 0.7249081135f, 0.1647282541f, 0.7956055403f, 0.1440360397f, }, + { 0.2799735367f, 0.0126588326f, 0.9017798305f, 0.1535160840f, 0.6107380986f, }, + { 0.8476133347f, 0.4680338502f, 0.1649422646f, 0.4023977220f, 0.7237221599f, }, + { 0.4168302119f, 0.4580890238f, 0.8868865967f, 0.5238973498f, 0.0652269050f, }, + { 0.0153818708f, 0.9041046500f, 0.7092889547f, 0.0111663546f, 0.4621684551f, }, + { 0.0902491584f, 0.6523821354f, 0.1322941184f, 0.9199751616f, 0.4080085754f, }, + { 0.4400327206f, 0.2632351518f, 0.2606683373f, 0.8077775240f, 0.5973885655f, }, + { 0.6986188293f, 0.6506662965f, 0.1713581234f, 0.1490210444f, 0.7423495054f, }, + { 0.5049230456f, 0.0724501386f, 0.1832771748f, 0.6878976226f, 0.5974779129f, }, + { 0.3058165908f, 0.1561415344f, 0.9164251089f, 0.5644869208f, 0.6269791126f, }, + { 0.5522856712f, 0.2483970970f, 0.4036790729f, 0.0354237705f, 0.2951531112f, }, + { 0.8220069408f, 0.2619857490f, 0.2251121104f, 0.5344994068f, 0.7805863023f, }, + { 0.3655418158f, 0.9763858914f, 0.9089639783f, 0.7168897390f, 0.8183358908f, }, + { 0.9113172293f, 0.7199918032f, 0.1787553579f, 0.6108998060f, 0.8505340219f, }, + { 0.0235511158f, 0.6668973565f, 0.6518573165f, 0.2543254197f, 0.9970578551f, }, + { 0.5384492278f, 0.4958584011f, 0.9289419651f, 0.3781471848f, 0.3958327174f, }, + { 0.7881753445f, 0.7029209733f, 0.1454364210f, 0.5860641599f, 0.9053874612f, }, + { 0.2266070247f, 0.3658647835f, 0.2602710128f, 0.9698561430f, 0.7805164456f, }, + { 0.9979770184f, 0.2569667101f, 0.9147117138f, 0.1744126827f, 0.4092676342f, }, + { 0.7785791755f, 0.7458903790f, 0.4073179066f, 0.9460712075f, 0.8895652294f, }, + { 0.5188017488f, 0.6643666625f, 0.7596962452f, 0.4671040475f, 0.4623226821f, }, + { 0.2402814925f, 0.1071826592f, 0.3894088566f, 0.9619060755f, 0.8857082725f, }, + { 0.6125600338f, 0.1127229929f, 0.7593019009f, 0.2643416226f, 0.9604693651f, }, + { 0.3696739376f, 0.4868840277f, 0.8987175822f, 0.6166923046f, 0.6629825830f, }, + { 0.2814643383f, 0.4152070880f, 0.3899195790f, 0.0908245593f, 0.6337742209f, }, + { 0.6660229564f, 0.0168991759f, 0.6627727747f, 0.9359357953f, 0.6843416691f, }, + { 0.5728343129f, 0.0547134019f, 0.6856599450f, 0.5507382751f, 0.9939987659f, }, + { 0.2345321774f, 0.1719274223f, 0.9141665697f, 0.3132954836f, 0.0179193784f, }, + { 0.9960456491f, 0.4326222539f, 0.5165576339f, 0.8867087960f, 0.2333941758f, }, + { 0.9952901006f, 0.0446933284f, 0.1494547427f, 0.6022816896f, 0.5697607994f, }, + { 0.3853867650f, 0.3632143736f, 0.8947452903f, 0.9174077511f, 0.9135496616f, }, + { 0.2308936268f, 0.4312505126f, 0.4076980650f, 0.5322026014f, 0.5938063264f, }, + { 0.6172964573f, 0.4926365316f, 0.6648594141f, 0.6481961608f, 0.6685955524f, }, + { 0.5235430598f, 0.2206870019f, 0.6387106776f, 0.1486610174f, 0.9072556496f, }, + { 0.0401729867f, 0.0251173992f, 0.1631743759f, 0.0747975558f, 0.3981306553f, }, + { 0.1973253936f, 0.8821077347f, 0.4138412476f, 0.5068641901f, 0.3525366187f, }, + { 0.5587912202f, 0.7680332661f, 0.6505341530f, 0.8928561807f, 0.5482527018f, }, + { 0.8525030613f, 0.0207585543f, 0.1790263206f, 0.6549869180f, 0.3725682199f, }, + { 0.4448303878f, 0.2896177173f, 0.8816843629f, 0.0501009487f, 0.2392381728f, }, + { 0.5724250078f, 0.5547547340f, 0.2343842834f, 0.6771595478f, 0.7919211388f, }, + { 0.2475765347f, 0.7252397537f, 0.3116749525f, 0.2228567451f, 0.4254527688f, }, + { 0.4732843339f, 0.7073062062f, 0.1659952700f, 0.8754320741f, 0.0422150232f, }, + { 0.5892957449f, 0.9554278851f, 0.7951545119f, 0.9398952127f, 0.0016460768f, }, + { 0.7696458101f, 0.2773800194f, 0.8399140239f, 0.7641743422f, 0.6685501337f, }, + { 0.1700147092f, 0.0859233364f, 0.1606788784f, 0.3248689175f, 0.1749015599f, }, + { 0.1241669506f, 0.2402480394f, 0.9337751269f, 0.7104728222f, 0.3777848184f, }, + { 0.3443015516f, 0.5725353360f, 0.6791664958f, 0.7653573751f, 0.2869972587f, }, + { 0.2914162278f, 0.5757843852f, 0.6274257302f, 0.3609881699f, 0.0656926185f, }, + { 0.1774376929f, 0.8991229534f, 0.1645248085f, 0.9711522460f, 0.7378920913f, }, + { 0.7183789015f, 0.7837990522f, 0.9019348621f, 0.3406390846f, 0.3585455716f, }, + { 0.1978515834f, 0.4827848375f, 0.6580856442f, 0.9271910191f, 0.0634329617f, }, + { 0.1452655494f, 0.3483816087f, 0.4230147898f, 0.9212183356f, 0.3086003661f, }, + { 0.7094407082f, 0.3381393552f, 0.7592514157f, 0.0466459319f, 0.9443041086f, }, + { 0.3657453954f, 0.0994238853f, 0.7956072092f, 0.4494190216f, 0.6249750257f, }, + { 0.7883846760f, 0.9120051861f, 0.3607588708f, 0.3643571138f, 0.7760267854f, }, + { 0.8128287792f, 0.6568604112f, 0.1636924148f, 0.3170692921f, 0.4483211637f, }, + { 0.1938449144f, 0.5941886306f, 0.8367087245f, 0.8368217945f, 0.0035205879f, }, + { 0.5739416480f, 0.4770686924f, 0.6647317410f, 0.0334105305f, 0.2560984492f, }, + { 0.8930671215f, 0.6633207202f, 0.2470958382f, 0.2723561823f, 0.1203128025f, }, + { 0.8624477386f, 0.2482250333f, 0.6392576694f, 0.6223504543f, 0.8426845074f, }, + { 0.5030641556f, 0.7673287392f, 0.6497668028f, 0.8381631970f, 0.2775277495f, }, + { 0.3833058774f, 0.8791123033f, 0.2771086097f, 0.3941847980f, 0.4843804538f, }, + { 0.2845208645f, 0.1185088307f, 0.4250343442f, 0.0023946362f, 0.2106015831f, }, + { 0.6604475379f, 0.2069336474f, 0.4172060788f, 0.3160545230f, 0.7236531973f, }, + { 0.0827618986f, 0.3691194057f, 0.8608131409f, 0.9748896360f, 0.7997055650f, }, + { 0.2435884625f, 0.4771180451f, 0.1623293608f, 0.3136681616f, 0.4357536137f, }, + { 0.3707086146f, 0.0670966059f, 0.4082645476f, 0.5677208304f, 0.1632437259f, }, + { 0.0399077833f, 0.4316281974f, 0.2769917846f, 0.8198401332f, 0.0051376601f, }, + { 0.4502624869f, 0.5391125679f, 0.8967124820f, 0.5494186282f, 0.2151868194f, }, + { 0.5544868708f, 0.3837798238f, 0.9139256477f, 0.9917652607f, 0.6647973657f, }, + { 0.9810667634f, 0.1827602386f, 0.4053958654f, 0.4926604629f, 0.0187435448f, }, + { 0.7587206960f, 0.5928065181f, 0.2180640846f, 0.3847024143f, 0.3599581420f, }, + { 0.1978143454f, 0.4026862085f, 0.2745231688f, 0.1516407728f, 0.6969855428f, }, + { 0.7653558254f, 0.2306651920f, 0.1905230731f, 0.9833192825f, 0.3286725581f, }, + { 0.6066728830f, 0.4284333587f, 0.6850233078f, 0.8764329553f, 0.3780399263f, }, + { 0.1258152425f, 0.1446966678f, 0.3769092262f, 0.7866101861f, 0.6098955274f, }, + { 0.3473505676f, 0.2391392738f, 0.4268153310f, 0.9702208042f, 0.3427807689f, }, + { 0.8359431624f, 0.9565569758f, 0.7956938744f, 0.9251024723f, 0.4239948094f, }, + { 0.9743397236f, 0.2967027128f, 0.1855548471f, 0.3840411603f, 0.9848009348f, }, + { 0.6076579690f, 0.7870281935f, 0.2100580633f, 0.7229981422f, 0.9958847165f, }, + { 0.7850106955f, 0.4386725724f, 0.9116359353f, 0.1110212803f, 0.2471448928f, }, + { 0.3857101202f, 0.1838507354f, 0.2601014376f, 0.1416177005f, 0.8650175929f, }, + { 0.8732871413f, 0.6230830550f, 0.6802329421f, 0.0996893495f, 0.6501978040f, }, + { 0.9553357959f, 0.5717819333f, 0.4062424302f, 0.2195142955f, 0.5251868963f, }, + { 0.8651615381f, 0.2904576063f, 0.2491702288f, 0.6506875157f, 0.8565377593f, }, + { 0.2186982781f, 0.2216417491f, 0.4146128595f, 0.3996264637f, 0.8225415349f, }, + { 0.5467898250f, 0.4502311051f, 0.4192685485f, 0.3646653295f, 0.7288874388f, }, + { 0.0694710910f, 0.7293733954f, 0.5945537090f, 0.7067605257f, 0.2717151046f, }, + { 0.2806371450f, 0.3468784690f, 0.1379666179f, 0.1567456573f, 0.8819831014f, }, + { 0.9803464413f, 0.4977178872f, 0.1560947001f, 0.2045936584f, 0.9162309170f, }, + { 0.0600311048f, 0.8369666934f, 0.8623803854f, 0.5504769683f, 0.7246150970f, }, + { 0.1883597821f, 0.5521970987f, 0.2744043469f, 0.3954136670f, 0.0458976068f, }, + { 0.1272772998f, 0.3680867255f, 0.6731156111f, 0.4167750478f, 0.8066455126f, }, + { 0.3769917488f, 0.1405894309f, 0.3766871691f, 0.3292651474f, 0.8986744881f, }, + { 0.2548906505f, 0.2380404323f, 0.9344167113f, 0.2000645846f, 0.3750537634f, }, + { 0.4498522580f, 0.0465830490f, 0.8664452434f, 0.0916056186f, 0.1723448634f, }, + { 0.1202788427f, 0.5274640322f, 0.6582357883f, 0.7431231737f, 0.4443565309f, }, + { 0.5510696173f, 0.6913768649f, 0.8997213244f, 0.3973141909f, 0.9220381975f, }, + { 0.3874337375f, 0.4627210200f, 0.3119893074f, 0.7152445912f, 0.3245284259f, }, + { 0.3801714182f, 0.7628766298f, 0.2708151042f, 0.0212438125f, 0.4925932884f, }, + { 0.4191493392f, 0.6402300000f, 0.6853370667f, 0.2417253405f, 0.4153464735f, }, + { 0.9706567526f, 0.8890759349f, 0.9221964478f, 0.0850019157f, 0.8838173747f, }, + { 0.1457756907f, 0.8103173375f, 0.5617719889f, 0.8932931423f, 0.2907245755f, }, + { 0.2658019066f, 0.6155971289f, 0.3797874153f, 0.0294378158f, 0.0609415583f, }, + { 0.7916467786f, 0.2828751504f, 0.6566563249f, 0.0338012911f, 0.3472755253f, }, + { 0.7622926235f, 0.7038429976f, 0.7583386302f, 0.4775670469f, 0.5229033232f, }, + { 0.0740877017f, 0.9934150577f, 0.6373165250f, 0.7957789898f, 0.7632263303f, }, + { 0.6507166028f, 0.9457629323f, 0.1677881777f, 0.2133068144f, 0.0720776320f, }, + { 0.3274128735f, 0.2949723899f, 0.1843675226f, 0.1939653456f, 0.4882145226f, }, + { 0.4674412310f, 0.0979263186f, 0.3892448843f, 0.0015220752f, 0.3349666595f, }, + { 0.8280725479f, 0.8958793879f, 0.2740472257f, 0.7528444529f, 0.6455445886f, }, + { 0.1103217825f, 0.1282761842f, 0.8768145442f, 0.8342537880f, 0.2627376318f, }, + { 0.3873414695f, 0.5884376764f, 0.5160834193f, 0.0325106718f, 0.7335627079f, }, + { 0.7235043645f, 0.0617941245f, 0.1420445889f, 0.6843103766f, 0.1855074316f, }, + { 0.2105052769f, 0.7432459593f, 0.1830675304f, 0.9505296350f, 0.1581544578f, }, + { 0.0524407662f, 0.5883249044f, 0.8929544687f, 0.9219861627f, 0.8933918476f, }, + { 0.6961153746f, 0.7027171254f, 0.7246829867f, 0.0311612673f, 0.9148760438f, }, + { 0.6262444258f, 0.6753783822f, 0.9055992365f, 0.6350241899f, 0.2108185589f, }, + { 0.9661568403f, 0.3177617490f, 0.9335716367f, 0.7393125296f, 0.4963877797f, }, + { 0.8014323115f, 0.9316043854f, 0.6702585220f, 0.9558092356f, 0.7424262166f, }, + { 0.2797902524f, 0.0351170786f, 0.6409977078f, 0.8424587250f, 0.7864570618f, }, + { 0.3171681464f, 0.5488686562f, 0.4319936633f, 0.2542414665f, 0.6736384630f, }, + { 0.4197515249f, 0.6089794636f, 0.8115475178f, 0.5550845861f, 0.5174214244f, }, + { 0.2807508409f, 0.0728380606f, 0.1486964524f, 0.2332748920f, 0.6294175386f, }, + { 0.6225250363f, 0.8801549077f, 0.1474074274f, 0.7764623165f, 0.6719228625f, }, + { 0.4223499298f, 0.7741437554f, 0.1457236856f, 0.5318447948f, 0.0769671202f, }, + { 0.9814693928f, 0.6644887328f, 0.2739057839f, 0.6445885301f, 0.3141367137f, }, + { 0.2762872875f, 0.7268882990f, 0.4102705717f, 0.7965539694f, 0.2357157469f, }, + { 0.2096191943f, 0.3290013671f, 0.5948249102f, 0.2858313024f, 0.2005606890f, }, + { 0.8308608532f, 0.4202457368f, 0.3120578229f, 0.3221062720f, 0.8646596074f, }, + { 0.4526916444f, 0.7762920260f, 0.3863493800f, 0.3756863773f, 0.8801331520f, }, + { 0.7549504042f, 0.6724306345f, 0.7578244805f, 0.4483213127f, 0.6669061184f, }, + { 0.8297504783f, 0.7228450179f, 0.9131419063f, 0.3085200489f, 0.2644110918f, }, + { 0.6776450276f, 0.5335254073f, 0.3853515685f, 0.0415925086f, 0.5043134689f, }, + { 0.1502651274f, 0.9326584339f, 0.5940889716f, 0.4335834086f, 0.0816059038f, }, + { 0.2779623270f, 0.6517646313f, 0.4175403714f, 0.8457265496f, 0.2253156602f, }, + { 0.4216952920f, 0.9016408324f, 0.6336846948f, 0.3655908406f, 0.1339345127f, }, + { 0.5112591982f, 0.7162753940f, 0.9189779758f, 0.6235325933f, 0.0686960071f, }, + { 0.7317407727f, 0.8305719495f, 0.7963162661f, 0.3763089180f, 0.2900558412f, }, + { 0.4539898634f, 0.1895425618f, 0.7576664686f, 0.9677003622f, 0.3269715607f, }, + { 0.6987845898f, 0.2969448566f, 0.9047911167f, 0.6835853457f, 0.9134425521f, }, + { 0.4491491318f, 0.5688306093f, 0.3349467814f, 0.1624736637f, 0.5968095660f, }, + { 0.4422278404f, 0.9865394831f, 0.1403383464f, 0.6019929647f, 0.7631724477f, }, + { 0.4821002185f, 0.2822735310f, 0.2637169063f, 0.0629151836f, 0.3392986059f, }, + { 0.8162535429f, 0.1576626301f, 0.6339266300f, 0.7746828198f, 0.7388460040f, }, + { 0.0366244018f, 0.8592647314f, 0.4098013639f, 0.9437143207f, 0.6170257926f, }, + { 0.7782698870f, 0.8248697519f, 0.8932003975f, 0.0028138529f, 0.8005768061f, }, + { 0.7718992233f, 0.1201800406f, 0.1735441536f, 0.4964210093f, 0.6338633895f, }, + { 0.5204722285f, 0.2782363296f, 0.3948111236f, 0.3842954338f, 0.1762899011f, }, + { 0.9185162187f, 0.1771546900f, 0.1382024288f, 0.0785585418f, 0.0221158117f, }, + { 0.2365419120f, 0.9691518545f, 0.2383108288f, 0.2399678081f, 0.0698488131f, }, + { 0.1705540568f, 0.1464137286f, 0.6299777627f, 0.4087302387f, 0.6929829121f, }, + { 0.6227343082f, 0.9799892902f, 0.1593679488f, 0.5159394145f, 0.6728126407f, }, + { 0.1613411754f, 0.4187045693f, 0.9052704573f, 0.0683438480f, 0.0806437209f, }, + { 0.9943744540f, 0.9430711865f, 0.2377529293f, 0.8877018094f, 0.8982362747f, }, + { 0.0628433526f, 0.0795353726f, 0.6034497023f, 0.2245612144f, 0.6433573365f, }, + { 0.5621058345f, 0.9191433191f, 0.7513613701f, 0.5223335624f, 0.3583497703f, }, + { 0.5554248095f, 0.2030288726f, 0.9177957177f, 0.2604083419f, 0.7229249477f, }, + { 0.8674602509f, 0.8993280530f, 0.1407557875f, 0.7070519924f, 0.2579062581f, }, + { 0.4066617191f, 0.9219773412f, 0.1692592800f, 0.9367558956f, 0.3897538483f, }, + { 0.0023197513f, 0.2951805592f, 0.4129855335f, 0.7490902543f, 0.2227606177f, }, + { 0.2080491632f, 0.8106707335f, 0.2692914009f, 0.7514678836f, 0.0471416153f, }, + { 0.4828400612f, 0.0049115932f, 0.7966802120f, 0.6464766264f, 0.2469250858f, }, + { 0.6870105267f, 0.5058383942f, 0.1847783476f, 0.6010066271f, 0.0280457847f, }, + { 0.6835210919f, 0.3537497520f, 0.2168741673f, 0.7643010616f, 0.3083560765f, }, + { 0.1191221401f, 0.7753403187f, 0.9169752598f, 0.3312447071f, 0.6547005773f, }, + { 0.9233077168f, 0.0502437577f, 0.4198615253f, 0.3854964972f, 0.6186883450f, }, + { 0.2353005260f, 0.2620733976f, 0.2423845083f, 0.8080005646f, 0.5128461123f, }, + { 0.9230268598f, 0.4494173825f, 0.9232423902f, 0.8044607639f, 0.0043455660f, }, + { 0.1539704055f, 0.8541145921f, 0.6568136215f, 0.1612754613f, 0.4538104832f, }, + { 0.8606331944f, 0.0418969467f, 0.3622143567f, 0.7007989287f, 0.8103873134f, }, + { 0.6201249361f, 0.9213223457f, 0.2733407021f, 0.2659450471f, 0.1974497885f, }, + { 0.9474107623f, 0.4292281568f, 0.6510161757f, 0.0553921796f, 0.2013494074f, }, + { 0.7537032962f, 0.9218379855f, 0.8922259212f, 0.7969861627f, 0.8842226863f, }, + { 0.5074092746f, 0.3536762297f, 0.1801438630f, 0.3248554170f, 0.5243495107f, }, + { 0.8030092716f, 0.5405832529f, 0.6296108961f, 0.7541767359f, 0.8891962767f, }, + { 0.6212946773f, 0.5982187390f, 0.4153193235f, 0.8618081808f, 0.0975739434f, }, + { 0.9169347286f, 0.3354103863f, 0.1634404808f, 0.0774655789f, 0.4144199491f, }, + { 0.1697692275f, 0.0305127427f, 0.6473826766f, 0.0559284762f, 0.1740518808f, }, + { 0.9584801793f, 0.3608543277f, 0.6506474614f, 0.7437055111f, 0.6545598507f, }, + { 0.5460421443f, 0.1271338165f, 0.6584819555f, 0.7702636719f, 0.6501505971f, }, + { 0.0096557727f, 0.7443832159f, 0.2116404474f, 0.8978964090f, 0.7366517186f, }, + { 0.5457256436f, 0.0882219896f, 0.9202632904f, 0.2240703702f, 0.9268023372f, }, + { 0.8391873240f, 0.2440102398f, 0.8974300027f, 0.2471573353f, 0.4037082493f, }, + { 0.6215553880f, 0.4451818466f, 0.9349750280f, 0.9120126367f, 0.8305487633f, }, + { 0.2451698333f, 0.6540192962f, 0.8015082479f, 0.1273851246f, 0.6529533863f, }, + { 0.1507285237f, 0.6806657314f, 0.8031535745f, 0.2254239768f, 0.0404616110f, }, + { 0.8686904311f, 0.1341269612f, 0.4574179351f, 0.4359958768f, 0.7218812108f, }, + { 0.2074009925f, 0.9264898300f, 0.6719136834f, 0.0693204552f, 0.6947955489f, }, + { 0.2404444963f, 0.2200752497f, 0.2397666872f, 0.6543200612f, 0.3302212954f, }, + { 0.3973362744f, 0.6467256546f, 0.1898995638f, 0.8515286446f, 0.6217008829f, }, + { 0.4965752065f, 0.5030667782f, 0.4232194424f, 0.9286808372f, 0.9781767130f, }, + { 0.3428289592f, 0.4960512519f, 0.6297627091f, 0.1246587634f, 0.5947698355f, }, + { 0.5881645679f, 0.6585828662f, 0.1542954892f, 0.9628793597f, 0.9022038579f, }, + { 0.1555876136f, 0.7502764463f, 0.4300754666f, 0.9101669788f, 0.6334246993f, }, + { 0.9918186069f, 0.1093794703f, 0.7305037379f, 0.1660741866f, 0.1111549363f, }, + { 0.1338825822f, 0.3090497553f, 0.9241870642f, 0.5034430623f, 0.4333055913f, }, + { 0.5386890769f, 0.5691626072f, 0.9126147628f, 0.3506309986f, 0.3669624031f, }, + { 0.3708983660f, 0.9459529519f, 0.2109967470f, 0.1695951372f, 0.7220228910f, }, + { 0.3855873942f, 0.2058136463f, 0.4778507650f, 0.5975036621f, 0.1925799251f, }, + { 0.8079403043f, 0.8593161106f, 0.8881294727f, 0.4832123816f, 0.8646829128f, }, + { 0.0450021140f, 0.2717565596f, 0.6545967460f, 0.7409936190f, 0.7127670050f, }, + { 0.0536489561f, 0.8121938705f, 0.2726101279f, 0.2017405480f, 0.4252589345f, }, + { 0.9599416256f, 0.9440070391f, 0.8914710283f, 0.2804166079f, 0.8410710096f, }, + { 0.8708735704f, 0.5246590376f, 0.4189571440f, 0.2666073143f, 0.5866301060f, }, + { 0.8477293849f, 0.0594590642f, 0.1793077290f, 0.5777279139f, 0.1884094626f, }, + { 0.0238688868f, 0.9711610675f, 0.6403006315f, 0.8423227668f, 0.5357096791f, }, + { 0.7835069895f, 0.0897694305f, 0.6887326241f, 0.1242933348f, 0.7735361457f, }, + { 0.4951869845f, 0.2474716753f, 0.8933708668f, 0.3120188117f, 0.1654740274f, }, + { 0.0457435772f, 0.7408176661f, 0.8978531957f, 0.4177000821f, 0.7712976336f, }, + { 0.2174149454f, 0.8904352784f, 0.6536405087f, 0.3068143725f, 0.9719513059f, }, + { 0.4117776453f, 0.8823066950f, 0.8472982645f, 0.4625660479f, 0.8050373197f, }, + { 0.6702994108f, 0.0600084476f, 0.4273302555f, 0.9303762317f, 0.9641988873f, }, + { 0.5589072108f, 0.3410102129f, 0.6692107320f, 0.8994773030f, 0.0259494763f, }, + { 0.1760968715f, 0.7839687467f, 0.8990438581f, 0.3484356999f, 0.0349773020f, }, + { 0.1674957275f, 0.2806791067f, 0.5621151924f, 0.2108184397f, 0.5541005135f, }, + { 0.0912834033f, 0.0941558704f, 0.4533232152f, 0.8271482587f, 0.2848333120f, }, + { 0.5222066641f, 0.0534446649f, 0.6859184504f, 0.4062723815f, 0.4238585532f, }, + { 0.2513298988f, 0.3285494745f, 0.6328689456f, 0.6720162034f, 0.9966812730f, }, + { 0.4865611792f, 0.4061975181f, 0.3122657835f, 0.2608599961f, 0.0360945873f, }, + { 0.9896106720f, 0.9801153541f, 0.2659962475f, 0.2279564738f, 0.9064323306f, }, + { 0.6422366500f, 0.5613036752f, 0.2223269939f, 0.2006824315f, 0.5620204210f, }, + { 0.0167060327f, 0.8294845819f, 0.1624858826f, 0.7587867379f, 0.9084835649f, }, + { 0.0810662434f, 0.0144402096f, 0.1442496926f, 0.4372602999f, 0.9424352646f, }, + { 0.0777170062f, 0.4542703331f, 0.5623986721f, 0.8255488873f, 0.3118360639f, }, + { 0.6332219243f, 0.1546555907f, 0.4071251154f, 0.6449183226f, 0.4380641878f, }, + { 0.3588815629f, 0.7259109616f, 0.8949323893f, 0.0310435332f, 0.8665700555f, }, + { 0.4032739699f, 0.3401636183f, 0.3998365998f, 0.3091824353f, 0.7601765990f, }, + { 0.8782159686f, 0.8804634809f, 0.3928438425f, 0.9785805345f, 0.8952303529f, }, + { 0.4265696108f, 0.5748035908f, 0.6350638866f, 0.7704594731f, 0.7251192927f, }, + { 0.0821672976f, 0.7988390326f, 0.6722599268f, 0.6567916274f, 0.0610449426f, }, + { 0.6711975932f, 0.4044577777f, 0.7087682486f, 0.3872709274f, 0.8910403252f, }, + { 0.2452526689f, 0.6968676448f, 0.1313157529f, 0.8255284429f, 0.3837303519f, }, + { 0.6059313416f, 0.7568653226f, 0.3676816523f, 0.9447989464f, 0.4323852658f, }, + { 0.0950854868f, 0.1700586975f, 0.3190297186f, 0.4781437814f, 0.5663873553f, }, + { 0.5921857953f, 0.5017104149f, 0.1776745617f, 0.7146577835f, 0.2253703773f, }, + { 0.7989724278f, 0.9696672559f, 0.4163217843f, 0.6855589747f, 0.4756537676f, }, + { 0.6429971457f, 0.7487652898f, 0.8873785138f, 0.6627467871f, 0.0111746527f, }, + { 0.6880887151f, 0.2055517435f, 0.6718572378f, 0.3650619090f, 0.1937220991f, }, + { 0.6632122397f, 0.9281525612f, 0.4237767160f, 0.9447239041f, 0.2356662154f, }, + { 0.4056119919f, 0.0449440032f, 0.1486060917f, 0.2460376322f, 0.8845275044f, }, + { 0.5975536704f, 0.1284107715f, 0.4094949663f, 0.7570086718f, 0.6579572558f, }, + { 0.0722086430f, 0.1990416944f, 0.8961207867f, 0.8151916265f, 0.2128580809f, }, + { 0.4906984270f, 0.9360303283f, 0.6462264061f, 0.7495074272f, 0.8169018626f, }, + { 0.8900119662f, 0.4769478440f, 0.2296860665f, 0.6628353000f, 0.7692196369f, }, + { 0.3276960552f, 0.4769940078f, 0.3937670290f, 0.3482863307f, 0.8662155271f, }, + { 0.6262189150f, 0.7110581994f, 0.6555246115f, 0.4248665571f, 0.4261446297f, }, + { 0.2971760631f, 0.9768515229f, 0.2526108325f, 0.6574644446f, 0.0995754302f, }, + { 0.8846825361f, 0.4494028389f, 0.6608137488f, 0.0787991062f, 0.2857209146f, }, + { 0.4740692377f, 0.9063662291f, 0.9237411618f, 0.6824497581f, 0.2829234302f, }, + { 0.6688630581f, 0.8890810013f, 0.6712776423f, 0.8890388012f, 0.5011259317f, }, + { 0.4517498016f, 0.1297598332f, 0.8847675323f, 0.9259518385f, 0.3250522614f, }, + { 0.5810523629f, 0.6190810204f, 0.2216880620f, 0.2125811428f, 0.1756294370f, }, + { 0.6121792793f, 0.9578194022f, 0.3417336345f, 0.3919051886f, 0.2609726787f, }, + { 0.6801815629f, 0.8407352567f, 0.2706527710f, 0.6578662992f, 0.3172609210f, }, + { 0.6947216988f, 0.4393965602f, 0.8963797688f, 0.2064710557f, 0.2251489758f, }, + { 0.0126833487f, 0.4193360507f, 0.8995458484f, 0.4652849734f, 0.9965226650f, }, + { 0.1726991236f, 0.6309124827f, 0.6526710391f, 0.5302717090f, 0.7298354506f, }, + { 0.0204058811f, 0.0812477916f, 0.9214099646f, 0.9160807133f, 0.5754440427f, }, + { 0.3724952340f, 0.8464245200f, 0.8983617425f, 0.3619753718f, 0.6741123199f, }, + { 0.9161174297f, 0.8163927794f, 0.6799796820f, 0.4092884064f, 0.8607659936f, }, + { 0.2220835984f, 0.8452451825f, 0.3982852101f, 0.2782756090f, 0.1027002558f, }, + { 0.8696690202f, 0.4094341099f, 0.1890173852f, 0.6893680096f, 0.8828161359f, }, + { 0.8367606997f, 0.3150655925f, 0.9322819710f, 0.0451948270f, 0.0074513466f, }, + { 0.0823246688f, 0.6867864728f, 0.3197860122f, 0.4163556099f, 0.8237211108f, }, + { 0.3670961261f, 0.5294805765f, 0.1739652604f, 0.1212077737f, 0.6274768710f, }, + { 0.9344421625f, 0.1420627087f, 0.8371850848f, 0.9862938523f, 0.0466496162f, }, + { 0.4052397311f, 0.0913202167f, 0.5805484653f, 0.3732404113f, 0.1624829918f, }, + { 0.3037349284f, 0.3561063409f, 0.8215609193f, 0.7996636629f, 0.9492594600f, }, + { 0.6057854295f, 0.5836023688f, 0.9080621004f, 0.6684545279f, 0.8334238529f, }, + { 0.0231123008f, 0.2039128095f, 0.9188492894f, 0.7504552603f, 0.2526971698f, }, + { 0.9760959744f, 0.2608017921f, 0.6587374210f, 0.8090463281f, 0.9347877502f, }, + { 0.2722188234f, 0.9445360899f, 0.9160112143f, 0.4180462658f, 0.7208918333f, }, + { 0.2895027399f, 0.9076516032f, 0.1260608137f, 0.0600589439f, 0.3237433434f, }, + { 0.3174104393f, 0.1950612813f, 0.7346307635f, 0.2903274894f, 0.8510568738f, }, + { 0.1247075722f, 0.6234763265f, 0.9235235453f, 0.3917286694f, 0.3930013478f, }, + { 0.5962136984f, 0.3196406364f, 0.9130704403f, 0.8777415156f, 0.7164982557f, }, + { 0.2132440954f, 0.4433366656f, 0.8953370452f, 0.5229977965f, 0.9834817052f, }, + { 0.9578446150f, 0.8181498051f, 0.3126172125f, 0.3691214323f, 0.4783980250f, }, + { 0.9724182487f, 0.3962811530f, 0.1378229409f, 0.5460863113f, 0.9529812336f, }, + { 0.7043054104f, 0.8286221027f, 0.9211901426f, 0.6903455853f, 0.6702198982f, }, + { 0.5512281060f, 0.7339170575f, 0.1466924548f, 0.5918322206f, 0.3278500438f, }, + { 0.5132637620f, 0.8653480411f, 0.9058117270f, 0.5126808882f, 0.0351459347f, }, + { 0.9121012688f, 0.8552727103f, 0.1450043321f, 0.6231027842f, 0.3432948589f, }, + { 0.1883990914f, 0.6612223387f, 0.3855815828f, 0.9724083543f, 0.5299458504f, }, + { 0.4795577526f, 0.5944921970f, 0.4068101048f, 0.4792802334f, 0.2116247863f, }, + { 0.5698096156f, 0.2297195345f, 0.6769658923f, 0.1775925905f, 0.0194287039f, }, + { 0.1139837131f, 0.6585344076f, 0.6397347450f, 0.4389112890f, 0.3355108798f, }, + { 0.4957669675f, 0.1260170937f, 0.1376509964f, 0.2432282716f, 0.2809645832f, }, + { 0.0897794887f, 0.3889560401f, 0.7109050155f, 0.4456769824f, 0.5898414850f, }, + { 0.4559552670f, 0.4442132413f, 0.1469720155f, 0.2309683412f, 0.4611694217f, }, + { 0.2127885222f, 0.6419813037f, 0.1400190741f, 0.4074942768f, 0.8746674657f, }, + { 0.6800274849f, 0.5546683669f, 0.1405323297f, 0.3087230921f, 0.3108388782f, }, + { 0.4684635401f, 0.3670452237f, 0.3547304273f, 0.4452068806f, 0.2501153052f, }, + { 0.1818600297f, 0.4486742914f, 0.4042747319f, 0.5299410224f, 0.6349546909f, }, + { 0.0964704156f, 0.3275614381f, 0.1729331613f, 0.3874901533f, 0.7976809144f, }, + { 0.7245351076f, 0.4126122892f, 0.5798994303f, 0.4871999323f, 0.5768399239f, }, + { 0.9808243513f, 0.5988185406f, 0.9243234992f, 0.1002269238f, 0.0668101907f, }, + { 0.5576942563f, 0.1547056288f, 0.9134264588f, 0.7999120951f, 0.2232726514f, }, + { 0.5103706717f, 0.6306093931f, 0.4064202011f, 0.6162929535f, 0.7642644644f, }, + { 0.3543204367f, 0.4339662790f, 0.8976281285f, 0.8275479674f, 0.6742182970f, }, + { 0.7274590731f, 0.9887321591f, 0.1506728083f, 0.3050062954f, 0.0947229713f, }, + { 0.5183111429f, 0.5123482347f, 0.6777183414f, 0.1473470032f, 0.7955759764f, }, + { 0.2448808253f, 0.8324652314f, 0.6503762007f, 0.7213102579f, 0.5583073497f, }, + { 0.0153511642f, 0.6225735545f, 0.6590080261f, 0.1195797697f, 0.6417117715f, }, + { 0.7954779863f, 0.7288566232f, 0.6481914520f, 0.8784126043f, 0.1893307716f, }, + { 0.4797648489f, 0.2614610791f, 0.6313613057f, 0.7609228492f, 0.9807720184f, }, + { 0.4273985028f, 0.3011860549f, 0.1374281645f, 0.7859547138f, 0.5002349615f, }, + { 0.6124469042f, 0.1579888612f, 0.9053065777f, 0.3004028201f, 0.2322366834f, }, + { 0.9418653846f, 0.2821920514f, 0.7463891506f, 0.9389582276f, 0.8774412870f, }, + { 0.5484405756f, 0.6432306170f, 0.1492760628f, 0.6636828184f, 0.1349965781f, }, + { 0.6846762896f, 0.0960200503f, 0.8032522202f, 0.5674996972f, 0.7586348057f, }, + { 0.2204396129f, 0.5765968561f, 0.1476237327f, 0.1252205670f, 0.4377010167f, }, + { 0.3201996088f, 0.7443005443f, 0.9039431810f, 0.0650240481f, 0.9854292274f, }, + { 0.3199845552f, 0.0192854386f, 0.1524990797f, 0.3533820808f, 0.2842772901f, }, + { 0.7961959243f, 0.0545875020f, 0.4254358411f, 0.4807631075f, 0.6584859490f, }, + { 0.9548473954f, 0.6311061978f, 0.9193943143f, 0.1140224487f, 0.0753248259f, }, + { 0.2469710708f, 0.5497260690f, 0.4086890817f, 0.8121051192f, 0.9592389464f, }, + { 0.0892099589f, 0.7681341171f, 0.4275183976f, 0.1507211328f, 0.3834882379f, }, + { 0.4134389758f, 0.2619946003f, 0.3815563321f, 0.4726091623f, 0.0917761400f, }, + { 0.5443322062f, 0.2896725535f, 0.1511472017f, 0.3457608521f, 0.6623216867f, }, + { 0.7363665104f, 0.3905221224f, 0.3386698365f, 0.5143055916f, 0.3104698956f, }, + { 0.7101206779f, 0.7432330847f, 0.3589529097f, 0.9071243405f, 0.5633781552f, }, + { 0.2478924245f, 0.3961749673f, 0.3940633833f, 0.4096750915f, 0.3424012661f, }, + { 0.0617133453f, 0.1200992018f, 0.9136456847f, 0.1307758391f, 0.9852566719f, }, + { 0.7767199874f, 0.6296752095f, 0.5157176852f, 0.8008569479f, 0.8990735412f, }, + { 0.3058244586f, 0.4828458130f, 0.8979612589f, 0.8620452285f, 0.1399817318f, }, + { 0.1294701844f, 0.5088728666f, 0.1795148104f, 0.2281204611f, 0.4375269413f, }, + { 0.1420404017f, 0.9967051148f, 0.6542924047f, 0.3547791839f, 0.1780012995f, }, + { 0.9740327597f, 0.1273075789f, 0.1317660809f, 0.8746281862f, 0.6012553573f, }, + { 0.8944063783f, 0.7546340823f, 0.6810714602f, 0.1449845731f, 0.1058138311f, }, + { 0.5945718288f, 0.0061858799f, 0.9088662863f, 0.0364964306f, 0.6593192220f, }, + { 0.4754303396f, 0.8641412854f, 0.1688663661f, 0.7769435048f, 0.8632110357f, }, + { 0.1978442222f, 0.3707467020f, 0.9008491039f, 0.4117237628f, 0.5911692977f, }, + { 0.4142937660f, 0.5437353849f, 0.1355583221f, 0.0121418666f, 0.2880280316f, }, + { 0.1683413535f, 0.8300601840f, 0.4028870165f, 0.2162528634f, 0.1172972098f, }, + { 0.9046423435f, 0.4391779602f, 0.1809546649f, 0.5494115353f, 0.7870641351f, }, + { 0.7402432561f, 0.0971550494f, 0.8864669204f, 0.1557355523f, 0.9877199531f, }, + { 0.9709496498f, 0.5582349896f, 0.6483392119f, 0.3776219189f, 0.0213725585f, }, + { 0.9192963243f, 0.5838835239f, 0.1824482828f, 0.0227799509f, 0.7876009941f, }, + { 0.6253976822f, 0.9414482117f, 0.6687080860f, 0.3885524273f, 0.6440524459f, }, + { 0.0235392302f, 0.4634030759f, 0.9037769437f, 0.7047700286f, 0.5639411211f, }, + { 0.0797672644f, 0.8715515733f, 0.1718950272f, 0.8510921001f, 0.3665633202f, }, + { 0.9105977416f, 0.8985737562f, 0.8899857998f, 0.1903748810f, 0.4420548379f, }, + { 0.7779110670f, 0.8723896742f, 0.6555142403f, 0.5234972835f, 0.5375967026f, }, + { 0.9539933205f, 0.2442766577f, 0.1733209044f, 0.1835743636f, 0.9667642117f, }, + { 0.8312539458f, 0.5093300343f, 0.1718380898f, 0.7006902099f, 0.2413630486f, }, + { 0.0014654149f, 0.1509610564f, 0.9248156548f, 0.8946156502f, 0.5608989596f, }, + { 0.7108150125f, 0.8669762611f, 0.3975015581f, 0.9709920883f, 0.0024339973f, }, + { 0.2460548133f, 0.6222757101f, 0.8269061446f, 0.5813835263f, 0.4670407474f, }, + { 0.9863980412f, 0.3343105614f, 0.3470014334f, 0.2081110477f, 0.8207169175f, }, + { 0.9644153714f, 0.8585681319f, 0.1764064282f, 0.6102626920f, 0.4040272832f, }, + { 0.1060658619f, 0.8057425022f, 0.1892712712f, 0.9302367568f, 0.6242657900f, }, + { 0.1917841882f, 0.8622600436f, 0.2701641619f, 0.7951965928f, 0.4226970375f, }, + { 0.7190234065f, 0.9243289232f, 0.1728080213f, 0.8271319270f, 0.5604746938f, }, + { 0.9233171344f, 0.3672805727f, 0.6523117423f, 0.3752385080f, 0.4378993511f, }, + { 0.3796490133f, 0.7206484675f, 0.3956534564f, 0.6423272491f, 0.6525249481f, }, + { 0.9342370629f, 0.0251514204f, 0.6400496364f, 0.9884830117f, 0.9577526450f, }, + { 0.5597369075f, 0.9522598386f, 0.4964574277f, 0.8011842966f, 0.4690652788f, }, + { 0.1251467615f, 0.6872444153f, 0.4052522182f, 0.3470003009f, 0.7000844479f, }, + { 0.6824920177f, 0.9659762979f, 0.6638742089f, 0.3225129247f, 0.6879724860f, }, + { 0.4053599238f, 0.9685959220f, 0.5156210661f, 0.5128187537f, 0.4436904490f, }, + { 0.3054828048f, 0.2305809557f, 0.6767401695f, 0.6256210208f, 0.6912963986f, }, + { 0.0165719297f, 0.3622584343f, 0.8970501423f, 0.5225399137f, 0.9967964292f, }, + { 0.2790033519f, 0.6947363615f, 0.1822600812f, 0.3191750944f, 0.6650258899f, }, + { 0.8257966638f, 0.5291721821f, 0.8534001112f, 0.3419867754f, 0.3102488220f, }, + { 0.6930023432f, 0.8994190097f, 0.5153676867f, 0.2931976616f, 0.0122786015f, }, + { 0.1052334905f, 0.9797928333f, 0.4045354426f, 0.5881813765f, 0.3011051416f, }, + { 0.2965386510f, 0.0004573388f, 0.3471882939f, 0.6470041871f, 0.5302002430f, }, + { 0.4859737754f, 0.6174158454f, 0.8969693780f, 0.0058193682f, 0.6505814195f, }, + { 0.8059725165f, 0.0950807557f, 0.9160533547f, 0.2175524086f, 0.4627268016f, }, + { 0.5596550703f, 0.8113400936f, 0.1713882685f, 0.9571608901f, 0.4924174547f, }, + { 0.1450736821f, 0.5452455878f, 0.4172867239f, 0.6108496785f, 0.7823422551f, }, + { 0.0386712477f, 0.6529629230f, 0.1452127993f, 0.5473229289f, 0.1835960746f, }, + { 0.0783243477f, 0.5350864530f, 0.9015673995f, 0.0844866112f, 0.3359190524f, }, + { 0.9643784761f, 0.4581473172f, 0.8363254070f, 0.3940873742f, 0.1640149802f, }, + { 0.4877164662f, 0.9655038118f, 0.1626916230f, 0.1304658651f, 0.6785253286f, }, + { 0.9600315094f, 0.0298520178f, 0.3318853676f, 0.6742720604f, 0.0945525169f, }, + { 0.9036905766f, 0.2719343007f, 0.8741890192f, 0.7281681895f, 0.1554527879f, }, + { 0.9616663456f, 0.5914126635f, 0.1760296226f, 0.9976099133f, 0.7520726323f, }, + { 0.1688483655f, 0.3248471022f, 0.6795883179f, 0.8341190815f, 0.6166484356f, }, + { 0.8056626916f, 0.3027607203f, 0.3298122585f, 0.4602755010f, 0.8861642480f, }, + { 0.8865209222f, 0.5903875232f, 0.8669798970f, 0.0391226187f, 0.2200651318f, }, + { 0.5297188163f, 0.4769316614f, 0.1774325967f, 0.5337143540f, 0.9587566853f, }, + { 0.9997043014f, 0.8805023432f, 0.4294218719f, 0.8598889709f, 0.7086170912f, }, + { 0.9648718238f, 0.2213305384f, 0.6635443568f, 0.1361998469f, 0.3925404847f, }, + { 0.5864224434f, 0.6962395310f, 0.6517305970f, 0.9046950340f, 0.1784210205f, }, + { 0.6329058409f, 0.3313221335f, 0.5627108812f, 0.8287445307f, 0.4045689404f, }, + { 0.4543702602f, 0.3818875849f, 0.6417444348f, 0.2352221310f, 0.5107812881f, }, + { 0.7521730661f, 0.4750962853f, 0.6823205948f, 0.0880354643f, 0.7503052950f, }, + { 0.4425649941f, 0.4795944691f, 0.1397001445f, 0.0751060024f, 0.6439360380f, }, + { 0.4449377656f, 0.7391952276f, 0.6456022263f, 0.1680421382f, 0.4670319557f, }, + { 0.9036478400f, 0.9686443210f, 0.1434570551f, 0.2034571916f, 0.5173873305f, }, + { 0.4233805239f, 0.7449593544f, 0.0830473825f, 0.0587290116f, 0.0174372904f, }, + { 0.8638056517f, 0.0822573155f, 0.3921276033f, 0.1190436408f, 0.1396870911f, }, + { 0.6370073557f, 0.2700611353f, 0.8451071978f, 0.4612392187f, 0.9389430285f, }, + { 0.4808869064f, 0.6855055690f, 0.4214901030f, 0.1914810985f, 0.6049960256f, }, + { 0.5583952665f, 0.5163834691f, 0.4186472595f, 0.9761022329f, 0.8153747916f, }, + { 0.7579475641f, 0.9782888889f, 0.6370413899f, 0.1821785122f, 0.3533138931f, }, + { 0.7604292035f, 0.7364311218f, 0.8843147159f, 0.8324496150f, 0.5752988458f, }, + { 0.2836911380f, 0.1390051246f, 0.2438068986f, 0.2202897519f, 0.8939470053f, }, + { 0.9549573660f, 0.7209321260f, 0.1797874421f, 0.6687067151f, 0.0287462510f, }, + { 0.2628550231f, 0.9769717455f, 0.6559457183f, 0.7245097756f, 0.7859728336f, }, + { 0.3450601101f, 0.2188907415f, 0.8735473156f, 0.5475753546f, 0.2021894306f, }, + { 0.3001955152f, 0.7872609496f, 0.9030789137f, 0.9642545581f, 0.1495675743f, }, + { 0.9555051923f, 0.1562586278f, 0.6548725367f, 0.6379058361f, 0.7781556249f, }, + { 0.9736641645f, 0.9092848897f, 0.5979778767f, 0.1667932272f, 0.5149010420f, }, + { 0.2302491963f, 0.6791695356f, 0.3860677183f, 0.7851263881f, 0.7275658250f, }, + { 0.0813269317f, 0.9373574853f, 0.6667549610f, 0.5001932979f, 0.2624501884f, }, + { 0.7798120975f, 0.3684160411f, 0.1640051901f, 0.4761397541f, 0.9312823415f, }, + { 0.8645301461f, 0.4468482733f, 0.8502453566f, 0.7807247043f, 0.5296833515f, }, + { 0.8604176641f, 0.4838578105f, 0.8039761782f, 0.9840853810f, 0.6276180744f, }, + { 0.3977661133f, 0.1270481050f, 0.1253633201f, 0.9693322778f, 0.9231203198f, }, + { 0.8149178028f, 0.0150943240f, 0.4160184562f, 0.6467252970f, 0.7587155104f, }, + { 0.8969345093f, 0.7054623961f, 0.6793894172f, 0.2178113759f, 0.3546513021f, }, + { 0.2665496767f, 0.4899263978f, 0.6756172776f, 0.6280219555f, 0.3134118617f, }, + { 0.7398167253f, 0.7667517662f, 0.1642062664f, 0.9851156473f, 0.9228929877f, }, + { 0.2422635853f, 0.0341797844f, 0.5910451412f, 0.0382496603f, 0.0711566508f, }, + { 0.7964251041f, 0.1534774601f, 0.1599242538f, 0.1677646190f, 0.3120250106f, }, + { 0.5375077128f, 0.8677089810f, 0.1629583985f, 0.0997991487f, 0.0999266431f, }, + { 0.1491451561f, 0.2721735239f, 0.1916758716f, 0.7117168903f, 0.6837921143f, }, + { 0.6700974703f, 0.4945374131f, 0.8876660466f, 0.8474770784f, 0.4904349744f, }, + { 0.5954986215f, 0.5295796394f, 0.9318428636f, 0.2431325018f, 0.2251081169f, }, + { 0.3525544703f, 0.8830800056f, 0.6442528367f, 0.0919857621f, 0.7368897200f, }, + { 0.8346413374f, 0.1389365047f, 0.1288894117f, 0.4958013892f, 0.1749054343f, }, + { 0.9606493711f, 0.4930073023f, 0.6563494205f, 0.3004741073f, 0.5815390944f, }, + { 0.0585923716f, 0.9045588970f, 0.2699732780f, 0.1810047328f, 0.4249069095f, }, + { 0.9539546371f, 0.9245915413f, 0.1500610411f, 0.8949918747f, 0.4106957316f, }, + { 0.2811679542f, 0.8173474669f, 0.4115311205f, 0.5708447695f, 0.5510478020f, }, + { 0.3119313419f, 0.8762995601f, 0.8760988116f, 0.9171943069f, 0.0340503976f, }, + { 0.6438157558f, 0.4692310691f, 0.1652504057f, 0.2901431024f, 0.4536658525f, }, + { 0.3589393497f, 0.5967445970f, 0.8729543090f, 0.2474726439f, 0.0587516092f, }, + { 0.2985112369f, 0.0822437108f, 0.6593500972f, 0.3413878977f, 0.9465652704f, }, + { 0.6105484366f, 0.5631908178f, 0.6818451881f, 0.1601658612f, 0.8971045613f, }, + { 0.9795738459f, 0.3555393815f, 0.4363043606f, 0.0050256136f, 0.0734817758f, }, + { 0.3814918697f, 0.2374612391f, 0.1523045599f, 0.9003127217f, 0.9376186728f, }, + { 0.9815377593f, 0.6239143610f, 0.4169765115f, 0.6183004975f, 0.2998521030f, }, + { 0.8537096381f, 0.7562656999f, 0.9315516353f, 0.6085984707f, 0.5989226699f, }, + { 0.4334717989f, 0.8152624965f, 0.1586142182f, 0.6697410941f, 0.1658185571f, }, + { 0.6954014301f, 0.2710048854f, 0.1332066804f, 0.9186689258f, 0.6678466797f, }, + { 0.4265735149f, 0.1948410124f, 0.4244428575f, 0.4671714008f, 0.9187193513f, }, + { 0.7071329355f, 0.5069113970f, 0.8943161368f, 0.9237628579f, 0.1427617073f, }, + { 0.3982107043f, 0.6053983569f, 0.4150694311f, 0.8683232665f, 0.0728719160f, }, + { 0.5080881119f, 0.2074956149f, 0.4066801369f, 0.4900521338f, 0.7531351447f, }, + { 0.7347860336f, 0.6732413173f, 0.1802725792f, 0.3157454133f, 0.3624019921f, }, + { 0.2683413625f, 0.7635646462f, 0.9230060577f, 0.4070904255f, 0.0910319611f, }, + { 0.7302482724f, 0.2909857333f, 0.1742155701f, 0.3506374657f, 0.2501560152f, }, + { 0.6942669749f, 0.1322372556f, 0.2435873747f, 0.1984533668f, 0.8072303534f, }, + { 0.9401080608f, 0.3957302272f, 0.4216497540f, 0.0129361553f, 0.1987362653f, }, + { 0.6652001143f, 0.8229570985f, 0.8834961653f, 0.1215176657f, 0.6130769253f, }, + { 0.0352021232f, 0.7741879225f, 0.6961135268f, 0.2316779792f, 0.0555125810f, }, + { 0.3297541440f, 0.9553067684f, 0.4184217155f, 0.5293486714f, 0.1265911311f, }, + { 0.7875778675f, 0.1896398067f, 0.8343408108f, 0.4115246236f, 0.0595137887f, }, + { 0.1582321525f, 0.3894644678f, 0.1535483003f, 0.7393954992f, 0.9608636498f, }, + { 0.4286241531f, 0.3562712669f, 0.9227654338f, 0.5660175681f, 0.8127071261f, }, + { 0.2985581756f, 0.4470497668f, 0.1396178901f, 0.4777880609f, 0.6422897577f, }, + { 0.7375066280f, 0.3262853920f, 0.8815809488f, 0.4984120131f, 0.9997048974f, }, + { 0.9831953645f, 0.6845543385f, 0.4124499559f, 0.2337611765f, 0.7102365494f, }, + { 0.7786266804f, 0.5955977440f, 0.4266300797f, 0.6664807200f, 0.2450855970f, }, + { 0.7969213724f, 0.5006770492f, 0.1295739561f, 0.8208860755f, 0.5081101656f, }, + { 0.9844864011f, 0.4558709860f, 0.3992567658f, 0.9340557456f, 0.8567868471f, }, + { 0.0450148731f, 0.9980211854f, 0.1490179896f, 0.1693647057f, 0.6558867097f, }, + { 0.2664994597f, 0.3672462404f, 0.8838720322f, 0.0873681605f, 0.4685999453f, }, + { 0.4295307398f, 0.4425379336f, 0.7042992711f, 0.2025313526f, 0.9999275804f, }, + { 0.3326367438f, 0.0899679363f, 0.1674279571f, 0.2296723127f, 0.9397018552f, }, + { 0.3025586605f, 0.5058240294f, 0.1710092276f, 0.1714102179f, 0.1267361790f, }, + { 0.0917770192f, 0.1141286641f, 0.2273677588f, 0.5732718110f, 0.5326727033f, }, + { 0.2547509074f, 0.1637577116f, 0.8045812845f, 0.3985255063f, 0.5129899979f, }, + { 0.3820587695f, 0.9105479121f, 0.3931562603f, 0.6405611038f, 0.3770503402f, }, + { 0.8133808374f, 0.2194528282f, 0.6605672836f, 0.0524763614f, 0.8783487082f, }, + { 0.7164062262f, 0.6115906835f, 0.1426462531f, 0.2933609784f, 0.4702317417f, }, + { 0.7032451034f, 0.1921256930f, 0.2354733795f, 0.6382959485f, 0.8865978718f, }, + { 0.0192057732f, 0.8496630788f, 0.8999813795f, 0.6268237829f, 0.5313404799f, }, + { 0.0641189441f, 0.3086328804f, 0.8465796709f, 0.6358977556f, 0.0649170876f, }, + { 0.8283549547f, 0.4401649535f, 0.6714228392f, 0.9972767234f, 0.2249906659f, }, + { 0.4198299646f, 0.1431726515f, 0.9378727674f, 0.7163347006f, 0.7697145939f, }, + { 0.3455986679f, 0.1547204256f, 0.3851391673f, 0.8393955827f, 0.4326666296f, }, + { 0.7566757202f, 0.8864159584f, 0.4580723643f, 0.9676396847f, 0.1817990094f, }, + { 0.3892149627f, 0.3138799071f, 0.6276299357f, 0.4725767374f, 0.1044836417f, }, + { 0.6377963424f, 0.0904172435f, 0.2334369123f, 0.1571315974f, 0.2801299691f, }, + { 0.1895081550f, 0.9949304461f, 0.1458076686f, 0.0432589389f, 0.7181853056f, }, + { 0.5023262501f, 0.6533163786f, 0.8917517662f, 0.2692360282f, 0.0019706525f, }, + { 0.9202683568f, 0.9309409857f, 0.8927053213f, 0.3768476248f, 0.9711019993f, }, + { 0.4748935401f, 0.2210260481f, 0.1874148101f, 0.6747671962f, 0.5749003291f, }, + { 0.4283550382f, 0.1019738615f, 0.6707483530f, 0.2130030543f, 0.7748587132f, }, + { 0.4822756350f, 0.5167794228f, 0.1707672775f, 0.6849746704f, 0.8548030853f, }, + { 0.2235736698f, 0.5266553164f, 0.9154382348f, 0.9482907057f, 0.5067411661f, }, + { 0.0289856698f, 0.9186859131f, 0.4012750685f, 0.5432290435f, 0.4675513506f, }, + { 0.0368444994f, 0.3931633234f, 0.4279684722f, 0.9741680622f, 0.2949175537f, }, + { 0.5810667872f, 0.3069746792f, 0.1663627774f, 0.4290866554f, 0.8663643599f, }, + { 0.1683333367f, 0.1055471376f, 0.0875001401f, 0.0989790633f, 0.8275893331f, }, + { 0.0992719159f, 0.2301808000f, 0.6367070079f, 0.2370247543f, 0.8747205138f, }, + { 0.4514143169f, 0.1646448672f, 0.6500702500f, 0.9903281927f, 0.7983329296f, }, + { 0.5187355280f, 0.5959643126f, 0.6576367021f, 0.7959789038f, 0.3748928607f, }, + { 0.1737102121f, 0.7423228621f, 0.6705230474f, 0.9572724700f, 0.0487582646f, }, + { 0.6198499203f, 0.3517143428f, 0.1527780294f, 0.1328037828f, 0.0332689509f, }, + { 0.8839493990f, 0.9367565513f, 0.4081926942f, 0.9256343842f, 0.0810200796f, }, + { 0.2912037671f, 0.3175346255f, 0.9003556967f, 0.4580399394f, 0.6945976019f, }, + { 0.8740369678f, 0.7800629735f, 0.2418091893f, 0.1369917989f, 0.6090449691f, }, + { 0.7959111333f, 0.1295394897f, 0.8837180138f, 0.1572343409f, 0.8273808956f, }, + { 0.0055001434f, 0.6556593776f, 0.3431199193f, 0.8167563081f, 0.7749109268f, }, + { 0.9453995228f, 0.6090634465f, 0.7402856350f, 0.2649319768f, 0.6009775996f, }, + { 0.4589247704f, 0.2533712089f, 0.1359140277f, 0.5452744961f, 0.5499470234f, }, + { 0.2021892220f, 0.1139321178f, 0.1392383277f, 0.4750790298f, 0.3616923094f, }, + { 0.5432898998f, 0.3631372452f, 0.4251794517f, 0.4017430842f, 0.1326609254f, }, + { 0.2797758877f, 0.2476499230f, 0.1850706935f, 0.7754347920f, 0.9962185621f, }, + { 0.0104077756f, 0.5964711308f, 0.1409658194f, 0.5563566685f, 0.6112495065f, }, + { 0.0144342883f, 0.9469462633f, 0.1482240260f, 0.2809222639f, 0.4099670053f, }, + { 0.0969356820f, 0.8448896408f, 0.6533840299f, 0.5754798055f, 0.0238633119f, }, + { 0.5094879270f, 0.3114691377f, 0.7252626419f, 0.8828182220f, 0.0272231102f, }, + { 0.3033470511f, 0.1127346382f, 0.8444536328f, 0.2579497099f, 0.5005813837f, }, + { 0.2244332433f, 0.7717435956f, 0.6684685946f, 0.8620620370f, 0.5720012188f, }, + { 0.8043491840f, 0.2534753978f, 0.3250861168f, 0.6674904227f, 0.3079463542f, }, + { 0.1014064252f, 0.2966237962f, 0.6742354631f, 0.9994797707f, 0.9290922284f, }, + { 0.7931342721f, 0.6584977508f, 0.8856663108f, 0.2655850053f, 0.9129021168f, }, + { 0.6259304881f, 0.0171551164f, 0.8471147418f, 0.4754230976f, 0.0494167134f, }, + { 0.4918880761f, 0.3221666217f, 0.8877533078f, 0.5579791069f, 0.8401954770f, }, + { 0.0526487865f, 0.4718564153f, 0.1661192477f, 0.5640808940f, 0.4317242205f, }, + { 0.2746406198f, 0.1762529612f, 0.1529570520f, 0.1078280210f, 0.5601892471f, }, + { 0.7048363090f, 0.0690748543f, 0.6475112438f, 0.8392729759f, 0.4782755971f, }, + { 0.2455220222f, 0.2011910379f, 0.3270663917f, 0.4266158640f, 0.1257507801f, }, + { 0.0745866075f, 0.4947209060f, 0.6699306965f, 0.9005715847f, 0.9656471610f, }, + { 0.9319583774f, 0.2998386919f, 0.4346162081f, 0.3470741808f, 0.3797458410f, }, + { 0.5868629217f, 0.7525513768f, 0.8942037225f, 0.5881661773f, 0.6908829212f, }, + { 0.7696894407f, 0.2496570498f, 0.9029788375f, 0.1449566782f, 0.9405493140f, }, + { 0.4535817206f, 0.8768938780f, 0.4309327304f, 0.4748589396f, 0.5439139009f, }, + { 0.4109740853f, 0.7917355895f, 0.7563589215f, 0.3225246966f, 0.7839621902f, }, + { 0.1879760027f, 0.9260431528f, 0.1582225859f, 0.6899860501f, 0.3005719185f, }, + { 0.7586849332f, 0.5602801442f, 0.1096993685f, 0.2853884399f, 0.7707833052f, }, + { 0.0994566008f, 0.6209869981f, 0.1324964464f, 0.4502699375f, 0.9661148787f, }, + { 0.5732976794f, 0.0974852666f, 0.1685871929f, 0.8425189853f, 0.8500508666f, }, + { 0.7247543335f, 0.7300504446f, 0.6574591398f, 0.4762884378f, 0.7749651670f, }, + { 0.7547982931f, 0.1737373769f, 0.4105111063f, 0.6613005400f, 0.8076131940f, }, + { 0.9561764002f, 0.0931298584f, 0.9024232626f, 0.9078714848f, 0.6997975707f, }, + { 0.3599743247f, 0.1181411669f, 0.6603565216f, 0.3643483222f, 0.3171017468f, }, + { 0.1548973918f, 0.4753058255f, 0.9083060026f, 0.5500577688f, 0.1667237729f, }, + { 0.0826494992f, 0.6106115580f, 0.3874568343f, 0.7749238610f, 0.3882563412f, }, + { 0.8583701253f, 0.3821409941f, 0.6783229113f, 0.1268156916f, 0.4928922355f, }, + { 0.6696636081f, 0.2424270362f, 0.2684422731f, 0.0114330519f, 0.3125860095f, }, + { 0.4406300783f, 0.8437696099f, 0.9155861735f, 0.2646900117f, 0.8090519905f, }, + { 0.6283949018f, 0.0367765725f, 0.1772430986f, 0.3054746389f, 0.4599150717f, }, + { 0.8190104365f, 0.7394275069f, 0.7182311416f, 0.4610926211f, 0.6376371384f, }, + { 0.4085309207f, 0.8459060192f, 0.7325575948f, 0.7600988150f, 0.8547167778f, }, + { 0.0650310591f, 0.4013541341f, 0.9293901920f, 0.1427175701f, 0.9910490513f, }, + { 0.4855956435f, 0.1426406205f, 0.5818157792f, 0.0753199831f, 0.4983699620f, }, + { 0.5131756663f, 0.6832227111f, 0.1547905803f, 0.4889817238f, 0.7748047709f, }, + { 0.2072787732f, 0.1941394508f, 0.6637356877f, 0.1102272943f, 0.6016145945f, }, + { 0.1908121705f, 0.7514318228f, 0.9765977263f, 0.7000197172f, 0.0801525190f, }, + { 0.6067320108f, 0.6231771708f, 0.6623160839f, 0.2423846424f, 0.8593481183f, }, + { 0.1949041188f, 0.5103950500f, 0.4818463624f, 0.4942823052f, 0.8545402884f, }, + { 0.2300429791f, 0.4972362816f, 0.4219648838f, 0.9282656908f, 0.1979885995f, }, + { 0.3346379697f, 0.9192470908f, 0.1100370437f, 0.4820858538f, 0.3073306084f, }, + { 0.7130808234f, 0.1265769452f, 0.1535943300f, 0.0496447124f, 0.3125340939f, }, + { 0.6444661617f, 0.9765006304f, 0.2505088151f, 0.0226930995f, 0.0922836587f, }, + { 0.3347234726f, 0.3649637997f, 0.4281927645f, 0.3127455711f, 0.1122071669f, }, + { 0.0545345657f, 0.6254195571f, 0.8825021386f, 0.0881243125f, 0.8705210090f, }, + { 0.9317770600f, 0.0682048425f, 0.1616327316f, 0.2368701845f, 0.3042016029f, }, + { 0.3014261425f, 0.6132721305f, 0.4239659607f, 0.0478611402f, 0.3440237641f, }, + { 0.8644068837f, 0.8166940212f, 0.9210947156f, 0.3142153919f, 0.3384123147f, }, + { 0.1293078214f, 0.3278070390f, 0.1385754943f, 0.5252557397f, 0.2037834078f, }, + { 0.1355125308f, 0.8481654525f, 0.1084564179f, 0.8895837069f, 0.9297063947f, }, + { 0.6626101732f, 0.9949202538f, 0.1371307671f, 0.7483708858f, 0.1548348367f, }, + { 0.9817621708f, 0.8498107195f, 0.4318315685f, 0.1167622134f, 0.9145144820f, }, + { 0.5134156346f, 0.0897483453f, 0.8054890037f, 0.8641226292f, 0.9845616221f, }, + { 0.6691633463f, 0.1699157953f, 0.9217935205f, 0.2860171795f, 0.2862279415f, }, + { 0.6314294934f, 0.9053294659f, 0.9261307120f, 0.7745748758f, 0.9740136266f, }, + { 0.5819452405f, 0.9823573828f, 0.6724982858f, 0.2563684285f, 0.9017974138f, }, + { 0.2216677815f, 0.0559061207f, 0.1497624665f, 0.0987473577f, 0.7248274088f, }, + { 0.0998611301f, 0.2070419639f, 0.8288671374f, 0.7161344886f, 0.9194735289f, }, + { 0.9933570027f, 0.9189748168f, 0.8072370291f, 0.1076514125f, 0.1849746555f, }, + { 0.7228713036f, 0.1596566886f, 0.5150070786f, 0.1441474855f, 0.0661570430f, }, + { 0.0499657430f, 0.9619827271f, 0.3996433318f, 0.6530802250f, 0.0733937249f, }, + { 0.1254796386f, 0.7117719054f, 0.9174353480f, 0.1034498066f, 0.4031996131f, }, + { 0.4448870420f, 0.0056870449f, 0.7002051473f, 0.2498449981f, 0.5136056542f, }, + { 0.8998672962f, 0.3057129085f, 0.4178559184f, 0.9258152246f, 0.1282432377f, }, + { 0.1412497461f, 0.9733054042f, 0.2212451696f, 0.4173105955f, 0.6131963134f, }, + { 0.3894228041f, 0.4253168106f, 0.1805790663f, 0.1834900081f, 0.3250872791f, }, + { 0.2628329098f, 0.1012361422f, 0.8649088740f, 0.3292372823f, 0.3081247211f, }, + { 0.7906532288f, 0.4821045399f, 0.4038228095f, 0.3939401209f, 0.9954417944f, }, + { 0.7555449605f, 0.3928602040f, 0.9311004281f, 0.1790024638f, 0.2462277859f, }, + { 0.2807508409f, 0.7482221127f, 0.6572058797f, 0.1095788851f, 0.5104633570f, }, + { 0.1752972603f, 0.7198436260f, 0.9060332179f, 0.8441591263f, 0.6085563302f, }, + { 0.4834625125f, 0.5609233975f, 0.2171468735f, 0.1443241388f, 0.1755244881f, }, + { 0.4814448357f, 0.4771549404f, 0.9263590574f, 0.5750821829f, 0.3008694649f, }, + { 0.3622517586f, 0.7558667660f, 0.3964896500f, 0.3350126743f, 0.5759840012f, }, + { 0.3580656052f, 0.5591519475f, 0.4119996130f, 0.0696884617f, 0.3114795089f, }, + { 0.3437252045f, 0.8193073273f, 0.1479767114f, 0.4128408432f, 0.1243752688f, }, + { 0.5946728587f, 0.0409310050f, 0.4223316312f, 0.0090654586f, 0.1084287986f, }, + { 0.9984366298f, 0.0191844888f, 0.6414379478f, 0.9009640217f, 0.7663844228f, }, + { 0.5437956452f, 0.7800726891f, 0.4090618789f, 0.4398626983f, 0.4832190275f, }, + { 0.9708737135f, 0.4200861752f, 0.8891196847f, 0.8342605829f, 0.7395022511f, }, + { 0.8493605852f, 0.9961255193f, 0.6666922569f, 0.1235389113f, 0.2227306813f, }, + { 0.4470238686f, 0.6090819240f, 0.4258388579f, 0.3845990300f, 0.9138085842f, }, + { 0.9417594075f, 0.5006828904f, 0.1883970946f, 0.2002666444f, 0.8500894904f, }, + { 0.6384903789f, 0.6395144463f, 0.9077315927f, 0.6697617173f, 0.8512086272f, }, + { 0.0087213283f, 0.9828585386f, 0.8887939453f, 0.4785058200f, 0.6037483811f, }, + { 0.6680338979f, 0.0823094770f, 0.9250529408f, 0.7282754183f, 0.2138310671f, }, + { 0.9064673781f, 0.1180551276f, 0.4089209139f, 0.9295975566f, 0.3489661515f, }, + { 0.4683424234f, 0.3454791009f, 0.6405939460f, 0.9373342991f, 0.1361351758f, }, + { 0.1580174714f, 0.7095093727f, 0.6009737849f, 0.4219673872f, 0.4093854129f, }, + { 0.0365004390f, 0.8813204765f, 0.8885269165f, 0.1298466623f, 0.0732654780f, }, + { 0.3649988770f, 0.0468754247f, 0.6433752775f, 0.1459098160f, 0.0063077481f, }, + { 0.4853258431f, 0.1841042191f, 0.8832054734f, 0.4282297492f, 0.1934542954f, }, + { 0.3117605448f, 0.8383365273f, 0.6514744163f, 0.9749878645f, 0.0530770086f, }, + { 0.5436596274f, 0.6135886312f, 0.9009683728f, 0.3213257194f, 0.1563519239f, }, + { 0.9562898278f, 0.5308704972f, 0.1094931588f, 0.8474324942f, 0.5754844546f, }, + { 0.6424849033f, 0.5405859351f, 0.8939579725f, 0.8778976202f, 0.6169037223f, }, + { 0.0304795280f, 0.3198828697f, 0.6932471991f, 0.7065448165f, 0.5434570909f, }, + { 0.6822314858f, 0.9275956154f, 0.9713617563f, 0.4064881206f, 0.4100089371f, }, + { 0.1566009223f, 0.7706454396f, 0.2333302498f, 0.5164099336f, 0.5639109612f, }, + { 0.9107143879f, 0.5185158253f, 0.6819518209f, 0.7086067796f, 0.4933575988f, }, + { 0.9691743255f, 0.0112421671f, 0.8904764652f, 0.2794344425f, 0.4883012772f, }, + { 0.9812871814f, 0.5195030570f, 0.4033726454f, 0.3408876359f, 0.1691515744f, }, + { 0.5729548335f, 0.1170704216f, 0.8523078561f, 0.6926349401f, 0.1522777230f, }, + { 0.2914416492f, 0.8682878613f, 0.1900887340f, 0.5545155406f, 0.2999169230f, }, + { 0.7042110562f, 0.6688691378f, 0.4181954861f, 0.5907233953f, 0.5364931822f, }, + { 0.3178125024f, 0.4444721937f, 0.8797751665f, 0.9706348181f, 0.2150214314f, }, + { 0.1254219860f, 0.7503415346f, 0.8539257050f, 0.6752343774f, 0.0771152377f, }, + { 0.7424693704f, 0.5134959817f, 0.3131100833f, 0.0930811092f, 0.4196280837f, }, + { 0.3641713262f, 0.6847283840f, 0.8790692091f, 0.3057268262f, 0.1299591810f, }, + { 0.6240565181f, 0.7508354783f, 0.6656332016f, 0.4449041486f, 0.3647877574f, }, + { 0.9470384717f, 0.8373682499f, 0.8402828574f, 0.0330159701f, 0.3996124566f, }, + { 0.5197124481f, 0.7568498850f, 0.1689542085f, 0.5623566508f, 0.0999487787f, }, + { 0.2317363620f, 0.3860290051f, 0.6407940984f, 0.3881893754f, 0.7424958944f, }, + { 0.6955646873f, 0.9519188404f, 0.3183825910f, 0.5039559603f, 0.9640315175f, }, + { 0.5231477022f, 0.4113701880f, 0.6200132370f, 0.9583541751f, 0.7986480594f, }, + { 0.5066821575f, 0.4510830939f, 0.4847787321f, 0.5880331993f, 0.5773647428f, }, + { 0.1079605669f, 0.5582280159f, 0.1478275061f, 0.6387441158f, 0.1026407704f, }, + { 0.8686447144f, 0.1952173114f, 0.4015249610f, 0.1868240237f, 0.8393335342f, }, + { 0.4752377570f, 0.9821380377f, 0.6739950776f, 0.2196918130f, 0.0606318936f, }, + { 0.5516039133f, 0.9350891113f, 0.1880293638f, 0.5697935224f, 0.6502375007f, }, + { 0.4571087360f, 0.6692596078f, 0.9151550531f, 0.4090929627f, 0.3097535670f, }, + { 0.2993274927f, 0.6691052318f, 0.6662060618f, 0.5693559647f, 0.1284941137f, }, + { 0.1559078097f, 0.8756325841f, 0.7216137052f, 0.4017215967f, 0.7726922631f, }, + { 0.8325593472f, 0.2783419192f, 0.5969438553f, 0.4422997236f, 0.5024647117f, }, + { 0.1190249324f, 0.8693013191f, 0.4092141688f, 0.3497573137f, 0.2997525036f, }, + { 0.8078672886f, 0.6940232515f, 0.4159009755f, 0.5166391134f, 0.6364046335f, }, + { 0.4608441889f, 0.5915109515f, 0.0833236277f, 0.5827288032f, 0.5242072940f, }, + { 0.5170875788f, 0.8344153166f, 0.4785903692f, 0.9900897145f, 0.4864663780f, }, + { 0.6633359194f, 0.3870778978f, 0.5059018135f, 0.0476362333f, 0.8434661627f, }, + { 0.2138791233f, 0.2459290624f, 0.6862183809f, 0.1308473796f, 0.3426493704f, }, + { 0.7578674555f, 0.6342275143f, 0.6435787082f, 0.1195597425f, 0.5193337202f, }, + { 0.3810512424f, 0.4044907689f, 0.4123164713f, 0.8873084188f, 0.3656779528f, }, + { 0.5191016793f, 0.7962290645f, 0.0902675390f, 0.2011779994f, 0.8783323169f, }, + { 0.5048565865f, 0.0004847192f, 0.1470967978f, 0.9501753449f, 0.1743204892f, }, + { 0.1420024931f, 0.4472053051f, 0.6552674174f, 0.0004886650f, 0.5994753838f, }, + { 0.3826992810f, 0.5664912462f, 0.6513465047f, 0.3832733929f, 0.4763419330f, }, + { 0.7680711746f, 0.8505775332f, 0.9013278484f, 0.0955141038f, 0.5956310034f, }, + { 0.7478993535f, 0.8505282402f, 0.6758541465f, 0.4612446129f, 0.5324606299f, }, + { 0.7694770694f, 0.9109046459f, 0.6616698503f, 0.0614098608f, 0.7205293775f, }, + { 0.1296790987f, 0.1050485075f, 0.4393767416f, 0.0802602097f, 0.2120990753f, }, + { 0.2436205149f, 0.1266466826f, 0.4755751789f, 0.7592602372f, 0.5264926553f, }, + { 0.8939450383f, 0.8498769999f, 0.3504982293f, 0.7799086571f, 0.9001188278f, }, + { 0.2059695423f, 0.9848666191f, 0.6470401287f, 0.7182145119f, 0.6424472332f, }, + { 0.0587065592f, 0.0607641377f, 0.9254674315f, 0.8149735928f, 0.9880042076f, }, + { 0.9194400907f, 0.6821730733f, 0.9367148280f, 0.9106260538f, 0.3409099281f, }, + { 0.9331636429f, 0.4657026827f, 0.3609704077f, 0.8818121552f, 0.4431084394f, }, + { 0.8020241857f, 0.3559144735f, 0.6619566083f, 0.9978672266f, 0.9673491120f, }, + { 0.8489344716f, 0.1804182380f, 0.1672132164f, 0.5263836384f, 0.3994589746f, }, + { 0.0287381634f, 0.1107078493f, 0.6943463087f, 0.2395181954f, 0.3626424670f, }, + { 0.9281479120f, 0.2158501446f, 0.8348618746f, 0.6657570004f, 0.4487101734f, }, + { 0.4169028699f, 0.6810869575f, 0.1680857390f, 0.3386934400f, 0.7856830955f, }, + { 0.3930340111f, 0.5037709475f, 0.4256667793f, 0.6027138233f, 0.0930257961f, }, + { 0.3480600119f, 0.9994454980f, 0.6560352445f, 0.7998132110f, 0.1585894078f, }, + { 0.2549083531f, 0.0676986575f, 0.8440742493f, 0.4874911010f, 0.3456216156f, }, + { 0.7144336104f, 0.5369933844f, 0.7299476266f, 0.7242155671f, 0.3749023378f, }, + { 0.8245159984f, 0.3005877435f, 0.1504479945f, 0.8338340521f, 0.8718520403f, }, + { 0.5468881726f, 0.9674741030f, 0.9544656873f, 0.9600237012f, 0.2268186808f, }, + { 0.8583984375f, 0.9616797566f, 0.1850372404f, 0.3228692412f, 0.9504075646f, }, + { 0.5561596155f, 0.4097749293f, 0.7365884185f, 0.3003263474f, 0.6284620762f, }, + { 0.0035583398f, 0.8621560931f, 0.6544016600f, 0.3989845216f, 0.4595173299f, }, + { 0.1566463709f, 0.0086835399f, 0.4000524879f, 0.8635722995f, 0.9393525720f, }, + { 0.2184841931f, 0.4614948928f, 0.2673926055f, 0.1875871122f, 0.7921754122f, }, + { 0.2353162766f, 0.5879690051f, 0.2635296285f, 0.8797479272f, 0.2997823358f, }, + { 0.9490447044f, 0.2076890171f, 0.4010803103f, 0.1394627690f, 0.6628655791f, }, + { 0.2707166076f, 0.7822429538f, 0.6469106078f, 0.0504862033f, 0.1232508495f, }, + { 0.6208113432f, 0.5297733545f, 0.4315978289f, 0.7746199965f, 0.9176148176f, }, + { 0.5735706687f, 0.8824555874f, 0.8449642062f, 0.7323825955f, 0.6090137362f, }, + { 0.6787286401f, 0.1138057783f, 0.6691028476f, 0.8794246316f, 0.9944544435f, }, + { 0.9590182304f, 0.7599397302f, 0.4360883832f, 0.4345399737f, 0.3566042483f, }, + { 0.5040525198f, 0.2876239717f, 0.8192380667f, 0.8512843251f, 0.6990298629f, }, + { 0.2681503594f, 0.2776573300f, 0.6658552885f, 0.2643640041f, 0.0171834268f, }, + { 0.9907699823f, 0.3918241262f, 0.3559646606f, 0.0335422903f, 0.4839356244f, }, + { 0.0600461066f, 0.8556994200f, 0.9708179832f, 0.2128672898f, 0.5060029030f, }, + { 0.8269757032f, 0.5930796862f, 0.4295219481f, 0.6134305000f, 0.2837088406f, }, + { 0.1868558377f, 0.2195377052f, 0.9196808934f, 0.6145523190f, 0.0224817824f, }, + { 0.1637152284f, 0.1638418883f, 0.8936216235f, 0.1830255538f, 0.3708207607f, }, + { 0.6877121329f, 0.4648887813f, 0.1414472908f, 0.4056530297f, 0.9507917166f, }, + { 0.6584733129f, 0.3516145647f, 0.8184752464f, 0.4552969933f, 0.8712670207f, }, + { 0.4879920185f, 0.0632367358f, 0.9106399417f, 0.6763438582f, 0.2545655966f, }, + { 0.3354371488f, 0.6134999990f, 0.7193791270f, 0.2599480450f, 0.6374192834f, }, + { 0.5459974408f, 0.3083664477f, 0.2264615297f, 0.6127052307f, 0.5290982723f, }, + { 0.1375788748f, 0.7831102610f, 0.6753757596f, 0.3794361949f, 0.9984954596f, }, + { 0.8989933133f, 0.6260385513f, 0.1556160003f, 0.6783794761f, 0.6539263129f, }, + { 0.0100090979f, 0.2173147351f, 0.6651876569f, 0.8369060159f, 0.8341432214f, }, + { 0.7952558994f, 0.4205495715f, 0.1869979799f, 0.5214561820f, 0.7868866920f, }, + { 0.4268647730f, 0.9521651268f, 0.6465340257f, 0.3335846066f, 0.0395368077f, }, + { 0.4426506758f, 0.6929479241f, 0.9862581491f, 0.7791219354f, 0.6375953555f, }, + { 0.7470532060f, 0.3558909297f, 0.4302069545f, 0.6914501786f, 0.5334445238f, }, + { 0.7177165747f, 0.4723176956f, 0.3912888765f, 0.8674814701f, 0.0588688217f, }, + { 0.1745981872f, 0.9388600588f, 0.9075108767f, 0.1771204025f, 0.8766767383f, }, + { 0.7872450352f, 0.9876473546f, 0.9102281332f, 0.0356241427f, 0.0852076039f, }, + { 0.1130689159f, 0.2634152472f, 0.8666511774f, 0.5163245201f, 0.9000962377f, }, + { 0.3857123554f, 0.0012086437f, 0.7136164904f, 0.7027332187f, 0.4787892103f, }, + { 0.2255398631f, 0.9207963347f, 0.3938958645f, 0.5700179338f, 0.1459939331f, }, + { 0.3002436459f, 0.3815087080f, 0.1841450483f, 0.9755260944f, 0.2721963823f, }, + { 0.7860645056f, 0.7627891302f, 0.1462470591f, 0.5796475410f, 0.9866490364f, }, + { 0.2338331044f, 0.6083744168f, 0.7401463389f, 0.6418339610f, 0.1436904520f, }, + { 0.6205012798f, 0.6930510998f, 0.3980046809f, 0.7106813192f, 0.6699492931f, }, + { 0.7765457630f, 0.3283892870f, 0.9113801718f, 0.4589560628f, 0.4300134182f, }, + { 0.3934683502f, 0.1645728201f, 0.8604982495f, 0.8263462782f, 0.3688060939f, }, + { 0.3331750631f, 0.7786345482f, 0.8378946781f, 0.5906920433f, 0.6261325479f, }, + { 0.5661553741f, 0.0168611892f, 0.1579812914f, 0.5492501259f, 0.1289457828f, }, + { 0.7631620169f, 0.4299164712f, 0.7248778343f, 0.8724287748f, 0.7588217854f, }, + { 0.4151751101f, 0.2290642858f, 0.8302940130f, 0.2409950495f, 0.8310200572f, }, + { 0.3934896886f, 0.1056550518f, 0.7282423377f, 0.8008365035f, 0.3993280828f, }, + { 0.6416932940f, 0.8496999741f, 0.1698106676f, 0.2010347843f, 0.3334994018f, }, + { 0.9605640173f, 0.6602769494f, 0.1665142179f, 0.9381275773f, 0.3133260608f, }, + { 0.6109694839f, 0.7216079831f, 0.2165700942f, 0.3999683261f, 0.7567145228f, }, + { 0.2962780595f, 0.0435902178f, 0.4306307137f, 0.3411400318f, 0.8858901262f, }, + { 0.8652980328f, 0.1155079082f, 0.8249346614f, 0.0917863026f, 0.7120097876f, }, + { 0.5722182393f, 0.2111754119f, 0.1511156708f, 0.7542660832f, 0.8388788104f, }, + { 0.2662346661f, 0.4258652329f, 0.6677465439f, 0.0139555167f, 0.0004739496f, }, + { 0.7597358823f, 0.7892562151f, 0.6452015042f, 0.4347984195f, 0.6189417839f, }, + { 0.2430407703f, 0.9443444014f, 0.1519926041f, 0.7088004351f, 0.5980795026f, }, + { 0.6512131691f, 0.3345483243f, 0.9272377491f, 0.4298903942f, 0.2581492662f, }, + { 0.7997309566f, 0.8973907828f, 0.5888721943f, 0.3186417818f, 0.0904048309f, }, + { 0.3913720250f, 0.7918083072f, 0.8923842311f, 0.8701627254f, 0.7434403896f, }, + { 0.0905955732f, 0.4714503586f, 0.4493075013f, 0.0799918622f, 0.1845664531f, }, + { 0.6881728172f, 0.3358751535f, 0.4706131816f, 0.7471582294f, 0.9739037156f, }, + { 0.1017585918f, 0.4079837799f, 0.9391186237f, 0.9765675068f, 0.0263471883f, }, + { 0.6413670182f, 0.2973709404f, 0.5145442486f, 0.8976982236f, 0.5243280530f, }, + { 0.1422182322f, 0.7193863988f, 0.7368603349f, 0.9693444967f, 0.6586734653f, }, + { 0.6579256654f, 0.6502546072f, 0.1010703519f, 0.5885951519f, 0.5621953011f, }, + { 0.1680923849f, 0.5930988193f, 0.6734765172f, 0.1098441258f, 0.8375173211f, }, + { 0.6467688680f, 0.4310235977f, 0.4349831641f, 0.5390320420f, 0.3829804361f, }, + { 0.6328964829f, 0.2367146462f, 0.5631510615f, 0.9513992071f, 0.8278053999f, }, + { 0.6178335547f, 0.2708016634f, 0.9486758113f, 0.2614699900f, 0.5559518933f, }, + { 0.8066895008f, 0.6080886722f, 0.6698721051f, 0.4653573334f, 0.7357473969f, }, + { 0.2607144713f, 0.8500569463f, 0.9294748902f, 0.1860525012f, 0.2754299045f, }, + { 0.3034132123f, 0.6319553256f, 0.9066848755f, 0.7306192517f, 0.8249600530f, }, + { 0.5916018486f, 0.2015920728f, 0.8553565145f, 0.7298870087f, 0.2292208374f, }, + { 0.4898203015f, 0.0343113467f, 0.3411170542f, 0.2187033147f, 0.1873072982f, }, + { 0.0390702896f, 0.1601516157f, 0.3303611577f, 0.4489412904f, 0.4218544662f, }, + { 0.2624753118f, 0.6617366672f, 0.9006288052f, 0.2701307535f, 0.2544170916f, }, + { 0.9371020198f, 0.8970537782f, 0.7438231707f, 0.7882292271f, 0.9120438099f, }, + { 0.3836613595f, 0.6246667504f, 0.7484745383f, 0.3733002543f, 0.8213787079f, }, + { 0.6606358886f, 0.1194297746f, 0.1390251815f, 0.0641699359f, 0.5383107662f, }, + { 0.6989690065f, 0.6185290217f, 0.6464617252f, 0.6420792937f, 0.3911742866f, }, + { 0.7028435469f, 0.3800960779f, 0.8826861978f, 0.0952752978f, 0.9624297619f, }, + { 0.8092130423f, 0.1167537272f, 0.3588655591f, 0.7875123620f, 0.1900581270f, }, + { 0.3969855309f, 0.6713926792f, 0.3758267760f, 0.9156392813f, 0.2398073077f, }, + { 0.6433664560f, 0.1709136367f, 0.1411291361f, 0.5585072637f, 0.8004847169f, }, + { 0.7030475736f, 0.0948406160f, 0.4112376273f, 0.1812635958f, 0.5112304091f, }, + { 0.9566822052f, 0.0574831404f, 0.4228295088f, 0.6620184779f, 0.8219641447f, }, + { 0.4642787278f, 0.8152669668f, 0.0818825886f, 0.0987984538f, 0.2002992034f, }, + { 0.6733680367f, 0.5868890285f, 0.9167151451f, 0.1864406765f, 0.8994914889f, }, + { 0.8071336150f, 0.3371865749f, 0.4333070219f, 0.0850254670f, 0.6565349698f, }, + { 0.3711113334f, 0.3182538450f, 0.8911077380f, 0.1244663969f, 0.1738931388f, }, + { 0.5745149851f, 0.6362468600f, 0.4004335403f, 0.2862538397f, 0.8227635026f, }, + { 0.3641233444f, 0.3736288249f, 0.7244967818f, 0.9711794257f, 0.2511951029f, }, + { 0.9590284228f, 0.3837921917f, 0.2047621608f, 0.4209816754f, 0.4912522435f, }, + { 0.3666148186f, 0.4686942399f, 0.8263337612f, 0.8343328238f, 0.1030248851f, }, + { 0.0634138510f, 0.7966393232f, 0.9208257794f, 0.8128236532f, 0.6137861013f, }, + { 0.7312135696f, 0.6441291571f, 0.8222352266f, 0.9601475000f, 0.1931410730f, }, + { 0.8020985126f, 0.8420400620f, 0.1575811058f, 0.2407231480f, 0.5854346752f, }, + { 0.6898014545f, 0.9830086827f, 0.5120115876f, 0.1920706928f, 0.0139490385f, }, + { 0.0747568533f, 0.3444298506f, 0.4224318862f, 0.2494165450f, 0.2130750567f, }, + { 0.8533776402f, 0.4178678393f, 0.4339362383f, 0.0111655975f, 0.8133564591f, }, + { 0.6119635701f, 0.0685145333f, 0.6695259809f, 0.2546260953f, 0.8285387158f, }, + { 0.3128049970f, 0.7133177519f, 0.3334894180f, 0.5241565704f, 0.0107328463f, }, + { 0.3183773458f, 0.3350363076f, 0.2044413835f, 0.2082778066f, 0.6074838042f, }, + { 0.2767891586f, 0.8898346424f, 0.6261834502f, 0.6542112231f, 0.8752353787f, }, + { 0.8254892826f, 0.7045267224f, 0.1614680290f, 0.4182889163f, 0.0221087150f, }, + { 0.1131518707f, 0.5885184407f, 0.7256597281f, 0.0343230143f, 0.8792519569f, }, + { 0.8066859841f, 0.1908041388f, 0.9513005018f, 0.7850510478f, 0.4657150507f, }, + { 0.5251334906f, 0.3207691312f, 0.5975010395f, 0.6800830364f, 0.2313966155f, }, + { 0.1338473260f, 0.2152001560f, 0.1785591096f, 0.0999648795f, 0.9366772771f, }, + { 0.5005745292f, 0.8090450764f, 0.1758912057f, 0.7367401719f, 0.3668246865f, }, + { 0.4100497663f, 0.2929191887f, 0.8173804283f, 0.9562621117f, 0.9764734507f, }, + { 0.4828430712f, 0.7929611802f, 0.8903346062f, 0.3020727634f, 0.4421176910f, }, + { 0.5683522820f, 0.7277359962f, 0.4031055272f, 0.8243548870f, 0.8226563334f, }, + { 0.6432737708f, 0.6184990406f, 0.1030192897f, 0.6947470903f, 0.3996037543f, }, + { 0.5164917707f, 0.2604589164f, 0.3293188214f, 0.6517642736f, 0.2140082717f, }, + { 0.5220531225f, 0.9566025734f, 0.3867221773f, 0.4390546679f, 0.5610719919f, }, + { 0.0391775891f, 0.6922944784f, 0.4326307774f, 0.2539777458f, 0.7005180120f, }, + { 0.2863841653f, 0.7115677595f, 0.2580014765f, 0.5631929040f, 0.7391983867f, }, + { 0.0284078829f, 0.0109637557f, 0.4719158411f, 0.9242167473f, 0.0944740772f, }, + { 0.6865310669f, 0.8619411588f, 0.1601572484f, 0.7063269019f, 0.9508878589f, }, + { 0.1181359291f, 0.9085135460f, 0.9176949859f, 0.3647930622f, 0.5507701039f, }, + { 0.8933278322f, 0.0304874647f, 0.6367725730f, 0.3497382700f, 0.9845890999f, }, + { 0.2813156545f, 0.5406025648f, 0.6808233261f, 0.6041739583f, 0.3164665699f, }, + { 0.5587679744f, 0.2653927803f, 0.9062872529f, 0.6394948363f, 0.5580250025f, }, + { 0.5873030424f, 0.4647721946f, 0.1778300405f, 0.4564669430f, 0.2894083858f, }, + { 0.0513518043f, 0.3682755530f, 0.9402056336f, 0.8427602649f, 0.0494848564f, }, + { 0.9241726398f, 0.8340312839f, 0.9196015596f, 0.3041978180f, 0.2783410251f, }, + { 0.5432807207f, 0.0412899218f, 0.9308462739f, 0.0627118871f, 0.7068531513f, }, + { 0.7357839346f, 0.4832003117f, 0.1682239175f, 0.5368898511f, 0.2093475908f, }, + { 0.5198550224f, 0.1553333700f, 0.4974581599f, 0.9676081538f, 0.8497615457f, }, + { 0.9911837578f, 0.5660502315f, 0.7206923366f, 0.7096755505f, 0.1248403564f, }, + { 0.8108434081f, 0.4490055740f, 0.4308193028f, 0.6498060822f, 0.4099439085f, }, + { 0.0305016227f, 0.4160023630f, 0.7270969152f, 0.6877042055f, 0.2469553053f, }, + { 0.8816401958f, 0.3038872778f, 0.9122524261f, 0.1799594462f, 0.6789157391f, }, + { 0.7397534847f, 0.8676870465f, 0.1907271743f, 0.2236480266f, 0.9832514524f, }, + { 0.5055263042f, 0.9711384773f, 0.5652813911f, 0.6370265484f, 0.1825530380f, }, + { 0.8266869783f, 0.4781101942f, 0.9109632373f, 0.4680729210f, 0.3929909766f, }, + { 0.6008589268f, 0.8158760071f, 0.9320793748f, 0.7751792669f, 0.3289398551f, }, + { 0.9922301769f, 0.0912288204f, 0.1703053415f, 0.4577171803f, 0.1787350327f, }, + { 0.9380621910f, 0.4138315022f, 0.5861997604f, 0.2016209513f, 0.9696668386f, }, + { 0.6058498621f, 0.3870098889f, 0.7085344195f, 0.3498209119f, 0.8449696898f, }, + { 0.1842520237f, 0.2444705516f, 0.1938156784f, 0.1163077801f, 0.7499436140f, }, + { 0.2309927940f, 0.6426023245f, 0.5831053257f, 0.8690395951f, 0.6308158040f, }, + { 0.9240636230f, 0.2654021084f, 0.6425374150f, 0.7697630525f, 0.5416702032f, }, + { 0.6263902783f, 0.5082946420f, 0.2389313430f, 0.2679293454f, 0.6879761219f, }, + { 0.6314243674f, 0.0733269751f, 0.8547760844f, 0.4395237565f, 0.1854390651f, }, + { 0.7209459543f, 0.1856156737f, 0.3298576474f, 0.1205248684f, 0.7189801931f, }, + { 0.8141445518f, 0.8007050753f, 0.8076544404f, 0.5967723131f, 0.8467640877f, }, + { 0.9726544023f, 0.7290840149f, 0.6843637824f, 0.9106625915f, 0.8134277463f, }, + { 0.8635859489f, 0.3311145902f, 0.6779747605f, 0.5588562489f, 0.1384872645f, }, + { 0.2485618293f, 0.2972164750f, 0.9278965592f, 0.8001593947f, 0.9885622263f, }, + { 0.0369857028f, 0.1422076225f, 0.5633337498f, 0.1424964666f, 0.7102304101f, }, + { 0.8189394474f, 0.9962999225f, 0.2269549221f, 0.3746351898f, 0.5649494529f, }, + { 0.3327106535f, 0.5111281276f, 0.7147293687f, 0.5896724463f, 0.1772960871f, }, + { 0.0696003288f, 0.2868678570f, 0.4734672606f, 0.3201722503f, 0.8205572367f, }, + { 0.6493142247f, 0.5078513622f, 0.1021946296f, 0.5274136066f, 0.4142716825f, }, + { 0.0141518442f, 0.4787433147f, 0.6653147936f, 0.8284615874f, 0.3456978202f, }, + { 0.2655246556f, 0.5080031753f, 0.9325185418f, 0.4208618104f, 0.0506246462f, }, + { 0.3445186615f, 0.8642750382f, 0.1808891147f, 0.4670973718f, 0.2968982756f, }, + { 0.0686587915f, 0.9685654640f, 0.0809030086f, 0.8395389318f, 0.3273274601f, }, + { 0.0880047157f, 0.1903434992f, 0.4982347488f, 0.1346488297f, 0.4266943634f, }, + { 0.6035117507f, 0.0966935828f, 0.1300992370f, 0.9324336648f, 0.0297081880f, }, + { 0.1309058964f, 0.3857354224f, 0.4325630069f, 0.0283364169f, 0.5884478688f, }, + { 0.0347402692f, 0.2881790996f, 0.1613280624f, 0.1500120312f, 0.5497354865f, }, + { 0.0285012387f, 0.0389477536f, 0.3889817297f, 0.8007153273f, 0.5705042481f, }, + { 0.2659349740f, 0.0010570318f, 0.1609654278f, 0.1462721825f, 0.2926569581f, }, + { 0.2858861685f, 0.5125892162f, 0.3573589921f, 0.8156566620f, 0.7254964113f, }, + { 0.7005371451f, 0.8094868064f, 0.6454237103f, 0.9892581105f, 0.2908501625f, }, + { 0.1424738616f, 0.7378989458f, 0.0941486955f, 0.4891970158f, 0.9065564871f, }, + { 0.4339940846f, 0.0668817908f, 0.9380901456f, 0.9236553311f, 0.6359699965f, }, + { 0.5167078972f, 0.5582013130f, 0.4722582698f, 0.1355872601f, 0.8772071004f, }, + { 0.8593617082f, 0.6964372993f, 0.4334558249f, 0.7329850793f, 0.5092103481f, }, + { 0.1499313265f, 0.6627041101f, 0.1942798495f, 0.8556510210f, 0.1749084294f, }, + { 0.2495054752f, 0.7571764588f, 0.4111095667f, 0.8502652645f, 0.8892777562f, }, + { 0.5684210658f, 0.6993981600f, 0.3964086771f, 0.3613114655f, 0.5198419690f, }, + { 0.7356907129f, 0.9176354408f, 0.0956576690f, 0.7030841112f, 0.2986163199f, }, + { 0.4681179225f, 0.0725374371f, 0.6352795959f, 0.6171233058f, 0.6124462485f, }, + { 0.2037614733f, 0.2117670327f, 0.8531679511f, 0.8580448627f, 0.5006189346f, }, + { 0.4058943093f, 0.4722923934f, 0.6105757952f, 0.8744378090f, 0.9505182505f, }, + { 0.1943543851f, 0.1816507280f, 0.1669910997f, 0.0268503428f, 0.9527678490f, }, + { 0.2039880008f, 0.8487119079f, 0.1559415609f, 0.1029749215f, 0.4526468217f, }, + { 0.2616906762f, 0.6895283461f, 0.9826630950f, 0.3306657672f, 0.9354221225f, }, + { 0.5582979321f, 0.5344530344f, 0.6940716505f, 0.4938591719f, 0.0580471046f, }, + { 0.6556633115f, 0.7009186745f, 0.0863900259f, 0.4495719671f, 0.8028429747f, }, + { 0.4457241297f, 0.9321414828f, 0.4026821554f, 0.8325545192f, 0.7769343853f, }, + { 0.3827864826f, 0.8611300588f, 0.1701369584f, 0.0021155092f, 0.2999592125f, }, + { 0.8664929271f, 0.8345423341f, 0.1517637521f, 0.7718462944f, 0.3676919937f, }, + { 0.0870517269f, 0.0474235229f, 0.4385928214f, 0.9065920115f, 0.4381890893f, }, + { 0.6570346355f, 0.5300208330f, 0.3139534593f, 0.0058077499f, 0.9511523247f, }, + { 0.2700853050f, 0.5979244709f, 0.9125925303f, 0.9729918838f, 0.6157622337f, }, + { 0.9815089107f, 0.1436649263f, 0.3338150978f, 0.4791634679f, 0.3831810951f, }, + { 0.4124719203f, 0.7307018638f, 0.8332329988f, 0.7855702043f, 0.0048999563f, }, + { 0.4295491874f, 0.6549654007f, 0.2341672331f, 0.8596075177f, 0.0836934224f, }, + { 0.9341716170f, 0.8679772615f, 0.4342018962f, 0.4922784269f, 0.9355442524f, }, + { 0.2842322290f, 0.2937251925f, 0.1297459006f, 0.2162142843f, 0.4766207635f, }, + { 0.0687699541f, 0.4193355739f, 0.1604968458f, 0.2525405586f, 0.3903907835f, }, + { 0.3836767077f, 0.0303397048f, 0.9095519185f, 0.8019656539f, 0.0196414758f, }, + { 0.4093062878f, 0.2114653438f, 0.9183588028f, 0.9276442528f, 0.5029817820f, }, + { 0.4427781999f, 0.0913025662f, 0.1694462895f, 0.6199722886f, 0.0954813659f, }, + { 0.7222938538f, 0.4514240324f, 0.6676730514f, 0.8516663909f, 0.6568403840f, }, + { 0.8855976462f, 0.5578103065f, 0.4024848044f, 0.6999971867f, 0.6150228381f, }, + { 0.0558919497f, 0.0335506909f, 0.6883626580f, 0.4106868505f, 0.3968059719f, }, + { 0.8370631933f, 0.7725564837f, 0.1515578181f, 0.1355218887f, 0.0965696499f, }, + { 0.2061236054f, 0.6590722203f, 0.6921544075f, 0.2580949962f, 0.1657614261f, }, + { 0.4687497914f, 0.4069403410f, 0.4022993147f, 0.7116939425f, 0.5114153028f, }, + { 0.1530843526f, 0.9127361774f, 0.4781102538f, 0.9606519938f, 0.4396675825f, }, + { 0.3828580379f, 0.9808019400f, 0.1555103660f, 0.3834106922f, 0.7655656934f, }, + { 0.6892883182f, 0.2358525991f, 0.8080509305f, 0.2543847859f, 0.4141985178f, }, + { 0.5237630010f, 0.3927200437f, 0.8692634106f, 0.7796307802f, 0.5972532630f, }, + { 0.3918390572f, 0.7336037159f, 0.6449653506f, 0.5304521918f, 0.3729677498f, }, + { 0.5095614195f, 0.0340902284f, 0.4854550958f, 0.3145000041f, 0.6774025559f, }, + { 0.6864208579f, 0.3714465499f, 0.6128278375f, 0.0291901436f, 0.5145798922f, }, + { 0.5950428843f, 0.8980699778f, 0.6679940820f, 0.1750890762f, 0.7357109189f, }, + { 0.9596466422f, 0.7845094800f, 0.9358209372f, 0.1966813803f, 0.7135280967f, }, + { 0.5178008080f, 0.0173361078f, 0.6123137474f, 0.6547294855f, 0.4717650414f, }, + { 0.3369775116f, 0.7588766813f, 0.2113792002f, 0.4504565001f, 0.9997866154f, }, + { 0.9297376275f, 0.9543070197f, 0.0810764581f, 0.7182134390f, 0.9580960274f, }, + { 0.3335441649f, 0.6319159865f, 0.1744812578f, 0.7624543309f, 0.1609711796f, }, + { 0.0907729939f, 0.9155431390f, 0.1144289672f, 0.7248440385f, 0.6789140701f, }, + { 0.6996889114f, 0.4020989537f, 0.2669022977f, 0.5844626427f, 0.1348224580f, }, + { 0.8918195367f, 0.3656269610f, 0.4345599413f, 0.1545763612f, 0.0310143251f, }, + { 0.8769407272f, 0.6558710337f, 0.6811839342f, 0.4751150310f, 0.8751748204f, }, + { 0.2593674958f, 0.5370489955f, 0.0872693956f, 0.8934871554f, 0.4328126311f, }, + { 0.4056480229f, 0.8251649141f, 0.8240369558f, 0.7671280503f, 0.4962546229f, }, + { 0.8575278521f, 0.3483728468f, 0.1870178878f, 0.8497405052f, 0.3999809623f, }, + { 0.8633293509f, 0.8636456132f, 0.8893032074f, 0.1341328174f, 0.2871872187f, }, + { 0.7100675106f, 0.8871203661f, 0.9068968892f, 0.0692605898f, 0.6812825799f, }, + { 0.9397863746f, 0.1812347472f, 0.7493067384f, 0.4513051212f, 0.2774569094f, }, + { 0.6819339991f, 0.8018819690f, 0.1597965062f, 0.1734782755f, 0.0756019801f, }, + { 0.3288019896f, 0.8074708581f, 0.3977744281f, 0.4172227979f, 0.3795339465f, }, + { 0.5714755654f, 0.3786454797f, 0.1577659249f, 0.8111919761f, 0.0794956163f, }, + { 0.8613734841f, 0.5612139106f, 0.2668287456f, 0.2859205902f, 0.6378533840f, }, + { 0.7570714355f, 0.2645949125f, 0.3640748262f, 0.7036595345f, 0.3899216950f, }, + { 0.8352665305f, 0.3902190626f, 0.9257256389f, 0.8727458119f, 0.2317052633f, }, + { 0.5590778589f, 0.6693051457f, 0.8371434808f, 0.3273995221f, 0.2169155031f, }, + { 0.6425605416f, 0.5820997357f, 0.3529684544f, 0.4491079152f, 0.3503600359f, }, + { 0.4263430536f, 0.3188545406f, 0.3294929862f, 0.6248637438f, 0.7757378817f, }, + { 0.2334027141f, 0.0908245742f, 0.6870774031f, 0.8244200945f, 0.5250817537f, }, + { 0.1963138431f, 0.4380604625f, 0.1462402195f, 0.7965565920f, 0.1289349049f, }, + { 0.7202720046f, 0.9723337293f, 0.7241522074f, 0.8911894560f, 0.1096275747f, }, + { 0.2065416723f, 0.7243855000f, 0.6788081527f, 0.2475246936f, 0.1352874190f, }, + { 0.7407495379f, 0.9530645609f, 0.9872140288f, 0.7841304541f, 0.4368758500f, }, + { 0.3915253282f, 0.5440089703f, 0.8794558048f, 0.8249010444f, 0.6420225501f, }, + { 0.7381120920f, 0.0268214736f, 0.4001717567f, 0.1846323162f, 0.1310052723f, }, + { 0.2781134844f, 0.4566048682f, 0.4801229239f, 0.1882273853f, 0.7020823359f, }, + { 0.2595421672f, 0.0385477692f, 0.7424936891f, 0.8389952779f, 0.3613405526f, }, + { 0.5802870989f, 0.7866603136f, 0.4464701712f, 0.3926239908f, 0.9616327286f, }, + { 0.9162272215f, 0.6212651134f, 0.4366322756f, 0.6135808229f, 0.1274108142f, }, + { 0.5895784497f, 0.2841680646f, 0.4352363348f, 0.7186092734f, 0.0466427058f, }, + { 0.0170223247f, 0.6835466027f, 0.8407039046f, 0.9057896137f, 0.2855497897f, }, + { 0.0934990421f, 0.7450328469f, 0.7398988008f, 0.8828210235f, 0.5230812430f, }, + { 0.2071357518f, 0.0259825513f, 0.6814307570f, 0.0072371885f, 0.3722944856f, }, + { 0.8310766816f, 0.1215560585f, 0.7335487604f, 0.7004206777f, 0.6623370647f, }, + { 0.2583527267f, 0.3123250604f, 0.3474857211f, 0.7388727069f, 0.4073099196f, }, + { 0.7627908587f, 0.1381584555f, 0.6446782351f, 0.9128720760f, 0.7933068871f, }, + { 0.6060509086f, 0.4652822614f, 0.8101439476f, 0.3185670674f, 0.7687624693f, }, + { 0.3617153466f, 0.3912070096f, 0.1838491410f, 0.2410293519f, 0.4311380386f, }, + { 0.2887026966f, 0.9380396605f, 0.3848942220f, 0.1811760962f, 0.5795959234f, }, + { 0.0440914482f, 0.5491430759f, 0.6439480782f, 0.4507356584f, 0.9021841884f, }, + { 0.2087834030f, 0.1570031643f, 0.3838095963f, 0.4434178174f, 0.6896343827f, }, + { 0.6827750206f, 0.0229131542f, 0.8081738949f, 0.3498229682f, 0.6070718169f, }, + { 0.3627763093f, 0.7984055877f, 0.6431685686f, 0.0156709664f, 0.1227724552f, }, + { 0.1833421290f, 0.3576773405f, 0.4977785647f, 0.1026713997f, 0.4667890668f, }, + { 0.4451530576f, 0.5176401138f, 0.3916107416f, 0.0233243480f, 0.0170923267f, }, + { 0.1561067849f, 0.3095591068f, 0.8609610200f, 0.2972145975f, 0.8388962150f, }, + { 0.1897151023f, 0.3870201409f, 0.6429683566f, 0.7384036779f, 0.6419062018f, }, + { 0.2360361814f, 0.7120126486f, 0.8898612261f, 0.4831516445f, 0.6283032298f, }, + { 0.4591472447f, 0.8968883157f, 0.6745625734f, 0.5177986026f, 0.8107450008f, }, + { 0.0418053530f, 0.3063744605f, 0.9330237508f, 0.6453488469f, 0.7959765792f, }, + { 0.6992160082f, 0.9159058332f, 0.6077382565f, 0.6991832256f, 0.9109363556f, }, + { 0.1860307455f, 0.3378934562f, 0.1416852921f, 0.5650724173f, 0.1131229326f, }, + { 0.0440860912f, 0.3396860361f, 0.0867897645f, 0.1091492698f, 0.5744010806f, }, + { 0.4074540436f, 0.0037240139f, 0.6170831323f, 0.6856091619f, 0.2162612975f, }, + { 0.0805536434f, 0.0801788047f, 0.6862949729f, 0.4118176103f, 0.9122155309f, }, + { 0.3419746161f, 0.1241234690f, 0.4353388846f, 0.7382239103f, 0.1663474441f, }, + { 0.8280405402f, 0.3344762325f, 0.8675277233f, 0.3227192760f, 0.5822569728f, }, + { 0.0457978770f, 0.6045931578f, 0.5117643476f, 0.1247794032f, 0.2967178524f, }, + { 0.2074579448f, 0.2794794440f, 0.6748496294f, 0.1948613673f, 0.7756725550f, }, + { 0.9086285830f, 0.4926901758f, 0.8503908515f, 0.2029168159f, 0.2463670224f, }, + { 0.8378603458f, 0.3506077528f, 0.3624764085f, 0.6620461941f, 0.8640121222f, }, + { 0.1357145458f, 0.4835884869f, 0.6683739424f, 0.4699124098f, 0.6225953698f, }, + { 0.3593974411f, 0.5019212961f, 0.9705158472f, 0.0883378386f, 0.2386964858f, }, + { 0.3500095308f, 0.5343665481f, 0.1081044450f, 0.5536872745f, 0.7516261935f, }, + { 0.7465256453f, 0.4513155520f, 0.4694375396f, 0.4306558669f, 0.8469504118f, }, + { 0.9364904761f, 0.2417010963f, 0.7490646243f, 0.5876585841f, 0.8733353615f, }, + { 0.3128331900f, 0.4122265279f, 0.6989183426f, 0.5105266571f, 0.0535654910f, }, + { 0.8299148679f, 0.0242418945f, 0.9185588956f, 0.2082293928f, 0.9853225350f, }, + { 0.4913113415f, 0.3892986476f, 0.2461258769f, 0.6064926386f, 0.0011067288f, }, + { 0.1212299541f, 0.4731827080f, 0.1531817317f, 0.3342418671f, 0.1954117715f, }, + { 0.4884608090f, 0.5371435881f, 0.0977821499f, 0.2985236943f, 0.4082343280f, }, + { 0.0633486286f, 0.9332410097f, 0.7562658191f, 0.1462827176f, 0.7750024796f, }, + { 0.0652500018f, 0.5739523172f, 0.1544017196f, 0.8901908994f, 0.1490109414f, }, + { 0.6529577971f, 0.8815354109f, 0.3971469700f, 0.2048260272f, 0.3529071212f, }, + { 0.5875724554f, 0.5927085280f, 0.1266954988f, 0.5011879206f, 0.0910030082f, }, + { 0.3343248963f, 0.0334817953f, 0.0805509314f, 0.8500270844f, 0.7750938535f, }, + { 0.8772351742f, 0.4890280366f, 0.1348344982f, 0.6879966259f, 0.0888044313f, }, + { 0.0169989243f, 0.5271959901f, 0.9097088575f, 0.4304543734f, 0.5892828703f, }, + { 0.0050274879f, 0.2732547820f, 0.9790849090f, 0.2645989358f, 0.8380880952f, }, + { 0.1086372435f, 0.3569742739f, 0.9542900920f, 0.7056402564f, 0.7933056355f, }, + { 0.7167707682f, 0.5924938321f, 0.9072985649f, 0.0828848258f, 0.7621644139f, }, + { 0.9772328138f, 0.9469763637f, 0.5058457851f, 0.6289201379f, 0.9255536795f, }, + { 0.7286605835f, 0.2185642123f, 0.7012956738f, 0.2237491608f, 0.4498312175f, }, + { 0.7092302442f, 0.4210345447f, 0.1594479829f, 0.1470935941f, 0.5360107422f, }, + { 0.9316938519f, 0.7837244868f, 0.8694490194f, 0.9044463634f, 0.0385332815f, }, + { 0.9328998923f, 0.5480153561f, 0.8506576419f, 0.3514102697f, 0.3335549533f, }, + { 0.8547057509f, 0.9253229499f, 0.9341187477f, 0.9743441939f, 0.7508043647f, }, + { 0.7718179226f, 0.1569196582f, 0.3478961587f, 0.6710835099f, 0.5593945384f, }, + { 0.2419265062f, 0.7894306779f, 0.1570723206f, 0.5822317600f, 0.5006517172f, }, + { 0.1849822402f, 0.1363085508f, 0.4725027978f, 0.7396745086f, 0.3428977430f, }, + { 0.5591301322f, 0.3199107051f, 0.8089527488f, 0.1712560654f, 0.4394634962f, }, + { 0.4981502891f, 0.4856630862f, 0.2357862145f, 0.2388254106f, 0.0351010896f, }, + { 0.5710847974f, 0.4366464615f, 0.9259338379f, 0.0600329712f, 0.3904333413f, }, + { 0.3421151042f, 0.3157694638f, 0.6413265467f, 0.8104304671f, 0.1200235188f, }, + { 0.0830668062f, 0.8340660930f, 0.5904067159f, 0.7680399418f, 0.8358713388f, }, + { 0.2072685659f, 0.0764363110f, 0.5783915520f, 0.2112138271f, 0.3830709755f, }, + { 0.0601869263f, 0.4537220597f, 0.9657811522f, 0.0833336636f, 0.7259430885f, }, + { 0.4583000541f, 0.0169388577f, 0.5914511681f, 0.5267070532f, 0.4983367622f, }, + { 0.4410881698f, 0.2045338005f, 0.3646363020f, 0.8419033885f, 0.0842576176f, }, + { 0.2401530892f, 0.3547943234f, 0.1362922639f, 0.6588394642f, 0.2725260854f, }, + { 0.4588307142f, 0.4906029701f, 0.5950623751f, 0.9093508124f, 0.4243634641f, }, + { 0.3915193081f, 0.9465374351f, 0.3146939576f, 0.4780483544f, 0.8329492807f, }, + { 0.4906239212f, 0.8728529215f, 0.2367291451f, 0.2351625264f, 0.2028754056f, }, + { 0.0626002252f, 0.2567110062f, 0.9072069526f, 0.8151605129f, 0.3406108320f, }, + { 0.2522044480f, 0.8848261237f, 0.8597984314f, 0.8956258297f, 0.0923095495f, }, + { 0.1891491860f, 0.7724922299f, 0.3699084818f, 0.3637740314f, 0.7616791725f, }, + { 0.8415308595f, 0.4516580701f, 0.3604699373f, 0.3181896508f, 0.0515080169f, }, + { 0.0954457223f, 0.7111102939f, 0.1747000217f, 0.7598531246f, 0.8066273332f, }, + { 0.1647458225f, 0.3623113036f, 0.3150498569f, 0.0163353235f, 0.0543379560f, }, + { 0.5891324282f, 0.3966631889f, 0.4356934726f, 0.6271911860f, 0.5625494719f, }, + { 0.8452944160f, 0.8934851885f, 0.3968222737f, 0.2144815773f, 0.6305014491f, }, + { 0.7155290246f, 0.8419492245f, 0.4611556232f, 0.9249689579f, 0.7501617670f, }, + { 0.3314435184f, 0.0565125830f, 0.3429313600f, 0.1730042398f, 0.2751477659f, }, + { 0.4938989282f, 0.3394090831f, 0.4372532964f, 0.8817516565f, 0.5378986001f, }, + { 0.4269252121f, 0.1613788009f, 0.1004349068f, 0.9144166708f, 0.0614690818f, }, + { 0.4175069630f, 0.8081547022f, 0.6270828247f, 0.0731840953f, 0.3279313743f, }, + { 0.1751840413f, 0.9850287437f, 0.8896231055f, 0.1453721374f, 0.1949591488f, }, + { 0.2354125381f, 0.5136641860f, 0.6115352511f, 0.3465471566f, 0.8145347238f, }, + { 0.5760233402f, 0.3436267972f, 0.3959923983f, 0.4955920577f, 0.3700324595f, }, + { 0.9119005799f, 0.0870294422f, 0.9118932486f, 0.7905231714f, 0.6448101997f, }, + { 0.7781744599f, 0.6675111651f, 0.9501693845f, 0.8006697297f, 0.1772782207f, }, + { 0.3519862890f, 0.4575143456f, 0.2463920265f, 0.0222055502f, 0.8029623032f, }, + { 0.4388314188f, 0.3895507455f, 0.8272166848f, 0.0712227970f, 0.0086836871f, }, + { 0.0583382100f, 0.5208097696f, 0.4368227422f, 0.3917193711f, 0.2425224781f, }, + { 0.0425471961f, 0.5299252272f, 0.2650638521f, 0.8536900878f, 0.4376364052f, }, + { 0.2677355111f, 0.0842754617f, 0.9467958212f, 0.7181984782f, 0.8604565859f, }, + { 0.4427039623f, 0.9674515724f, 0.2147976309f, 0.0458503179f, 0.2609435022f, }, + { 0.6098490357f, 0.0492365733f, 0.9763779044f, 0.7538525462f, 0.2662951946f, }, + { 0.1765021980f, 0.6485223770f, 0.9113210440f, 0.9639800787f, 0.1664206088f, }, + { 0.7312519550f, 0.8011575341f, 0.1750256270f, 0.1216477081f, 0.0419374555f, }, + { 0.8335712552f, 0.1575871557f, 0.7052847743f, 0.2843056321f, 0.3427282274f, }, + { 0.6447112560f, 0.8313282132f, 0.7289963365f, 0.7704250813f, 0.9594829679f, }, + { 0.3326021433f, 0.6668556929f, 0.3947283626f, 0.4203561842f, 0.6810554862f, }, + { 0.2593998611f, 0.8157794476f, 0.8850485682f, 0.4403123558f, 0.1217138544f, }, + { 0.2663836777f, 0.1377358437f, 0.5714122057f, 0.7233152390f, 0.9704425931f, }, + { 0.3707490265f, 0.8292267323f, 0.6394523978f, 0.9205230474f, 0.0151811857f, }, + { 0.7781304121f, 0.4585623443f, 0.1551069915f, 0.5581462383f, 0.7087328434f, }, + { 0.3037422001f, 0.7703436613f, 0.1191074178f, 0.5610741973f, 0.2212775201f, }, + { 0.2266217172f, 0.3249739408f, 0.1444245726f, 0.4954843521f, 0.4883134663f, }, + { 0.0165311620f, 0.7669098377f, 0.4550737739f, 0.4728942215f, 0.3186995387f, }, + { 0.9998926520f, 0.8258782029f, 0.7184599042f, 0.8980119228f, 0.4501090050f, }, + { 0.7367163301f, 0.2032585442f, 0.5111448765f, 0.4004929960f, 0.0225323737f, }, + { 0.0493962578f, 0.9443931580f, 0.2091137022f, 0.5240599513f, 0.8398843408f, }, + { 0.6376557350f, 0.1873658895f, 0.7559183240f, 0.9759896994f, 0.5703735352f, }, + { 0.0628793016f, 0.5546751618f, 0.4501508772f, 0.2687877715f, 0.7107744217f, }, + { 0.2857188284f, 0.7967153192f, 0.2016096711f, 0.9645403624f, 0.8644922972f, }, + { 0.8842019439f, 0.1875291765f, 0.3322648108f, 0.4761361182f, 0.3367213607f, }, + { 0.7613025904f, 0.8173988461f, 0.0989113450f, 0.6687331200f, 0.9080137610f, }, + { 0.9667162895f, 0.6956284642f, 0.8096591234f, 0.8457599282f, 0.6717919111f, }, + { 0.8705635667f, 0.9489148259f, 0.6710203886f, 0.3002463579f, 0.2998501360f, }, + { 0.3160033822f, 0.6578463912f, 0.6006550193f, 0.0363289751f, 0.9943091273f, }, + { 0.1890118122f, 0.0703749657f, 0.3407917619f, 0.5849888325f, 0.3387600482f, }, + { 0.4162254632f, 0.9856636524f, 0.9276933670f, 0.8593608141f, 0.9642176032f, }, + { 0.4634823203f, 0.5592925549f, 0.8305687904f, 0.4186003804f, 0.8516093493f, }, + { 0.9270362854f, 0.3840446472f, 0.0739694536f, 0.7066030502f, 0.2068160474f, }, + { 0.5414479375f, 0.7055885196f, 0.6389597058f, 0.8722547889f, 0.4726699889f, }, + { 0.0565524362f, 0.6615542173f, 0.6320179701f, 0.3033626676f, 0.3720220625f, }, + { 0.5759089589f, 0.1501083821f, 0.4762971103f, 0.9857511520f, 0.7193703055f, }, + { 0.9492504001f, 0.3415102065f, 0.3943712413f, 0.7835905552f, 0.9502909780f, }, + { 0.1891704500f, 0.2711829245f, 0.4374268651f, 0.7912049890f, 0.8699505925f, }, + { 0.6306788921f, 0.8195926547f, 0.8105173111f, 0.2698025405f, 0.0511786118f, }, + { 0.6671817303f, 0.2733749449f, 0.4416516423f, 0.1568770707f, 0.0450827479f, }, + { 0.2075933069f, 0.5332290530f, 0.6865766644f, 0.3394750357f, 0.2891942859f, }, + { 0.8160287738f, 0.0811059102f, 0.0933496207f, 0.3262147307f, 0.1257323325f, }, + { 0.8794260025f, 0.2458494306f, 0.3873524368f, 0.2770903409f, 0.8134116530f, }, + { 0.9295834899f, 0.6427857280f, 0.8298889399f, 0.5580617785f, 0.5519288778f, }, + { 0.0379861444f, 0.9809321761f, 0.2174515128f, 0.1686883718f, 0.9292478561f, }, + { 0.8038243055f, 0.2706521451f, 0.1250205636f, 0.1165471673f, 0.0111545036f, }, + { 0.0832745507f, 0.9543334246f, 0.8845676184f, 0.2836107612f, 0.5429202914f, }, + { 0.9929301143f, 0.4784838259f, 0.4672245681f, 0.6021637321f, 0.0531420857f, }, + { 0.8136103153f, 0.8867183924f, 0.1105587557f, 0.9744117856f, 0.2273890078f, }, + { 0.7338820696f, 0.5361839533f, 0.5016311407f, 0.5255926847f, 0.9699062109f, }, + { 0.5812864304f, 0.0696033984f, 0.8309278488f, 0.2830432355f, 0.5610606670f, }, + { 0.8383012414f, 0.5630249977f, 0.3481446207f, 0.8960926533f, 0.5736455321f, }, + { 0.9144532084f, 0.9868558049f, 0.8713914156f, 0.2994676828f, 0.9111017585f, }, + { 0.3667350113f, 0.1784031987f, 0.1360322833f, 0.1677575111f, 0.5294641256f, }, + { 0.8101564646f, 0.4679417312f, 0.5953064561f, 0.0041121347f, 0.8711330891f, }, + { 0.1849019229f, 0.6867338419f, 0.1314645261f, 0.7478774786f, 0.8659111261f, }, + { 0.1300583631f, 0.4138152003f, 0.5927445292f, 0.5115417838f, 0.8252084255f, }, + { 0.8341360092f, 0.9880930781f, 0.9846140146f, 0.7015816569f, 0.0945248976f, }, + { 0.2514465153f, 0.5822964907f, 0.0740369856f, 0.8085967302f, 0.9746395946f, }, + { 0.7712832689f, 0.5332258344f, 0.7056349516f, 0.0089736320f, 0.9124835730f, }, + { 0.7920742035f, 0.5780259967f, 0.8840830326f, 0.9795336127f, 0.3776562214f, }, + { 0.0407537147f, 0.6358982325f, 0.2445732802f, 0.5306778550f, 0.8776224852f, }, + { 0.8776873350f, 0.0425837934f, 0.9779911041f, 0.9589082003f, 0.1079860032f, }, + { 0.4782677293f, 0.1582049429f, 0.2630234063f, 0.8286108375f, 0.5946872234f, }, + { 0.9040866494f, 0.3944332600f, 0.1866375357f, 0.1170084104f, 0.4502029717f, }, + { 0.2786411643f, 0.2126310468f, 0.5640877485f, 0.0811040401f, 0.1173522845f, }, + { 0.0272191558f, 0.9356313944f, 0.9463676810f, 0.1437636763f, 0.0217576530f, }, + { 0.3301321268f, 0.5628141165f, 0.9827442765f, 0.6763537526f, 0.5231515765f, }, + { 0.8283814788f, 0.9153424501f, 0.8565432429f, 0.4869456291f, 0.0976596177f, }, + { 0.0150311012f, 0.7154917717f, 0.1171679199f, 0.6261239648f, 0.2845695615f, }, + { 0.3835113943f, 0.5246586204f, 0.2396226376f, 0.0743172541f, 0.9756772518f, }, + { 0.5552558899f, 0.4920856059f, 0.8595582247f, 0.9239670634f, 0.4855814874f, }, + { 0.0186718721f, 0.3817270994f, 0.1436758935f, 0.7701418400f, 0.0159273893f, }, + { 0.4843561649f, 0.3735987842f, 0.0915456489f, 0.7107504010f, 0.3094100654f, }, + { 0.2103396654f, 0.7813894749f, 0.5958394408f, 0.2775469422f, 0.2737840116f, }, + { 0.4791265428f, 0.9234282970f, 0.1753854305f, 0.9831110835f, 0.6923159361f, }, + { 0.1733113676f, 0.1942755878f, 0.3934293687f, 0.6355052590f, 0.6115870476f, }, + { 0.7110312581f, 0.2632095516f, 0.4379674196f, 0.6868646741f, 0.3348045647f, }, + { 0.0654596910f, 0.1631321460f, 0.9838313460f, 0.7933228612f, 0.8076031804f, }, + { 0.8481760025f, 0.5067156553f, 0.3508308530f, 0.4742254615f, 0.7989317775f, }, + { 0.0746053755f, 0.6456249356f, 0.3222734630f, 0.9467936158f, 0.1122535542f, }, + { 0.3018892109f, 0.2831256390f, 0.3153758049f, 0.2754183114f, 0.8856149912f, }, + { 0.8746976256f, 0.7178336978f, 0.2249367684f, 0.9353727698f, 0.7245397568f, }, + { 0.7894397378f, 0.6409669518f, 0.3924964070f, 0.5909869671f, 0.3518097997f, }, + { 0.6271018386f, 0.8589516878f, 0.9280321002f, 0.7557398081f, 0.2396811247f, }, + { 0.1658686697f, 0.4882411659f, 0.3920782506f, 0.9502453208f, 0.7839587927f, }, + { 0.4287987947f, 0.5076959133f, 0.2041479200f, 0.5182649493f, 0.8606436849f, }, + { 0.4864339232f, 0.4363496006f, 0.9769991040f, 0.1470107883f, 0.2376187444f, }, + { 0.1851831824f, 0.1019903645f, 0.3685579598f, 0.9751429558f, 0.5995606184f, }, + { 0.9943735600f, 0.5076721311f, 0.5937624574f, 0.8511978388f, 0.8245548606f, }, + { 0.3623926640f, 0.1518627405f, 0.9339181185f, 0.6894369125f, 0.9985749722f, }, + { 0.6585057974f, 0.0338354632f, 0.9860187173f, 0.6257272959f, 0.5095349550f, }, + { 0.9617368579f, 0.9781840444f, 0.1751133800f, 0.7549227476f, 0.5547288060f, }, + { 0.0327180512f, 0.0599303208f, 0.4582598805f, 0.1306438744f, 0.1135984883f, }, + { 0.1533396095f, 0.5107070208f, 0.2424806207f, 0.2703402638f, 0.0711744428f, }, + { 0.6802138090f, 0.4304876029f, 0.9608894587f, 0.4107354879f, 0.3658602536f, }, + { 0.5136194825f, 0.1151609868f, 0.3909173310f, 0.7900308371f, 0.3888326585f, }, + { 0.0395116732f, 0.3562890589f, 0.7558521032f, 0.7811126113f, 0.4824492037f, }, + { 0.3559090793f, 0.2841065824f, 0.3907046616f, 0.8769912124f, 0.5726684928f, }, + { 0.3293185234f, 0.5808791518f, 0.2414705455f, 0.5155170560f, 0.1191220358f, }, + { 0.3706066310f, 0.9229975343f, 0.8829728961f, 0.9934974313f, 0.9956690073f, }, + { 0.3080435991f, 0.3201626837f, 0.7061017752f, 0.3680316508f, 0.1773843914f, }, + { 0.6431954503f, 0.6753837466f, 0.4638431370f, 0.1081115827f, 0.8923600316f, }, + { 0.0838319287f, 0.2551401258f, 0.3566832542f, 0.7253879309f, 0.6957392097f, }, + { 0.4831503332f, 0.1040834114f, 0.6730811596f, 0.6486983895f, 0.7294738889f, }, + { 0.6658418775f, 0.2938364744f, 0.5878557563f, 0.3946224749f, 0.4375346303f, }, + { 0.8853557110f, 0.0000372552f, 0.0856423751f, 0.4632995725f, 0.2137127072f, }, + { 0.7650732398f, 0.3130430877f, 0.1070211083f, 0.1473210752f, 0.9530454278f, }, + { 0.5617345572f, 0.9885767102f, 0.3906081617f, 0.4245825410f, 0.4737696946f, }, + { 0.3506936133f, 0.3437172771f, 0.1431273073f, 0.7426561117f, 0.4721824527f, }, + { 0.7624740005f, 0.4083818197f, 0.4430501461f, 0.8167119622f, 0.4418946505f, }, + { 0.3301723599f, 0.3836306036f, 0.9444649816f, 0.4999565184f, 0.5716143250f, }, + { 0.3669410050f, 0.6270698309f, 0.8446861506f, 0.3124131560f, 0.1835474521f, }, + { 0.9047849774f, 0.2396325767f, 0.1429901123f, 0.0389769599f, 0.0502107330f, }, + { 0.8418549299f, 0.8715009689f, 0.6386577487f, 0.9042218924f, 0.8849251270f, }, + { 0.3418840766f, 0.9361316562f, 0.3192526102f, 0.6912338734f, 0.5182607770f, }, + { 0.1899265796f, 0.0173734780f, 0.2089390010f, 0.4606061578f, 0.7150601149f, }, + { 0.5969145894f, 0.8508781195f, 0.9332725406f, 0.9179911613f, 0.9683256745f, }, + { 0.4579477012f, 0.4199973643f, 0.0844962224f, 0.9824535847f, 0.5024600625f, }, + { 0.0237647370f, 0.6078844666f, 0.3199034631f, 0.8134011626f, 0.5628958344f, }, + { 0.9588027596f, 0.2605622709f, 0.8317540884f, 0.7054128051f, 0.4369589388f, }, + { 0.4170838892f, 0.5606330633f, 0.2457968593f, 0.7619985938f, 0.0341589488f, }, + { 0.5006690621f, 0.4155363739f, 0.7130327821f, 0.2712416053f, 0.6648243070f, }, + { 0.5912088156f, 0.3358378112f, 0.5966815352f, 0.6747763753f, 0.8688060641f, }, + { 0.3815539777f, 0.4404865205f, 0.9729708433f, 0.5631290078f, 0.7851571441f, }, + { 0.4995941818f, 0.7379410863f, 0.4381160438f, 0.1947965622f, 0.5504481196f, }, + { 0.3403409719f, 0.6923238039f, 0.1318474412f, 0.6971157789f, 0.5042705536f, }, + { 0.6147609949f, 0.8256763220f, 0.5663008094f, 0.5690183640f, 0.7246423364f, }, + { 0.0324248746f, 0.4992567897f, 0.5960013866f, 0.0469658189f, 0.1898077428f, }, + { 0.8522686958f, 0.6649093628f, 0.9887406826f, 0.0252875052f, 0.6290403008f, }, + { 0.0328523293f, 0.7139846683f, 0.7103829384f, 0.7547162175f, 0.9542254806f, }, + { 0.4170601070f, 0.7140755653f, 0.3330325782f, 0.5456433296f, 0.9399647117f, }, + { 0.7306978106f, 0.5830063820f, 0.6278259754f, 0.7200785279f, 0.2016974986f, }, + { 0.3213150203f, 0.8907136917f, 0.8135768175f, 0.3760290146f, 0.9012579322f, }, + { 0.3641786277f, 0.0825980827f, 0.9283821583f, 0.6921314001f, 0.8686619401f, }, + { 0.1112581566f, 0.7397516966f, 0.5642287731f, 0.4594828188f, 0.5542762280f, }, + { 0.2048978359f, 0.5553704500f, 0.6030684710f, 0.4922237098f, 0.8047754169f, }, + { 0.7408219576f, 0.2340663821f, 0.6029233336f, 0.2060526907f, 0.1866772026f, }, + { 0.2265682518f, 0.2986113727f, 0.4917030334f, 0.2884304523f, 0.2630929351f, }, + { 0.7390643954f, 0.7078934908f, 0.1757444292f, 0.5590769649f, 0.0598539114f, }, + { 0.4706227481f, 0.1923512071f, 0.9459436536f, 0.2502581775f, 0.3539232910f, }, + { 0.7448531985f, 0.6115530729f, 0.3902298212f, 0.5567745566f, 0.6504777670f, }, + { 0.1128614917f, 0.3313013613f, 0.6106067896f, 0.2649244666f, 0.3016350567f, }, + { 0.3085319996f, 0.8217318058f, 0.9789041281f, 0.1459272057f, 0.3668057024f, }, + { 0.8655315638f, 0.1588408500f, 0.5848766565f, 0.9888049960f, 0.0894221961f, }, + { 0.3332826793f, 0.2789309919f, 0.1181809306f, 0.9494949579f, 0.3430446386f, }, + { 0.2062487155f, 0.0432579592f, 0.9632441401f, 0.4702299535f, 0.1169214919f, }, + { 0.5384122133f, 0.6296311617f, 0.6362570524f, 0.0417566597f, 0.5912191272f, }, + { 0.9845989943f, 0.1991962343f, 0.1424074769f, 0.0808833241f, 0.0490931123f, }, + { 0.9592280984f, 0.4744875133f, 0.9286555648f, 0.1063276157f, 0.7112447023f, }, + { 0.0670767874f, 0.2152061015f, 0.3390373588f, 0.8407714367f, 0.4625172913f, }, + { 0.5842505693f, 0.8396597505f, 0.6824946404f, 0.2750900686f, 0.4497860372f, }, + { 0.8813002706f, 0.5115079284f, 0.9452683330f, 0.3588356376f, 0.8357884884f, }, + { 0.8354519606f, 0.1911046505f, 0.8405693173f, 0.5500881672f, 0.1489245892f, }, + { 0.2501815259f, 0.8681357503f, 0.4384571016f, 0.0615533479f, 0.5015689135f, }, + { 0.6131845713f, 0.8447030187f, 0.8690897226f, 0.9871802330f, 0.4340125620f, }, + { 0.9867694974f, 0.9618659019f, 0.3397503197f, 0.3236250579f, 0.1413733661f, }, + { 0.6534880400f, 0.9623055458f, 0.8792701960f, 0.8622050881f, 0.5128693581f, }, + { 0.0369032547f, 0.5767930746f, 0.9628917575f, 0.5522519350f, 0.9288233519f, }, + { 0.2572678030f, 0.5665532351f, 0.8364526033f, 0.6230912805f, 0.5498634577f, }, + { 0.5407697558f, 0.5359740257f, 0.1422781348f, 0.9193217158f, 0.3704392016f, }, + { 0.3856170177f, 0.2676878273f, 0.6280194521f, 0.1544111967f, 0.5832184553f, }, + { 0.1945493519f, 0.3047843277f, 0.4401015043f, 0.8022740483f, 0.0360309221f, }, + { 0.2359977216f, 0.7373479009f, 0.4828464389f, 0.3620660007f, 0.8571884036f, }, + { 0.5318132639f, 0.9350997806f, 0.8570907712f, 0.0008136479f, 0.7000207901f, }, + { 0.8121096492f, 0.3856165111f, 0.4496850073f, 0.0661716536f, 0.6575084925f, }, + { 0.4410060644f, 0.8657597899f, 0.3155948818f, 0.6615034342f, 0.2577296495f, }, + { 0.7420792580f, 0.5577799082f, 0.4389205575f, 0.1031861976f, 0.2608876526f, }, + { 0.7229738832f, 0.7676143646f, 0.7554867864f, 0.2057462782f, 0.6458973885f, }, + { 0.8839143515f, 0.6852776408f, 0.3689500093f, 0.6128994226f, 0.2233593166f, }, + { 0.1574926078f, 0.5333741903f, 0.6326267719f, 0.8821051717f, 0.5588636994f, }, + { 0.5097069144f, 0.1709168106f, 0.9465764761f, 0.4048224092f, 0.7366812825f, }, + { 0.4597676992f, 0.9413823485f, 0.4674285650f, 0.5278868079f, 0.5498680472f, }, + { 0.6697951555f, 0.6220095754f, 0.4390029609f, 0.1852650940f, 0.6468935609f, }, + { 0.9477636814f, 0.8576923609f, 0.6362062693f, 0.8641003966f, 0.1851697266f, }, + { 0.6700004339f, 0.1485266685f, 0.3252539337f, 0.7413428426f, 0.2075637132f, }, + { 0.2519851923f, 0.4584752321f, 0.2663576007f, 0.4554472268f, 0.1294109821f, }, + { 0.5419273376f, 0.4185232520f, 0.3404965997f, 0.4292206168f, 0.0063953195f, }, + { 0.9042156339f, 0.5913402438f, 0.6057822108f, 0.3318530321f, 0.1125598103f, }, + { 0.8107571602f, 0.4140805304f, 0.1248736978f, 0.0863618106f, 0.9532760978f, }, + { 0.4480581284f, 0.6362037063f, 0.1388506293f, 0.8980421424f, 0.4660278261f, }, + { 0.8584802151f, 0.5359734893f, 0.4874933660f, 0.8987547159f, 0.0682118312f, }, + { 0.8878780007f, 0.9740576148f, 0.7552759051f, 0.8526294827f, 0.4248991013f, }, + { 0.3988091350f, 0.5761463642f, 0.9476581812f, 0.8188049793f, 0.5850878358f, }, + { 0.0180105343f, 0.1690450311f, 0.8622763157f, 0.7330220938f, 0.9796077013f, }, + { 0.8889474869f, 0.7919277549f, 0.1122894138f, 0.8653057218f, 0.1189263314f, }, + { 0.4084248245f, 0.2443926930f, 0.7443601489f, 0.5515754223f, 0.7709879875f, }, + { 0.3673099875f, 0.3389573693f, 0.2154583931f, 0.3615200818f, 0.7420564890f, }, + { 0.3151056767f, 0.2117549628f, 0.9700726271f, 0.4528015256f, 0.4639360309f, }, + { 0.7585829496f, 0.0081312750f, 0.0860575661f, 0.9605270028f, 0.5847569704f, }, + { 0.6709223986f, 0.6396714449f, 0.3648293316f, 0.1234715581f, 0.0868903175f, }, + { 0.0644297600f, 0.1366702169f, 0.8287847638f, 0.6706626415f, 0.1918775886f, }, + { 0.1597213596f, 0.6075517535f, 0.4497085512f, 0.5078248978f, 0.3656344712f, }, + { 0.3203390837f, 0.3556327522f, 0.7300463915f, 0.3629629910f, 0.3622173965f, }, + { 0.5749477744f, 0.7641447186f, 0.2175557762f, 0.0997704864f, 0.9750205278f, }, + { 0.6072089672f, 0.2837329507f, 0.7329918742f, 0.5933936238f, 0.5173432231f, }, + { 0.2274439782f, 0.8076895475f, 0.0807430819f, 0.2984331250f, 0.6452993751f, }, + { 0.9948908687f, 0.5898016691f, 0.9900293350f, 0.1963420063f, 0.2902719378f, }, + { 0.2897566557f, 0.1611588597f, 0.9794832468f, 0.0688853338f, 0.1645004451f, }, + { 0.6816020012f, 0.7845854163f, 0.2658532560f, 0.5870781541f, 0.1510099322f, }, + { 0.1010521203f, 0.9625496864f, 0.1306971759f, 0.7898432016f, 0.7819833755f, }, + { 0.4105321467f, 0.7624241114f, 0.3898871839f, 0.2751394510f, 0.1849643886f, }, + { 0.0323388502f, 0.2609303594f, 0.3490280509f, 0.9759741426f, 0.8370570540f, }, + { 0.7335006595f, 0.1259791404f, 0.7148767710f, 0.2044129074f, 0.7900349498f, }, + { 0.5788567662f, 0.9213893414f, 0.4962672591f, 0.7827541828f, 0.2302873284f, }, + { 0.0544130541f, 0.7783476710f, 0.3501540720f, 0.3865097165f, 0.8153201342f, }, + { 0.5859671235f, 0.2365583181f, 0.2372176796f, 0.5250331163f, 0.0443457291f, }, + { 0.8457442522f, 0.6412010789f, 0.2312082946f, 0.2995659709f, 0.1753683835f, }, + { 0.4336808920f, 0.2301672399f, 0.4608553350f, 0.9934188128f, 0.8866185546f, }, + { 0.8231829405f, 0.4947065115f, 0.8329749107f, 0.2581706643f, 0.5288423896f, }, + { 0.7267872691f, 0.6947799921f, 0.6358758211f, 0.3470119536f, 0.9147358537f, }, + { 0.1160683036f, 0.2022097856f, 0.3886943161f, 0.9786373377f, 0.1892386973f, }, + { 0.2845241427f, 0.0562943406f, 0.3672907948f, 0.9900227189f, 0.5833330750f, }, + { 0.1575425267f, 0.9664130807f, 0.3369441330f, 0.5078743696f, 0.8506065011f, }, + { 0.7281443477f, 0.5049641728f, 0.9787535071f, 0.3344016969f, 0.8094183803f, }, + { 0.3837445974f, 0.6564620733f, 0.4685125649f, 0.6480392814f, 0.1251861602f, }, + { 0.0107197817f, 0.1855049580f, 0.4773720205f, 0.1253501624f, 0.5780951977f, }, + { 0.8945932388f, 0.1428237557f, 0.1782084852f, 0.6178655624f, 0.0087716524f, }, + { 0.5825682282f, 0.7363885641f, 0.5880399346f, 0.6319678426f, 0.9568156004f, }, + { 0.4372547567f, 0.4117933214f, 0.9570138454f, 0.4562333226f, 0.0147247240f, }, + { 0.8327901959f, 0.8294945955f, 0.3523861766f, 0.8022853136f, 0.6378967166f, }, + { 0.7279042006f, 0.8972856998f, 0.2499193847f, 0.2757280767f, 0.3737303317f, }, + { 0.4609211087f, 0.3148642778f, 0.9514909983f, 0.3195999563f, 0.0761469752f, }, + { 0.6374220848f, 0.8876250982f, 0.5965381265f, 0.0007383316f, 0.1852566302f, }, + { 0.1487594396f, 0.1143126413f, 0.6909267902f, 0.6222657561f, 0.1421835423f, }, + { 0.2163372189f, 0.9070070982f, 0.9298444986f, 0.3753599524f, 0.6777666807f, }, + { 0.3184583485f, 0.6389521360f, 0.8375228643f, 0.3248925507f, 0.2856884599f, }, + { 0.2291556299f, 0.8633516431f, 0.2655961215f, 0.9367564321f, 0.7854658961f, }, + { 0.2809183300f, 0.5630016923f, 0.3595665395f, 0.3839953244f, 0.4284386635f, }, + { 0.8873651028f, 0.5412272215f, 0.1782570630f, 0.4236218631f, 0.3652393520f, }, + { 0.7126258612f, 0.3216156960f, 0.6357123256f, 0.2265520990f, 0.5721607804f, }, + { 0.4778600931f, 0.3107969463f, 0.1367669404f, 0.3404520452f, 0.5942929983f, }, + { 0.3942337632f, 0.2979925871f, 0.1951848567f, 0.4729828238f, 0.7501001954f, }, + { 0.6589679122f, 0.5952326059f, 0.7186437249f, 0.6826527715f, 0.9515743256f, }, + { 0.2105532438f, 0.9471620321f, 0.4804215729f, 0.1124587655f, 0.4335258901f, }, + { 0.7551532388f, 0.7733113766f, 0.0783382654f, 0.2885888517f, 0.8958244920f, }, + { 0.8712418079f, 0.3927388787f, 0.8634191751f, 0.5191621780f, 0.5919325352f, }, + { 0.8640490174f, 0.5846663117f, 0.9602948427f, 0.0991103053f, 0.9496303201f, }, + { 0.7012666464f, 0.5834546089f, 0.0743006617f, 0.2192893326f, 0.0044159824f, }, + { 0.8875482678f, 0.9161846638f, 0.2652477622f, 0.2977103889f, 0.7025682926f, }, + { 0.9855603576f, 0.0087101785f, 0.4396715760f, 0.9723095894f, 0.0659022853f, }, + { 0.9122033119f, 0.1336005032f, 0.7489508390f, 0.3304834366f, 0.8549153805f, }, + { 0.3025889397f, 0.2665978968f, 0.9892198443f, 0.5173229575f, 0.3744891286f, }, + { 0.8874340653f, 0.1104984879f, 0.6282754540f, 0.6229367256f, 0.3589352965f, }, + { 0.7712169290f, 0.0302241705f, 0.6347808838f, 0.9150835276f, 0.9460471869f, }, + { 0.7598267198f, 0.2905746400f, 0.7529472113f, 0.5606840253f, 0.0738537386f, }, + { 0.3570119441f, 0.0135366321f, 0.3886126280f, 0.3621165156f, 0.3774941266f, }, + { 0.7559077144f, 0.0655572787f, 0.1813212931f, 0.5657911301f, 0.2029305696f, }, + { 0.8516904116f, 0.2806179821f, 0.6828679442f, 0.7818730474f, 0.5800003409f, }, + { 0.6047840714f, 0.2156374902f, 0.9419383407f, 0.3020962179f, 0.7256852388f, }, + { 0.0609827414f, 0.3350419104f, 0.4851172268f, 0.4306640923f, 0.5299456716f, }, + { 0.6867406368f, 0.0583693348f, 0.7255308032f, 0.3476333320f, 0.0635933504f, }, + { 0.9911341071f, 0.0611126088f, 0.0815501437f, 0.1212034225f, 0.1592897177f, }, + { 0.0597240999f, 0.1882285774f, 0.6781055331f, 0.2596292198f, 0.1077294052f, }, + { 0.1352300495f, 0.0448611602f, 0.5108820796f, 0.3657792509f, 0.1486221701f, }, + { 0.7091449499f, 0.0353681594f, 0.9301335812f, 0.8339682817f, 0.9392266870f, }, + { 0.1925535202f, 0.8164636493f, 0.6836991310f, 0.0249739978f, 0.9023748040f, }, + { 0.1218321845f, 0.1839622110f, 0.9348144531f, 0.4286737144f, 0.9748869538f, }, + { 0.5097845197f, 0.8491890430f, 0.5711638927f, 0.4680051208f, 0.6587874889f, }, + { 0.9002233148f, 0.2112870216f, 0.6346377134f, 0.7902280688f, 0.0296326280f, }, + { 0.9171761274f, 0.3519519567f, 0.5936511159f, 0.8897253871f, 0.6063346863f, }, + { 0.0924998298f, 0.8609267473f, 0.2311925590f, 0.0959152505f, 0.2161154896f, }, + { 0.1615293473f, 0.8053162694f, 0.2094037682f, 0.0073373597f, 0.5269560814f, }, + { 0.0615060776f, 0.6802668571f, 0.8214485645f, 0.0660875067f, 0.8492749929f, }, + { 0.5870412588f, 0.6753711104f, 0.9623897076f, 0.6564074159f, 0.9217193127f, }, + { 0.3767517209f, 0.0150573831f, 0.8463239074f, 0.1042795032f, 0.4882674813f, }, + { 0.0036249761f, 0.4475171566f, 0.1816152483f, 0.4341139197f, 0.3727532327f, }, + { 0.0205756538f, 0.8007926345f, 0.9693693519f, 0.2170890421f, 0.3233875036f, }, + { 0.3912367523f, 0.7034336925f, 0.9578071833f, 0.0427973270f, 0.4719061255f, }, + { 0.3165228069f, 0.5144750476f, 0.9703150392f, 0.1011901572f, 0.8679248691f, }, + { 0.8223432899f, 0.0407943204f, 0.6343313456f, 0.1056611836f, 0.6949219108f, }, + { 0.8749068379f, 0.7360510230f, 0.4877324104f, 0.6418207288f, 0.1990425885f, }, + { 0.6515081525f, 0.7983100414f, 0.9734125137f, 0.8395516872f, 0.6505805254f, }, + { 0.4581978917f, 0.8411237597f, 0.4651216269f, 0.5258325338f, 0.8255993724f, }, + { 0.0932482779f, 0.4222149253f, 0.4398647845f, 0.9860431552f, 0.6527469754f, }, + { 0.4647019804f, 0.0393914171f, 0.1352805942f, 0.5043900609f, 0.9310443997f, }, + { 0.0939329118f, 0.3112483323f, 0.9413509369f, 0.9663134813f, 0.6922456622f, }, + { 0.6697505713f, 0.1931533962f, 0.2143135220f, 0.8276033401f, 0.8858920932f, }, + { 0.7464785576f, 0.7450338602f, 0.4487583935f, 0.0469353870f, 0.2878799438f, }, + { 0.7755366564f, 0.1041728631f, 0.2338117212f, 0.5379500389f, 0.3419001698f, }, + { 0.0938941613f, 0.0629621074f, 0.1864347607f, 0.6573240161f, 0.5124857426f, }, + { 0.9413253069f, 0.1264335513f, 0.9302647114f, 0.3441043496f, 0.1859531552f, }, + { 0.4256654978f, 0.5935873985f, 0.9305386543f, 0.9631909728f, 0.1347593218f, }, + { 0.2154324651f, 0.3538596928f, 0.3273724318f, 0.0041027772f, 0.0934103429f, }, + { 0.2257991731f, 0.5610166192f, 0.3360533416f, 0.2801225483f, 0.0188695099f, }, + { 0.6096316576f, 0.5419935584f, 0.4941622615f, 0.5897194743f, 0.7221100926f, }, + { 0.8308253884f, 0.8577889800f, 0.4596455395f, 0.3866485357f, 0.1359159946f, }, + { 0.8164426088f, 0.8281993270f, 0.0968906134f, 0.7434515357f, 0.3830186129f, }, + { 0.5761756897f, 0.0386156216f, 0.2260080725f, 0.7623475194f, 0.6814588904f, }, + { 0.3514319360f, 0.9675538540f, 0.8338597417f, 0.0156834833f, 0.4322239757f, }, + { 0.1978540421f, 0.9607005715f, 0.0880531222f, 0.3144739866f, 0.6504595876f, }, + { 0.0619592033f, 0.7440487742f, 0.5105684400f, 0.4522305429f, 0.4000442326f, }, + { 0.1058543250f, 0.4792780876f, 0.3761950135f, 0.0112884650f, 0.7108566165f, }, + { 0.1537749469f, 0.0266981274f, 0.1352066547f, 0.8747116923f, 0.6969444156f, }, + { 0.1751065552f, 0.5347428322f, 0.3883734941f, 0.8203840852f, 0.2736755610f, }, + { 0.6362014413f, 0.4096245766f, 0.2385546714f, 0.8809883595f, 0.1217237785f, }, + { 0.6194738150f, 0.4113697708f, 0.1345291138f, 0.3856600523f, 0.5819554925f, }, + { 0.5339958668f, 0.8144325018f, 0.6828483939f, 0.8512167335f, 0.1485446244f, }, + { 0.5331157446f, 0.7378240228f, 0.5104088187f, 0.3281626105f, 0.5483035445f, }, + { 0.3432752490f, 0.7210670710f, 0.4403606355f, 0.5788609385f, 0.7402853370f, }, + { 0.5148429871f, 0.4699332118f, 0.1141299382f, 0.0198406763f, 0.8596696258f, }, + { 0.9190923572f, 0.1077200025f, 0.1058468446f, 0.3524709046f, 0.4952397645f, }, + { 0.5295362473f, 0.6823336482f, 0.0898813680f, 0.9296429157f, 0.9508863688f, }, + { 0.1838008314f, 0.8354221582f, 0.8821309209f, 0.5493785739f, 0.5963098407f, }, + { 0.2842168212f, 0.3851438761f, 0.0946061313f, 0.7525454164f, 0.4981763661f, }, + { 0.3869765103f, 0.0694613457f, 0.5099048018f, 0.7751111984f, 0.4524391890f, }, + { 0.1479069442f, 0.1934044659f, 0.4646208286f, 0.7183054090f, 0.8842082024f, }, + { 0.7150661349f, 0.2974754870f, 0.9721947908f, 0.8158836365f, 0.1040677354f, }, + { 0.6557854414f, 0.8579548597f, 0.3344733417f, 0.4862904251f, 0.5034834146f, }, + { 0.6619328856f, 0.4588610828f, 0.7238252759f, 0.6895897985f, 0.7830691934f, }, + { 0.3887063563f, 0.8197688460f, 0.1817125231f, 0.3514803946f, 0.1376305670f, }, + { 0.3502693176f, 0.0915137902f, 0.8618733883f, 0.1762868315f, 0.5926885009f, }, + { 0.0159674007f, 0.5508555174f, 0.4503343999f, 0.9569186568f, 0.6248606443f, }, + { 0.3265845180f, 0.9851868153f, 0.2197668105f, 0.9132761359f, 0.6558382511f, }, + { 0.1590070873f, 0.2210666090f, 0.7333306074f, 0.1416611820f, 0.4143800735f, }, + { 0.7012246251f, 0.5665413737f, 0.5648188591f, 0.5274944901f, 0.5120862126f, }, + { 0.8858002424f, 0.4135948122f, 0.9943007231f, 0.2888781428f, 0.8798441887f, }, + { 0.0955133662f, 0.1354070455f, 0.4959470630f, 0.0209824257f, 0.4498231411f, }, + { 0.7650064230f, 0.4894126654f, 0.6157168746f, 0.9058071375f, 0.9255406260f, }, + { 0.5323749781f, 0.9057061672f, 0.6342281699f, 0.9844349027f, 0.3900440335f, }, + { 0.3267960846f, 0.1053059921f, 0.3658140302f, 0.8208549619f, 0.4848240614f, }, + { 0.3231238425f, 0.8643591404f, 0.4406141341f, 0.7466545105f, 0.5113521814f, }, + { 0.9286953807f, 0.8059811592f, 0.1911488026f, 0.5330706239f, 0.0909626335f, }, + { 0.6589865088f, 0.9123917222f, 0.8108007312f, 0.6411517859f, 0.5061846375f, }, + { 0.1401813477f, 0.8855273724f, 0.1327907294f, 0.7768970132f, 0.7572786808f, }, + { 0.3620576262f, 0.6685598493f, 0.6831928492f, 0.3181948364f, 0.8907656074f, }, + { 0.8488835692f, 0.0757274106f, 0.5749354959f, 0.5752964020f, 0.4452306032f, }, + { 0.1889589578f, 0.0504652373f, 0.8334448934f, 0.5043759942f, 0.5595218539f, }, + { 0.0515798032f, 0.8898085952f, 0.6334125996f, 0.5381021500f, 0.0010347045f, }, + { 0.1597247869f, 0.9458835721f, 0.6902890205f, 0.7163779140f, 0.0197655261f, }, + { 0.8996863365f, 0.8865029216f, 0.6332854033f, 0.6583458185f, 0.6594056487f, }, + { 0.6951137781f, 0.7752588987f, 0.5021913648f, 0.6187083721f, 0.8058285117f, }, + { 0.1089947000f, 0.4366185665f, 0.3214475513f, 0.5644149184f, 0.3249928951f, }, + { 0.9725453854f, 0.0408105999f, 0.2468603402f, 0.1586236507f, 0.7713789940f, }, + { 0.9597951174f, 0.1194453537f, 0.5973563790f, 0.5355741978f, 0.6467792392f, }, + { 0.7512522936f, 0.1091663688f, 0.4407377839f, 0.9880781770f, 0.3036382198f, }, + { 0.8701978326f, 0.2114735544f, 0.0998489931f, 0.7444351912f, 0.5905585289f, }, + { 0.2769057155f, 0.3093628585f, 0.8283479810f, 0.9164166451f, 0.8449749351f, }, + { 0.0223075040f, 0.8893482089f, 0.1820281297f, 0.4852268696f, 0.1288422495f, }, + { 0.3043598533f, 0.9004296660f, 0.1886506528f, 0.1783746779f, 0.0880562216f, }, + { 0.2077170908f, 0.6934641004f, 0.5955366492f, 0.5970172286f, 0.2155250460f, }, + { 0.6623733044f, 0.4411697090f, 0.6323363185f, 0.9843344688f, 0.8477121592f, }, + { 0.5396968722f, 0.2380565107f, 0.8279913068f, 0.3993844092f, 0.3761107922f, }, + { 0.9137117863f, 0.8715309501f, 0.0830032527f, 0.1437654346f, 0.6770006418f, }, + { 0.6913329959f, 0.0367433205f, 0.3516072333f, 0.1324456632f, 0.3115328550f, }, + { 0.7668557763f, 0.1891957819f, 0.9350593090f, 0.5624659657f, 0.2871337533f, }, + { 0.5827600956f, 0.1353468448f, 0.6321440935f, 0.9487624168f, 0.4500167966f, }, + { 0.2647919357f, 0.4096116722f, 0.8818699718f, 0.5759581327f, 0.0538389124f, }, + { 0.9059103131f, 0.6533465385f, 0.4650319815f, 0.9372612834f, 0.6696007252f, }, + { 0.3554721475f, 0.0600751266f, 0.7197126746f, 0.4189397395f, 0.3530926406f, }, + { 0.8329718113f, 0.0920599028f, 0.6878132820f, 0.4325293005f, 0.6437871456f, }, + { 0.5340192914f, 0.0173568130f, 0.7114211321f, 0.2314292490f, 0.1877427846f, }, + { 0.4141532779f, 0.1278582811f, 0.4719299674f, 0.3102020025f, 0.4923864901f, }, + { 0.2105416358f, 0.4928782582f, 0.8812971711f, 0.3619814217f, 0.0837717578f, }, + { 0.8824574351f, 0.6092460752f, 0.7426846027f, 0.6008812189f, 0.4180557430f, }, + { 0.9838443398f, 0.7598111629f, 0.1344215125f, 0.9633333683f, 0.4567791820f, }, + { 0.5808681846f, 0.5132725835f, 0.1173246875f, 0.3292801380f, 0.7500274777f, }, + { 0.2492450327f, 0.9107430577f, 0.3316108882f, 0.1339779347f, 0.1828310192f, }, + { 0.7911765575f, 0.0374624245f, 0.9327452183f, 0.0589537658f, 0.3001240492f, }, + { 0.0855284408f, 0.2838529050f, 0.1826589704f, 0.4163714051f, 0.1758664101f, }, + { 0.2196706831f, 0.2664064765f, 0.9963974357f, 0.5459251404f, 0.0950668007f, }, + { 0.0900135115f, 0.8869558573f, 0.8550109863f, 0.0372654907f, 0.8010394573f, }, + { 0.9088296294f, 0.7798512578f, 0.9584836960f, 0.1617002636f, 0.7462898493f, }, + { 0.3375258148f, 0.8354582191f, 0.8358682394f, 0.7142186761f, 0.1502233893f, }, + { 0.8161059618f, 0.6727679968f, 0.7303199172f, 0.0075955139f, 0.5751823783f, }, + { 0.6335357428f, 0.2204233855f, 0.8489583731f, 0.4292674065f, 0.3852149248f, }, + { 0.1407428980f, 0.1640124023f, 0.1336183548f, 0.1801067889f, 0.1159457639f, }, + { 0.6652910709f, 0.7758769393f, 0.6840639114f, 0.4032720625f, 0.5570705533f, }, + { 0.5599435568f, 0.8328366280f, 0.6131256819f, 0.6266252398f, 0.4926441312f, }, + { 0.8959797025f, 0.1590007693f, 0.9684049487f, 0.7161019444f, 0.5822111368f, }, + { 0.7390566468f, 0.1586971283f, 0.8475266695f, 0.2790088654f, 0.3047635257f, }, + { 0.5757278204f, 0.8096774220f, 0.3161999285f, 0.0171908140f, 0.9406358600f, }, + { 0.3323770761f, 0.0032348870f, 0.8377987742f, 0.0286723543f, 0.2757017612f, }, + { 0.3810116053f, 0.2213836759f, 0.5660986900f, 0.8849477172f, 0.2123749107f, }, + { 0.6509358287f, 0.0104319341f, 0.5874458551f, 0.8807432055f, 0.4075576365f, }, + { 0.0296776071f, 0.0945936143f, 0.3302911222f, 0.3617616296f, 0.8985818624f, }, + { 0.0672378764f, 0.3647645712f, 0.2363392860f, 0.4530104697f, 0.0280950461f, }, + { 0.5405143499f, 0.1119930521f, 0.4619932175f, 0.2404984832f, 0.3364930153f, }, + { 0.8458412290f, 0.7214118838f, 0.9757335782f, 0.2733468115f, 0.4997842014f, }, + { 0.2196719348f, 0.0033935609f, 0.3427042663f, 0.7041660547f, 0.2852859497f, }, + { 0.6518928409f, 0.7352138162f, 0.3479509056f, 0.8747956157f, 0.4917884767f, }, + { 0.5791017413f, 0.3640214503f, 0.2190613002f, 0.3163473606f, 0.5945124626f, }, + { 0.2400048673f, 0.1566741019f, 0.2226224095f, 0.3369036615f, 0.2598891556f, }, + { 0.7465403080f, 0.3397649229f, 0.3434500694f, 0.4686655104f, 0.3742912710f, }, + { 0.0895045251f, 0.8132685423f, 0.4481364191f, 0.9891664982f, 0.0339491703f, }, + { 0.0423345231f, 0.1885800809f, 0.1342749447f, 0.3767119348f, 0.6284828186f, }, + { 0.8631264567f, 0.4307189286f, 0.7542389631f, 0.6370449662f, 0.3033391833f, }, + { 0.5593363643f, 0.2838163376f, 0.3682669103f, 0.9592128992f, 0.0637939498f, }, + { 0.0881183147f, 0.5055900812f, 0.1340163350f, 0.2795638442f, 0.7212033272f, }, + { 0.7197009325f, 0.3564022481f, 0.0801254809f, 0.0061451457f, 0.2375537306f, }, + { 0.5419400334f, 0.8424689770f, 0.8418055177f, 0.9790504575f, 0.8613957167f, }, + { 0.9847568870f, 0.8034096956f, 0.6317728758f, 0.7207365036f, 0.1682742834f, }, + { 0.2284196019f, 0.9551849365f, 0.3246108294f, 0.8061655164f, 0.0622744374f, }, + { 0.5614647865f, 0.8936647177f, 0.3613034487f, 0.2679057419f, 0.4133438766f, }, + { 0.9373534322f, 0.7108463645f, 0.4410406351f, 0.3049180806f, 0.9229277968f, }, + { 0.4370742440f, 0.7806338668f, 0.8810411692f, 0.7186604738f, 0.6573174000f, }, + { 0.3585429192f, 0.2101356983f, 0.7539672852f, 0.3990959525f, 0.9771047831f, }, + { 0.3499864638f, 0.0303151328f, 0.5823196769f, 0.8352752328f, 0.0330622271f, }, + { 0.1605356485f, 0.6936785579f, 0.4670228660f, 0.5163946748f, 0.0871832594f, }, + { 0.2151990235f, 0.6732758880f, 0.3221806288f, 0.5438848138f, 0.6597198248f, }, + { 0.5375214219f, 0.1837992370f, 0.3309822679f, 0.0041797226f, 0.4072039723f, }, + { 0.1410609484f, 0.6040471196f, 0.1111649722f, 0.6163387895f, 0.9907863140f, }, + { 0.7735633254f, 0.9464170337f, 0.2350548208f, 0.2136842757f, 0.3965293169f, }, + { 0.5376062393f, 0.6553274989f, 0.9616764784f, 0.8119949102f, 0.3124815822f, }, + { 0.2487912029f, 0.2529064417f, 0.3311287165f, 0.8549385071f, 0.2516104281f, }, + { 0.3843016028f, 0.6873926520f, 0.6020010710f, 0.8498594761f, 0.0024988640f, }, + { 0.1869705170f, 0.6236429214f, 0.3680001199f, 0.8916360736f, 0.6753105521f, }, + { 0.3512377441f, 0.1900529414f, 0.3229677379f, 0.6994846463f, 0.6495521069f, }, + { 0.1122881621f, 0.9941564798f, 0.7231782675f, 0.0322511010f, 0.1577460021f, }, + { 0.8889950514f, 0.3813840449f, 0.3696404397f, 0.6655992866f, 0.2321232259f, }, + { 0.7000734210f, 0.1588107198f, 0.9868922830f, 0.4453627467f, 0.7543982863f, }, + { 0.2691113949f, 0.2306683958f, 0.6842470169f, 0.2703482211f, 0.8989942670f, }, + { 0.0121822748f, 0.0096744820f, 0.7537097931f, 0.3252431154f, 0.4124893248f, }, + { 0.5688163042f, 0.4196397364f, 0.8253999352f, 0.9125783443f, 0.8752539158f, }, + { 0.9069935083f, 0.2914037406f, 0.1835056394f, 0.6422432065f, 0.8277579546f, }, + { 0.5990942717f, 0.3666738272f, 0.8527797461f, 0.3489917517f, 0.1525890976f, }, + { 0.8823184371f, 0.8649030328f, 0.8242565989f, 0.4307527244f, 0.0591854490f, }, + { 0.0342851058f, 0.2395575494f, 0.4413515329f, 0.3086756170f, 0.0644474924f, }, + { 0.5168740749f, 0.5283330679f, 0.9846208096f, 0.5072614551f, 0.1457142681f, }, + { 0.3547078371f, 0.8516544700f, 0.9829388857f, 0.8079034090f, 0.5265082717f, }, + { 0.1526004821f, 0.4594575763f, 0.2128100395f, 0.5326172113f, 0.8612877727f, }, + { 0.6328709126f, 0.1260940731f, 0.6312543154f, 0.8444578052f, 0.9790022373f, }, + { 0.3889540732f, 0.3475797772f, 0.4702761769f, 0.6669821143f, 0.7565659285f, }, + { 0.7595517635f, 0.7196069956f, 0.0800545290f, 0.2127159387f, 0.4909484088f, }, + { 0.0033205582f, 0.4057670236f, 0.6309975982f, 0.0869123191f, 0.9404982328f, }, + { 0.5116655231f, 0.9860128760f, 0.0965213627f, 0.8937316537f, 0.7201290727f, }, + { 0.1486718953f, 0.6349852681f, 0.8498548269f, 0.2738034427f, 0.6460675001f, }, + { 0.6294287443f, 0.3644131422f, 0.2646060288f, 0.7742468715f, 0.8052113652f, }, + { 0.8815364838f, 0.1684703976f, 0.8409839869f, 0.9413342476f, 0.4865612984f, }, + { 0.2367703021f, 0.1877286583f, 0.9781593680f, 0.7963556647f, 0.0708820969f, }, + { 0.8610283136f, 0.7909523845f, 0.7435487509f, 0.1387254149f, 0.8519986272f, }, + { 0.4294517636f, 0.0161501523f, 0.3307070136f, 0.9879044294f, 0.7054966092f, }, + { 0.5582140684f, 0.5907460451f, 0.5063688159f, 0.8520300388f, 0.3246189952f, }, + { 0.1063985974f, 0.4999367595f, 0.9665479064f, 0.5503758192f, 0.3585774302f, }, + { 0.3141995966f, 0.2438623309f, 0.7391360402f, 0.3353982866f, 0.8666503429f, }, + { 0.9106597900f, 0.5628968477f, 0.9354690909f, 0.0864307433f, 0.4837855697f, }, + { 0.3575817943f, 0.9084280133f, 0.9456790090f, 0.7300344706f, 0.8756796718f, }, + { 0.0627546683f, 0.7112050653f, 0.0986539721f, 0.9588924646f, 0.2920324206f, }, + { 0.1126644388f, 0.6120675802f, 0.5796947479f, 0.0650828630f, 0.6106427312f, }, + { 0.6074388623f, 0.8853486180f, 0.7408217192f, 0.2658755481f, 0.4856550694f, }, + { 0.7822978497f, 0.7912334204f, 0.2156379670f, 0.9274978042f, 0.4397214353f, }, + { 0.9381591678f, 0.9227067828f, 0.2639899552f, 0.4685123265f, 0.4078754485f, }, + { 0.6575052738f, 0.6114271879f, 0.9782764316f, 0.9106327295f, 0.8625913262f, }, + { 0.8558455706f, 0.6101471186f, 0.3666706383f, 0.4018512964f, 0.6479181647f, }, + { 0.9207193851f, 0.1614161730f, 0.4416292608f, 0.8584919572f, 0.8091099858f, }, + { 0.6615940332f, 0.3224806190f, 0.9934113026f, 0.1739115119f, 0.7504195571f, }, + { 0.1157584339f, 0.6743510365f, 0.9435926676f, 0.1545098871f, 0.8688474298f, }, + { 0.7150465250f, 0.9398179054f, 0.4420393705f, 0.1914434880f, 0.0326377451f, }, + { 0.4120532274f, 0.3268280923f, 0.7025625110f, 0.1996662915f, 0.3905383945f, }, + { 0.5729266405f, 0.5840837359f, 0.6943033934f, 0.8447760940f, 0.0144008398f, }, + { 0.9386386871f, 0.0002243735f, 0.4859568775f, 0.0586826168f, 0.2571247816f, }, + { 0.5092034936f, 0.2398022264f, 0.5654715896f, 0.9001114964f, 0.6657202244f, }, + { 0.1338600814f, 0.5887948275f, 0.3743414283f, 0.6042672396f, 0.7137978077f, }, + { 0.1104032099f, 0.7170971632f, 0.4850760102f, 0.3490588367f, 0.1988735497f, }, + { 0.2973527312f, 0.4160914421f, 0.5928805470f, 0.5131810904f, 0.2957490087f, }, + { 0.6015573740f, 0.9918369651f, 0.4423586130f, 0.2893592715f, 0.5733824968f, }, + { 0.8718593121f, 0.6390318274f, 0.4930015206f, 0.0591595396f, 0.9997956753f, }, + { 0.7617285252f, 0.2150458843f, 0.9999592900f, 0.6327126026f, 0.8118473291f, }, + { 0.7057132125f, 0.4828370810f, 0.6083679795f, 0.0587826483f, 0.9548948407f, }, + { 0.4787119031f, 0.7368876338f, 0.3668374121f, 0.5363883972f, 0.6838585734f, }, + { 0.2969213426f, 0.0981562138f, 0.2267682254f, 0.8281888366f, 0.0498473495f, }, + { 0.5847372413f, 0.1802515835f, 0.3845758140f, 0.7568612099f, 0.5419732332f, }, + { 0.9395964146f, 0.5739356875f, 0.4684714973f, 0.6320396066f, 0.2544209659f, }, + { 0.8097112775f, 0.5742420554f, 0.7068752646f, 0.1715442985f, 0.7959094644f, }, + { 0.0168016627f, 0.2332548648f, 0.1837963909f, 0.5056391358f, 0.2332014740f, }, + { 0.4081544578f, 0.4895038605f, 0.7006309032f, 0.5027516484f, 0.5000659227f, }, + { 0.5839354992f, 0.2640284300f, 0.6145825386f, 0.6977632046f, 0.3110732734f, }, + { 0.2615603805f, 0.2004319727f, 0.8688012362f, 0.7412906289f, 0.6822055578f, }, + { 0.2076299042f, 0.5859739780f, 0.9355570078f, 0.3478323519f, 0.5619545579f, }, + { 0.8974535465f, 0.0640840903f, 0.1853112131f, 0.6816211939f, 0.1149656400f, }, + { 0.1383968890f, 0.2473840714f, 0.5649874806f, 0.4116217196f, 0.5084484816f, }, + { 0.4974224567f, 0.0893179625f, 0.0995039046f, 0.2082732916f, 0.0543951131f, }, + { 0.0839584097f, 0.7227418423f, 0.2475279421f, 0.5749147534f, 0.0388351567f, }, + { 0.8974410295f, 0.9450010061f, 0.3381021619f, 0.7286146879f, 0.9115239382f, }, + { 0.2934806943f, 0.6838433743f, 0.1233035997f, 0.8173927665f, 0.5362653732f, }, + { 0.1595509052f, 0.0571826808f, 0.9823575616f, 0.2818324566f, 0.7082684040f, }, + { 0.3605043292f, 0.6125229597f, 0.6308466792f, 0.1706397533f, 0.3916153908f, }, + { 0.1341548562f, 0.2777822614f, 0.3164154291f, 0.4997781515f, 0.1627987176f, }, + { 0.3505487442f, 0.3648134768f, 0.8111594319f, 0.5003600717f, 0.2473016679f, }, + { 0.8895004392f, 0.3389880657f, 0.9711527824f, 0.7164833546f, 0.8985875249f, }, + { 0.9126531482f, 0.0141888680f, 0.3881369233f, 0.3607708812f, 0.5681939125f, }, + { 0.0056669842f, 0.3106762469f, 0.6164679527f, 0.3158658743f, 0.2425299138f, }, + { 0.8327383399f, 0.0544877350f, 0.2382235229f, 0.1739102155f, 0.9040178061f, }, + { 0.5898420215f, 0.9327718616f, 0.6847351193f, 0.0030442751f, 0.7230296731f, }, + { 0.7431026101f, 0.0114322230f, 0.7418098450f, 0.5972414017f, 0.2529012859f, }, + { 0.7586994767f, 0.6880294681f, 0.4425160885f, 0.9543884397f, 0.4084641933f, }, + { 0.3098642230f, 0.1807775795f, 0.1860131323f, 0.5633924007f, 0.8983878493f, }, + { 0.6125662327f, 0.1844114959f, 0.2258224785f, 0.0209375322f, 0.2123383433f, }, + { 0.6231752038f, 0.1008179262f, 0.8807303309f, 0.7672935724f, 0.2301377356f, }, + { 0.3846559823f, 0.8949285746f, 0.7048419118f, 0.1913291216f, 0.4082647860f, }, + { 0.5372482538f, 0.2536475062f, 0.2272657752f, 0.3890919089f, 0.9411203265f, }, + { 0.8043738604f, 0.9846765995f, 0.6039310098f, 0.9101876616f, 0.7753551006f, }, + { 0.7114196420f, 0.7980414033f, 0.8325216174f, 0.8614086509f, 0.6663145423f, }, + { 0.8518819213f, 0.3203050196f, 0.3335241079f, 0.3518493772f, 0.9558016062f, }, + { 0.4489892125f, 0.8110271692f, 0.2194582373f, 0.4013445675f, 0.1789831519f, }, + { 0.1117102578f, 0.0900359228f, 0.6109364033f, 0.7894284725f, 0.9664831161f, }, + { 0.7519912124f, 0.9377236962f, 0.4804982543f, 0.3369966447f, 0.1355315894f, }, + { 0.5390704274f, 0.4640378952f, 0.9938179255f, 0.7938830853f, 0.0836521983f, }, + { 0.3594265878f, 0.8181815743f, 0.7077993155f, 0.9233137369f, 0.4639542103f, }, + { 0.9924058914f, 0.3647743165f, 0.9614247680f, 0.4376363754f, 0.7425180078f, }, + { 0.0934674665f, 0.4547329843f, 0.5054649115f, 0.3461502194f, 0.7163566351f, }, + { 0.8879771233f, 0.2729289234f, 0.0745265633f, 0.5380026102f, 0.3289803863f, }, + { 0.5222221613f, 0.1877923757f, 0.1328493357f, 0.0496345311f, 0.1499144733f, }, + { 0.3467061222f, 0.6405905485f, 0.9760402441f, 0.9165933728f, 0.6199049354f, }, + { 0.7768987417f, 0.2197535187f, 0.4428177476f, 0.2261802107f, 0.4996104538f, }, + { 0.7293562889f, 0.5672805309f, 0.3172640204f, 0.2026030868f, 0.4785240591f, }, + { 0.4913944006f, 0.7779044509f, 0.5808085203f, 0.7753463984f, 0.8481456041f, }, + { 0.4185773432f, 0.0636490583f, 0.2597759962f, 0.5669569969f, 0.6010169983f, }, + { 0.2516151369f, 0.5157063603f, 0.2595796883f, 0.1936789155f, 0.2085859925f, }, + { 0.3346258402f, 0.3297136128f, 0.9562583566f, 0.6215136647f, 0.6502712369f, }, + { 0.2481307685f, 0.0084344987f, 0.8677152991f, 0.4063928127f, 0.6221209168f, }, + { 0.3143794537f, 0.3887699544f, 0.8804819584f, 0.0703434497f, 0.9605405927f, }, + { 0.9578213096f, 0.4416987598f, 0.1304423511f, 0.5404391885f, 0.7425362468f, }, + { 0.0978558287f, 0.6900287867f, 0.3879061937f, 0.5578132868f, 0.5812071562f, }, + { 0.9349294901f, 0.4391316772f, 0.4432170093f, 0.7729845047f, 0.2459201217f, }, + { 0.7654583454f, 0.3748521805f, 0.5990301371f, 0.9123783112f, 0.0015843224f, }, + { 0.1684563607f, 0.2466392815f, 0.6305578947f, 0.9636501074f, 0.2792312503f, }, + { 0.8585432172f, 0.7121519446f, 0.7422158718f, 0.5092861056f, 0.6871256232f, }, + { 0.9511637688f, 0.1920464933f, 0.5825737119f, 0.3723974526f, 0.7501792908f, }, + { 0.3154392242f, 0.9485397935f, 0.8645617366f, 0.2213997692f, 0.8308188319f, }, + { 0.4566854239f, 0.0607529506f, 0.5722083449f, 0.1499218643f, 0.5635485053f, }, + { 0.5197700262f, 0.4420594871f, 0.8801415563f, 0.7600139380f, 0.3799042404f, }, + { 0.5031815171f, 0.5662955046f, 0.7226250768f, 0.3605501950f, 0.6452532411f, }, + { 0.3513295352f, 0.2542692125f, 0.7034443021f, 0.4753168821f, 0.2306824178f, }, + { 0.8163626790f, 0.9267743230f, 0.9443190694f, 0.0058742445f, 0.1496275514f, }, + { 0.0118881967f, 0.3408871889f, 0.2208471000f, 0.7757240534f, 0.0296530053f, }, + { 0.4139153659f, 0.5206468105f, 0.5755940080f, 0.2113564312f, 0.4428433478f, }, + { 0.3051337004f, 0.5834974647f, 0.8254798055f, 0.7833608985f, 0.0181669220f, }, + { 0.2403490990f, 0.0737338066f, 0.3866648376f, 0.3034789860f, 0.5941126347f, }, + { 0.5588826537f, 0.6095137596f, 0.8114073873f, 0.6450126171f, 0.7001381516f, }, + { 0.8186420202f, 0.6263337135f, 0.5924562812f, 0.8774192333f, 0.3935771585f, }, + { 0.6096420884f, 0.2573115826f, 0.3642942011f, 0.1805870235f, 0.8106171489f, }, + { 0.0540286563f, 0.4247581661f, 0.3522080183f, 0.7224126458f, 0.5399610996f, }, + { 0.7888705730f, 0.8132427335f, 0.3499590456f, 0.1198204830f, 0.0559551194f, }, + { 0.4177697003f, 0.6245722771f, 0.6233429313f, 0.1478041112f, 0.9678903222f, }, + { 0.4913440645f, 0.4542281926f, 0.3845035136f, 0.5083712339f, 0.7815141678f, }, + { 0.1192287952f, 0.0725990012f, 0.9776978493f, 0.1138687432f, 0.9672344923f, }, + { 0.6535125971f, 0.0900786519f, 0.3577122092f, 0.1582210958f, 0.9457894564f, }, + { 0.3660543263f, 0.7710797191f, 0.1157049015f, 0.8386038542f, 0.2983358502f, }, + { 0.1096769497f, 0.1643242836f, 0.8145321012f, 0.9719124436f, 0.7222680449f, }, + { 0.9247113466f, 0.2312997580f, 0.9383603930f, 0.2620245516f, 0.3362186253f, }, + { 0.9061502814f, 0.5343630314f, 0.6183997393f, 0.1343059689f, 0.2738068998f, }, + { 0.1643908918f, 0.5637273788f, 0.1862617731f, 0.1463156343f, 0.4017370045f, }, + { 0.8155725002f, 0.1778775156f, 0.3755882382f, 0.5740320683f, 0.8760424256f, }, + { 0.7082151175f, 0.2367805988f, 0.3366532028f, 0.8647821546f, 0.8833859563f, }, + { 0.7119086981f, 0.0102619529f, 0.5810371041f, 0.7102273703f, 0.6976253390f, }, + { 0.1131074280f, 0.8345491290f, 0.9653796554f, 0.3620071411f, 0.6602659822f, }, + { 0.4560212493f, 0.6226450205f, 0.6850894690f, 0.1572125405f, 0.8515325785f, }, + { 0.6337410808f, 0.4552631676f, 0.0999221653f, 0.3569681644f, 0.2102586776f, }, + { 0.1856330782f, 0.4125151336f, 0.3394840062f, 0.0394442603f, 0.4163199365f, }, + { 0.9662784338f, 0.0697449967f, 0.8360053897f, 0.2896710932f, 0.0359874591f, }, + { 0.7867653370f, 0.8380057216f, 0.4434750378f, 0.3650088608f, 0.3339615464f, }, + { 0.8419455290f, 0.1101514176f, 0.1932760030f, 0.6056220531f, 0.9751375914f, }, + { 0.6409477592f, 0.0609767810f, 0.4897474349f, 0.8246864080f, 0.7614607811f, }, + { 0.5389257669f, 0.3856091499f, 0.2594721615f, 0.0367720872f, 0.2024967223f, }, + { 0.9304299355f, 0.4899468124f, 0.9995617867f, 0.5433477163f, 0.8025810719f, }, + { 0.9870956540f, 0.8349505067f, 0.4915114045f, 0.5112369061f, 0.0056635598f, }, + { 0.1366325170f, 0.0737384856f, 0.2319887877f, 0.2104884982f, 0.4120398164f, }, + { 0.6513785720f, 0.3657837212f, 0.1258129627f, 0.9503030777f, 0.1412268579f, }, + { 0.5740091801f, 0.9589503407f, 0.5845239162f, 0.5547816157f, 0.9706026316f, }, + { 0.5319734216f, 0.5832948685f, 0.1303028017f, 0.5718185902f, 0.4020925462f, }, + { 0.5447438359f, 0.3475812078f, 0.9912302494f, 0.8306050897f, 0.7230103016f, }, + { 0.9911502600f, 0.5369269252f, 0.1953288317f, 0.0794127807f, 0.0636800006f, }, + { 0.7410554290f, 0.8864943385f, 0.9625645876f, 0.5974848270f, 0.7411218286f, }, + { 0.3124462068f, 0.6898980737f, 0.9473048449f, 0.0530501865f, 0.7610924840f, }, + { 0.0374028832f, 0.2104890943f, 0.8381552100f, 0.5363779664f, 0.7638151646f, }, + { 0.6957225800f, 0.0061193723f, 0.7355313301f, 0.4099118412f, 0.2053324133f, }, + { 0.6216631532f, 0.2103295773f, 0.4950518608f, 0.7491188645f, 0.9204540253f, }, + { 0.7864974737f, 0.0669203326f, 0.7533058524f, 0.4840839207f, 0.9197073579f, }, + { 0.0098696332f, 0.0392509550f, 0.8801055551f, 0.3021447361f, 0.8860538602f, }, + { 0.9670569897f, 0.8739258051f, 0.9866670370f, 0.3653389215f, 0.4252314568f, }, + { 0.8417608142f, 0.8153506517f, 0.6112138033f, 0.5409707427f, 0.2828131914f, }, + { 0.1746225804f, 0.2098007351f, 0.9803739190f, 0.3456439972f, 0.0932259560f, }, + { 0.3656488955f, 0.9607333541f, 0.4857932627f, 0.0540026277f, 0.0309639461f, }, + { 0.4139657617f, 0.4425235689f, 0.1147096083f, 0.3207749128f, 0.7377182245f, }, + { 0.5659776926f, 0.1802824289f, 0.6868826747f, 0.2534175217f, 0.0101310452f, }, + { 0.9892764688f, 0.2440845817f, 0.3840390742f, 0.1323882639f, 0.6377233863f, }, + { 0.3155703247f, 0.0583552234f, 0.9497178793f, 0.3537640274f, 0.4335217476f, }, + { 0.0797655135f, 0.4302970171f, 0.6873253584f, 0.7047187686f, 0.0676008165f, }, + { 0.6867033839f, 0.3069249690f, 0.8439173698f, 0.4000784159f, 0.8992196321f, }, + { 0.2155394256f, 0.7116828561f, 0.7415392399f, 0.1127741858f, 0.8006007671f, }, + { 0.8664174080f, 0.7662979960f, 0.9940198064f, 0.3937835097f, 0.0996102542f, }, + { 0.5758724213f, 0.2917481959f, 0.4936659038f, 0.4889099896f, 0.0807329416f, }, + { 0.7622966766f, 0.6588274240f, 0.0972428247f, 0.7306827307f, 0.5750696063f, }, + { 0.3164197206f, 0.9228847623f, 0.9389179945f, 0.7374790907f, 0.2787623107f, }, + { 0.1098381355f, 0.8879435658f, 0.7260176539f, 0.5998212099f, 0.1403766572f, }, + { 0.8413100839f, 0.7874947786f, 0.4863704443f, 0.9021820426f, 0.6195128560f, }, + { 0.8403536081f, 0.6130164862f, 0.8119343519f, 0.6748429537f, 0.7750338316f, }, + { 0.6284690499f, 0.4818571508f, 0.5027428269f, 0.5123698115f, 0.9755698442f, }, + { 0.0920620412f, 0.5276015997f, 0.3574312627f, 0.7350004911f, 0.8633834124f, }, + { 0.7308514118f, 0.2754515707f, 0.2403506488f, 0.4963224828f, 0.5496905446f, }, + { 0.3678574562f, 0.8803086877f, 0.5837444663f, 0.4420125782f, 0.9142297506f, }, + { 0.2338100374f, 0.5414126515f, 0.4642713070f, 0.8458287716f, 0.1897608638f, }, + { 0.6672560573f, 0.8075864315f, 0.1115928218f, 0.9206107259f, 0.3868331611f, }, + { 0.0620223954f, 0.5052169561f, 0.8395518661f, 0.5886182785f, 0.4294970036f, }, + { 0.2574808598f, 0.7904385328f, 0.4711658657f, 0.9760697484f, 0.4254173636f, }, + { 0.1452739090f, 0.1344710141f, 0.5664320588f, 0.7476805449f, 0.8503814340f, }, + { 0.3368009031f, 0.1843090653f, 0.4472481608f, 0.9580815434f, 0.9925722480f, }, + { 0.4382192492f, 0.3289498687f, 0.8497692347f, 0.0160838012f, 0.5981659293f, }, + { 0.0213400461f, 0.5788072944f, 0.8587673903f, 0.3360802829f, 0.6177465320f, }, + { 0.7836791873f, 0.5629882216f, 0.9517893195f, 0.5061355233f, 0.5904608965f, }, + { 0.6512061357f, 0.4160226882f, 0.0962378383f, 0.9110269547f, 0.6063472033f, }, + { 0.6786859632f, 0.3235947490f, 0.1291635931f, 0.6824570298f, 0.4486574531f, }, + { 0.5658966303f, 0.8614020348f, 0.1033774912f, 0.9621068835f, 0.4241328239f, }, + { 0.9065781236f, 0.7641761899f, 0.4628043473f, 0.5470159054f, 0.8281406760f, }, + { 0.6051493883f, 0.3470966518f, 0.6876112223f, 0.1222088411f, 0.3250820935f, }, + { 0.5467187762f, 0.0261743814f, 0.8707129955f, 0.0428438261f, 0.9649776816f, }, + { 0.9087430835f, 0.0445340574f, 0.8385478854f, 0.6599641442f, 0.5853400230f, }, + { 0.1669427752f, 0.8626984954f, 0.3403065801f, 0.3652212322f, 0.5059336424f, }, + { 0.0763827264f, 0.1150694489f, 0.3194148540f, 0.8091986775f, 0.5464925766f, }, + { 0.5441807508f, 0.0728710964f, 0.3835804164f, 0.1930861175f, 0.1869702488f, }, + { 0.9345911145f, 0.6641216874f, 0.2405291200f, 0.6489296556f, 0.2630651593f, }, + { 0.6894470453f, 0.6631412506f, 0.7083969116f, 0.6253930330f, 0.2718397081f, }, + { 0.2755969465f, 0.6364558339f, 0.1876875758f, 0.3867566586f, 0.6713857651f, }, + { 0.6147570610f, 0.7384813428f, 0.1290114969f, 0.8446626067f, 0.7999385595f, }, + { 0.7899394631f, 0.3870192766f, 0.7309619188f, 0.7668225765f, 0.6994328499f, }, + { 0.7905895114f, 0.2458200008f, 0.8412302732f, 0.4817615151f, 0.0345448442f, }, + { 0.1440443546f, 0.0575356744f, 0.7082183361f, 0.6574723125f, 0.6297582388f, }, + { 0.6852607131f, 0.5967175961f, 0.3452194631f, 0.0422707126f, 0.3618138134f, }, + { 0.7588474154f, 0.0806893334f, 0.9697507024f, 0.8915631175f, 0.0795703456f, }, + { 0.9414138794f, 0.5351119041f, 0.9970599413f, 0.5188505650f, 0.6056861877f, }, + { 0.8986028433f, 0.7396928072f, 0.8685028553f, 0.0610375293f, 0.9054767489f, }, + { 0.0686211884f, 0.7645062208f, 0.1286374032f, 0.7891623378f, 0.8546707034f, }, + { 0.8971526623f, 0.8220834732f, 0.4947240949f, 0.8800817132f, 0.6376647949f, }, + { 0.5345884562f, 0.5540660620f, 0.8494138122f, 0.1309119910f, 0.4054251015f, }, + { 0.7870629430f, 0.1657799035f, 0.2226566374f, 0.6938433051f, 0.0596604198f, }, + { 0.5089665651f, 0.6152022481f, 0.2162503302f, 0.3299781084f, 0.5625262856f, }, + { 0.2163345665f, 0.6128764749f, 0.4757869840f, 0.1991271377f, 0.0431080796f, }, + { 0.4841201305f, 0.8944839835f, 0.3669667840f, 0.2307933569f, 0.9543874860f, }, + { 0.0057743210f, 0.1158067510f, 0.8536692858f, 0.6796045899f, 0.7620867491f, }, + { 0.6416705847f, 0.7092313766f, 0.5932567120f, 0.8697406054f, 0.2132903486f, }, + { 0.6728556156f, 0.5684846640f, 0.4631045163f, 0.4493266940f, 0.7338997722f, }, + { 0.5376614928f, 0.2144454867f, 0.0748951212f, 0.7730345726f, 0.1944203526f, }, + { 0.3529481590f, 0.7865818143f, 0.9558824897f, 0.4345997870f, 0.7765372396f, }, + { 0.8037161231f, 0.2317197472f, 0.7192084193f, 0.0153634753f, 0.3003410101f, }, + { 0.6400128603f, 0.2504938841f, 0.0992698446f, 0.7063420415f, 0.0099773267f, }, + { 0.7390035987f, 0.0615290441f, 0.4707089961f, 0.5414413810f, 0.6103296876f, }, + { 0.3876440227f, 0.7493652105f, 0.7075729370f, 0.8746657968f, 0.6761112213f, }, + { 0.9280777574f, 0.3244438767f, 0.6302939057f, 0.9078069925f, 0.1916857660f, }, + { 0.6700091958f, 0.8522417545f, 0.4562306702f, 0.0559391901f, 0.6790363789f, }, + { 0.8358801007f, 0.4056897163f, 0.2502582967f, 0.2603704035f, 0.1371598393f, }, + { 0.2917786539f, 0.1924762577f, 0.2479661852f, 0.6426951885f, 0.3451469839f, }, + { 0.4626781642f, 0.4580256045f, 0.8152709603f, 0.9253610969f, 0.8740119338f, }, + { 0.1653442681f, 0.6612082124f, 0.2589413226f, 0.2781197727f, 0.3580009043f, }, + { 0.9173426628f, 0.5489230752f, 0.1186219305f, 0.4879653752f, 0.0466545671f, }, + { 0.7891098857f, 0.6873882413f, 0.6292541027f, 0.4851434827f, 0.1927900463f, }, + { 0.0179721322f, 0.4936065972f, 0.2188114375f, 0.3742282391f, 0.4090329111f, }, + { 0.0127426684f, 0.1404912472f, 0.1283657849f, 0.2888801098f, 0.8650583029f, }, + { 0.6060962677f, 0.1412445754f, 0.6956457496f, 0.5314219594f, 0.1088551357f, }, + { 0.7804940343f, 0.4022661746f, 0.6290392280f, 0.8669286966f, 0.1982601136f, }, + { 0.9571256638f, 0.9981527328f, 0.9534710646f, 0.4901667237f, 0.4240596890f, }, + { 0.1593286097f, 0.5785304308f, 0.7360011339f, 0.1323255152f, 0.0603630766f, }, + { 0.8328416944f, 0.8003894091f, 0.8644387722f, 0.8853911161f, 0.0547731891f, }, + { 0.1304800510f, 0.9531883597f, 0.9741320014f, 0.7511789203f, 0.4847228527f, }, + { 0.0036087602f, 0.7787177563f, 0.2231317014f, 0.8908236027f, 0.8398417830f, }, + { 0.9895917773f, 0.7132139802f, 0.9796285629f, 0.2885993123f, 0.9813839793f, }, + { 0.7872307301f, 0.0064284578f, 0.8356505036f, 0.6256528497f, 0.3742916584f, }, + { 0.0523047522f, 0.3924313784f, 0.4971599877f, 0.2718709409f, 0.1670233756f, }, + { 0.5745553374f, 0.6665002704f, 0.4626360834f, 0.5488221645f, 0.6938694119f, }, + { 0.9108516574f, 0.9139137268f, 0.1279039085f, 0.8663606048f, 0.4086821973f, }, + { 0.8364224434f, 0.2065530270f, 0.2246541679f, 0.1123322621f, 0.0945468321f, }, + { 0.5835648775f, 0.4890106022f, 0.9410333037f, 0.5644700527f, 0.9592372775f, }, + { 0.1224060804f, 0.9236732721f, 0.3174877167f, 0.9467978477f, 0.5198745728f, }, + { 0.0485831536f, 0.8266622424f, 0.7527025342f, 0.6687675118f, 0.1173956916f, }, + { 0.0601795502f, 0.2746645510f, 0.9714960456f, 0.4920203388f, 0.6523286700f, }, + { 0.5817349553f, 0.5424330831f, 0.9945071936f, 0.9854079485f, 0.1750667840f, }, + { 0.1041650176f, 0.7712997198f, 0.2010931075f, 0.5643197298f, 0.3105701506f, }, + { 0.6160590649f, 0.2411288321f, 0.7326831222f, 0.8359069228f, 0.5147955418f, }, + { 0.7042996883f, 0.2073970437f, 0.1275481135f, 0.8247780204f, 0.6077878475f, }, + { 0.4602186382f, 0.1170402169f, 0.9502198100f, 0.7957844734f, 0.9325250983f, }, + { 0.3157202899f, 0.3050266802f, 0.4586791992f, 0.1108791456f, 0.1124928370f, }, + { 0.3644186556f, 0.7116021514f, 0.3260851800f, 0.5575646162f, 0.0133089861f, }, + { 0.7624040246f, 0.4636411071f, 0.8134638071f, 0.0132898800f, 0.5121221542f, }, + { 0.8495969176f, 0.2147338390f, 0.4577469230f, 0.1550133526f, 0.6249404550f, }, + { 0.7996145487f, 0.0154999942f, 0.6986239552f, 0.3063335121f, 0.0806614831f, }, + { 0.7876155972f, 0.5409100056f, 0.8788184524f, 0.6057672501f, 0.3525770903f, }, + { 0.6737350225f, 0.6845631599f, 0.3328086436f, 0.7934619188f, 0.7132768631f, }, + { 0.5827698708f, 0.4467804134f, 0.4437303245f, 0.7394418120f, 0.0858435482f, }, + { 0.3042074442f, 0.5407271385f, 0.8784964085f, 0.4904243052f, 0.6883462071f, }, + { 0.6630073190f, 0.7607935667f, 0.1878093034f, 0.1727387756f, 0.8242181540f, }, + { 0.6557357907f, 0.4891088903f, 0.6216499209f, 0.9459804893f, 0.2746068537f, }, + { 0.3103235662f, 0.9846129417f, 0.9898667932f, 0.7004886866f, 0.8533517122f, }, + { 0.0875477716f, 0.2399024665f, 0.1991463155f, 0.9756264687f, 0.9097051620f, }, + { 0.9844086766f, 0.5507794023f, 0.3435892463f, 0.6975043416f, 0.3778296709f, }, + { 0.9768900275f, 0.7871194482f, 0.7164797783f, 0.1035963073f, 0.9966811538f, }, + { 0.0161318630f, 0.2886805832f, 0.4763332307f, 0.9340108633f, 0.3747584820f, }, + { 0.6156099439f, 0.6358549595f, 0.3833848536f, 0.8874871135f, 0.1775773466f, }, + { 0.6076810956f, 0.0144416057f, 0.5983795524f, 0.4989981949f, 0.2998563051f, }, + { 0.1397931427f, 0.9007832408f, 0.9800312519f, 0.4623484015f, 0.3303070068f, }, + { 0.1568520963f, 0.3382826447f, 0.6101305485f, 0.7970088720f, 0.8208984137f, }, + { 0.7174112797f, 0.2492059469f, 0.9842574000f, 0.2528163195f, 0.8717679977f, }, + { 0.1330204457f, 0.5358535647f, 0.8569151759f, 0.4248799086f, 0.5758572221f, }, + { 0.2576922476f, 0.9399523139f, 0.6880307198f, 0.9472165704f, 0.5887063146f, }, + { 0.3130824268f, 0.7306442857f, 0.7189573646f, 0.9321358204f, 0.7711728811f, }, + { 0.4314511418f, 0.0353943147f, 0.0751349255f, 0.3468002081f, 0.0769719854f, }, + { 0.8144614100f, 0.3647552729f, 0.2275924683f, 0.2530769110f, 0.0799076408f, }, + { 0.6245332360f, 0.1952098161f, 0.5933178067f, 0.2895852029f, 0.9435052276f, }, + { 0.4773633480f, 0.7610867023f, 0.9627574682f, 0.7952138186f, 0.5373384953f, }, + { 0.8328925371f, 0.9714542031f, 0.8651910424f, 0.6556310058f, 0.3876988292f, }, + { 0.8613392711f, 0.7431043983f, 0.3542761803f, 0.8959987760f, 0.1267197281f, }, + { 0.6910918951f, 0.1712021381f, 0.7022235990f, 0.5588705540f, 0.3900049925f, }, + { 0.7235428691f, 0.3325441778f, 0.6974832416f, 0.0704269409f, 0.7410370708f, }, + { 0.7909677625f, 0.2982308567f, 0.9362434149f, 0.0376744531f, 0.6909531355f, }, + { 0.3316640556f, 0.1610975266f, 0.8481178284f, 0.2934847772f, 0.1013458446f, }, + { 0.5397228599f, 0.1649630219f, 0.2080588192f, 0.5333530307f, 0.1599848717f, }, + { 0.2619313896f, 0.3819122016f, 0.4560312331f, 0.9565147758f, 0.0253188051f, }, + { 0.0065284190f, 0.7945774794f, 0.8782905936f, 0.4303889275f, 0.7094818354f, }, + { 0.6978183389f, 0.3478265405f, 0.3459337056f, 0.6579891443f, 0.7187235951f, }, + { 0.6364232898f, 0.7624219060f, 0.4469431341f, 0.7514004707f, 0.2800546587f, }, + { 0.9099124074f, 0.6974939704f, 0.7451266050f, 0.3748708367f, 0.6414527893f, }, + { 0.9883816838f, 0.7743804455f, 0.3747880459f, 0.5890847445f, 0.0526064523f, }, + { 0.5049400926f, 0.7521902323f, 0.7097460628f, 0.0133493152f, 0.0833647102f, }, + { 0.2128605694f, 0.4006058574f, 0.7058876753f, 0.8946155310f, 0.8722225428f, }, + { 0.1559185386f, 0.4045276046f, 0.8426536322f, 0.3118899763f, 0.9879300594f, }, + { 0.6213791370f, 0.7936516404f, 0.7308436036f, 0.0356463343f, 0.7056118250f, }, + { 0.4863812327f, 0.2313183397f, 0.2509463727f, 0.2516500652f, 0.6078686118f, }, + { 0.8682948351f, 0.3590525687f, 0.7395040393f, 0.1889497191f, 0.2628301382f, }, + { 0.6305530667f, 0.6102344990f, 0.2281642556f, 0.9519263506f, 0.3817784786f, }, + { 0.6842796803f, 0.6145751476f, 0.2107230723f, 0.3641068339f, 0.2403616309f, }, + { 0.4144880176f, 0.4114216268f, 0.6100968719f, 0.8568821549f, 0.7609243989f, }, + { 0.7093672156f, 0.4434010983f, 0.8321857452f, 0.1048112959f, 0.0360628292f, }, + { 0.2742269933f, 0.9084026217f, 0.9770795703f, 0.4224666655f, 0.9528692365f, }, + { 0.6835575700f, 0.7113526464f, 0.8657730222f, 0.2597964108f, 0.4025377631f, }, + { 0.8820057511f, 0.7653574944f, 0.6186743379f, 0.6942235231f, 0.9867048264f, }, + { 0.4002628922f, 0.1797582656f, 0.1887810230f, 0.4196100831f, 0.5604269505f, }, + { 0.3068850935f, 0.0115590133f, 0.7105202675f, 0.8668804169f, 0.4384834766f, }, + { 0.9664412141f, 0.1454813033f, 0.4807569981f, 0.8667165041f, 0.2904396355f, }, + { 0.9420385957f, 0.0874461010f, 0.3442692161f, 0.7635858059f, 0.1445941478f, }, + { 0.2934573591f, 0.8491559029f, 0.7168706656f, 0.6976367831f, 0.0318241194f, }, + { 0.2881803215f, 0.2604030967f, 0.4439538121f, 0.8615469933f, 0.5918800235f, }, + { 0.4154109955f, 0.8675551414f, 0.6267600060f, 0.3865536749f, 0.0840766579f, }, + { 0.9852864146f, 0.8851239085f, 0.2447821200f, 0.6427243352f, 0.9368599057f, }, + { 0.9069287181f, 0.3239406347f, 0.0971427709f, 0.8410053849f, 0.5610182285f, }, + { 0.1890131533f, 0.4704453349f, 0.5942676067f, 0.0422278903f, 0.5234427452f, }, + { 0.7600780129f, 0.5776534677f, 0.6907634139f, 0.1705881208f, 0.0085717291f, }, + { 0.6283030510f, 0.9940350652f, 0.9520592093f, 0.2493636608f, 0.0954099447f, }, + { 0.8150551915f, 0.7757933140f, 0.9748542309f, 0.2951864898f, 0.7933490872f, }, + { 0.9063792825f, 0.0002953771f, 0.2243842334f, 0.6186184883f, 0.0568240546f, }, + { 0.6053550243f, 0.7720879316f, 0.9695298076f, 0.1935105622f, 0.3159848452f, }, + { 0.3655947149f, 0.4058556259f, 0.7265959978f, 0.9902883768f, 0.9081606865f, }, + { 0.2359461635f, 0.1397742480f, 0.7361820936f, 0.7937223315f, 0.7442050576f, }, + { 0.9850770235f, 0.6497853398f, 0.8510286808f, 0.4860012829f, 0.5907452106f, }, + { 0.2167189121f, 0.1377938092f, 0.6289006472f, 0.0871337950f, 0.0762696937f, }, + { 0.4715523720f, 0.6736221313f, 0.6886904240f, 0.9280806780f, 0.8371128440f, }, + { 0.4015913010f, 0.4574222565f, 0.4443146288f, 0.4098426700f, 0.2670778930f, }, + { 0.0694016591f, 0.6219701171f, 0.6286345720f, 0.4461866319f, 0.5418575406f, }, + { 0.0135321096f, 0.0677327588f, 0.5886047482f, 0.8423889875f, 0.1192927733f, }, + { 0.6001479030f, 0.6895483732f, 0.8432075381f, 0.7416180372f, 0.4256332815f, }, + { 0.3968738914f, 0.8858185410f, 0.3350656331f, 0.2864353955f, 0.6958817840f, }, + { 0.1205930412f, 0.1171584278f, 0.1149816886f, 0.2236678749f, 0.7210913897f, }, + { 0.4349879920f, 0.5387935638f, 0.4522722363f, 0.2054409534f, 0.1394047439f, }, + { 0.9162051082f, 0.4145580232f, 0.2460494637f, 0.8880847096f, 0.7661312222f, }, + { 0.0692350566f, 0.0498695225f, 0.8656570911f, 0.2401022017f, 0.5986857414f, }, + { 0.4742872715f, 0.5297006965f, 0.7017870545f, 0.8131196499f, 0.1880405247f, }, + { 0.7624046803f, 0.0425453596f, 0.3456826210f, 0.1948477179f, 0.5889691114f, }, + { 0.4063898921f, 0.7032834291f, 0.2197003365f, 0.1332048476f, 0.2356624156f, }, + { 0.1127961352f, 0.5407912731f, 0.7228294015f, 0.1118651405f, 0.9419350028f, }, + { 0.7622610331f, 0.5045526028f, 0.4526423514f, 0.2535529435f, 0.5909439325f, }, + { 0.9553532600f, 0.8894069791f, 0.4924957156f, 0.2825604975f, 0.9615020156f, }, + { 0.6506593227f, 0.1076390743f, 0.7318255305f, 0.8115561604f, 0.4576620162f, }, + { 0.2357361615f, 0.9980915189f, 0.5082566142f, 0.1415290833f, 0.5745783448f, }, + { 0.4344147444f, 0.7112027407f, 0.4928105474f, 0.6305655241f, 0.1600139737f, }, + { 0.1338317990f, 0.5621593595f, 0.9909422398f, 0.8261014223f, 0.9591542482f, }, + { 0.0873595551f, 0.9861614704f, 0.9482286572f, 0.1440095901f, 0.8397452235f, }, + { 0.1696817428f, 0.0457092971f, 0.5855281949f, 0.0714847669f, 0.5959162116f, }, + { 0.9181247354f, 0.4636716247f, 0.5860897303f, 0.0811086595f, 0.7844895124f, }, + { 0.4872695506f, 0.6522870064f, 0.4908350110f, 0.8570812941f, 0.2767620683f, }, + { 0.8551632166f, 0.3027701676f, 0.4815404415f, 0.0709288567f, 0.4738177061f, }, + { 0.6032003164f, 0.6594517231f, 0.7161087394f, 0.2173037231f, 0.2599665225f, }, + { 0.3804168105f, 0.4761337340f, 0.5078952312f, 0.8699969649f, 0.5516405702f, }, + { 0.8603464365f, 0.9857818484f, 0.3585600555f, 0.0500799641f, 0.7745358348f, }, + { 0.4608804584f, 0.2265810668f, 0.8342124820f, 0.9297932386f, 0.3621640205f, }, + { 0.5930344462f, 0.8654689193f, 0.2204990834f, 0.4176615179f, 0.2209315449f, }, + { 0.7752798200f, 0.5158697963f, 0.9415253401f, 0.2958724797f, 0.8061077595f, }, + { 0.5304133892f, 0.0893381014f, 0.9878226519f, 0.3377200365f, 0.6867077351f, }, + { 0.4476513565f, 0.5538997054f, 0.5739765167f, 0.3571768701f, 0.4131403267f, }, + { 0.0929111168f, 0.5565102100f, 0.9651411772f, 0.3798374832f, 0.0632320791f, }, + { 0.5498932600f, 0.1417344362f, 0.1210399419f, 0.0177628510f, 0.4034406841f, }, + { 0.0922165886f, 0.5885695815f, 0.8250400424f, 0.1410054564f, 0.1222052276f, }, + { 0.5145093203f, 0.3669571579f, 0.6265506744f, 0.5228474736f, 0.6551961899f, }, + { 0.9257059097f, 0.5194458961f, 0.3653381765f, 0.0294633694f, 0.0354222544f, }, + { 0.4401383102f, 0.2481490970f, 0.5992058516f, 0.7401285768f, 0.8858845830f, }, + { 0.7719102502f, 0.0151219610f, 0.5746850967f, 0.4455586076f, 0.8436070681f, }, + { 0.4173793197f, 0.3875162601f, 0.7000482678f, 0.1844448447f, 0.3057107329f, }, + { 0.2676621377f, 0.3392877877f, 0.4444096684f, 0.4012240767f, 0.9351375699f, }, + { 0.3178731203f, 0.1349570155f, 0.6891089678f, 0.5363838673f, 0.9238854051f, }, + { 0.4843406081f, 0.8264052272f, 0.3290589154f, 0.2438129783f, 0.4649564922f, }, + { 0.4032748044f, 0.0300827958f, 0.4542402923f, 0.3767758310f, 0.7134159207f, }, + { 0.1657409966f, 0.9967322946f, 0.4633623660f, 0.2063730508f, 0.4553405643f, }, + { 0.2845554352f, 0.4003728032f, 0.9496721029f, 0.5719822645f, 0.8392899036f, }, + { 0.0304997861f, 0.5205277801f, 0.0911632702f, 0.0499893390f, 0.7010195255f, }, + { 0.9202510715f, 0.7321734428f, 0.9610123634f, 0.5609013438f, 0.5010135174f, }, + { 0.4444954097f, 0.2198403180f, 0.2466250658f, 0.4549592137f, 0.1495590806f, }, + { 0.9709001184f, 0.7507070899f, 0.2522841096f, 0.7290827632f, 0.5225729942f, }, + { 0.8766907454f, 0.3237386048f, 0.6189660430f, 0.4427610636f, 0.3849479258f, }, + { 0.1568824649f, 0.8203613758f, 0.4653980434f, 0.7652044892f, 0.4826052189f, }, + { 0.9296943545f, 0.9880217910f, 0.7044270039f, 0.8996956944f, 0.7534894347f, }, + { 0.2450878918f, 0.6374186873f, 0.0752013028f, 0.1555137783f, 0.4394538105f, }, + { 0.5105174184f, 0.7012284994f, 0.2241654992f, 0.3767915666f, 0.0934778824f, }, + { 0.6147289872f, 0.2979862392f, 0.2234163731f, 0.1969837844f, 0.3035095632f, }, + { 0.3574070036f, 0.9383932352f, 0.6258143783f, 0.9383162260f, 0.7566910982f, }, + { 0.9049782753f, 0.4750487506f, 0.4910390675f, 0.4398009479f, 0.5762134790f, }, + { 0.6256769896f, 0.3810784221f, 0.9718868136f, 0.0816104934f, 0.3740687072f, }, + { 0.7439019680f, 0.5902351737f, 0.9540218115f, 0.7133101225f, 0.9791391492f, }, + { 0.0507985614f, 0.4420216084f, 0.6248494387f, 0.5034208298f, 0.9062337279f, }, + { 0.4590478539f, 0.9563519359f, 0.9566506743f, 0.1338829398f, 0.4563919008f, }, + { 0.9957278371f, 0.1856461763f, 0.3339993954f, 0.4809197485f, 0.2929502726f, }, + { 0.7176794410f, 0.0985678285f, 0.2182638049f, 0.3093981743f, 0.7474626303f, }, + { 0.9061188698f, 0.6710234880f, 0.9993618727f, 0.8222120404f, 0.8543561101f, }, + { 0.2173118740f, 0.7567624450f, 0.2481429428f, 0.1177003682f, 0.0282668062f, }, + { 0.4208782613f, 0.1810830086f, 0.7177898884f, 0.6889427304f, 0.5673372149f, }, + { 0.7197733521f, 0.6740778685f, 0.9462325573f, 0.9223800898f, 0.7216035128f, }, + { 0.7357454896f, 0.6583784223f, 0.3596801460f, 0.5852091312f, 0.0120691061f, }, + { 0.3554546535f, 0.4189505279f, 0.5985988975f, 0.0133819943f, 0.1601126641f, }, + { 0.3970699608f, 0.3265931308f, 0.0776758790f, 0.1438793987f, 0.9221845269f, }, + { 0.8603001237f, 0.8481134772f, 0.2103779465f, 0.2099492550f, 0.5709760785f, }, + { 0.6750032306f, 0.9859799743f, 0.9644153118f, 0.7434251904f, 0.9419956803f, }, + { 0.9512263536f, 0.6862620115f, 0.6133762002f, 0.1747208834f, 0.1991396695f, }, + { 0.5563628078f, 0.4616844356f, 0.7273113728f, 0.1822764874f, 0.8541821241f, }, + { 0.4850552082f, 0.0484853722f, 0.9807727337f, 0.9844093323f, 0.7370347977f, }, + { 0.9904833436f, 0.1611956805f, 0.7372457981f, 0.3390260041f, 0.5344291925f, }, + { 0.7474996448f, 0.5275216699f, 0.1902983338f, 0.2796644270f, 0.0610496290f, }, + { 0.2386909723f, 0.7674853802f, 0.7342913747f, 0.3636198640f, 0.6287329197f, }, + { 0.0470547155f, 0.8481873274f, 0.4714873433f, 0.9730053544f, 0.9766517878f, }, + { 0.8406447768f, 0.3762824237f, 0.9858224392f, 0.5772919059f, 0.1027430445f, }, + { 0.4636325538f, 0.5047873259f, 0.8323110938f, 0.8190895915f, 0.6579908133f, }, + { 0.5425127745f, 0.4359837472f, 0.1914416552f, 0.3090336025f, 0.3940243423f, }, + { 0.3814967573f, 0.2863974869f, 0.5668816566f, 0.0048141344f, 0.3945276141f, }, + { 0.4284969866f, 0.4679206312f, 0.3583089411f, 0.6822469234f, 0.3160546720f, }, + { 0.3729407489f, 0.5919202566f, 0.8121685386f, 0.5080659389f, 0.6589282751f, }, + { 0.3328192234f, 0.9700210094f, 0.1273731291f, 0.2296688110f, 0.4794546366f, }, + { 0.1675478220f, 0.4324451685f, 0.9676478505f, 0.5311928988f, 0.3113810718f, }, + { 0.7129261494f, 0.6461684704f, 0.0756587908f, 0.3368423283f, 0.8374305964f, }, + { 0.2220462412f, 0.1855718642f, 0.4783749282f, 0.6551553011f, 0.6076968312f, }, + { 0.3363366127f, 0.4101237953f, 0.4448086321f, 0.5928441882f, 0.8119885921f, }, + { 0.4445488453f, 0.7243288755f, 0.3810153306f, 0.9638563395f, 0.5408384800f, }, + { 0.5058643818f, 0.5885255337f, 0.9752150178f, 0.5600872636f, 0.8830175400f, }, + { 0.0798128396f, 0.9053880572f, 0.4712941051f, 0.6497660875f, 0.4507645965f, }, + { 0.6673766971f, 0.7133527994f, 0.2159910053f, 0.0084344158f, 0.6858344078f, }, + { 0.9443193078f, 0.7377422452f, 0.8780963421f, 0.1384434849f, 0.7856494784f, }, + { 0.5152956843f, 0.4240128696f, 0.5068760514f, 0.5287197828f, 0.5258048177f, }, + { 0.1662804037f, 0.5033773184f, 0.1168889403f, 0.3436156511f, 0.2719661295f, }, + { 0.8476766348f, 0.2318153679f, 0.9616276622f, 0.4859198332f, 0.4795930386f, }, + { 0.2771559060f, 0.4795325994f, 0.6116051674f, 0.3470634520f, 0.3930682242f, }, + { 0.6133131385f, 0.4782887995f, 0.5835899711f, 0.8871667981f, 0.4774041176f, }, + { 0.9090421796f, 0.2580033839f, 0.8123038411f, 0.8245674372f, 0.3271803856f, }, + { 0.7480770946f, 0.1403973401f, 0.2290938646f, 0.6817570329f, 0.0546809845f, }, + { 0.3159823120f, 0.2598330081f, 0.8642247915f, 0.4841615558f, 0.1427160501f, }, + { 0.8543668389f, 0.1379592121f, 0.3617588878f, 0.2347296178f, 0.9176930189f, }, + { 0.5909702182f, 0.4116297066f, 0.2329913378f, 0.4446891844f, 0.0723623484f, }, + { 0.2920983136f, 0.4300553501f, 0.3281433284f, 0.9396935105f, 0.4636707604f, }, + { 0.5373799205f, 0.7666693330f, 0.9547126293f, 0.6674847007f, 0.6217921972f, }, + { 0.2800422311f, 0.6113741994f, 0.2581831217f, 0.8107113838f, 0.4138760567f, }, + { 0.4890097976f, 0.9507597089f, 0.8125252128f, 0.9345319867f, 0.2564773560f, }, + { 0.1827517450f, 0.7972067595f, 0.1270797104f, 0.8169758320f, 0.8379308581f, }, + { 0.7362793684f, 0.4217238426f, 0.2488209456f, 0.4310501218f, 0.8307220340f, }, + { 0.3932117522f, 0.8506226540f, 0.4821075797f, 0.4116683900f, 0.2897019088f, }, + { 0.6916832924f, 0.5381910205f, 0.9620926380f, 0.2499948740f, 0.9155715704f, }, + { 0.4886517525f, 0.8423064947f, 0.7285782695f, 0.7464314699f, 0.6170300245f, }, + { 0.2314840555f, 0.4685018957f, 0.3374244273f, 0.8669199347f, 0.7746947408f, }, + { 0.7931564450f, 0.5985640287f, 0.3626371622f, 0.7060728073f, 0.8677656651f, }, + { 0.0950168520f, 0.9316201210f, 0.6041450500f, 0.5664063096f, 0.8524709344f, }, + { 0.3141123354f, 0.8056180477f, 0.5873332620f, 0.2671475708f, 0.5725752115f, }, + { 0.8379953504f, 0.5832053423f, 0.0888812169f, 0.2255203873f, 0.1762754768f, }, + { 0.6569383740f, 0.3056329489f, 0.6257125139f, 0.9745829105f, 0.8757616282f, }, + { 0.2457380444f, 0.4310993850f, 0.4766687751f, 0.3253744543f, 0.3752191365f, }, + { 0.8658375740f, 0.0141341379f, 0.4831534326f, 0.8672434092f, 0.3036774695f, }, + { 0.8385505080f, 0.8431173563f, 0.9773830175f, 0.0220353529f, 0.6942073703f, }, + { 0.2914274335f, 0.7381055355f, 0.1923779398f, 0.5319308639f, 0.4835444391f, }, + { 0.3336100280f, 0.7379875779f, 0.5724130273f, 0.0294773132f, 0.1880078316f, }, + { 0.4339447320f, 0.6408196688f, 0.4933020771f, 0.6970547438f, 0.3242316246f, }, + { 0.4152032733f, 0.9341998100f, 0.8396334648f, 0.3977614939f, 0.6332161427f, }, + { 0.2081637979f, 0.4721533656f, 0.9604850411f, 0.1380777955f, 0.0482439660f, }, + { 0.5506162643f, 0.9098795652f, 0.0957558826f, 0.2242902368f, 0.0983351544f, }, + { 0.5391968489f, 0.8824328780f, 0.4490297139f, 0.4489945471f, 0.7209504843f, }, + { 0.1355364323f, 0.1784058809f, 0.6016484499f, 0.4410499632f, 0.4408858716f, }, + { 0.6682451367f, 0.9612405896f, 0.7276591659f, 0.6378405690f, 0.6854436398f, }, + { 0.9506758451f, 0.6711990237f, 0.4868029654f, 0.3220705986f, 0.9669231772f, }, + { 0.0850694478f, 0.7843524218f, 0.7350974679f, 0.2146740556f, 0.9742834568f, }, + { 0.2213732302f, 0.8762681484f, 0.8600668907f, 0.0668335930f, 0.4596683085f, }, + { 0.9433848858f, 0.3610410690f, 0.7110331059f, 0.8381390572f, 0.3911342025f, }, + { 0.7709762454f, 0.9853550196f, 0.3288127780f, 0.9515877962f, 0.8525200486f, }, + { 0.2900376618f, 0.6394186020f, 0.1162578017f, 0.9362347722f, 0.7002198696f, }, + { 0.6981595755f, 0.6356016994f, 0.5828221440f, 0.6320328712f, 0.0423277356f, }, + { 0.2105759829f, 0.7961422205f, 0.4677138627f, 0.7609971166f, 0.3446505666f, }, + { 0.6791944504f, 0.8783214092f, 0.9797452092f, 0.8128815293f, 0.2441538572f, }, + { 0.5962013602f, 0.7215726376f, 0.3357588947f, 0.1584632695f, 0.0808582976f, }, + { 0.7421919107f, 0.2647459209f, 0.1067559794f, 0.9396389723f, 0.5399952531f, }, + { 0.2420759350f, 0.3401932418f, 0.9482945800f, 0.1740137339f, 0.8906546235f, }, + { 0.5897881389f, 0.1642927974f, 0.0961570516f, 0.7805370688f, 0.8832169175f, }, + { 0.4894460440f, 0.2167413831f, 0.6983233690f, 0.6962680817f, 0.8386267424f, }, + { 0.0313055888f, 0.6795799136f, 0.9550771117f, 0.4919249415f, 0.7872869968f, }, + { 0.4157477915f, 0.3483664393f, 0.1983267218f, 0.6012227535f, 0.3024815917f, }, + { 0.5351226330f, 0.0609250739f, 0.2494800240f, 0.9480771422f, 0.2198663801f, }, + { 0.2126268446f, 0.3705193996f, 0.8346916437f, 0.8270356655f, 0.9727078676f, }, + { 0.0323539302f, 0.4445431232f, 0.4450592101f, 0.9611444473f, 0.3080556691f, }, + { 0.2617457509f, 0.7292874455f, 0.1193473339f, 0.1001462117f, 0.7902913094f, }, + { 0.0596965998f, 0.9968909621f, 0.5749673843f, 0.4251702726f, 0.1569124013f, }, + { 0.3395343721f, 0.3950080276f, 0.3652063906f, 0.0174267907f, 0.5359101295f, }, + { 0.1195266396f, 0.0486422442f, 0.8778693080f, 0.8146002293f, 0.0167063754f, }, + { 0.3572813869f, 0.3127619028f, 0.7064229250f, 0.6038604975f, 0.2698771656f, }, + { 0.6805381775f, 0.5190973282f, 0.1073414385f, 0.8062596917f, 0.8032501936f, }, + { 0.1856200695f, 0.9114516973f, 0.0944496095f, 0.2546859086f, 0.2401405871f, }, + { 0.4728344977f, 0.9648797512f, 0.5893321037f, 0.5576858521f, 0.3481232822f, }, + { 0.0945585072f, 0.6381896138f, 0.1949055195f, 0.6527691483f, 0.9095736146f, }, + { 0.3607141376f, 0.5445485115f, 0.4842854738f, 0.2827373147f, 0.1348775625f, }, + { 0.2789441347f, 0.8388562799f, 0.1268759817f, 0.5527347326f, 0.8142587543f, }, + { 0.4092592895f, 0.2760647833f, 0.6904397011f, 0.2268581539f, 0.0737444758f, }, + { 0.5233128667f, 0.3356019258f, 0.8127546906f, 0.1676381230f, 0.0961625129f, }, + { 0.4309432209f, 0.4931345284f, 0.0758187175f, 0.3106442094f, 0.7043816447f, }, + { 0.1580911875f, 0.2360448688f, 0.2543705702f, 0.5382861495f, 0.2221642137f, }, + { 0.0146207483f, 0.2620170116f, 0.8492237329f, 0.4924086034f, 0.7259045243f, }, + { 0.1783511043f, 0.1624470055f, 0.0984077081f, 0.4531139433f, 0.2366993427f, }, + { 0.6850262880f, 0.6448300481f, 0.8274722099f, 0.0897763893f, 0.3065722883f, }, + { 0.8206403255f, 0.9633809328f, 0.4788635075f, 0.3187713921f, 0.0032228290f, }, + { 0.7713975310f, 0.7631881833f, 0.9470386505f, 0.1535011232f, 0.0942638963f, }, + { 0.6044945717f, 0.8014805317f, 0.9991723299f, 0.5837679505f, 0.4806862175f, }, + { 0.5388597250f, 0.9995372295f, 0.3176338971f, 0.3117991686f, 0.9587724209f, }, + { 0.1803224087f, 0.5125344992f, 0.5671827793f, 0.3978010416f, 0.5753285885f, }, + { 0.6354757547f, 0.4403678179f, 0.3724274039f, 0.1003797725f, 0.3434965014f, }, + { 0.4373765290f, 0.3443910182f, 0.4598889649f, 0.1338540614f, 0.9342237711f, }, + { 0.2481911033f, 0.9781090617f, 0.9438737631f, 0.5074093342f, 0.1323044747f, }, + { 0.0377569720f, 0.4687357843f, 0.8416351676f, 0.1401805580f, 0.4396491051f, }, + { 0.8875662684f, 0.0923208296f, 0.7026885152f, 0.8824400902f, 0.9131188989f, }, + { 0.1884187758f, 0.5805519819f, 0.0842102170f, 0.6626949906f, 0.1777051538f, }, + { 0.6922248006f, 0.7608190179f, 0.1256106198f, 0.1444312185f, 0.2503958642f, }, + { 0.8018246889f, 0.5259380937f, 0.5674023628f, 0.9871163964f, 0.3510495424f, }, + { 0.0578156598f, 0.2405378968f, 0.0759974495f, 0.2578216195f, 0.6539394855f, }, + { 0.7198444009f, 0.0253831148f, 0.2085484713f, 0.2555891275f, 0.8574421406f, }, + { 0.8061947823f, 0.7883300185f, 0.7374021411f, 0.4412709773f, 0.5182559490f, }, + { 0.1814599186f, 0.4829825163f, 0.7223602533f, 0.8123971224f, 0.3735327721f, }, + { 0.5997964144f, 0.2294329703f, 0.0976012796f, 0.9362025261f, 0.0727647766f, }, + { 0.1982873082f, 0.2486504018f, 0.4970142245f, 0.6135889292f, 0.5866930485f, }, + { 0.7806620598f, 0.3538209200f, 0.3620573282f, 0.4277704060f, 0.6942183375f, }, + { 0.3908770382f, 0.3935398459f, 0.9744939208f, 0.3427796066f, 0.7350586057f, }, + { 0.5315275192f, 0.8318429589f, 0.3563607037f, 0.3339850008f, 0.1535255462f, }, + { 0.7680259347f, 0.0571767911f, 0.1175855249f, 0.7937267423f, 0.5988506079f, }, + { 0.6767882109f, 0.7536016703f, 0.2283532917f, 0.0489633419f, 0.0630292743f, }, + { 0.2855349481f, 0.3330864012f, 0.0763960108f, 0.7449605465f, 0.7582602501f, }, + { 0.8074395061f, 0.7624371052f, 0.8774601817f, 0.3936000466f, 0.2269419134f, }, + { 0.1247892454f, 0.4588497579f, 0.7377902269f, 0.9872066975f, 0.9756523371f, }, + { 0.2382634282f, 0.6669289470f, 0.4485808313f, 0.8125393391f, 0.1628699899f, }, + { 0.2217127383f, 0.1648612767f, 0.8512941003f, 0.5740059018f, 0.9343020320f, }, + { 0.7131489515f, 0.5580295324f, 0.8603314161f, 0.4995054305f, 0.7676098943f, }, + { 0.5554981232f, 0.7536829114f, 0.7116505504f, 0.9476801157f, 0.3018324375f, }, + { 0.8664983511f, 0.9348188639f, 0.4759433568f, 0.4701786041f, 0.5058752894f, }, + { 0.5095126629f, 0.1311616153f, 0.8654143214f, 0.3166510463f, 0.5378813744f, }, + { 0.2013948709f, 0.0993477255f, 0.4519537091f, 0.9983737469f, 0.1207369864f, }, + { 0.6530140638f, 0.7837896347f, 0.7238932252f, 0.3284585476f, 0.3622599542f, }, + { 0.0752364397f, 0.3907876611f, 0.6253241897f, 0.2432800531f, 0.6425753832f, }, + { 0.3214516342f, 0.4299878180f, 0.8175384998f, 0.3163611591f, 0.9293256402f, }, + { 0.8103592992f, 0.7277007103f, 0.4727446139f, 0.8018363714f, 0.6558837295f, }, + { 0.8454443812f, 0.1660367996f, 0.2164804190f, 0.0496755987f, 0.6659568548f, }, + { 0.4616822302f, 0.6498546004f, 0.3592532575f, 0.1597846895f, 0.4006915689f, }, + { 0.3373423219f, 0.4660783708f, 0.6921073794f, 0.9315503836f, 0.4527882934f, }, + { 0.7930449843f, 0.6267275214f, 0.4539354146f, 0.2994103432f, 0.2003165781f, }, + { 0.0871245041f, 0.6667624712f, 0.5696305037f, 0.6824337840f, 0.3605321050f, }, + { 0.1615563780f, 0.2643332481f, 0.7145193219f, 0.2466212362f, 0.9364427328f, }, + { 0.4457659125f, 0.8910381198f, 0.9924890399f, 0.1392472088f, 0.8901849389f, }, + { 0.3864786029f, 0.1517654657f, 0.0765987635f, 0.3266053200f, 0.2312912792f, }, + { 0.0069322316f, 0.0878866166f, 0.9894841909f, 0.2040011138f, 0.7337638140f, }, + { 0.2110845000f, 0.6273645163f, 0.1985735446f, 0.0254147574f, 0.8889908791f, }, + { 0.0073242798f, 0.5627350807f, 0.5844052434f, 0.8754569292f, 0.0123460963f, }, + { 0.6318338513f, 0.8050666451f, 0.4450735152f, 0.5133627653f, 0.0196723938f, }, + { 0.9419804215f, 0.0577819645f, 0.9805383086f, 0.9528379440f, 0.3217454851f, }, + { 0.6840943694f, 0.1429686695f, 0.8581956029f, 0.6390916705f, 0.9005090594f, }, + { 0.5938857794f, 0.4355608523f, 0.3769831061f, 0.7763158679f, 0.6176721454f, }, + { 0.2209536880f, 0.0212988835f, 0.0865329951f, 0.8693550229f, 0.8441941142f, }, + { 0.5100947618f, 0.8796753883f, 0.8336679935f, 0.3645589054f, 0.4451568723f, }, + { 0.8358271718f, 0.6758773327f, 0.6004961729f, 0.6701435447f, 0.1521773338f, }, + { 0.1673108637f, 0.8883163333f, 0.8515177965f, 0.9166519046f, 0.9826393127f, }, + { 0.5249327421f, 0.9182383418f, 0.9364526272f, 0.7881016135f, 0.2090890706f, }, + { 0.7566294670f, 0.8035737276f, 0.9582333565f, 0.1049007997f, 0.2908365726f, }, + { 0.5890104175f, 0.8243371844f, 0.1194223389f, 0.4081142545f, 0.2338810265f, }, + { 0.6160389185f, 0.6119486690f, 0.4776177406f, 0.0227558762f, 0.9259954095f, }, + { 0.1666756123f, 0.0716510937f, 0.4589239061f, 0.2758954763f, 0.9412941337f, }, + { 0.5593962073f, 0.0932300612f, 0.6230918765f, 0.8459309936f, 0.5486456156f, }, + { 0.0464796945f, 0.9127272367f, 0.3356038034f, 0.7685136199f, 0.5551348925f, }, + { 0.6268597245f, 0.6607300043f, 0.6237701774f, 0.2467627674f, 0.6620935798f, }, + { 0.5111476183f, 0.7794272304f, 0.3487963974f, 0.3341582417f, 0.0624056980f, }, + { 0.3957013488f, 0.7614648938f, 0.4593580365f, 0.6479206681f, 0.8111057281f, }, + { 0.9376099706f, 0.6937710047f, 0.3772794604f, 0.4229111671f, 0.4413614571f, }, + { 0.1265666485f, 0.4300340414f, 0.4679362178f, 0.7703757286f, 0.6060098410f, }, + { 0.1987234205f, 0.1677688062f, 0.9635212421f, 0.4137647152f, 0.4632101953f, }, + { 0.2615934312f, 0.9184596539f, 0.2104500234f, 0.5944142938f, 0.3657301962f, }, + { 0.1276734024f, 0.9990953207f, 0.8774257898f, 0.0335525461f, 0.6755540371f, }, + { 0.7107648849f, 0.7014051676f, 0.9966768622f, 0.7137983441f, 0.4623017013f, }, + { 0.7589473724f, 0.9008278251f, 0.8293208480f, 0.6131841540f, 0.0364639089f, }, + { 0.3610078990f, 0.2650863230f, 0.8528714776f, 0.0846442133f, 0.1303368062f, }, + { 0.7339023948f, 0.2469002753f, 0.8481484056f, 0.5709772110f, 0.5678458214f, }, + { 0.7875075936f, 0.9358733296f, 0.7294030786f, 0.4321549237f, 0.5476644635f, }, + { 0.0062022726f, 0.5369589329f, 0.8516149521f, 0.2920427024f, 0.7357532382f, }, + { 0.2664783895f, 0.6757333875f, 0.7338925004f, 0.8482565880f, 0.9381582141f, }, + { 0.3306468129f, 0.6813066006f, 0.1940691769f, 0.5831599236f, 0.2621940970f, }, + { 0.8393519521f, 0.7582423687f, 0.6250113845f, 0.1029042825f, 0.3049384058f, }, + { 0.1147881150f, 0.2778901160f, 0.1158706546f, 0.2541174591f, 0.4413500130f, }, + { 0.4687660635f, 0.8511252999f, 0.8545516133f, 0.4600425065f, 0.3129352927f, }, + { 0.4309563637f, 0.9128248096f, 0.2374057472f, 0.1449033916f, 0.2247983068f, }, + { 0.1139339134f, 0.7892076373f, 0.9811329842f, 0.7229756713f, 0.4996600151f, }, + { 0.3327669501f, 0.2376016527f, 0.1924882680f, 0.9562231302f, 0.6383762360f, }, + { 0.7746983171f, 0.6095607877f, 0.1264629215f, 0.3252653182f, 0.6244151592f, }, + { 0.8594142795f, 0.9114995003f, 0.2029479444f, 0.4649728835f, 0.8383985758f, }, + { 0.9478753209f, 0.4653606117f, 0.7175844312f, 0.0369942226f, 0.9802376628f, }, + { 0.8346555829f, 0.5406475663f, 0.9916311502f, 0.2031923532f, 0.0845073089f, }, + { 0.5141957998f, 0.3817309737f, 0.9369073510f, 0.2497378141f, 0.3190106452f, }, + { 0.3978219926f, 0.3709410429f, 0.6247541904f, 0.5197868347f, 0.9216369987f, }, + { 0.1635272056f, 0.1833685786f, 0.2327118516f, 0.1730478704f, 0.6909444928f, }, + { 0.0854606628f, 0.5745798945f, 0.5908014774f, 0.2927988172f, 0.4878441393f, }, + { 0.8586933613f, 0.5167756677f, 0.6894454956f, 0.8916371465f, 0.3964881003f, }, + { 0.9860044718f, 0.9942120314f, 0.0953668430f, 0.7742109895f, 0.2737941444f, }, + { 0.8385732174f, 0.6917213202f, 0.3581351638f, 0.9537432194f, 0.9525402188f, }, + { 0.6977182031f, 0.4957823455f, 0.4505446553f, 0.1610960215f, 0.4250429869f, }, + { 0.3574729562f, 0.9883974791f, 0.9719611406f, 0.2679769099f, 0.9791812301f, }, + { 0.5709615350f, 0.8454045057f, 0.4813876450f, 0.4942132235f, 0.7109752893f, }, + { 0.7994604707f, 0.4398852289f, 0.3708130419f, 0.1553531587f, 0.6839964390f, }, + { 0.5957900286f, 0.5644886494f, 0.3234615326f, 0.2455180883f, 0.5604027510f, }, + { 0.6479611397f, 0.2143692672f, 0.1001929939f, 0.4399291277f, 0.1362857223f, }, + { 0.4006000757f, 0.9352084398f, 0.9691118002f, 0.2800741792f, 0.4347353876f, }, + { 0.6775333881f, 0.4759157002f, 0.9522026777f, 0.6314189434f, 0.4368703961f, }, + { 0.7306324840f, 0.6146345735f, 0.5676653981f, 0.6176615953f, 0.4205251038f, }, + { 0.5016265512f, 0.9025579095f, 0.7031668425f, 0.2271645963f, 0.2319591343f, }, + { 0.1156300306f, 0.5132398605f, 0.6020544171f, 0.7331430316f, 0.1956321150f, }, + { 0.4690348804f, 0.4377467930f, 0.5987631679f, 0.4761746526f, 0.4909768701f, }, + { 0.4606193900f, 0.0851616934f, 0.8352513909f, 0.8645496368f, 0.1553876549f, }, + { 0.4663003385f, 0.1310831159f, 0.4509260356f, 0.2993837595f, 0.0253132004f, }, + { 0.3018710017f, 0.5657193065f, 0.4945896268f, 0.0871900693f, 0.2675220370f, }, + { 0.1069414318f, 0.8611401320f, 0.3497680724f, 0.9007937312f, 0.5912517905f, }, + { 0.3611748219f, 0.6403226256f, 0.1201638058f, 0.8576251268f, 0.8542069793f, }, + { 0.3814446330f, 0.4951846004f, 0.3692566752f, 0.3071427643f, 0.8993784189f, }, + { 0.5468031168f, 0.5076970458f, 0.4790928364f, 0.4134563208f, 0.6398875117f, }, + { 0.4520143270f, 0.3022944033f, 0.2004839629f, 0.3785291910f, 0.3368770182f, }, + { 0.8978018165f, 0.5118446350f, 0.7467024922f, 0.1707707047f, 0.9671769738f, }, + { 0.5305405855f, 0.9875631928f, 0.8132194877f, 0.1337793171f, 0.5579952598f, }, + { 0.6376201510f, 0.7767909169f, 0.5033586621f, 0.6321769953f, 0.7027930021f, }, + { 0.7520409226f, 0.9649431109f, 0.8488312960f, 0.2216664106f, 0.7385339737f, }, + { 0.4746312201f, 0.7217161059f, 0.1007732823f, 0.2756705582f, 0.2097121328f, }, + { 0.3803449869f, 0.0996471271f, 0.1247078553f, 0.1910810173f, 0.9140561223f, }, + { 0.9149492979f, 0.2098353654f, 0.0767227113f, 0.8985806108f, 0.5108911395f, }, + { 0.0579735190f, 0.0932726488f, 0.8484842181f, 0.6559702754f, 0.1479938924f, }, + { 0.5624613762f, 0.0650652051f, 0.4862146974f, 0.3929865956f, 0.1172559559f, }, + { 0.3398821056f, 0.1384844780f, 0.1928209513f, 0.0195196439f, 0.6771742702f, }, + { 0.0458020084f, 0.7051184177f, 0.3182299137f, 0.2961904705f, 0.9633932114f, }, + { 0.9399008155f, 0.9739258885f, 0.4551944137f, 0.3778558969f, 0.2500957251f, }, + { 0.8838933706f, 0.0593246184f, 0.1153664067f, 0.4514839947f, 0.1898387372f, }, + { 0.8777770400f, 0.2831133604f, 0.9571491480f, 0.1251278818f, 0.0011613120f, }, + { 0.9415122271f, 0.3109248579f, 0.8637772799f, 0.1987070292f, 0.7606064677f, }, + { 0.8804537654f, 0.9864602089f, 0.6242680550f, 0.9054766297f, 0.0135219246f, }, + { 0.4445034862f, 0.7930389047f, 0.4553536177f, 0.9931444526f, 0.5695111156f, }, + { 0.9076140523f, 0.3628516495f, 0.2413775772f, 0.2246656269f, 0.2492729127f, }, + { 0.2140420377f, 0.8332853317f, 0.4634194374f, 0.3134782612f, 0.3238672316f, }, + { 0.1031284779f, 0.0113073327f, 0.2099336833f, 0.6925781369f, 0.5516031384f, }, + { 0.5016957521f, 0.9267175198f, 0.3327459395f, 0.4775586426f, 0.8115748763f, }, + { 0.9885401726f, 0.2994841039f, 0.7220330834f, 0.7301324010f, 0.7197967172f, }, + { 0.7332207561f, 0.4420665503f, 0.9687745571f, 0.3987165093f, 0.2138202488f, }, + { 0.3549204767f, 0.4881627560f, 0.5687426925f, 0.4792328179f, 0.4545526505f, }, + { 0.7456848025f, 0.8266603351f, 0.7363662720f, 0.5405669808f, 0.1186807007f, }, + { 0.5594927669f, 0.1221431792f, 0.7213705182f, 0.3600413799f, 0.1001317799f, }, + { 0.4034047723f, 0.4291865528f, 0.8388757110f, 0.7330092788f, 0.1052424833f, }, + { 0.2259417027f, 0.1105057597f, 0.2018852979f, 0.3272077143f, 0.8765095472f, }, + { 0.0674096793f, 0.8788019419f, 0.7016536593f, 0.6269735098f, 0.2225112170f, }, + { 0.4780000448f, 0.6294401884f, 0.1244457513f, 0.6985848546f, 0.4502319098f, }, + { 0.3785289526f, 0.7983933687f, 0.8313836455f, 0.5055503845f, 0.3313944042f, }, + { 0.6351121068f, 0.1403211802f, 0.4739008844f, 0.0747067481f, 0.8008176088f, }, + { 0.7154566050f, 0.0499024726f, 0.0813915581f, 0.1123222411f, 0.5307773948f, }, + { 0.1312803179f, 0.8110383153f, 0.8392069936f, 0.5230840445f, 0.2836365700f, }, + { 0.0054080924f, 0.8937095404f, 0.0980529264f, 0.1302062720f, 0.8063662648f, }, + { 0.3854928613f, 0.7761619687f, 0.3354136944f, 0.1252057105f, 0.6662501097f, }, + { 0.3357446194f, 0.7088520527f, 0.0770222023f, 0.4251736403f, 0.5111199021f, }, + { 0.6855781674f, 0.4052618742f, 0.3323065042f, 0.8265476227f, 0.1167191640f, }, + { 0.6723505259f, 0.6701938510f, 0.9685565233f, 0.0711848959f, 0.5260928273f, }, + { 0.6076920629f, 0.3108952641f, 0.8435906768f, 0.9416271448f, 0.9846994877f, }, + { 0.1855924129f, 0.5663276911f, 0.4537580013f, 0.8979920745f, 0.7847290039f, }, + { 0.7361888885f, 0.1889137328f, 0.1929481924f, 0.0232265070f, 0.3375096023f, }, + { 0.6617968082f, 0.2212614119f, 0.9393060803f, 0.5212082863f, 0.8870098591f, }, + { 0.3537924290f, 0.5832626820f, 0.1242193878f, 0.8544337153f, 0.8400560617f, }, + { 0.0959598795f, 0.3635807037f, 0.1118642092f, 0.6802095771f, 0.5064644217f, }, + { 0.9823185205f, 0.6989775896f, 0.7123054862f, 0.4045607150f, 0.4966390133f, }, + { 0.8842440248f, 0.8391990066f, 0.6193109155f, 0.8753837347f, 0.1364841759f, }, + { 0.4475662410f, 0.2754028141f, 0.6013192534f, 0.1445985585f, 0.5003407001f, }, + { 0.1361014396f, 0.9297602177f, 0.8518981934f, 0.0815051123f, 0.0945660397f, }, + { 0.0012459117f, 0.6253946424f, 0.9371947050f, 0.0474925898f, 0.8939760327f, }, + { 0.6494599581f, 0.1971486658f, 0.3466871679f, 0.7588170767f, 0.6341680288f, }, + { 0.1042030975f, 0.3886485994f, 0.2138887793f, 0.5676799417f, 0.2615441382f, }, + { 0.9391229749f, 0.8828005791f, 0.8169338703f, 0.8846142888f, 0.6647264957f, }, + { 0.1761172116f, 0.9707154036f, 0.2150721848f, 0.9363744259f, 0.9244748950f, }, + { 0.5471165776f, 0.5807911158f, 0.3485389054f, 0.9248163104f, 0.8228940368f, }, + { 0.0052462667f, 0.3914928734f, 0.2096524388f, 0.0005516103f, 0.7375964522f, }, + { 0.2354965359f, 0.4176761210f, 0.3314989209f, 0.8970170617f, 0.4880024791f, }, + { 0.0816915706f, 0.7369010448f, 0.9373006225f, 0.3696057200f, 0.8428009748f, }, + { 0.0736789331f, 0.2280396521f, 0.5821270943f, 0.0584719330f, 0.3581435382f, }, + { 0.1616331041f, 0.6217598915f, 0.9673713446f, 0.3144538701f, 0.4228736758f, }, + { 0.0501745380f, 0.1365508884f, 0.1239498556f, 0.3767664135f, 0.1245062351f, }, + { 0.9411391020f, 0.5597434640f, 0.2432802618f, 0.1177022383f, 0.9828823805f, }, + { 0.5732818246f, 0.5690141916f, 0.7410579920f, 0.7377525568f, 0.5536352992f, }, + { 0.3127796650f, 0.0813401341f, 0.5995092988f, 0.6044751406f, 0.8976248503f, }, + { 0.8933287859f, 0.4303652644f, 0.3695982993f, 0.3806284964f, 0.1915928125f, }, + { 0.3295152187f, 0.2113520205f, 0.6142043471f, 0.2390473187f, 0.2425870448f, }, + { 0.4643111229f, 0.7850609422f, 0.6896291971f, 0.2183747143f, 0.6610050201f, }, + { 0.8135676980f, 0.5605117083f, 0.2067536861f, 0.4337595701f, 0.8145171404f, }, + { 0.6546877623f, 0.6641609669f, 0.2240635902f, 0.3341553807f, 0.2463578731f, }, + { 0.3477292061f, 0.6060934067f, 0.3568925858f, 0.9741356373f, 0.1253962219f, }, + { 0.9572333097f, 0.3292025626f, 0.1934153736f, 0.3506695628f, 0.3197994232f, }, + { 0.7673865557f, 0.3394889832f, 0.9738976359f, 0.0118315266f, 0.2237675339f, }, + { 0.9870002270f, 0.7293080688f, 0.8434551954f, 0.4114209414f, 0.5717520118f, }, + { 0.7320540547f, 0.0851389915f, 0.8259694576f, 0.2623659670f, 0.1792937368f, }, + { 0.2053468823f, 0.6026678085f, 0.6966399550f, 0.6216934919f, 0.7105730176f, }, + { 0.3972368538f, 0.0794398263f, 0.3343624175f, 0.9353908896f, 0.9383234382f, }, + { 0.6858880520f, 0.6926443577f, 0.5899420381f, 0.2411883324f, 0.0054839212f, }, + { 0.6277690530f, 0.5622318387f, 0.1236412749f, 0.1567172706f, 0.2633028924f, }, + { 0.3694952726f, 0.6559251547f, 0.2420992255f, 0.3786820769f, 0.4614876509f, }, + { 0.6046964526f, 0.0808842182f, 0.9537930489f, 0.6488133669f, 0.4923732281f, }, + { 0.3406393826f, 0.4382499754f, 0.3532691002f, 0.3964454830f, 0.5908070207f, }, + { 0.1699593812f, 0.4565968812f, 0.8477159739f, 0.2887396812f, 0.0889187157f, }, + { 0.3336563408f, 0.2646266222f, 0.4892828465f, 0.5698387623f, 0.9159831405f, }, + { 0.3048604727f, 0.9648923278f, 0.7392615676f, 0.0243725926f, 0.1714320779f, }, + { 0.1084999070f, 0.0367825441f, 0.3710096180f, 0.9211341739f, 0.2153574228f, }, + { 0.5695092678f, 0.7773594856f, 0.5896557570f, 0.5982893705f, 0.0694507286f, }, + { 0.9977914691f, 0.3256978691f, 0.7132851481f, 0.9346677065f, 0.8114140630f, }, + { 0.5519405007f, 0.6570034027f, 0.7136706114f, 0.5569085479f, 0.4026521444f, }, + { 0.2814316452f, 0.5861511230f, 0.6899533868f, 0.2677451372f, 0.8730933070f, }, + { 0.3686316013f, 0.4344552159f, 0.0909462199f, 0.2535964251f, 0.7624672055f, }, + { 0.8116710782f, 0.8147524595f, 0.9394989610f, 0.2248317301f, 0.2147198766f, }, + { 0.5063940883f, 0.5379254818f, 0.3599090576f, 0.6583744884f, 0.3434786797f, }, + { 0.4244596660f, 0.7596738935f, 0.2084387541f, 0.5009082556f, 0.6744301915f, }, + { 0.5992817879f, 0.1896120608f, 0.7406286597f, 0.2486787140f, 0.4530976117f, }, + { 0.6744608879f, 0.2095753551f, 0.4823930264f, 0.7823876739f, 0.3765383661f, }, + { 0.9853712916f, 0.2303975374f, 0.4578667283f, 0.2903458178f, 0.1877734661f, }, + { 0.6396134496f, 0.3907129467f, 0.4557606280f, 0.4524177611f, 0.1143905967f, }, + { 0.4972776771f, 0.1982475221f, 0.5681200027f, 0.7287925482f, 0.3329362273f, }, + { 0.1402145177f, 0.7971151471f, 0.3701738715f, 0.8660424352f, 0.9241887331f, }, + { 0.6609226465f, 0.1375495940f, 0.9839039445f, 0.1976160854f, 0.0645802096f, }, + { 0.2378273159f, 0.2878572941f, 0.7316655517f, 0.9580275416f, 0.8398702741f, }, + { 0.1477702707f, 0.2122959942f, 0.8661295772f, 0.8981107473f, 0.8248787522f, }, + { 0.9845820069f, 0.4242613018f, 0.4454645216f, 0.6181744933f, 0.2368302345f, }, + { 0.9030548930f, 0.7935050130f, 0.2573867440f, 0.3478713036f, 0.2280597687f, }, + { 0.7250045538f, 0.8665587306f, 0.6154014468f, 0.0533810966f, 0.3748954833f, }, + { 0.4587683678f, 0.2867780030f, 0.7520769835f, 0.0273093954f, 0.0042338748f, }, + { 0.1857025921f, 0.7098686099f, 0.3267929554f, 0.3929757178f, 0.6830078363f, }, + { 0.5508182645f, 0.1895754188f, 0.6147466898f, 0.5261494517f, 0.7503330112f, }, + { 0.6770864725f, 0.7391172647f, 0.5067530274f, 0.5356315374f, 0.1920151412f, }, + { 0.2963668108f, 0.1455132812f, 0.3366815448f, 0.8031961918f, 0.4450727999f, }, + { 0.5501939058f, 0.8613340259f, 0.9883643985f, 0.6972109675f, 0.9742780924f, }, + { 0.1099400893f, 0.2395523489f, 0.9988744259f, 0.1077969074f, 0.4153169990f, }, + { 0.0588932708f, 0.9196064472f, 0.8149036169f, 0.8517987728f, 0.0252866689f, }, + { 0.0953830108f, 0.2633779049f, 0.7283058763f, 0.8969675303f, 0.1672089100f, }, + { 0.3223496377f, 0.6078441143f, 0.4913718998f, 0.1757031530f, 0.1439203322f, }, + { 0.5155597329f, 0.9438691735f, 0.2287101299f, 0.4516201913f, 0.3377495408f, }, + { 0.4717217982f, 0.8018072844f, 0.8219818473f, 0.8504306674f, 0.3374880254f, }, + { 0.2135060281f, 0.2922736406f, 0.8710723519f, 0.3306492865f, 0.0082137948f, }, + { 0.3698562980f, 0.1283289045f, 0.5767781734f, 0.4584751427f, 0.5883739591f, }, + { 0.1277351826f, 0.6547388434f, 0.1159709990f, 0.7972878218f, 0.4853661358f, }, + { 0.3138843179f, 0.2907148600f, 0.5912071466f, 0.6736337543f, 0.6416894197f, }, + { 0.0878887698f, 0.0332779400f, 0.5049689412f, 0.4261991978f, 0.7340114713f, }, + { 0.8835486174f, 0.8107994795f, 0.8632270098f, 0.5172512531f, 0.4250636101f, }, + { 0.9245924950f, 0.0804544538f, 0.8521693349f, 0.2593485713f, 0.8861954808f, }, + { 0.9965476394f, 0.7498392463f, 0.5007619262f, 0.4783139229f, 0.8900547028f, }, + { 0.9759549499f, 0.9762283564f, 0.5782196522f, 0.6812186837f, 0.8369456530f, }, + { 0.1108711287f, 0.9366273284f, 0.7295014858f, 0.8142197132f, 0.2871185243f, }, + { 0.4120090902f, 0.1552238762f, 0.6241229773f, 0.5901588798f, 0.2742916346f, }, + { 0.1171537116f, 0.3824864030f, 0.5003535748f, 0.4441032708f, 0.0590588301f, }, + { 0.6863034964f, 0.9412550926f, 0.1030604541f, 0.0928372443f, 0.5788758993f, }, + { 0.8600938320f, 0.2622856796f, 0.3243178129f, 0.8198421597f, 0.0608036108f, }, + { 0.1628451347f, 0.8431297541f, 0.9489488006f, 0.6022754312f, 0.8219873309f, }, + { 0.4523790479f, 0.1439618915f, 0.8226832747f, 0.4325985610f, 0.7620059252f, }, + { 0.9233322740f, 0.7550235391f, 0.7420312762f, 0.4091481268f, 0.0080681676f, }, + { 0.2857249677f, 0.9518624544f, 0.3186929524f, 0.7156636715f, 0.4819736481f, }, + { 0.5875384808f, 0.9693861008f, 0.9397718906f, 0.0921026245f, 0.2843349874f, }, + { 0.5598794818f, 0.0486467890f, 0.9986028671f, 0.5000310540f, 0.4492876530f, }, + { 0.4568943977f, 0.9110516906f, 0.7378745675f, 0.7045658231f, 0.0468285158f, }, + { 0.8894015551f, 0.4627184570f, 0.9816171527f, 0.8598627448f, 0.3145548701f, }, + { 0.4362269640f, 0.8303482533f, 0.9762394428f, 0.2679318190f, 0.5415852666f, }, + { 0.5135583282f, 0.6443652511f, 0.3441093564f, 0.0424862392f, 0.0372759365f, }, + { 0.4417820573f, 0.3755637109f, 0.2501712143f, 0.2316745967f, 0.7696728706f, }, + { 0.6399767399f, 0.7234238982f, 0.7173735499f, 0.4333938062f, 0.2061416209f, }, + { 0.2962370515f, 0.2198407352f, 0.4978379905f, 0.9131329060f, 0.5881273150f, }, + { 0.0274527725f, 0.6304520369f, 0.0822640583f, 0.7789397836f, 0.2952448726f, }, + { 0.9690179825f, 0.6306386590f, 0.9882766008f, 0.0559663810f, 0.7868189812f, }, + { 0.4752716720f, 0.4644761384f, 0.7389196754f, 0.7591849566f, 0.9672090411f, }, + { 0.7063110471f, 0.3089451194f, 0.5869594216f, 0.0322247148f, 0.3714854717f, }, + { 0.5593369603f, 0.5605016947f, 0.4590870738f, 0.1472124606f, 0.7597146630f, }, + { 0.1137700230f, 0.0231368188f, 0.0824881941f, 0.8750936389f, 0.8093255758f, }, + { 0.8402462602f, 0.9431380033f, 0.3831848502f, 0.8019486070f, 0.2096938789f, }, + { 0.1450119019f, 0.3844654560f, 0.3742665350f, 0.2803847492f, 0.5975660086f, }, + { 0.3614365160f, 0.2386488020f, 0.3639670908f, 0.4613662660f, 0.6767667532f, }, + { 0.3152884841f, 0.7785329819f, 0.7170776725f, 0.1606929004f, 0.0003200504f, }, + { 0.1895649135f, 0.8482950926f, 0.5920988917f, 0.5268387794f, 0.0284580551f, }, + { 0.4860107303f, 0.0186922047f, 0.8770759702f, 0.6451025009f, 0.7139035463f, }, + { 0.9079555869f, 0.1674161255f, 0.5850836635f, 0.5902752876f, 0.7807475924f, }, + { 0.1328028440f, 0.3550823927f, 0.8763128519f, 0.1409061104f, 0.8169325590f, }, + { 0.9549198747f, 0.8043766618f, 0.2520909905f, 0.2921890914f, 0.2164543271f, }, + { 0.1631576717f, 0.3762800395f, 0.9681814313f, 0.5349851847f, 0.1762493998f, }, + { 0.1457073689f, 0.4141866267f, 0.7167933583f, 0.0741236061f, 0.3502106965f, }, + { 0.4994255900f, 0.6865019798f, 0.6151999831f, 0.6936876774f, 0.4316572845f, }, + { 0.8288618326f, 0.3615471125f, 0.1165324077f, 0.1875971407f, 0.8852591515f, }, + { 0.9565691352f, 0.6450730562f, 0.6239424944f, 0.0546527803f, 0.5138095617f, }, + { 0.3606646657f, 0.7399159670f, 0.8311212659f, 0.2305879593f, 0.9957374930f, }, + { 0.7951257825f, 0.8651072383f, 0.3753368855f, 0.9134725332f, 0.7602509856f, }, + { 0.9706268311f, 0.8244435787f, 0.3721625209f, 0.6374471784f, 0.5216542482f, }, + { 0.3955391943f, 0.2386873513f, 0.0774426162f, 0.5409342647f, 0.4465825558f, }, + { 0.4333544374f, 0.6054271460f, 0.2237069160f, 0.7153035998f, 0.0594313666f, }, + { 0.0070756031f, 0.2461550236f, 0.1136701703f, 0.9059683681f, 0.3941738605f, }, + { 0.1404842287f, 0.0317301974f, 0.7502588034f, 0.5847977996f, 0.0649694577f, }, + { 0.1061957181f, 0.5282829404f, 0.4730309546f, 0.2068706751f, 0.1621830612f, }, + { 0.1909047812f, 0.8948611617f, 0.9865431786f, 0.7400736213f, 0.1817373633f, }, + { 0.4399060607f, 0.1900535673f, 0.8541012406f, 0.2264830172f, 0.8624314666f, }, + { 0.5312672853f, 0.6027213335f, 0.5833280683f, 0.4415327907f, 0.0209361687f, }, + { 0.8725429177f, 0.2334536612f, 0.5764690638f, 0.9340544939f, 0.5233708024f, }, + { 0.1558216959f, 0.0848767087f, 0.5894972086f, 0.8474051356f, 0.8646258712f, }, + { 0.1642981768f, 0.9041957855f, 0.3494294882f, 0.4702101052f, 0.5831885934f, }, + { 0.8700035810f, 0.6872510910f, 0.4935644567f, 0.9922966361f, 0.4028345346f, }, + { 0.4728413522f, 0.9360169172f, 0.3550862670f, 0.9761881232f, 0.9902327657f, }, + { 0.2360545397f, 0.9305037856f, 0.8544446230f, 0.4889979362f, 0.5349009037f, }, + { 0.5605379939f, 0.0027216305f, 0.4967855513f, 0.7788662910f, 0.1598034203f, }, + { 0.7722503543f, 0.2635759115f, 0.4510564208f, 0.9028128386f, 0.8464687467f, }, + { 0.0689743459f, 0.0221440047f, 0.0927997679f, 0.6848770976f, 0.0185078271f, }, + { 0.4341053963f, 0.9401435256f, 0.1077991053f, 0.3218205273f, 0.8370077014f, }, + { 0.4700568318f, 0.2065735161f, 0.1232072338f, 0.4821394980f, 0.4384912848f, }, + { 0.2750694156f, 0.1081104428f, 0.7501275539f, 0.8727841973f, 0.6592043638f, }, + { 0.5953353643f, 0.5154623985f, 0.2369224280f, 0.5137948394f, 0.2640386522f, }, + { 0.4883022904f, 0.4222793877f, 0.4547099471f, 0.8611297011f, 0.0144379279f, }, + { 0.2389405966f, 0.8194677830f, 0.8239278793f, 0.7628059387f, 0.7923669815f, }, + { 0.5518986583f, 0.7996187806f, 0.8428180814f, 0.0249920711f, 0.7157523036f, }, + { 0.0713605061f, 0.6955949664f, 0.4699112177f, 0.0088879559f, 0.6098486781f, }, + { 0.6564207077f, 0.5613965392f, 0.8421915174f, 0.6314644814f, 0.4711484611f, }, + { 0.3293690085f, 0.5417262316f, 0.2409638166f, 0.8098592758f, 0.7550401688f, }, + { 0.6757278442f, 0.3804965019f, 0.9431912899f, 0.4660125971f, 0.3469995260f, }, + { 0.0495499820f, 0.1130461022f, 0.4922482669f, 0.8316611052f, 0.0151698245f, }, + { 0.0455924571f, 0.0121565908f, 0.9508566260f, 0.9071891904f, 0.2990972698f, }, + { 0.1534688324f, 0.4337702692f, 0.0883032233f, 0.0341987051f, 0.8537461758f, }, + { 0.9790410399f, 0.0959524885f, 0.3532785475f, 0.4711985588f, 0.4264074564f, }, + { 0.6033026576f, 0.4930888712f, 0.3830340505f, 0.8081395030f, 0.8650298715f, }, + { 0.3055000603f, 0.9386534095f, 0.6185915470f, 0.7397578359f, 0.8365952373f, }, + { 0.1950814277f, 0.4230749309f, 0.4665976763f, 0.3757816553f, 0.7839651704f, }, + { 0.2714221776f, 0.0238825232f, 0.9983488917f, 0.2932229638f, 0.1275342405f, }, + { 0.2862882614f, 0.5271909833f, 0.6195485592f, 0.7636455894f, 0.0629235059f, }, + { 0.7156965733f, 0.2240773588f, 0.3827791810f, 0.9618224502f, 0.1208055168f, }, + { 0.7182992101f, 0.8265799284f, 0.9834881425f, 0.8465484977f, 0.5064244866f, }, + { 0.7334889770f, 0.3593994975f, 0.2179753631f, 0.2499547899f, 0.4832870960f, }, + { 0.8165280819f, 0.6433015466f, 0.1011388898f, 0.2491493225f, 0.6251221895f, }, + { 0.8351825476f, 0.8837730885f, 0.7009636164f, 0.9816825986f, 0.6400768161f, }, + { 0.1942286044f, 0.4964185357f, 0.3493340313f, 0.5624901056f, 0.4142114818f, }, + { 0.6982345581f, 0.0816430375f, 0.8636327982f, 0.3288758397f, 0.3235695958f, }, + { 0.0303881895f, 0.7907371521f, 0.6138248444f, 0.7707505822f, 0.2155624926f, }, + { 0.3126775026f, 0.0312359128f, 0.2055072635f, 0.5789466500f, 0.2451235205f, }, + { 0.6063526869f, 0.9235547185f, 0.3514375687f, 0.4948537350f, 0.1510845274f, }, + { 0.6556584239f, 0.2413987219f, 0.3424600959f, 0.9098784328f, 0.0940340310f, }, + { 0.1902333796f, 0.6079003215f, 0.6011973619f, 0.5664134622f, 0.9802165627f, }, + { 0.4605019987f, 0.7017213702f, 0.2302764356f, 0.0650736094f, 0.1494943053f, }, + { 0.6371325254f, 0.0086101834f, 0.7200685143f, 0.0810939893f, 0.5592622757f, }, + { 0.4485433698f, 0.6802972555f, 0.6205402613f, 0.1653340310f, 0.6748952866f, }, + { 0.4643500447f, 0.1593366861f, 0.7041004896f, 0.7166278362f, 0.1366539598f, }, + { 0.5593001246f, 0.4440142810f, 0.6229517460f, 0.5157993436f, 0.5213665962f, }, + { 0.1731904000f, 0.1288991719f, 0.8259183168f, 0.5144808292f, 0.9389974475f, }, + { 0.7881699800f, 0.7169192433f, 0.3419306278f, 0.2688764632f, 0.8584477901f, }, + { 0.6510105729f, 0.2690030634f, 0.2007313818f, 0.6019917727f, 0.3356880546f, }, + { 0.0651813149f, 0.5939823985f, 0.6929972768f, 0.9691227674f, 0.6415561438f, }, + { 0.7519631386f, 0.4215687215f, 0.1228209287f, 0.5847188830f, 0.5488744974f, }, + { 0.6373246908f, 0.0474342480f, 0.1138400808f, 0.9913181067f, 0.1629347950f, }, + { 0.4973835349f, 0.6254672408f, 0.6227023005f, 0.8053219914f, 0.0934493616f, }, + { 0.7392053604f, 0.0407494158f, 0.6953820586f, 0.1026247442f, 0.3242538273f, }, + { 0.9589509368f, 0.0437330976f, 0.5770876408f, 0.5448153615f, 0.3181137741f, }, + { 0.7390189171f, 0.3121966720f, 0.4732785225f, 0.9423683882f, 0.5617355704f, }, + { 0.9677296281f, 0.1870141178f, 0.9401267767f, 0.8919708729f, 0.3776246309f, }, + { 0.9423304796f, 0.6372370124f, 0.3747296929f, 0.1637496799f, 0.3287710547f, }, + { 0.1781536341f, 0.2898077965f, 0.1956719011f, 0.2145705819f, 0.2864238620f, }, + { 0.9346353412f, 0.7648710012f, 0.6211333275f, 0.4202655554f, 0.6675941944f, }, + { 0.3724445105f, 0.2103198916f, 0.9429937005f, 0.6409393549f, 0.9144501686f, }, + { 0.9311948419f, 0.0387277342f, 0.7028912902f, 0.8848278522f, 0.7504281998f, }, + { 0.7315697074f, 0.8166554570f, 0.3738918602f, 0.1557686031f, 0.7847886682f, }, + { 0.4125709236f, 0.5739986897f, 0.8182309866f, 0.4204152524f, 0.9961208105f, }, + { 0.1337789744f, 0.8342238665f, 0.7159512043f, 0.0682141855f, 0.7818093300f, }, + { 0.6113092899f, 0.1265794486f, 0.3459638655f, 0.1549623311f, 0.4131218791f, }, + { 0.4264710248f, 0.2668181062f, 0.9455268383f, 0.7712184191f, 0.1320666820f, }, + { 0.4694555104f, 0.0086664017f, 0.4457104802f, 0.7159432769f, 0.0337547176f, }, + { 0.2647216618f, 0.4527841508f, 0.8764959574f, 0.5165018439f, 0.8749205470f, }, + { 0.3994765878f, 0.2661662698f, 0.9404622316f, 0.7213953137f, 0.0779966936f, }, + { 0.7699434161f, 0.9601191878f, 0.5917244554f, 0.7436037660f, 0.7265306115f, }, + { 0.5331710577f, 0.9649403095f, 0.7461229563f, 0.1577638239f, 0.1233422831f, }, + { 0.4796034992f, 0.2960034311f, 0.5717763305f, 0.0491046421f, 0.5753382444f, }, + { 0.4763813615f, 0.6436579823f, 0.9660188556f, 0.4250706732f, 0.1054467559f, }, + { 0.7750216722f, 0.6982519031f, 0.2201368511f, 0.9212501645f, 0.9318611622f, }, + { 0.8586993217f, 0.4595151246f, 0.4544635117f, 0.8432085514f, 0.9247248173f, }, + { 0.0365047753f, 0.9654330015f, 0.8264771104f, 0.0376608036f, 0.4492781758f, }, + { 0.1058536917f, 0.3432896435f, 0.2352729738f, 0.9503269792f, 0.0749945343f, }, + { 0.2234555930f, 0.9738846421f, 0.7322180271f, 0.2067189217f, 0.8659912348f, }, + { 0.9642325640f, 0.5460907817f, 0.9585637450f, 0.0354396738f, 0.6169741750f, }, + { 0.7099645734f, 0.9816644788f, 0.4517419636f, 0.0953767225f, 0.5571715236f, }, + { 0.6565949321f, 0.0623320453f, 0.6225028038f, 0.6433296204f, 0.0129790707f, }, + { 0.7715957165f, 0.8371360898f, 0.4941186309f, 0.9075725675f, 0.1588838398f, }, + { 0.4867556989f, 0.7108978629f, 0.7019207478f, 0.0364425257f, 0.7733047605f, }, + { 0.2023717612f, 0.3168994784f, 0.3704363108f, 0.9331393242f, 0.4755581915f, }, + { 0.8266717196f, 0.9457639456f, 0.6074644327f, 0.9668362737f, 0.9510031939f, }, + { 0.5254657865f, 0.1426365823f, 0.5963256955f, 0.7344507575f, 0.8503690958f, }, + { 0.2499096096f, 0.7108363509f, 0.9408258200f, 0.9992586374f, 0.5567165017f, }, + { 0.9616196156f, 0.2910158932f, 0.1227196753f, 0.5921880007f, 0.9253353477f, }, + { 0.4614745080f, 0.7173299789f, 0.8424515724f, 0.6755405664f, 0.9408789873f, }, + { 0.9209164381f, 0.1908068508f, 0.2003200054f, 0.3124685287f, 0.8087954521f, }, + { 0.5242611170f, 0.6289529204f, 0.6980254054f, 0.1620536894f, 0.7590764761f, }, + { 0.6776715517f, 0.4167804420f, 0.4525309503f, 0.6873601079f, 0.6441275477f, }, + { 0.2402851582f, 0.8918765187f, 0.7217081785f, 0.6020851731f, 0.6847493052f, }, + { 0.8492304683f, 0.7355428934f, 0.0947460234f, 0.3588216007f, 0.8229489326f, }, + { 0.8866733909f, 0.3527204394f, 0.4839482009f, 0.9514900446f, 0.9171634316f, }, + { 0.5798678398f, 0.8700700402f, 0.2567514181f, 0.2472462505f, 0.9536755085f, }, + { 0.5097897053f, 0.0595137477f, 0.6220785975f, 0.6314375401f, 0.0052603451f, }, + { 0.4557119012f, 0.3513344228f, 0.5795360208f, 0.2327984571f, 0.1657098830f, }, + { 0.7886769772f, 0.8890479207f, 0.2429098487f, 0.4871490598f, 0.2671397626f, }, + { 0.7175374031f, 0.7549058199f, 0.9726084471f, 0.3851055205f, 0.5513847470f, }, + { 0.4111255705f, 0.0779726356f, 0.8733567595f, 0.7498862743f, 0.7931258082f, }, + { 0.2799656093f, 0.8763404489f, 0.3736275733f, 0.6477729678f, 0.0880915597f, }, + { 0.8108944893f, 0.8728898764f, 0.8266988993f, 0.1610427350f, 0.1892506182f, }, + { 0.1411487609f, 0.0869028941f, 0.8278047442f, 0.8747546077f, 0.5107010007f, }, + { 0.4084055722f, 0.3980386257f, 0.4770012796f, 0.3506475389f, 0.4807008505f, }, + { 0.7788491845f, 0.3133334816f, 0.5976699591f, 0.6842749715f, 0.3748018146f, }, + { 0.8610635996f, 0.1022957861f, 0.9418399334f, 0.8243051767f, 0.1967420876f, }, + { 0.9247750044f, 0.7166752219f, 0.2410049587f, 0.1345794052f, 0.1353064775f, }, + { 0.9325634241f, 0.1108572036f, 0.9813696146f, 0.1351464540f, 0.2093860060f, }, + { 0.9749392271f, 0.2828991413f, 0.2484795600f, 0.2666292191f, 0.1520102471f, }, + { 0.4139654338f, 0.3740066886f, 0.1225339025f, 0.8656436205f, 0.4221470952f, }, + { 0.0319013111f, 0.7414957881f, 0.9600464106f, 0.2753627300f, 0.5269204378f, }, + { 0.7114865184f, 0.1122055501f, 0.4771135151f, 0.8740446568f, 0.4567165673f, }, + { 0.2876826823f, 0.6616845131f, 0.4751175344f, 0.0586588420f, 0.2287436724f, }, + { 0.0853352547f, 0.2039020509f, 0.7204459310f, 0.7545861006f, 0.6928667426f, }, + { 0.8831790686f, 0.0137837529f, 0.5853300095f, 0.1472780704f, 0.4519954026f, }, + { 0.0097109666f, 0.6952510476f, 0.2078256607f, 0.0373575352f, 0.8211422563f, }, + { 0.0558194369f, 0.7313686609f, 0.4689704478f, 0.0956792310f, 0.8963633180f, }, + { 0.1120448038f, 0.8181142807f, 0.2486581802f, 0.1398879588f, 0.5254757404f, }, + { 0.4015758932f, 0.5145997405f, 0.9422720075f, 0.8330059052f, 0.1405406892f, }, + { 0.2055794895f, 0.5196123719f, 0.2358682454f, 0.9054501653f, 0.7132432461f, }, + { 0.5218886137f, 0.2069944590f, 0.9510710835f, 0.9345709682f, 0.8948713541f, }, + { 0.7883835435f, 0.5115756392f, 0.1945326626f, 0.8407603502f, 0.7063624263f, }, + { 0.8107746243f, 0.5006308556f, 0.6917774081f, 0.0947859362f, 0.9130716324f, }, + { 0.6934458017f, 0.8371333480f, 0.5858495235f, 0.4684022069f, 0.1297370195f, }, + { 0.8348796368f, 0.2570964694f, 0.8386361599f, 0.6226717830f, 0.1130922958f, }, + { 0.9165218472f, 0.9632377028f, 0.2056088150f, 0.6110759974f, 0.4853537083f, }, + { 0.7115112543f, 0.5202045441f, 0.2516072392f, 0.5528147221f, 0.6722636223f, }, + { 0.0857901201f, 0.3362386525f, 0.7351680994f, 0.1903360337f, 0.7454760075f, }, + { 0.1719599664f, 0.3871241510f, 0.0932018459f, 0.5050786138f, 0.3789227903f, }, + { 0.4801812768f, 0.3383860588f, 0.2529097497f, 0.1465537101f, 0.7296524048f, }, + { 0.8325640559f, 0.6243760586f, 0.7460099459f, 0.5149294138f, 0.4651752710f, }, + { 0.6389155388f, 0.2837399840f, 0.4793967307f, 0.4775217175f, 0.7251787782f, }, + { 0.5939979553f, 0.7855195999f, 0.2565509081f, 0.2451145947f, 0.8145719767f, }, + { 0.9989110231f, 0.4190405905f, 0.7036142945f, 0.2327067256f, 0.5372658372f, }, + { 0.3613760471f, 0.1656554788f, 0.7119393349f, 0.6189714074f, 0.4541467130f, }, + { 0.1851339340f, 0.9553622603f, 0.9637113810f, 0.6177098155f, 0.4731043875f, }, + { 0.1212384477f, 0.3031343222f, 0.8617272973f, 0.6502091885f, 0.9532495141f, }, + { 0.1428751349f, 0.5784316063f, 0.8611226678f, 0.7624854445f, 0.3929765522f, }, + { 0.3805690408f, 0.2545896173f, 0.4466824830f, 0.0148397582f, 0.7657743096f, }, + { 0.2754941881f, 0.2660249472f, 0.3798875213f, 0.0561728552f, 0.2154681683f, }, + { 0.7341149449f, 0.0007955993f, 0.9754754901f, 0.7575864196f, 0.4401446283f, }, + { 0.3954862356f, 0.9139688015f, 0.0888266265f, 0.9475591183f, 0.1982856691f, }, + { 0.3180034757f, 0.1625751108f, 0.6209735870f, 0.0859823376f, 0.3882405758f, }, + { 0.9705940485f, 0.1734909266f, 0.0772138909f, 0.0918193385f, 0.5063413978f, }, + { 0.5866190791f, 0.6064302921f, 0.5918045044f, 0.0902755186f, 0.4035459459f, }, + { 0.2529979944f, 0.4870192409f, 0.7385742664f, 0.5739389658f, 0.5148332715f, }, + { 0.3613711298f, 0.6982057691f, 0.8151579499f, 0.0558659509f, 0.8067486882f, }, + { 0.8757463098f, 0.0754071176f, 0.5679771304f, 0.5892222524f, 0.6132609844f, }, + { 0.4841753244f, 0.6670720577f, 0.2203004360f, 0.6152839661f, 0.2635495067f, }, + { 0.6389313340f, 0.9386772513f, 0.4869751036f, 0.1686008424f, 0.7793906927f, }, + { 0.9790409207f, 0.3224077225f, 0.8712618351f, 0.5796620250f, 0.3888646662f, }, + { 0.2546674609f, 0.0513000451f, 0.0885773450f, 0.4971133173f, 0.1139139161f, }, + { 0.5330253839f, 0.4458592236f, 0.3802547753f, 0.0015436492f, 0.1718741059f, }, + { 0.1361114830f, 0.2954665422f, 0.4838488400f, 0.9782880545f, 0.1594657898f, }, + { 0.7138190269f, 0.7218046784f, 0.2323043793f, 0.6022443771f, 0.6132761240f, }, + { 0.5647003055f, 0.2424000800f, 0.3284954727f, 0.0589503162f, 0.5575588346f, }, + { 0.6864364147f, 0.2493986487f, 0.7412534356f, 0.0820376799f, 0.5341425538f, }, + { 0.0063022207f, 0.9143952727f, 0.6206943989f, 0.7297399640f, 0.3183074892f, }, + { 0.5311909318f, 0.5075007677f, 0.2363121957f, 0.7450247407f, 0.7809490561f, }, + { 0.5307874084f, 0.2871339321f, 0.0779721290f, 0.0620434582f, 0.6296265125f, }, + { 0.8584765792f, 0.6359632611f, 0.6179780960f, 0.8185879588f, 0.1748676598f, }, + { 0.3249195814f, 0.4600475132f, 0.2011979520f, 0.8418532610f, 0.8995137215f, }, + { 0.0039332760f, 0.0563738309f, 0.7099885941f, 0.7007045746f, 0.7458211184f, }, + { 0.9885305166f, 0.3783204854f, 0.0826100335f, 0.9335113168f, 0.2823200822f, }, + { 0.6438007951f, 0.9114531279f, 0.8699083328f, 0.9901625514f, 0.6779408455f, }, + { 0.9690108299f, 0.5257256627f, 0.4997349977f, 0.8986558914f, 0.3242087662f, }, + { 0.9182067513f, 0.2991752625f, 0.3558880091f, 0.2111450881f, 0.2120029628f, }, + { 0.0263157599f, 0.4290898740f, 0.1083222777f, 0.7784960866f, 0.7758093476f, }, + { 0.6886820197f, 0.7317797542f, 0.4681655765f, 0.5954000950f, 0.9929780960f, }, + { 0.3185992241f, 0.8502960205f, 0.9525064230f, 0.2416978776f, 0.1468276083f, }, + { 0.8019496799f, 0.6480351090f, 0.3450838625f, 0.1173318177f, 0.4027911425f, }, + { 0.0391170271f, 0.7285984159f, 0.8304167390f, 0.9850556254f, 0.5423062444f, }, + { 0.0818975791f, 0.5483108163f, 0.2151320577f, 0.9997138381f, 0.5160960555f, }, + { 0.5859099627f, 0.1212509349f, 0.4737671018f, 0.3530995548f, 0.5802864432f, }, + { 0.7772214413f, 0.2383177727f, 0.6023976207f, 0.4735913873f, 0.4751731753f, }, + { 0.3340452313f, 0.7923023105f, 0.4606459439f, 0.9486450553f, 0.9033490419f, }, + { 0.8815308213f, 0.1388822794f, 0.2302107215f, 0.5003027916f, 0.1892398000f, }, + { 0.2944695354f, 0.8203642964f, 0.3520234227f, 0.5205004215f, 0.3420150578f, }, + { 0.1313518733f, 0.2285410017f, 0.4750854969f, 0.1811993420f, 0.6650058031f, }, + { 0.8825643659f, 0.2593260407f, 0.4513739347f, 0.5593579412f, 0.0403011777f, }, + { 0.2482140511f, 0.7435663342f, 0.6120058298f, 0.7297807932f, 0.1407711208f, }, + { 0.3960608542f, 0.0546920225f, 0.2039171457f, 0.0254108403f, 0.4188559055f, }, + { 0.4640986621f, 0.8288553953f, 0.5997421741f, 0.0178059582f, 0.8276942372f, }, + { 0.2168370485f, 0.0862968042f, 0.0785248429f, 0.4705827832f, 0.1424753219f, }, + { 0.1090355963f, 0.0635560080f, 0.1221310049f, 0.9232905507f, 0.7839717269f, }, + { 0.3394386172f, 0.5255436897f, 0.6179113984f, 0.6680825353f, 0.9542113543f, }, + { 0.6983990669f, 0.6871361732f, 0.4743655324f, 0.6466472745f, 0.9830511808f, }, + { 0.1112656891f, 0.6871949434f, 0.8293682337f, 0.1073063388f, 0.1485439688f, }, + { 0.4966143668f, 0.3621051908f, 0.6897413731f, 0.5554760695f, 0.4509290159f, }, + { 0.6146492958f, 0.6667609215f, 0.0924460217f, 0.4585912824f, 0.7487086058f, }, + { 0.1128270552f, 0.5709548593f, 0.0877091512f, 0.1401374191f, 0.6482701898f, }, + { 0.7608259320f, 0.9945762753f, 0.2145056576f, 0.3915721476f, 0.3191218972f, }, + { 0.4560193419f, 0.9845030308f, 0.0788487345f, 0.1208945960f, 0.8802305460f, }, + { 0.2661793828f, 0.2456931919f, 0.9981367588f, 0.4506645203f, 0.4504982829f, }, + { 0.9565261602f, 0.8473084569f, 0.1133293286f, 0.8762695193f, 0.9337145686f, }, + { 0.2534602284f, 0.3628862202f, 0.3275935054f, 0.2089666277f, 0.2992331684f, }, + { 0.6649219990f, 0.7315315008f, 0.9478498697f, 0.6084333658f, 0.4357850254f, }, + { 0.1365931928f, 0.4972289801f, 0.4691647291f, 0.9750099778f, 0.4458443522f, }, + { 0.2258721441f, 0.2522766590f, 0.1220288649f, 0.7289676070f, 0.7348276377f, }, + { 0.3755582571f, 0.3497219086f, 0.9531602859f, 0.8352612853f, 0.6633071899f, }, + { 0.0456891730f, 0.3805855215f, 0.8235828280f, 0.4252410829f, 0.7493836880f, }, + { 0.1456706375f, 0.6497740746f, 0.7125581503f, 0.1624079943f, 0.1373025924f, }, + { 0.1279350668f, 0.9708826542f, 0.0857626721f, 0.3923688829f, 0.4117092490f, }, + { 0.1969340444f, 0.5416286588f, 0.9817547202f, 0.9610751867f, 0.0845267698f, }, + { 0.3368629813f, 0.0690044612f, 0.4572432637f, 0.9595646858f, 0.2418597490f, }, + { 0.9865912199f, 0.4423881471f, 0.3373891115f, 0.0673551485f, 0.3699241579f, }, + { 0.4154234529f, 0.9594244957f, 0.5812380314f, 0.5115464330f, 0.1990439892f, }, + { 0.8013362885f, 0.9563085437f, 0.1061981991f, 0.7063205838f, 0.7125397921f, }, + { 0.6885972619f, 0.2192605138f, 0.6091698408f, 0.6059626341f, 0.2404647619f, }, + { 0.6032620668f, 0.6457625031f, 0.8460487127f, 0.4852031171f, 0.2487026453f, }, + { 0.0366728604f, 0.1735072583f, 0.6197302938f, 0.0397418551f, 0.1751434356f, }, + { 0.4093625247f, 0.0172295254f, 0.2076015025f, 0.5433748364f, 0.0509383641f, }, + { 0.5896348953f, 0.2516341507f, 0.8555691838f, 0.6506301761f, 0.7745659947f, }, + { 0.8766552210f, 0.1228426024f, 0.9877105951f, 0.7690671682f, 0.4693732560f, }, + { 0.3430191576f, 0.2883387506f, 0.2496049404f, 0.4174309671f, 0.7055002451f, }, + { 0.3456101716f, 0.6632670164f, 0.4655898809f, 0.9639615417f, 0.3936365247f, }, + { 0.5241488218f, 0.7119670510f, 0.9832746983f, 0.0365021713f, 0.1418611556f, }, + { 0.5869303346f, 0.9949745536f, 0.2289099246f, 0.7857643366f, 0.7014958262f, }, + { 0.8856402040f, 0.7443384528f, 0.1151549369f, 0.0570810400f, 0.5269777775f, }, + { 0.2219097316f, 0.4180500209f, 0.9574242234f, 0.1995432675f, 0.8916079998f, }, + { 0.9351537824f, 0.3360730410f, 0.4645262659f, 0.4120020866f, 0.1104221940f, }, + { 0.5611331463f, 0.6386611462f, 0.3377301395f, 0.7225644588f, 0.9313002229f, }, + { 0.2981921136f, 0.4605979621f, 0.9575611353f, 0.1653224230f, 0.1528882980f, }, + { 0.1236567870f, 0.1312875301f, 0.9425463080f, 0.3917533755f, 0.0589572191f, }, + { 0.6515007019f, 0.6880768538f, 0.8231864572f, 0.6149953008f, 0.7472731471f, }, + { 0.9031752348f, 0.3369258046f, 0.3466275632f, 0.6369885206f, 0.1158203036f, }, + { 0.5125613809f, 0.2982789874f, 0.4604129195f, 0.1476354748f, 0.1393106431f, }, + { 0.1006692275f, 0.6609869599f, 0.4564038217f, 0.4572893977f, 0.0572066456f, }, + { 0.7080409527f, 0.9572702050f, 0.6036813855f, 0.8634923697f, 0.6499301791f, }, + { 0.6245829463f, 0.8936629891f, 0.0847953558f, 0.4449445307f, 0.6379930377f, }, + { 0.7438736558f, 0.2923384011f, 0.7096884251f, 0.3461559117f, 0.0198387168f, }, + { 0.1270768046f, 0.0211520232f, 0.9564839005f, 0.3647421300f, 0.7926282287f, }, + { 0.7122219801f, 0.4070749581f, 0.6913565993f, 0.9376250505f, 0.6553639174f, }, + { 0.5594186783f, 0.2159312665f, 0.4742873609f, 0.9990153313f, 0.7695833445f, }, + { 0.8024565578f, 0.1413995922f, 0.5684570670f, 0.4031882882f, 0.8406370878f, }, + { 0.3902987540f, 0.1381790936f, 0.3201354444f, 0.1551815420f, 0.7198241949f, }, + { 0.2351662070f, 0.8418413997f, 0.7066733241f, 0.5653064251f, 0.3583040237f, }, + { 0.4102395177f, 0.9087673426f, 0.5705324411f, 0.9249805212f, 0.5928071141f, }, + { 0.0126413815f, 0.9960880280f, 0.6977165937f, 0.6824188232f, 0.6318088770f, }, + { 0.1370527446f, 0.6809042692f, 0.3438777030f, 0.8870877624f, 0.9437358975f, }, + { 0.3634917140f, 0.5165042877f, 0.8414770365f, 0.8369385600f, 0.2037138492f, }, + { 0.7863583565f, 0.4692445099f, 0.2232517451f, 0.4170775115f, 0.2558470666f, }, + { 0.6936772466f, 0.2843486071f, 0.7230042219f, 0.4351403713f, 0.6764482856f, }, + { 0.8232243061f, 0.1461527050f, 0.9427404404f, 0.9088268876f, 0.8979268670f, }, + { 0.2267044932f, 0.4442048669f, 0.2051906139f, 0.5698810220f, 0.3392190933f, }, + { 0.0771049634f, 0.3125287592f, 0.3603034914f, 0.7278358936f, 0.4766102135f, }, + { 0.7205414176f, 0.1379755288f, 0.3613466620f, 0.1172247231f, 0.5505853891f, }, + { 0.8976436257f, 0.1885688454f, 0.7072427273f, 0.5713613033f, 0.0896134153f, }, + { 0.1108992770f, 0.4499467611f, 0.8732603192f, 0.4181646109f, 0.9823195338f, }, + { 0.6648517251f, 0.0476900302f, 0.2431214452f, 0.1597129554f, 0.9605688453f, }, + { 0.8735862970f, 0.9620782137f, 0.2449910343f, 0.4972401857f, 0.8360961080f, }, + { 0.9318570495f, 0.0118331537f, 0.0871321484f, 0.9110755324f, 0.1245511919f, }, + { 0.0120295202f, 0.7309275270f, 0.2558850050f, 0.8504547477f, 0.2086956203f, }, + { 0.5944172144f, 0.6177854538f, 0.9679172039f, 0.6963319778f, 0.4652388096f, }, + { 0.1282349527f, 0.8594450355f, 0.2049074620f, 0.6912082434f, 0.3491280377f, }, + { 0.5212653875f, 0.7254321575f, 0.8557592034f, 0.5330650210f, 0.8922915459f, }, + { 0.4428530931f, 0.4409148991f, 0.2075135857f, 0.2139482945f, 0.2372723818f, }, + { 0.1344977617f, 0.3403683305f, 0.4871248007f, 0.6766581535f, 0.3431895375f, }, + { 0.8300520778f, 0.2341357917f, 0.3823474646f, 0.4674374461f, 0.2806982100f, }, + { 0.5980251431f, 0.0239732657f, 0.8454552889f, 0.4936358929f, 0.8911316395f, }, + { 0.2736046016f, 0.1264330149f, 0.1217748150f, 0.5203144550f, 0.9563813210f, }, + { 0.6798967719f, 0.8966814280f, 0.2325180471f, 0.8903793097f, 0.8114367723f, }, + { 0.2934849858f, 0.0136003289f, 0.8234140277f, 0.3610075712f, 0.5958183408f, }, + { 0.9930573106f, 0.0314410664f, 0.9526392221f, 0.0255242772f, 0.5699372292f, }, + { 0.0087598842f, 0.6366280913f, 0.7207630873f, 0.9496116638f, 0.3954304457f, }, + { 0.3128762841f, 0.5304647088f, 0.1213271618f, 0.1467175335f, 0.4860333800f, }, + { 0.4939534664f, 0.1531855166f, 0.2000542432f, 0.6310173869f, 0.6595714092f, }, + { 0.7309086919f, 0.7785629630f, 0.4514578879f, 0.6676999331f, 0.2192534953f, }, + { 0.7403250337f, 0.9841399193f, 0.6916406155f, 0.7269148827f, 0.9438167810f, }, + { 0.6998386383f, 0.4706457257f, 0.2070418447f, 0.4841609299f, 0.7389830351f, }, + { 0.2683275938f, 0.0676938370f, 0.4881869853f, 0.2454564720f, 0.1602723002f, }, + { 0.5296664834f, 0.7877382636f, 0.4697082043f, 0.2750242352f, 0.6280722618f, }, + { 0.9084600210f, 0.9373245239f, 0.6219260097f, 0.7891891003f, 0.6690227985f, }, + { 0.1422366947f, 0.7514579296f, 0.4901350737f, 0.8721100092f, 0.2750261426f, }, + { 0.5114755034f, 0.8930193186f, 0.5866002440f, 0.5487608314f, 0.2491485775f, }, + { 0.1582965553f, 0.1406119913f, 0.1947881579f, 0.1997673810f, 0.6640841365f, }, + { 0.4515717924f, 0.7628028989f, 0.2299791127f, 0.7113984227f, 0.0862207487f, }, + { 0.4640478194f, 0.7691074014f, 0.1014884338f, 0.9796831608f, 0.0766738132f, }, + { 0.9116546512f, 0.4276819825f, 0.8561990261f, 0.5936996341f, 0.1075137705f, }, + { 0.0239505097f, 0.3316314518f, 0.4879444540f, 0.1845136583f, 0.3887792230f, }, + { 0.1391853690f, 0.9428163767f, 0.2558288574f, 0.2862555385f, 0.2294884175f, }, + { 0.0425246134f, 0.7538257241f, 0.7470843792f, 0.0413450673f, 0.1121925861f, }, + { 0.2891909480f, 0.7587980032f, 0.3463464975f, 0.6197323799f, 0.6763352156f, }, + { 0.2324884683f, 0.0440495051f, 0.2137145698f, 0.6355563402f, 0.7238734961f, }, + { 0.9867273569f, 0.0739541277f, 0.4701449871f, 0.4313713908f, 0.6602859497f, }, + { 0.6086152196f, 0.4417156279f, 0.9974262714f, 0.0975009874f, 0.8445842862f, }, + { 0.5522742867f, 0.3969660699f, 0.6214118600f, 0.7788109183f, 0.7136057615f, }, + { 0.2289288491f, 0.2130244672f, 0.6027131677f, 0.6124268174f, 0.9251578450f, }, + { 0.0616566502f, 0.8236808181f, 0.1958899200f, 0.4427541792f, 0.2653938234f, }, + { 0.1808390319f, 0.5971671939f, 0.2315298319f, 0.9344127774f, 0.2182364315f, }, + { 0.7783111334f, 0.4874379933f, 0.3447670937f, 0.6238422990f, 0.9411003590f, }, + { 0.9611390829f, 0.7089878917f, 0.1187877357f, 0.6627644300f, 0.4982549846f, }, + { 0.6327852607f, 0.5914241076f, 0.5998700857f, 0.6847869754f, 0.2001991421f, }, + { 0.2943502367f, 0.2379508168f, 0.2451606393f, 0.5758971572f, 0.9493308067f, }, + { 0.2112886310f, 0.1238107979f, 0.9436278343f, 0.4755471647f, 0.6834369302f, }, + { 0.5818591714f, 0.0113358516f, 0.7210019231f, 0.9679825306f, 0.3710557818f, }, + { 0.2515459955f, 0.2659612596f, 0.8592920899f, 0.3314473331f, 0.6388500333f, }, + { 0.9415346384f, 0.9097257853f, 0.3393050432f, 0.9217511415f, 0.1159513220f, }, + { 0.7385159731f, 0.1135490239f, 0.5887776613f, 0.6945705414f, 0.7332811356f, }, + { 0.2237532437f, 0.3118081689f, 0.0983192325f, 0.0391748250f, 0.6431609988f, }, + { 0.7369810939f, 0.7353634238f, 0.6044911742f, 0.5575240254f, 0.2729411125f, }, + { 0.4577404559f, 0.7433678508f, 0.5883631110f, 0.2749655843f, 0.8003346920f, }, + { 0.0185033157f, 0.8160027266f, 0.1016062647f, 0.4272126555f, 0.4561058283f, }, + { 0.4552623928f, 0.0299864579f, 0.1988892108f, 0.4020333290f, 0.7105627060f, }, + { 0.7255421877f, 0.6319249272f, 0.4746235013f, 0.4684766531f, 0.1954155117f, }, + { 0.9501298070f, 0.2715771794f, 0.9850295186f, 0.8014503121f, 0.1959972680f, }, + { 0.4614772499f, 0.3934194148f, 0.7261785865f, 0.7577277422f, 0.7315858603f, }, + { 0.1758584380f, 0.5568647981f, 0.3278964758f, 0.7147050500f, 0.4275215864f, }, + { 0.9476006031f, 0.0250451006f, 0.9447517395f, 0.7898845673f, 0.4516260624f, }, + { 0.5857234597f, 0.0512867458f, 0.3506784439f, 0.0615031905f, 0.6430190802f, }, + { 0.7824978828f, 0.1282590479f, 0.7053239942f, 0.2010644525f, 0.5349711776f, }, + { 0.1372918785f, 0.6280158162f, 0.4919610918f, 0.7425698638f, 0.6999062896f, }, + { 0.2883373201f, 0.9213928580f, 0.4459832311f, 0.3443984687f, 0.4061470926f, }, + { 0.7968639731f, 0.2202416509f, 0.2530643046f, 0.9734023213f, 0.0877880007f, }, + { 0.2693817914f, 0.3541754484f, 0.1994337142f, 0.9290516973f, 0.5692538023f, }, + { 0.9975730181f, 0.2123656869f, 0.7291432023f, 0.6331786513f, 0.7425414324f, }, + { 0.9666696787f, 0.9205757976f, 0.9922174215f, 0.6824410558f, 0.3949363232f, }, + { 0.4523568451f, 0.3250179291f, 0.8157433867f, 0.7998639941f, 0.6998991966f, }, + { 0.9239279032f, 0.8988652229f, 0.9555116296f, 0.1968290061f, 0.9351155758f, }, + { 0.1396250725f, 0.8221547604f, 0.6174406409f, 0.9926145077f, 0.1054789126f, }, + { 0.2044666409f, 0.8935524821f, 0.5867761374f, 0.0919070765f, 0.9262919426f, }, + { 0.8059595227f, 0.6214087009f, 0.9671977758f, 0.3435967267f, 0.9270213246f, }, + { 0.7631459832f, 0.5441656709f, 0.5690038800f, 0.7316193581f, 0.0488156527f, }, + { 0.6897270083f, 0.4517463148f, 0.0790012106f, 0.6756342053f, 0.0092511894f, }, + { 0.8497228622f, 0.2521197498f, 0.0792140812f, 0.3596895635f, 0.9127144217f, }, + { 0.8415563107f, 0.9236878157f, 0.8178555965f, 0.7622930408f, 0.4520805478f, }, + { 0.7207684517f, 0.0002339473f, 0.8758230209f, 0.9918480515f, 0.0707794428f, }, + { 0.9606991410f, 0.4286506176f, 0.1999435574f, 0.4169917405f, 0.9239530563f, }, + { 0.9947629571f, 0.6634295583f, 0.1124853790f, 0.6303933263f, 0.9871919751f, }, + { 0.0817595869f, 0.3557197750f, 0.3711491525f, 0.9300679564f, 0.5547308326f, }, + { 0.2435157299f, 0.0209109467f, 0.4599942267f, 0.4878067970f, 0.8793050051f, }, + { 0.0423153229f, 0.8052753210f, 0.7139890790f, 0.9856292605f, 0.4745872319f, }, + { 0.5374484658f, 0.6929543614f, 0.3381887376f, 0.8924344778f, 0.7035735846f, }, + { 0.0163216051f, 0.9601459503f, 0.4612768292f, 0.9745629430f, 0.6749196649f, }, + { 0.8972948790f, 0.4060208797f, 0.4955765009f, 0.1287103891f, 0.0165866725f, }, + { 0.2238298953f, 0.7431547642f, 0.1179674938f, 0.4836426973f, 0.1631947905f, }, + { 0.6472587585f, 0.1457427144f, 0.5792192221f, 0.4989259541f, 0.3163287044f, }, + { 0.8858006001f, 0.6277303100f, 0.8673131466f, 0.1005147174f, 0.3907134831f, }, + { 0.5618023872f, 0.1673547477f, 0.9736580849f, 0.0937287509f, 0.1883356422f, }, + { 0.2679286599f, 0.8614320755f, 0.9980326891f, 0.1604878306f, 0.9749154449f, }, + { 0.7830008268f, 0.7333298326f, 0.2121554017f, 0.0217836369f, 0.3229865432f, }, + { 0.9212281108f, 0.1436148435f, 0.3445620239f, 0.1202699766f, 0.8970475197f, }, + { 0.3069497943f, 0.9134603143f, 0.5702125430f, 0.9975665808f, 0.8581698537f, }, + { 0.1285094619f, 0.8788124323f, 0.6045054197f, 0.0238512605f, 0.7748757005f, }, + { 0.4398401380f, 0.1355615109f, 0.3822240233f, 0.0692974851f, 0.2045793086f, }, + { 0.9858217835f, 0.1212140545f, 0.6925217509f, 0.7451168895f, 0.0625852048f, }, + { 0.3625119030f, 0.2956384718f, 0.8160207868f, 0.7297493219f, 0.4369413555f, }, + { 0.4427506328f, 0.9191280007f, 0.5053682923f, 0.0208856091f, 0.7545157671f, }, + { 0.4905830324f, 0.7630480528f, 0.8163150549f, 0.0459906720f, 0.3951961696f, }, + { 0.0753518045f, 0.9801540375f, 0.4568540156f, 0.2488125265f, 0.0453826711f, }, + { 0.8161067367f, 0.5382704139f, 0.4462370872f, 0.3017324209f, 0.5584515929f, }, + { 0.1887043715f, 0.2579388916f, 0.3778715730f, 0.7925445437f, 0.0965660885f, }, + { 0.2905142903f, 0.3557309806f, 0.5700449944f, 0.9479649663f, 0.7678772211f, }, + { 0.0886231884f, 0.6995251775f, 0.7007929087f, 0.8652918935f, 0.0007268046f, }, + { 0.5928665996f, 0.7081015706f, 0.7118461132f, 0.9706901908f, 0.5527791381f, }, + { 0.8002860546f, 0.9183729291f, 0.4663964510f, 0.5793769956f, 0.8500337601f, }, + { 0.5833042860f, 0.6461704373f, 0.9975832701f, 0.1549375802f, 0.6594515443f, }, + { 0.1252454221f, 0.7635897398f, 0.7337523103f, 0.3376353979f, 0.3710575402f, }, + { 0.6128252149f, 0.9710690975f, 0.8680807352f, 0.6498346329f, 0.1112478748f, }, + { 0.8256502151f, 0.2143385410f, 0.3277817070f, 0.8420673013f, 0.9919103384f, }, + { 0.8114714026f, 0.0686456636f, 0.4891083837f, 0.8183916807f, 0.2314342111f, }, + { 0.0107376315f, 0.6101437807f, 0.6048409939f, 0.4214161038f, 0.0740544200f, }, + { 0.4440822899f, 0.6659262776f, 0.7429590821f, 0.5334573984f, 0.1436345279f, }, + { 0.8273325562f, 0.6509962678f, 0.8577843904f, 0.4713813365f, 0.8589822054f, }, + { 0.2995867729f, 0.7118763328f, 0.4795556664f, 0.5618416667f, 0.2473500222f, }, + { 0.2611320019f, 0.1521219313f, 0.8589732051f, 0.3526566029f, 0.7523092628f, }, + { 0.1629066020f, 0.2931720316f, 0.9873413444f, 0.7275877595f, 0.4169563055f, }, + { 0.7788833976f, 0.2867764533f, 0.7046756148f, 0.3725337386f, 0.3487041295f, }, + { 0.4292491376f, 0.9839559793f, 0.8297261596f, 0.3751640618f, 0.8055593371f, }, + { 0.7824987769f, 0.2732902467f, 0.0794270039f, 0.3340784907f, 0.8225383759f, }, + { 0.7576157451f, 0.3639462888f, 0.0950459167f, 0.9562528729f, 0.6696684957f, }, + { 0.2531193495f, 0.1102652326f, 0.9973129034f, 0.5259512067f, 0.4486361742f, }, + { 0.1217166260f, 0.2532446086f, 0.2533878684f, 0.5227922797f, 0.6851757765f, }, + { 0.0456724465f, 0.0627416968f, 0.1024873331f, 0.8391531110f, 0.3122954071f, }, + { 0.4181184471f, 0.0407995172f, 0.5753110647f, 0.7601435184f, 0.7494844198f, }, + { 0.4329914153f, 0.8947479129f, 0.3733733296f, 0.8037199974f, 0.8332307339f, }, + { 0.6123935580f, 0.1712171882f, 0.9597785473f, 0.7852883339f, 0.2586878538f, }, + { 0.0667347908f, 0.6348582506f, 0.8200544119f, 0.9943733811f, 0.6395456791f, }, + { 0.3788574040f, 0.5369496942f, 0.7073846459f, 0.9713602662f, 0.4833183289f, }, + { 0.9504200220f, 0.5106997490f, 0.7156969309f, 0.4145727456f, 0.9691243768f, }, + { 0.7705577016f, 0.0867787153f, 0.3629156053f, 0.0385666601f, 0.5566432476f, }, + { 0.8073791862f, 0.0475577898f, 0.1199062988f, 0.8657071590f, 0.8219990134f, }, + { 0.4498991966f, 0.4685618281f, 0.9492120743f, 0.5188637972f, 0.7686650753f, }, + { 0.9533615708f, 0.3956490159f, 0.8229101300f, 0.3728880882f, 0.0523726046f, }, + { 0.3930147588f, 0.1948387921f, 0.3819127083f, 0.9490925670f, 0.9356982112f, }, + { 0.7871661782f, 0.7788950205f, 0.4811519682f, 0.6680958867f, 0.3531906009f, }, + { 0.9469300508f, 0.1462316960f, 0.7090854049f, 0.7653840780f, 0.1048402339f, }, + { 0.3884967566f, 0.6369208694f, 0.9961783886f, 0.4592943490f, 0.0401006490f, }, + { 0.8780415058f, 0.9070742130f, 0.5693956017f, 0.5113674402f, 0.1680454910f, }, + { 0.7372827530f, 0.8425877690f, 0.8466967940f, 0.5854989886f, 0.3763777018f, }, + { 0.3345259428f, 0.8910778761f, 0.6998677254f, 0.2376101613f, 0.4466179311f, }, + { 0.4397892356f, 0.0550868772f, 0.3258031011f, 0.4882633686f, 0.3589040041f, }, + { 0.4302520752f, 0.4230765700f, 0.3555707932f, 0.7924712300f, 0.3051471710f, }, + { 0.8035071492f, 0.3244303465f, 0.9959524274f, 0.5242580175f, 0.1691230237f, }, + { 0.9817291498f, 0.6370483637f, 0.2214593142f, 0.6237680912f, 0.7317706943f, }, + { 0.2123642564f, 0.5662378669f, 0.8755405545f, 0.0382173099f, 0.9036038518f, }, + { 0.4578294754f, 0.5786895156f, 0.9733422399f, 0.0495842174f, 0.4375197589f, }, + { 0.4351761937f, 0.1135349572f, 0.2546425760f, 0.0248554032f, 0.8161369562f, }, + { 0.2190146297f, 0.6860049963f, 0.1960452050f, 0.0352771319f, 0.2413027585f, }, + { 0.7161464691f, 0.3802536428f, 0.8222718835f, 0.3158311844f, 0.0334501863f, }, + { 0.3936675787f, 0.0391162671f, 0.9727173448f, 0.1614153534f, 0.2138577998f, }, + { 0.6744181514f, 0.4630596936f, 0.8166452646f, 0.2091270983f, 0.0185563192f, }, + { 0.4274769127f, 0.8440701962f, 0.3554680645f, 0.8421376944f, 0.6874022484f, }, + { 0.1224175766f, 0.6366341114f, 0.9902863503f, 0.3611939251f, 0.8088998199f, }, + { 0.8627935052f, 0.0289100613f, 0.8563232422f, 0.5871095657f, 0.6004161835f, }, + { 0.8465287089f, 0.0090341298f, 0.7314211726f, 0.3766885102f, 0.3236398697f, }, + { 0.0295174047f, 0.8263036013f, 0.3535175920f, 0.7824463844f, 0.4067432582f, }, + { 0.2425942421f, 0.9574813843f, 0.1088294163f, 0.0213277340f, 0.1390373260f, }, + { 0.3716480732f, 0.9880857468f, 0.6051029563f, 0.5667526722f, 0.6627444625f, }, + { 0.7452079058f, 0.6381437778f, 0.6991891861f, 0.0915775225f, 0.8574279547f, }, + { 0.4486729205f, 0.1775697470f, 0.4835519195f, 0.4997417033f, 0.7389014363f, }, + { 0.0297268983f, 0.1309955716f, 0.3774424195f, 0.0679163635f, 0.4449722469f, }, + { 0.5063613057f, 0.1582536995f, 0.7153995037f, 0.4372690916f, 0.9653238058f, }, + { 0.1947146654f, 0.6954976916f, 0.0796119571f, 0.7796846628f, 0.0982839540f, }, + { 0.7249370217f, 0.9101967812f, 0.6947941184f, 0.9772434235f, 0.1000230387f, }, + { 0.0627140701f, 0.3216978014f, 0.6097059250f, 0.2297454327f, 0.0119149787f, }, + { 0.1160531417f, 0.9487152100f, 0.3632621765f, 0.1822129339f, 0.9330781102f, }, + { 0.5299761295f, 0.3621833026f, 0.3637073338f, 0.3499561548f, 0.8000932932f, }, + { 0.7873043418f, 0.9634428024f, 0.3726097643f, 0.9717751145f, 0.4088863730f, }, + { 0.5839247108f, 0.8906176686f, 0.6159471869f, 0.0071535492f, 0.6307464838f, }, + { 0.3992320895f, 0.9570859671f, 0.3818312287f, 0.7671108246f, 0.4070791900f, }, + { 0.8651296496f, 0.6620508432f, 0.7383896112f, 0.4500457048f, 0.6506568193f, }, + { 0.9673782587f, 0.2506396174f, 0.6053761840f, 0.0333377346f, 0.1263488084f, }, + { 0.5372824073f, 0.1368582100f, 0.3385664225f, 0.5816929340f, 0.6568664312f, }, + { 0.9489669800f, 0.1676198393f, 0.8753718138f, 0.3355306089f, 0.5114132762f, }, + { 0.6217404008f, 0.3242197037f, 0.9819551110f, 0.0864357278f, 0.8356361389f, }, + { 0.3123811781f, 0.7548118234f, 0.9649080634f, 0.3195282519f, 0.4657706618f, }, + { 0.1659842879f, 0.0179208852f, 0.3410169184f, 0.6629857421f, 0.4000360668f, }, + { 0.6039986610f, 0.8727364540f, 0.3633773029f, 0.7532644868f, 0.4613541663f, }, + { 0.3372956514f, 0.3035933971f, 0.3539285660f, 0.8623511195f, 0.8679077625f, }, + { 0.4180698097f, 0.0938651934f, 0.3813124001f, 0.2187110335f, 0.3081974387f, }, + { 0.8026303649f, 0.2900233269f, 0.4799141288f, 0.9359755516f, 0.1660941094f, }, + { 0.9102481604f, 0.8046797514f, 0.7432105541f, 0.3032379150f, 0.0383345820f, }, + { 0.5777049065f, 0.0851248205f, 0.2318288535f, 0.1761349440f, 0.1863940507f, }, + { 0.0926936939f, 0.1571556032f, 0.3655378520f, 0.5580291152f, 0.3688516319f, }, + { 0.9562922716f, 0.2313475013f, 0.1131516993f, 0.3747984171f, 0.9255852103f, }, + { 0.6531363130f, 0.3787752688f, 0.8681831956f, 0.3708764017f, 0.6930493712f, }, + { 0.8526188731f, 0.4943924546f, 0.6201373935f, 0.2607451975f, 0.3788252771f, }, + { 0.1772005558f, 0.3147800863f, 0.4998929501f, 0.5430523753f, 0.5828727484f, }, + { 0.5276942253f, 0.2671915293f, 0.6172901392f, 0.8603032827f, 0.2252665609f, }, + { 0.0025494958f, 0.7112596631f, 0.5840349793f, 0.7707068920f, 0.4372451305f, }, + { 0.9639129043f, 0.3048937321f, 0.9957541227f, 0.0169848576f, 0.3490648568f, }, + { 0.6452852488f, 0.1195521131f, 0.0891323760f, 0.4797008038f, 0.7618827224f, }, + { 0.7511904240f, 0.3172937036f, 0.5042762756f, 0.7574118972f, 0.1239449978f, }, + { 0.0675380528f, 0.1497418135f, 0.8718197346f, 0.4139747620f, 0.7576328516f, }, + { 0.4542947114f, 0.0975281075f, 0.4528908134f, 0.6023204923f, 0.9132833481f, }, + { 0.8874340653f, 0.7145345211f, 0.6168897748f, 0.4055404365f, 0.2497811913f, }, + { 0.1992354542f, 0.3368881047f, 0.9666627645f, 0.5256541371f, 0.3254370987f, }, + { 0.3248044550f, 0.8387818336f, 0.4825591147f, 0.9431799054f, 0.6354573369f, }, + { 0.9499405026f, 0.7504870892f, 0.1213849634f, 0.6421335340f, 0.9956735373f, }, + { 0.9023224711f, 0.0781245828f, 0.4833248258f, 0.2823326588f, 0.0766531751f, }, + { 0.9768341780f, 0.3095526993f, 0.3804157078f, 0.9668009281f, 0.9641554952f, }, + { 0.6013793945f, 0.9502558708f, 0.6086623669f, 0.8903332949f, 0.2578724027f, }, + { 0.3313767016f, 0.4894917905f, 0.4484708905f, 0.2259163260f, 0.4085065126f, }, + { 0.8818717003f, 0.2174347192f, 0.8455646634f, 0.6382569671f, 0.4248079062f, }, + { 0.5699709058f, 0.7125941515f, 0.2122523934f, 0.4254791141f, 0.2413930446f, }, + { 0.9907722473f, 0.8595077395f, 0.3662498891f, 0.0858681425f, 0.2003610432f, }, + { 0.7320672870f, 0.7189976573f, 0.7126919627f, 0.1260681152f, 0.9237770438f, }, + { 0.2121254355f, 0.2329794019f, 0.7497869134f, 0.2305739373f, 0.5531195402f, }, + { 0.8613305688f, 0.8040324450f, 0.7141299248f, 0.2954059541f, 0.0493266210f, }, + { 0.2381578684f, 0.9175969362f, 0.0937628448f, 0.8792830706f, 0.8279401660f, }, + { 0.2427871525f, 0.2329107076f, 0.5039531589f, 0.0249296203f, 0.6457495093f, }, + { 0.8977932334f, 0.2240513712f, 0.4567748308f, 0.5897205472f, 0.6699187160f, }, + { 0.8265719414f, 0.7500471473f, 0.1965749115f, 0.6302676797f, 0.7611974478f, }, + { 0.8504530191f, 0.0336682461f, 0.3204943836f, 0.9087586999f, 0.7265447378f, }, + { 0.7310765386f, 0.0510477982f, 0.5815448761f, 0.5994582772f, 0.3822634518f, }, + { 0.3697357774f, 0.5650444031f, 0.3549293876f, 0.0434908234f, 0.0979609266f, }, + { 0.0154667785f, 0.4530055225f, 0.9662120938f, 0.1614695638f, 0.7071575522f, }, + { 0.1132308170f, 0.1410227716f, 0.6164314747f, 0.2150831223f, 0.9072050452f, }, + { 0.7162016034f, 0.8550454378f, 0.3414458334f, 0.1084508300f, 0.1664104909f, }, + { 0.4281729460f, 0.8701855540f, 0.1207372472f, 0.9941589236f, 0.3148859143f, }, + { 0.2372272313f, 0.9850754142f, 0.5776262283f, 0.5698000789f, 0.4583282173f, }, + { 0.6283044815f, 0.6476567984f, 0.5762419701f, 0.6628118753f, 0.0429071300f, }, + { 0.7270650268f, 0.3997713923f, 0.3806994855f, 0.1262766570f, 0.7418123484f, }, + { 0.3250063658f, 0.4168527722f, 0.4895493090f, 0.2272565812f, 0.1438979208f, }, + { 0.1117988452f, 0.6251049638f, 0.8167061806f, 0.8875539899f, 0.9729827046f, }, + { 0.7656977773f, 0.8770171404f, 0.5038051605f, 0.7887247801f, 0.1168617383f, }, + { 0.3116078675f, 0.1227975190f, 0.9747693539f, 0.2202394605f, 0.1609618664f, }, + { 0.6544929147f, 0.9847650528f, 0.1964287907f, 0.1128766015f, 0.7317509651f, }, + { 0.9587103128f, 0.9569885731f, 0.8212876320f, 0.3012783229f, 0.5396449566f, }, + { 0.0822739154f, 0.1669502407f, 0.4535298944f, 0.1045399308f, 0.2326706797f, }, + { 0.7211957574f, 0.1725761443f, 0.1090020388f, 0.9110841155f, 0.7424035072f, }, + { 0.0952135399f, 0.7983450294f, 0.6084074974f, 0.1354191899f, 0.1631673425f, }, + { 0.7506678104f, 0.6232589483f, 0.9955670834f, 0.9209811687f, 0.7083567381f, }, + { 0.9326409101f, 0.6125705242f, 0.4989732206f, 0.9193303585f, 0.2860678136f, }, + { 0.0823112875f, 0.4839625955f, 0.2536306381f, 0.5479493737f, 0.6388376951f, }, + { 0.0453141741f, 0.4826551080f, 0.7265326977f, 0.6185632348f, 0.7928264737f, }, + { 0.8148653507f, 0.5979046226f, 0.4907150567f, 0.4259094596f, 0.2750523984f, }, + { 0.5032152534f, 0.9398130774f, 0.1177121177f, 0.6255344748f, 0.6250491142f, }, + { 0.4064733982f, 0.6375170350f, 0.8745219111f, 0.8796836138f, 0.8532630205f, }, + { 0.4660728276f, 0.8731740117f, 0.4991939068f, 0.8051498532f, 0.3857492208f, }, + { 0.4393017888f, 0.5774713159f, 0.8751817346f, 0.2497480214f, 0.1225357130f, }, + { 0.5686126947f, 0.5423402190f, 0.3715670407f, 0.1960609108f, 0.9498376250f, }, + { 0.9286199808f, 0.5931366682f, 0.0895980597f, 0.6700481772f, 0.7122668624f, }, + { 0.7852167487f, 0.2095805556f, 0.1205843836f, 0.0965914205f, 0.6631560922f, }, + { 0.4250650704f, 0.6672289968f, 0.1019007564f, 0.4534848630f, 0.9535769820f, }, + { 0.9987455010f, 0.7370687723f, 0.7268777490f, 0.1901751608f, 0.5218352079f, }, + { 0.4628792405f, 0.5360019207f, 0.9595204592f, 0.6740662456f, 0.4350104034f, }, + { 0.2011793107f, 0.1465158463f, 0.6928260922f, 0.1001470163f, 0.4388425946f, }, + { 0.5688267350f, 0.3112915158f, 0.7445172071f, 0.1193323582f, 0.2360310256f, }, + { 0.4373345375f, 0.0794776529f, 0.5034395456f, 0.2514289916f, 0.9695624113f, }, + { 0.2928332388f, 0.4828954339f, 0.1128163040f, 0.8096698523f, 0.3271968663f, }, + { 0.0070475815f, 0.5048404336f, 0.3420736194f, 0.5957426429f, 0.5034209490f, }, + { 0.0467573777f, 0.0866089314f, 0.3781569898f, 0.0511842147f, 0.4236863256f, }, + { 0.4832280278f, 0.1298995316f, 0.3254944980f, 0.4886581004f, 0.2808347344f, }, + { 0.1632497162f, 0.9324332476f, 0.7381750941f, 0.9247043729f, 0.6494550109f, }, + { 0.2842035890f, 0.9766307473f, 0.4984682202f, 0.2164747268f, 0.8801805377f, }, + { 0.2317802459f, 0.0640138686f, 0.3264730871f, 0.8873134255f, 0.9579545259f, }, + { 0.3043885827f, 0.3691073060f, 0.4993454218f, 0.5357220769f, 0.9869284630f, }, + { 0.1675363928f, 0.7938717604f, 0.9448657632f, 0.1998690665f, 0.1756056696f, }, + { 0.9188715219f, 0.6501764655f, 0.6160176992f, 0.0469477884f, 0.1634267867f, }, + { 0.5466885567f, 0.8115056753f, 0.9506032467f, 0.2070759833f, 0.3146564662f, }, + { 0.9475520253f, 0.9481077790f, 0.6936659217f, 0.5450612307f, 0.8787096143f, }, + { 0.0365482643f, 0.6658070683f, 0.5773863792f, 0.7063529491f, 0.9643990397f, }, + { 0.6712903976f, 0.3493689299f, 0.5029823184f, 0.2275436223f, 0.5883646011f, }, + { 0.4191149771f, 0.9181865454f, 0.4477844238f, 0.5201436281f, 0.2364486158f, }, + { 0.4923554659f, 0.5922198892f, 0.3541801870f, 0.8049176335f, 0.7382533550f, }, + { 0.2164010257f, 0.2086770684f, 0.1126588583f, 0.2506896257f, 0.0253463313f, }, + { 0.6147183180f, 0.6813946366f, 0.9952555895f, 0.9241989851f, 0.7347947955f, }, + { 0.8986344337f, 0.9093507528f, 0.7320833802f, 0.0637358129f, 0.5786748528f, }, + { 0.2041351497f, 0.9720759988f, 0.3660450578f, 0.3743502498f, 0.9402874112f, }, + { 0.4614389241f, 0.2404455245f, 0.4987286925f, 0.2129998207f, 0.9457387328f, }, + { 0.0680792481f, 0.8658601642f, 0.1114604697f, 0.5944278240f, 0.4896151125f, }, + { 0.9095861912f, 0.5056038499f, 0.7152558565f, 0.9873967171f, 0.5209948421f, }, + { 0.1580729932f, 0.3511795700f, 0.7343806624f, 0.1190539822f, 0.2643718123f, }, + { 0.1854335517f, 0.6738094687f, 0.8574145436f, 0.7591252923f, 0.6000130177f, }, + { 0.6562792659f, 0.1711489111f, 0.0935755372f, 0.3591185510f, 0.9283712506f, }, + { 0.9310843945f, 0.7392662168f, 0.9951130748f, 0.0500456542f, 0.6062055230f, }, + { 0.9735014439f, 0.8118783832f, 0.9933413863f, 0.5091601014f, 0.7534648776f, }, + { 0.4702884257f, 0.4837325811f, 0.8748822212f, 0.3242496252f, 0.4819259048f, }, + { 0.3093471229f, 0.3443407416f, 0.8627332449f, 0.9251258969f, 0.2689518034f, }, + { 0.3046764731f, 0.1928446591f, 0.1198169291f, 0.1495826542f, 0.6378797293f, }, + { 0.2686856985f, 0.9570152164f, 0.9947019815f, 0.1990495622f, 0.2749607563f, }, + { 0.5109820962f, 0.9176478386f, 0.4903918505f, 0.8261681199f, 0.5460631251f, }, + { 0.2360353917f, 0.2749695480f, 0.6143262386f, 0.6701139808f, 0.3681367338f, }, + { 0.9531452060f, 0.3165539205f, 0.4957964122f, 0.3156306744f, 0.5551447272f, }, + { 0.9845524430f, 0.6112276912f, 0.4660908580f, 0.5778311491f, 0.9631324410f, }, + { 0.6188763976f, 0.4325700700f, 0.7473918200f, 0.0001590878f, 0.5029233098f, }, + { 0.8169631958f, 0.5849395394f, 0.6122626066f, 0.0817533210f, 0.5868864655f, }, + { 0.4827097654f, 0.6982395649f, 0.3717678189f, 0.2450601608f, 0.7834322453f, }, + { 0.2144843638f, 0.3409645855f, 0.6935594082f, 0.3648827970f, 0.0000875066f, }, + { 0.8874372840f, 0.5773923993f, 0.1110025197f, 0.8355071545f, 0.1763495505f, }, + { 0.4284993410f, 0.6867538691f, 0.9493530989f, 0.0053610913f, 0.3553719223f, }, + { 0.3044171035f, 0.1689673513f, 0.4888363183f, 0.5148839951f, 0.1849452853f, }, + { 0.8977135420f, 0.5622053742f, 0.7448571324f, 0.4181466997f, 0.8386263847f, }, + { 0.0828802586f, 0.1039325222f, 0.3719890416f, 0.1263474673f, 0.1929699481f, }, + { 0.3933362365f, 0.9732549787f, 0.6950267553f, 0.9268715382f, 0.2290516049f, }, + { 0.3549911082f, 0.8957679272f, 0.8208107948f, 0.9116737843f, 0.6784629226f, }, + { 0.5388345718f, 0.0991296545f, 0.1107911542f, 0.0892379582f, 0.7999423742f, }, + { 0.5470073819f, 0.7215728760f, 0.6994650960f, 0.1151193008f, 0.4629767239f, }, + { 0.9143349528f, 0.3864607811f, 0.8207213879f, 0.4732268155f, 0.9044671059f, }, + { 0.6332444549f, 0.3183722496f, 0.1102230772f, 0.6502102017f, 0.0288210697f, }, + { 0.2329647243f, 0.4846595526f, 0.0926136672f, 0.0725705847f, 0.3844283521f, }, + { 0.1943542510f, 0.7195215821f, 0.9552853107f, 0.0029267881f, 0.4404609799f, }, + { 0.8157118559f, 0.8993971348f, 0.9530659914f, 0.0251294896f, 0.4696230888f, }, + { 0.2433969826f, 0.4437613487f, 0.6069117188f, 0.0249261167f, 0.2878941894f, }, + { 0.7518885136f, 0.2064859122f, 0.3729958832f, 0.8526729345f, 0.8765500188f, }, + { 0.1196160987f, 0.1560146213f, 0.9917750955f, 0.6061599851f, 0.6992319226f, }, + { 0.3257593513f, 0.5934751630f, 0.1969375014f, 0.6941183209f, 0.7192718983f, }, + { 0.7439805865f, 0.7995327711f, 0.5814304352f, 0.6509905457f, 0.6821700931f, }, + { 0.9240818620f, 0.8600212932f, 0.2069315761f, 0.4911104143f, 0.2240150869f, }, + { 0.7310242653f, 0.0722467005f, 0.6079446077f, 0.3617984653f, 0.0263829455f, }, + { 0.5297412276f, 0.5292071104f, 0.1026685387f, 0.8852197528f, 0.6495633125f, }, + { 0.1348335296f, 0.6153002977f, 0.2536665499f, 0.9145803452f, 0.4500297010f, }, + { 0.9723751545f, 0.4874490798f, 0.2541497052f, 0.8461133838f, 0.2418480068f, }, + { 0.7919373512f, 0.3639681041f, 0.8574426770f, 0.7154712677f, 0.4449679255f, }, + { 0.2921220064f, 0.9632802010f, 0.1971003264f, 0.4514510334f, 0.2025432736f, }, + { 0.5638692379f, 0.9063289762f, 0.9670272470f, 0.1134938151f, 0.9271347523f, }, + { 0.6158794761f, 0.4567608237f, 0.8724793196f, 0.9493952394f, 0.1250747442f, }, + { 0.7632551789f, 0.6459383965f, 0.6055327654f, 0.5985218287f, 0.8341413140f, }, + { 0.5781115890f, 0.4106989801f, 0.4886804819f, 0.1700046062f, 0.1751469672f, }, + { 0.0712313876f, 0.0060056001f, 0.2552906871f, 0.5950299501f, 0.4510626197f, }, + { 0.3425444663f, 0.3547513783f, 0.1053880081f, 0.1309315860f, 0.1485359371f, }, + { 0.6286115646f, 0.3000409007f, 0.3247758448f, 0.4307258427f, 0.9875839949f, }, + { 0.3725546896f, 0.3639473915f, 0.8579477072f, 0.7508904934f, 0.2939893901f, }, + { 0.6965373755f, 0.1464508772f, 0.1981201470f, 0.4385713041f, 0.2386756390f, }, + { 0.7043921947f, 0.7125582695f, 0.1093184352f, 0.0525701419f, 0.6196929812f, }, + { 0.9083886743f, 0.0573458448f, 0.3793531358f, 0.2368870378f, 0.5250951648f, }, + { 0.5019509792f, 0.7252567410f, 0.1076457128f, 0.6533917785f, 0.3564069569f, }, + { 0.5055052042f, 0.5126312971f, 0.6135913134f, 0.0554074161f, 0.1367645413f, }, + { 0.9312745333f, 0.2536841035f, 0.6951342225f, 0.0748187751f, 0.6311951280f, }, + { 0.0188628323f, 0.3141627610f, 0.5778902173f, 0.3528655767f, 0.6846556664f, }, + { 0.7535302639f, 0.2358576357f, 0.9556433558f, 0.8498365879f, 0.2634832561f, }, + { 0.9960318208f, 0.6866603494f, 0.4476959407f, 0.7637553215f, 0.1790231019f, }, + { 0.5332064629f, 0.3107205927f, 0.8719856739f, 0.4060469270f, 0.8876172900f, }, + { 0.9628082514f, 0.0821799263f, 0.2135345787f, 0.1705842763f, 0.8398225904f, }, + { 0.5999576449f, 0.1157513708f, 0.5789451003f, 0.0749146342f, 0.8721115589f, }, + { 0.1720396131f, 0.6878544092f, 0.6958033442f, 0.1263245940f, 0.8466808796f, }, + { 0.6459790468f, 0.0377204679f, 0.3731245995f, 0.7613993883f, 0.6150441170f, }, + { 0.3008291125f, 0.6000047922f, 0.3232116997f, 0.2798737884f, 0.4621870220f, }, + { 0.9881314635f, 0.2652508020f, 0.5693171620f, 0.3449803889f, 0.5217292309f, }, + { 0.9983772635f, 0.9307537079f, 0.1050129980f, 0.7995977402f, 0.1074760333f, }, + { 0.8598355055f, 0.0546879917f, 0.4472883344f, 0.0554624051f, 0.5906053185f, }, + { 0.1967779547f, 0.8042863011f, 0.0837237984f, 0.1196473241f, 0.6863863468f, }, + { 0.8187760115f, 0.0936076418f, 0.8703626990f, 0.0070706848f, 0.5882076621f, }, + { 0.1541550457f, 0.5542744994f, 0.5786755681f, 0.0510488749f, 0.6514968872f, }, + { 0.3789161146f, 0.1947258264f, 0.8200846314f, 0.9011314511f, 0.6856721640f, }, + { 0.5712757111f, 0.2621073425f, 0.7450839877f, 0.8122548461f, 0.6465995312f, }, + { 0.0416614637f, 0.2290412486f, 0.7455627918f, 0.6397697926f, 0.3629002571f, }, + { 0.8228716850f, 0.1884628832f, 0.5719586015f, 0.6196064353f, 0.6371018291f, }, + { 0.1819969118f, 0.0812063366f, 0.6993542314f, 0.7633036971f, 0.3576462567f, }, + { 0.5038872957f, 0.2568106651f, 0.6964512467f, 0.6638218164f, 0.6864572167f, }, + { 0.5060910583f, 0.8209236264f, 0.2132483572f, 0.5150474906f, 0.2505054772f, }, + { 0.5849402547f, 0.5576609373f, 0.8584353328f, 0.2709881067f, 0.3911837339f, }, + { 0.0717428178f, 0.8063868880f, 0.9854500890f, 0.2922576964f, 0.6165569425f, }, + { 0.5360495448f, 0.3380460441f, 0.1066793203f, 0.8847293854f, 0.2702046037f, }, + { 0.0845943391f, 0.1421237141f, 0.6967819929f, 0.2939101160f, 0.5227125883f, }, + { 0.6093758345f, 0.3591115773f, 0.0898398310f, 0.9364658594f, 0.1500737965f, }, + { 0.5283372402f, 0.1166105419f, 0.2130886614f, 0.1770049036f, 0.1603613347f, }, + { 0.4738532305f, 0.7488376498f, 0.1979478300f, 0.7045380473f, 0.3662438393f, }, + { 0.0240056049f, 0.8615483046f, 0.9587606192f, 0.3142572939f, 0.6351529956f, }, + { 0.4874440134f, 0.6046891809f, 0.4658892155f, 0.3537878692f, 0.3472965956f, }, + { 0.9004520178f, 0.6417368650f, 0.1063744947f, 0.3013700545f, 0.9507634044f, }, + { 0.1984396875f, 0.6292235255f, 0.0839637220f, 0.7518445253f, 0.1709179282f, }, + { 0.9580810666f, 0.5593107939f, 0.5777112246f, 0.8203430176f, 0.8708991408f, }, + { 0.2535334229f, 0.6119022369f, 0.3215396404f, 0.3635187447f, 0.4651461542f, }, + { 0.2674832046f, 0.1868050992f, 0.7456719279f, 0.2249475718f, 0.3843463361f, }, + { 0.4775032401f, 0.0381310806f, 0.7469258308f, 0.4766734838f, 0.1781844497f, }, + { 0.2872119546f, 0.0247516911f, 0.5743784308f, 0.8435814977f, 0.1614839584f, }, + { 0.7057003975f, 0.7824842930f, 0.6978332400f, 0.6601962447f, 0.9840054512f, }, + { 0.4877744317f, 0.1160784662f, 0.2020426691f, 0.0615979880f, 0.8641144633f, }, + { 0.6781823635f, 0.2974123359f, 0.2550798953f, 0.7159431577f, 0.7229922414f, }, + { 0.5250487328f, 0.8703799248f, 0.6971628070f, 0.1131960899f, 0.2792929709f, }, + { 0.6081331968f, 0.5276256800f, 0.7477125525f, 0.7101683021f, 0.4097843170f, }, + { 0.4817813039f, 0.8531027436f, 0.1036189422f, 0.7745128870f, 0.1178154647f, }, + { 0.4748421907f, 0.9949620962f, 0.3791393340f, 0.8383822441f, 0.8166930676f, }, + { 0.1728985459f, 0.4132170677f, 0.2125788927f, 0.2135537416f, 0.1492347270f, }, + { 0.8608900309f, 0.3694796860f, 0.6126662493f, 0.0871528462f, 0.6817799807f, }, + { 0.4815687537f, 0.5816547275f, 0.6061651707f, 0.8967537284f, 0.2043928504f, }, + { 0.3496925533f, 0.7584263086f, 0.3207936883f, 0.8046333790f, 0.6244502068f, }, + { 0.5535951853f, 0.3710155487f, 0.7478141189f, 0.8568129539f, 0.5567179918f, }, + { 0.0837281570f, 0.0019600135f, 0.6064441204f, 0.5771192312f, 0.8251596093f, }, + { 0.8247803450f, 0.2491392791f, 0.7487629652f, 0.8003931046f, 0.7262272835f, }, + { 0.0639881641f, 0.4659017324f, 0.3788300157f, 0.2949594259f, 0.3163681328f, }, + { 0.7640358806f, 0.1101438701f, 0.1056645438f, 0.3873530626f, 0.4960630536f, }, + { 0.6864768267f, 0.9154553413f, 0.8615294695f, 0.2559624314f, 0.7989096642f, }, + { 0.6625117660f, 0.9001371264f, 0.7480590343f, 0.6873580813f, 0.7042953968f, }, + { 0.6001659036f, 0.9630150199f, 0.1048192158f, 0.2887103260f, 0.3989432156f, }, + { 0.0453191102f, 0.4998694956f, 0.8727855682f, 0.6800495982f, 0.9642062783f, }, + { 0.8788028359f, 0.8932741880f, 0.3262511790f, 0.9138993621f, 0.2269975692f, }, + { 0.8641566634f, 0.1462096572f, 0.0843187422f, 0.2788262665f, 0.6114114523f, }, + { 0.3318571448f, 0.9067651629f, 0.4616480470f, 0.1266877949f, 0.2502485216f, }, + { 0.5860577822f, 0.0958286002f, 0.0922295079f, 0.4288218617f, 0.9074413180f, }, + { 0.4079282582f, 0.6137171388f, 0.0851320103f, 0.5717654824f, 0.3757576048f, }, + { 0.7709387541f, 0.5636160970f, 0.7495493889f, 0.8735838532f, 0.2498029768f, }, + { 0.0087167388f, 0.4318227172f, 0.8701936007f, 0.6245196462f, 0.8999392986f, }, + { 0.1284180433f, 0.4009063840f, 0.9929772615f, 0.8151273131f, 0.1400654167f, }, + { 0.8394128680f, 0.4778622091f, 0.0906223208f, 0.0628775582f, 0.0993851870f, }, + { 0.5617870688f, 0.4811372757f, 0.6064599156f, 0.7258613706f, 0.4005918205f, }, + { 0.5493366122f, 0.5253468156f, 0.1974477470f, 0.6060486436f, 0.9414649010f, }, + { 0.1814007461f, 0.8229306340f, 0.8198007941f, 0.2062007040f, 0.9575828314f, }, + { 0.1041302457f, 0.1171427444f, 0.0852282196f, 0.5917007923f, 0.7063627243f, }, + { 0.0833598897f, 0.5979328156f, 0.3241254687f, 0.5886921287f, 0.8592047095f, }, + { 0.5126150250f, 0.1024457440f, 0.9590021968f, 0.5871566534f, 0.9378551245f, }, + { 0.2742413282f, 0.3772708178f, 0.8194110394f, 0.3097124994f, 0.5186815262f, }, + { 0.5790687203f, 0.3888548911f, 0.3783981502f, 0.5485949516f, 0.2360849977f, }, + { 0.1109971181f, 0.1770060807f, 0.0904324874f, 0.8018411398f, 0.2950742543f, }, + { 0.0381450877f, 0.5604131222f, 0.3210267127f, 0.3792554736f, 0.2347474247f, }, + { 0.7373712063f, 0.3776365817f, 0.9647908211f, 0.5733613372f, 0.8895215988f, }, + { 0.9122301340f, 0.8845624328f, 0.9890085459f, 0.3346363306f, 0.4683856964f, }, + { 0.8458541036f, 0.9644401073f, 0.5725477934f, 0.6002668142f, 0.9618119001f, }, + { 0.0490464680f, 0.8619559407f, 0.8179126382f, 0.1007454395f, 0.2741018534f, }, + { 0.2529154420f, 0.2252032608f, 0.9641648531f, 0.2719295323f, 0.0849194601f, }, + { 0.4006107152f, 0.6589605212f, 0.3210944235f, 0.0674258247f, 0.1288291514f, }, + { 0.4096716344f, 0.6497788429f, 0.8458643556f, 0.0803250298f, 0.8487070203f, }, + { 0.5242260098f, 0.8959512115f, 0.8697840571f, 0.6578457952f, 0.7050910592f, }, + { 0.0260187238f, 0.6544261575f, 0.3784641922f, 0.6697351336f, 0.6984977722f, }, + { 0.2300171852f, 0.2275477648f, 0.4618140161f, 0.0043802550f, 0.1367783546f, }, + { 0.5262473822f, 0.5664927363f, 0.8188179135f, 0.2854401469f, 0.5096173286f, }, + { 0.8460619450f, 0.6538503766f, 0.1976764202f, 0.8113370538f, 0.6878486276f, }, + { 0.2772192657f, 0.5029959083f, 0.3217979074f, 0.8682016730f, 0.9023321867f, }, + { 0.2392933965f, 0.3244680464f, 0.2063642442f, 0.3317535222f, 0.4532529712f, }, + { 0.6298089623f, 0.9295437932f, 0.9851393104f, 0.9638314843f, 0.9375714064f, }, + { 0.9435333610f, 0.8102272749f, 0.6071764827f, 0.9091103077f, 0.2624617815f, }, + { 0.7722917199f, 0.4389513731f, 0.8667045832f, 0.3425230980f, 0.0033291576f, }, + { 0.9231454730f, 0.9432785511f, 0.9592960477f, 0.2287584394f, 0.0247588865f, }, + { 0.1442265064f, 0.2602964342f, 0.0918844566f, 0.6565052271f, 0.9979584217f, }, + { 0.2181335390f, 0.4316166937f, 0.0917130336f, 0.6942002177f, 0.9575509429f, }, + { 0.1220782027f, 0.6995287538f, 0.8739034534f, 0.3485262990f, 0.4598202407f, }, + { 0.6827418208f, 0.2721637189f, 0.8722845316f, 0.4672423899f, 0.9703562260f, }, + { 0.4107722938f, 0.8949344754f, 0.1996881366f, 0.6141865253f, 0.9579420686f, }, + { 0.4882082641f, 0.4934619963f, 0.9897007346f, 0.7543770075f, 0.3250934780f, }, + { 0.8106310368f, 0.2069644034f, 0.9926779866f, 0.2243934423f, 0.7587417364f, }, + { 0.7491098642f, 0.8762744069f, 0.9906857610f, 0.4297075570f, 0.9256587029f, }, + { 0.2549348772f, 0.1323014796f, 0.1039625034f, 0.2169004679f, 0.1334284395f, }, + { 0.9942365885f, 0.8120270371f, 0.4623450041f, 0.2175034285f, 0.0858128145f, }, + { 0.4969757497f, 0.1789617538f, 0.8189846277f, 0.2477202863f, 0.7505609989f, }, + { 0.1874369234f, 0.8741084933f, 0.1042470410f, 0.6346544027f, 0.4555490911f, }, + { 0.7371039391f, 0.4959346652f, 0.1045920923f, 0.1488533467f, 0.2084970623f, }, + { 0.2087403238f, 0.8766234517f, 0.4639246166f, 0.2548867464f, 0.7751787901f, }, + { 0.7511588335f, 0.0367171839f, 0.8742753863f, 0.7835904956f, 0.1286349744f, }, + { 0.2470860481f, 0.1739185601f, 0.3238283992f, 0.7448464632f, 0.3101584911f, }, + { 0.3149905205f, 0.1473620832f, 0.1043146625f, 0.8647398949f, 0.2620262802f, }, + { 0.6992393732f, 0.8620148301f, 0.2021593451f, 0.3004637957f, 0.5054730773f, }, + { 0.6774873137f, 0.0113230776f, 0.3227222562f, 0.2864091694f, 0.4225244820f, }, + { 0.7935581207f, 0.0975255296f, 0.3237173557f, 0.8806690574f, 0.8842474818f, }, + { 0.3075688779f, 0.8881561160f, 0.2061693072f, 0.2642721832f, 0.7491376996f, }, + { 0.6765557528f, 0.8286225200f, 0.9639666080f, 0.4441624284f, 0.9878573418f, }, + { 0.9235497117f, 0.6316314936f, 0.2025715560f, 0.5196759105f, 0.2212169319f, }, + { 0.6624719501f, 0.9407488108f, 0.2060395926f, 0.2672573626f, 0.4387931228f, }, + { 0.2834221721f, 0.7842905521f, 0.5729217529f, 0.8006983399f, 0.6752763391f, }, + { 0.8671710491f, 0.8866243362f, 0.9910276532f, 0.2595298886f, 0.4719019532f, }, + { 0.6245686412f, 0.1164552271f, 0.2028439790f, 0.2505145371f, 0.7376209497f, }, + { 0.3879756331f, 0.6127753258f, 0.2036545426f, 0.7027260661f, 0.4211112261f, }, + { 0.1811889112f, 0.8868420124f, 0.2035310566f, 0.8182333708f, 0.6264363527f, }, + { 0.3459434509f, 0.9136525989f, 0.9919847250f, 0.5912823081f, 0.9506404996f, }, + { 0.0292777400f, 0.4034550190f, 0.5760018229f, 0.5426461697f, 0.2608519495f, }, + { 0.1179740056f, 0.4091444314f, 0.5757969618f, 0.6824651361f, 0.4251429737f, }, + { 0.0928455889f, 0.3766567707f, 0.2033229172f, 0.7959060073f, 0.6874306202f, }, + { 0.2414992452f, 0.6848184466f, 0.5737532973f, 0.8973307610f, 0.2751243412f, }, + { 0.3875006735f, 0.8072223663f, 0.5735291839f, 0.9130150676f, 0.2748070061f, }, + { 0.2921602428f, 0.9884731770f, 0.5731204748f, 0.5407849550f, 0.3014898002f, }, + { 0.4359965920f, 0.2804161608f, 0.5733448863f, 0.9205425978f, 0.2539848983f, }, +}; diff --git a/samplers/halton.cpp b/samplers/halton.cpp new file mode 100644 index 0000000..237b5a3 --- /dev/null +++ b/samplers/halton.cpp @@ -0,0 +1,90 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// samplers/halton.cpp* +#include "stdafx.h" +#include "samplers/halton.h" +#include "paramset.h" +#include "camera.h" +#include "montecarlo.h" + +// HaltonSampler Method Definitions +Sampler *HaltonSampler::GetSubSampler(int num, int count) { + int x0, x1, y0, y1; + ComputeSubWindow(num, count, &x0, &x1, &y0, &y1); + if (x0 == x1 || y0 == y1) return NULL; + return new HaltonSampler(x0, x1, y0, y1, samplesPerPixel, shutterOpen, + shutterClose); +} + + +HaltonSampler::HaltonSampler(int xs, int xe, int ys, int ye, int ps, + float sopen, float sclose) + : Sampler(xs, xe, ys, ye, ps, sopen, sclose) { + int delta = max(xPixelEnd - xPixelStart, + yPixelEnd - yPixelStart); + wantedSamples = samplesPerPixel * delta * delta; + currentSample = 0; +} + + +int HaltonSampler::GetMoreSamples(Sample *samples, RNG &rng) { +retry: + if (currentSample >= wantedSamples) return 0; + // Generate sample with Halton sequence and reject if outside image extent + float u = (float)RadicalInverse(currentSample, 3); + float v = (float)RadicalInverse(currentSample, 2); + float lerpDelta = float(max(xPixelEnd - xPixelStart, + yPixelEnd - yPixelStart)); + samples->imageX = Lerp(u, xPixelStart, xPixelStart + lerpDelta); + samples->imageY = Lerp(v, yPixelStart, yPixelStart + lerpDelta); + ++currentSample; + if (samples->imageX >= xPixelEnd || samples->imageY >= yPixelEnd) + goto retry; + + // Generate lens, time, and integrator samples for _HaltonSampler_ + samples->lensU = (float)RadicalInverse(currentSample, 5); + samples->lensV = (float)RadicalInverse(currentSample, 7); + samples->time = Lerp((float)RadicalInverse(currentSample, 11), + shutterOpen, shutterClose); + for (uint32_t i = 0; i < samples->n1D.size(); ++i) + LatinHypercube(samples->oneD[i], samples->n1D[i], 1, rng); + for (uint32_t i = 0; i < samples->n2D.size(); ++i) + LatinHypercube(samples->twoD[i], samples->n2D[i], 2, rng); + return 1; +} + + +HaltonSampler *CreateHaltonSampler(const ParamSet ¶ms, const Film *film, + const Camera *camera) { + // Initialize common sampler parameters + int xstart, xend, ystart, yend; + film->GetSampleExtent(&xstart, &xend, &ystart, ¥d); + int nsamp = params.FindOneInt("pixelsamples", 4); + if (PbrtOptions.quickRender) nsamp = 1; + return new HaltonSampler(xstart, xend, ystart, yend, nsamp, + camera->shutterOpen, camera->shutterClose); +} + + diff --git a/samplers/halton.h b/samplers/halton.h new file mode 100644 index 0000000..fb586c9 --- /dev/null +++ b/samplers/halton.h @@ -0,0 +1,53 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_SAMPLERS_HALTON_H +#define PBRT_SAMPLERS_HALTON_H + +// samplers/halton.h* +#include "sampler.h" +#include "film.h" + +// HaltonSampler Declarations +class HaltonSampler : public Sampler { +public: + HaltonSampler(int xs, int xe, int ys, int ye, int ps, float sopen, float sclose); + int MaximumSampleCount() { return 1; } + int GetMoreSamples(Sample *sample, RNG &rng); + Sampler *GetSubSampler(int num, int count); + int RoundSize(int size) const { return size; } + +private: + // HaltonSampler Private Data + int wantedSamples, currentSample; +}; + + +HaltonSampler *CreateHaltonSampler(const ParamSet ¶ms, const Film *film, + const Camera *camera); + +#endif // PBRT_SAMPLERS_HALTON_H diff --git a/samplers/lowdiscrepancy.cpp b/samplers/lowdiscrepancy.cpp new file mode 100644 index 0000000..c45564f --- /dev/null +++ b/samplers/lowdiscrepancy.cpp @@ -0,0 +1,85 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// samplers/lowdiscrepancy.cpp* +#include "stdafx.h" +#include "samplers/lowdiscrepancy.h" +#include "camera.h" +#include "montecarlo.h" + +// LDSampler Method Definitions +LDSampler::LDSampler(int xstart, int xend, int ystart, int yend, int ps, + float sopen, float sclose) + : Sampler(xstart, xend, ystart, yend, RoundUpPow2(ps), sopen, sclose) { + xPos = xPixelStart; + yPos = yPixelStart; + if (!IsPowerOf2(ps)) { + Warning("Pixel samples being rounded up to power of 2"); + nPixelSamples = RoundUpPow2(ps); + } else + nPixelSamples = ps; + sampleBuf = NULL; +} + + +LDSampler::~LDSampler() { + delete[] sampleBuf; +} + + +Sampler *LDSampler::GetSubSampler(int num, int count) { + int x0, x1, y0, y1; + ComputeSubWindow(num, count, &x0, &x1, &y0, &y1); + if (x0 == x1 || y0 == y1) return NULL; + return new LDSampler(x0, x1, y0, y1, nPixelSamples, shutterOpen, shutterClose); +} + + +int LDSampler::GetMoreSamples(Sample *samples, RNG &rng) { + if (yPos == yPixelEnd) return 0; + if (sampleBuf == NULL) + sampleBuf = new float[LDPixelSampleFloatsNeeded(samples, + nPixelSamples)]; + LDPixelSample(xPos, yPos, shutterOpen, shutterClose, + nPixelSamples, samples, sampleBuf, rng); + if (++xPos == xPixelEnd) { + xPos = xPixelStart; + ++yPos; + } + return nPixelSamples; +} + + +LDSampler *CreateLowDiscrepancySampler(const ParamSet ¶ms, const Film *film, + const Camera *camera) { + // Initialize common sampler parameters + int xstart, xend, ystart, yend; + film->GetSampleExtent(&xstart, &xend, &ystart, ¥d); + int nsamp = params.FindOneInt("pixelsamples", 4); + if (PbrtOptions.quickRender) nsamp = 1; + return new LDSampler(xstart, xend, ystart, yend, nsamp, + camera->shutterOpen, camera->shutterClose); +} + + diff --git a/samplers/lowdiscrepancy.h b/samplers/lowdiscrepancy.h new file mode 100644 index 0000000..427b999 --- /dev/null +++ b/samplers/lowdiscrepancy.h @@ -0,0 +1,58 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_SAMPLERS_LOWDISCREPANCY_H +#define PBRT_SAMPLERS_LOWDISCREPANCY_H + +// samplers/lowdiscrepancy.h* +#include "sampler.h" +#include "paramset.h" +#include "film.h" +#include "parallel.h" + +// LDSampler Declarations +class LDSampler : public Sampler { +public: + // LDSampler Public Methods + LDSampler(int xstart, int xend, int ystart, int yend, + int nsamp, float sopen, float sclose); + ~LDSampler(); + Sampler *GetSubSampler(int num, int count); + int RoundSize(int size) const { return RoundUpPow2(size); } + int GetMoreSamples(Sample *sample, RNG &rng); + int MaximumSampleCount() { return nPixelSamples; } +private: + // LDSampler Private Data + int xPos, yPos, nPixelSamples; + float *sampleBuf; +}; + + +LDSampler *CreateLowDiscrepancySampler(const ParamSet ¶ms, const Film *film, + const Camera *camera); + +#endif // PBRT_SAMPLERS_LOWDISCREPANCY_H diff --git a/samplers/random.cpp b/samplers/random.cpp new file mode 100644 index 0000000..817cf03 --- /dev/null +++ b/samplers/random.cpp @@ -0,0 +1,115 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// samplers/random.cpp* +#include "stdafx.h" +#include "samplers/random.h" +#include "montecarlo.h" +#include "camera.h" + +RandomSampler::RandomSampler(int xstart, int xend, + int ystart, int yend, int ns, float sopen, float sclose) + : Sampler(xstart, xend, ystart, yend, ns, sopen, sclose) { + xPos = xPixelStart; + yPos = yPixelStart; + nSamples = ns; + // Get storage for a pixel's worth of stratified samples + imageSamples = AllocAligned(5 * nSamples); + lensSamples = imageSamples + 2 * nSamples; + timeSamples = lensSamples + 2 * nSamples; + + RNG rng(xstart + ystart * (xend-xstart)); + for (int i = 0; i < 5 * nSamples; ++i) + imageSamples[i] = rng.RandomFloat(); + + // Shift image samples to pixel coordinates + for (int o = 0; o < 2 * nSamples; o += 2) { + imageSamples[o] += xPos; + imageSamples[o+1] += yPos; + } + samplePos = 0; +} + + + +Sampler *RandomSampler::GetSubSampler(int num, int count) { + int x0, x1, y0, y1; + ComputeSubWindow(num, count, &x0, &x1, &y0, &y1); + if (x0 == x1 || y0 == y1) return NULL; + return new RandomSampler(x0, x1, y0, y1, nSamples, + shutterOpen, shutterClose); +} + + + +int RandomSampler::GetMoreSamples(Sample *sample, RNG &rng) { + if (samplePos == nSamples) { + if (xPixelStart == xPixelEnd || yPixelStart == yPixelEnd) + return 0; + if (++xPos == xPixelEnd) { + xPos = xPixelStart; + ++yPos; + } + if (yPos == yPixelEnd) + return 0; + + for (int i = 0; i < 5 * nSamples; ++i) + imageSamples[i] = rng.RandomFloat(); + + // Shift image samples to pixel coordinates + for (int o = 0; o < 2 * nSamples; o += 2) { + imageSamples[o] += xPos; + imageSamples[o+1] += yPos; + } + samplePos = 0; + } + // Return next \mono{RandomSampler} sample point + sample->imageX = imageSamples[2*samplePos]; + sample->imageY = imageSamples[2*samplePos+1]; + sample->lensU = lensSamples[2*samplePos]; + sample->lensV = lensSamples[2*samplePos+1]; + sample->time = Lerp(timeSamples[samplePos], shutterOpen, shutterClose); + // Generate stratified samples for integrators + for (uint32_t i = 0; i < sample->n1D.size(); ++i) + for (uint32_t j = 0; j < sample->n1D[i]; ++j) + sample->oneD[i][j] = rng.RandomFloat(); + for (uint32_t i = 0; i < sample->n2D.size(); ++i) + for (uint32_t j = 0; j < 2*sample->n2D[i]; ++j) + sample->twoD[i][j] = rng.RandomFloat(); + ++samplePos; + return 1; +} + + + +Sampler *CreateRandomSampler(const ParamSet ¶ms, + const Film *film, const Camera *camera) { + int ns = params.FindOneInt("pixelsamples", 4); + int xstart, xend, ystart, yend; + film->GetSampleExtent(&xstart, &xend, &ystart, ¥d); + return new RandomSampler(xstart, xend, ystart, yend, ns, + camera->shutterOpen, camera->shutterClose); +} + + diff --git a/samplers/random.h b/samplers/random.h new file mode 100644 index 0000000..93eca72 --- /dev/null +++ b/samplers/random.h @@ -0,0 +1,58 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_SAMPLERS_RANDOM_H +#define PBRT_SAMPLERS_RANDOM_H + +// samplers/random.h* +#include "sampler.h" +#include "paramset.h" +#include "film.h" +class RandomSampler : public Sampler { +public: + RandomSampler(int xstart, int xend, int ystart, + int yend, int ns, float sopen, float sclose); + ~RandomSampler() { + FreeAligned(imageSamples); + } + int MaximumSampleCount() { return 1; } + int GetMoreSamples(Sample *sample, RNG &rng); + int RoundSize(int sz) const { return sz; } + Sampler *GetSubSampler(int num, int count); +private: + // RandomSampler Private Data + bool jitterSamples; + int xPos, yPos, nSamples; + float *imageSamples, *lensSamples, *timeSamples; + int samplePos; +}; + + +Sampler *CreateRandomSampler(const ParamSet ¶ms, const Film *film, + const Camera *camera); + +#endif // PBRT_SAMPLERS_RANDOM_H diff --git a/samplers/stratified.cpp b/samplers/stratified.cpp new file mode 100644 index 0000000..ec96296 --- /dev/null +++ b/samplers/stratified.cpp @@ -0,0 +1,123 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// samplers/stratified.cpp* +#include "stdafx.h" +#include "samplers/stratified.h" +#include "paramset.h" +#include "camera.h" +#include "montecarlo.h" + +// StratifiedSampler Method Definitions +StratifiedSampler::StratifiedSampler(int xstart, int xend, + int ystart, int yend, int xs, int ys, bool jitter, + float sopen, float sclose) + : Sampler(xstart, xend, ystart, yend, xs * ys, sopen, sclose) { + jitterSamples = jitter; + xPos = xPixelStart; + yPos = yPixelStart; + xPixelSamples = xs; + yPixelSamples = ys; + sampleBuf = new float[5 * xPixelSamples * yPixelSamples]; +} + + +StratifiedSampler::~StratifiedSampler() { + delete[] sampleBuf; +} + + +Sampler *StratifiedSampler::GetSubSampler(int num, int count) { + int x0, x1, y0, y1; + ComputeSubWindow(num, count, &x0, &x1, &y0, &y1); + if (x0 == x1 || y0 == y1) return NULL; + return new StratifiedSampler(x0, x1, y0, y1, xPixelSamples, + yPixelSamples, jitterSamples, shutterOpen, shutterClose); +} + + +int StratifiedSampler::GetMoreSamples(Sample *samples, RNG &rng) { + if (yPos == yPixelEnd) return 0; + int nSamples = xPixelSamples * yPixelSamples; + // Generate stratified camera samples for _(xPos, yPos)_ + + // Generate initial stratified samples into _sampleBuf_ memory + float *bufp = sampleBuf; + float *imageSamples = bufp; bufp += 2 * nSamples; + float *lensSamples = bufp; bufp += 2 * nSamples; + float *timeSamples = bufp; + StratifiedSample2D(imageSamples, xPixelSamples, yPixelSamples, rng, + jitterSamples); + StratifiedSample2D(lensSamples, xPixelSamples, yPixelSamples, rng, + jitterSamples); + StratifiedSample1D(timeSamples, xPixelSamples * yPixelSamples, rng, + jitterSamples); + + // Shift stratified image samples to pixel coordinates + for (int o = 0; o < 2 * xPixelSamples * yPixelSamples; o += 2) { + imageSamples[o] += xPos; + imageSamples[o+1] += yPos; + } + + // Decorrelate sample dimensions + Shuffle(lensSamples, xPixelSamples*yPixelSamples, 2, rng); + Shuffle(timeSamples, xPixelSamples*yPixelSamples, 1, rng); + + // Initialize stratified _samples_ with sample values + for (int i = 0; i < nSamples; ++i) { + samples[i].imageX = imageSamples[2*i]; + samples[i].imageY = imageSamples[2*i+1]; + samples[i].lensU = lensSamples[2*i]; + samples[i].lensV = lensSamples[2*i+1]; + samples[i].time = Lerp(timeSamples[i], shutterOpen, shutterClose); + // Generate stratified samples for integrators + for (uint32_t j = 0; j < samples[i].n1D.size(); ++j) + LatinHypercube(samples[i].oneD[j], samples[i].n1D[j], 1, rng); + for (uint32_t j = 0; j < samples[i].n2D.size(); ++j) + LatinHypercube(samples[i].twoD[j], samples[i].n2D[j], 2, rng); + } + + // Advance to next pixel for stratified sampling + if (++xPos == xPixelEnd) { + xPos = xPixelStart; + ++yPos; + } + return nSamples; +} + + +StratifiedSampler *CreateStratifiedSampler(const ParamSet ¶ms, const Film *film, + const Camera *camera) { + bool jitter = params.FindOneBool("jitter", true); + // Initialize common sampler parameters + int xstart, xend, ystart, yend; + film->GetSampleExtent(&xstart, &xend, &ystart, ¥d); + int xsamp = params.FindOneInt("xsamples", 2); + int ysamp = params.FindOneInt("ysamples", 2); + if (PbrtOptions.quickRender) xsamp = ysamp = 1; + return new StratifiedSampler(xstart, xend, ystart, yend, xsamp, ysamp, + jitter, camera->shutterOpen, camera->shutterClose); +} + + diff --git a/samplers/stratified.h b/samplers/stratified.h new file mode 100644 index 0000000..ed31ffa --- /dev/null +++ b/samplers/stratified.h @@ -0,0 +1,58 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_SAMPLERS_STRATIFIED_H +#define PBRT_SAMPLERS_STRATIFIED_H + +// samplers/stratified.h* +#include "sampler.h" +#include "film.h" + +// StratifiedSampler Declarations +class StratifiedSampler : public Sampler { +public: + // StratifiedSampler Public Methods + StratifiedSampler(int xstart, int xend, int ystart, int yend, + int xs, int ys, bool jitter, float sopen, float sclose); + ~StratifiedSampler(); + int RoundSize(int size) const { return size; } + Sampler *GetSubSampler(int num, int count); + int GetMoreSamples(Sample *sample, RNG &rng); + int MaximumSampleCount() { return xPixelSamples * yPixelSamples; } +private: + // StratifiedSampler Private Data + int xPixelSamples, yPixelSamples; + bool jitterSamples; + int xPos, yPos; + float *sampleBuf; +}; + + +StratifiedSampler *CreateStratifiedSampler(const ParamSet ¶ms, const Film *film, + const Camera *camera); + +#endif // PBRT_SAMPLERS_STRATIFIED_H diff --git a/shapes/Archive.zip b/shapes/Archive.zip new file mode 100644 index 0000000..ee32e71 Binary files /dev/null and b/shapes/Archive.zip differ diff --git a/shapes/cone.cpp b/shapes/cone.cpp new file mode 100644 index 0000000..4a722f7 --- /dev/null +++ b/shapes/cone.cpp @@ -0,0 +1,211 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// shapes/cone.cpp* +#include "stdafx.h" +#include "shapes/cone.h" +#include "paramset.h" + +// Cone Method Definitions +Cone::Cone(const Transform *o2w, const Transform *w2o, bool ro, + float ht, float rad, float tm) + : Shape(o2w, w2o, ro) { + radius = rad; + height = ht; + phiMax = Radians( Clamp( tm, 0.0f, 360.0f ) ); +} + + +BBox Cone::ObjectBound() const { + Point p1 = Point( -radius, -radius, 0 ); + Point p2 = Point( radius, radius, height ); + return BBox( p1, p2 ); +} + + +bool Cone::Intersect(const Ray &r, float *tHit, float *rayEpsilon, + DifferentialGeometry *dg) const { + float phi; + Point phit; + // Transform _Ray_ to object space + Ray ray; + (*WorldToObject)(r, &ray); + + // Compute quadratic cone coefficients + float k = radius / height; + k = k*k; + float A = ray.d.x * ray.d.x + ray.d.y * ray.d.y - + k * ray.d.z * ray.d.z; + float B = 2 * (ray.d.x * ray.o.x + ray.d.y * ray.o.y - + k * ray.d.z * (ray.o.z-height) ); + float C = ray.o.x * ray.o.x + ray.o.y * ray.o.y - + k * (ray.o.z -height) * (ray.o.z-height); + + // Solve quadratic equation for _t_ values + float t0, t1; + if (!Quadratic(A, B, C, &t0, &t1)) + return false; + + // Compute intersection distance along ray + if (t0 > ray.maxt || t1 < ray.mint) + return false; + float thit = t0; + if (t0 < ray.mint) { + thit = t1; + if (thit > ray.maxt) return false; + } + + // Compute cone inverse mapping + phit = ray(thit); + phi = atan2f(phit.y, phit.x); + if (phi < 0.) phi += 2.f*M_PI; + + // Test cone intersection against clipping parameters + if (phit.z < 0 || phit.z > height || phi > phiMax) { + if (thit == t1) return false; + thit = t1; + if (t1 > ray.maxt) return false; + // Compute cone inverse mapping + phit = ray(thit); + phi = atan2f(phit.y, phit.x); + if (phi < 0.) phi += 2.f*M_PI; + if (phit.z < 0 || phit.z > height || phi > phiMax) + return false; + } + + // Find parametric representation of cone hit + float u = phi / phiMax; + float v = phit.z / height; + + // Compute cone $\dpdu$ and $\dpdv$ + Vector dpdu(-phiMax * phit.y, phiMax * phit.x, 0); + Vector dpdv(-phit.x / (1.f - v), + -phit.y / (1.f - v), height); + + // Compute cone $\dndu$ and $\dndv$ + Vector d2Pduu = -phiMax * phiMax * + Vector(phit.x, phit.y, 0.); + Vector d2Pduv = phiMax / (1.f - v) * + Vector(-phit.y, -phit.x, 0.); + Vector d2Pdvv(0, 0, 0); + + // Compute coefficients for fundamental forms + float E = Dot(dpdu, dpdu); + float F = Dot(dpdu, dpdv); + float G = Dot(dpdv, dpdv); + Vector N = Normalize(Cross(dpdu, dpdv)); + float e = Dot(N, d2Pduu); + float f = Dot(N, d2Pduv); + float g = Dot(N, d2Pdvv); + + // Compute $\dndu$ and $\dndv$ from fundamental form coefficients + float invEGF2 = 1.f / (E*G - F*F); + Normal dndu = Normal((f*F - e*G) * invEGF2 * dpdu + + (e*F - f*E) * invEGF2 * dpdv); + Normal dndv = Normal((g*F - f*G) * invEGF2 * dpdu + + (f*F - g*E) * invEGF2 * dpdv); + + // Initialize _DifferentialGeometry_ from parametric information + const Transform &o2w = *ObjectToWorld; + *dg = DifferentialGeometry(o2w(phit), o2w(dpdu), o2w(dpdv), + o2w(dndu), o2w(dndv), u, v, this); + + // Update _tHit_ for quadric intersection + *tHit = thit; + + // Compute _rayEpsilon_ for quadric intersection + *rayEpsilon = 5e-4f * *tHit; + return true; +} + + + +bool Cone::IntersectP(const Ray &r) const { + float phi; + Point phit; + // Transform _Ray_ to object space + Ray ray; + (*WorldToObject)(r, &ray); + + // Compute quadratic cone coefficients + float k = radius / height; + k = k*k; + float A = ray.d.x * ray.d.x + ray.d.y * ray.d.y - + k * ray.d.z * ray.d.z; + float B = 2 * (ray.d.x * ray.o.x + ray.d.y * ray.o.y - + k * ray.d.z * (ray.o.z-height) ); + float C = ray.o.x * ray.o.x + ray.o.y * ray.o.y - + k * (ray.o.z -height) * (ray.o.z-height); + + // Solve quadratic equation for _t_ values + float t0, t1; + if (!Quadratic(A, B, C, &t0, &t1)) + return false; + + // Compute intersection distance along ray + if (t0 > ray.maxt || t1 < ray.mint) + return false; + float thit = t0; + if (t0 < ray.mint) { + thit = t1; + if (thit > ray.maxt) return false; + } + + // Compute cone inverse mapping + phit = ray(thit); + phi = atan2f(phit.y, phit.x); + if (phi < 0.) phi += 2.f*M_PI; + + // Test cone intersection against clipping parameters + if (phit.z < 0 || phit.z > height || phi > phiMax) { + if (thit == t1) return false; + thit = t1; + if (t1 > ray.maxt) return false; + // Compute cone inverse mapping + phit = ray(thit); + phi = atan2f(phit.y, phit.x); + if (phi < 0.) phi += 2.f*M_PI; + if (phit.z < 0 || phit.z > height || phi > phiMax) + return false; + } + return true; +} + + +float Cone::Area() const { + return phiMax*height*height* + sqrtf((height*height)+ + (radius*radius))/(2.0f*radius); +} + + +Cone *CreateConeShape(const Transform *o2w, const Transform *w2o, + bool reverseOrientation, const ParamSet ¶ms) { + float radius = params.FindOneFloat("radius", 1); + float height = params.FindOneFloat("height", 1); + float phimax = params.FindOneFloat("phimax", 360); + return new Cone(o2w, w2o, reverseOrientation, height, radius, phimax); +} + + diff --git a/shapes/cone.h b/shapes/cone.h new file mode 100644 index 0000000..d94e2ab --- /dev/null +++ b/shapes/cone.h @@ -0,0 +1,54 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_SHAPES_CONE_H +#define PBRT_SHAPES_CONE_H + +// shapes/cone.h* +#include "shape.h" + +// Cone Declarations +class Cone : public Shape { +public: + // Cone Public Methods + Cone(const Transform *o2w, const Transform *w2o, bool ro, + float height, float rad, float tm); + BBox ObjectBound() const; + bool Intersect(const Ray &ray, float *tHit, float *rayEpsilon, + DifferentialGeometry *dg) const; + bool IntersectP(const Ray &ray) const; + float Area() const; +protected: + // Cone Private Data + float radius, height, phiMax; +}; + + +Cone *CreateConeShape(const Transform *o2w, const Transform *w2o, + bool reverseOrientation, const ParamSet ¶ms); + +#endif // PBRT_SHAPES_CONE_H diff --git a/shapes/cylinder.cpp b/shapes/cylinder.cpp new file mode 100644 index 0000000..a63424d --- /dev/null +++ b/shapes/cylinder.cpp @@ -0,0 +1,206 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// shapes/cylinder.cpp* +#include "stdafx.h" +#include "shapes/cylinder.h" +#include "paramset.h" + +// Cylinder Method Definitions +Cylinder::Cylinder(const Transform *o2w, const Transform *w2o, bool ro, + float rad, float z0, float z1, float pm) + : Shape(o2w, w2o, ro) { + radius = rad; + zmin = min(z0, z1); + zmax = max(z0, z1); + phiMax = Radians(Clamp(pm, 0.0f, 360.0f)); +} + + +BBox Cylinder::ObjectBound() const { + Point p1 = Point(-radius, -radius, zmin); + Point p2 = Point( radius, radius, zmax); + return BBox(p1, p2); +} + + +bool Cylinder::Intersect(const Ray &r, float *tHit, float *rayEpsilon, + DifferentialGeometry *dg) const { + float phi; + Point phit; + // Transform _Ray_ to object space + Ray ray; + (*WorldToObject)(r, &ray); + + // Compute quadratic cylinder coefficients + float A = ray.d.x*ray.d.x + ray.d.y*ray.d.y; + float B = 2 * (ray.d.x*ray.o.x + ray.d.y*ray.o.y); + float C = ray.o.x*ray.o.x + ray.o.y*ray.o.y - radius*radius; + + // Solve quadratic equation for _t_ values + float t0, t1; + if (!Quadratic(A, B, C, &t0, &t1)) + return false; + + // Compute intersection distance along ray + if (t0 > ray.maxt || t1 < ray.mint) + return false; + float thit = t0; + if (t0 < ray.mint) { + thit = t1; + if (thit > ray.maxt) return false; + } + + // Compute cylinder hit point and $\phi$ + phit = ray(thit); + phi = atan2f(phit.y, phit.x); + if (phi < 0.) phi += 2.f*M_PI; + + // Test cylinder intersection against clipping parameters + if (phit.z < zmin || phit.z > zmax || phi > phiMax) { + if (thit == t1) return false; + thit = t1; + if (t1 > ray.maxt) return false; + // Compute cylinder hit point and $\phi$ + phit = ray(thit); + phi = atan2f(phit.y, phit.x); + if (phi < 0.) phi += 2.f*M_PI; + if (phit.z < zmin || phit.z > zmax || phi > phiMax) + return false; + } + + // Find parametric representation of cylinder hit + float u = phi / phiMax; + float v = (phit.z - zmin) / (zmax - zmin); + + // Compute cylinder $\dpdu$ and $\dpdv$ + Vector dpdu(-phiMax * phit.y, phiMax * phit.x, 0); + Vector dpdv(0, 0, zmax - zmin); + + // Compute cylinder $\dndu$ and $\dndv$ + Vector d2Pduu = -phiMax * phiMax * Vector(phit.x, phit.y, 0); + Vector d2Pduv(0, 0, 0), d2Pdvv(0, 0, 0); + + // Compute coefficients for fundamental forms + float E = Dot(dpdu, dpdu); + float F = Dot(dpdu, dpdv); + float G = Dot(dpdv, dpdv); + Vector N = Normalize(Cross(dpdu, dpdv)); + float e = Dot(N, d2Pduu); + float f = Dot(N, d2Pduv); + float g = Dot(N, d2Pdvv); + + // Compute $\dndu$ and $\dndv$ from fundamental form coefficients + float invEGF2 = 1.f / (E*G - F*F); + Normal dndu = Normal((f*F - e*G) * invEGF2 * dpdu + + (e*F - f*E) * invEGF2 * dpdv); + Normal dndv = Normal((g*F - f*G) * invEGF2 * dpdu + + (f*F - g*E) * invEGF2 * dpdv); + + // Initialize _DifferentialGeometry_ from parametric information + const Transform &o2w = *ObjectToWorld; + *dg = DifferentialGeometry(o2w(phit), o2w(dpdu), o2w(dpdv), + o2w(dndu), o2w(dndv), u, v, this); + + // Update _tHit_ for quadric intersection + *tHit = thit; + + // Compute _rayEpsilon_ for quadric intersection + *rayEpsilon = 5e-4f * *tHit; + return true; +} + + +bool Cylinder::IntersectP(const Ray &r) const { + float phi; + Point phit; + // Transform _Ray_ to object space + Ray ray; + (*WorldToObject)(r, &ray); + + // Compute quadratic cylinder coefficients + float A = ray.d.x*ray.d.x + ray.d.y*ray.d.y; + float B = 2 * (ray.d.x*ray.o.x + ray.d.y*ray.o.y); + float C = ray.o.x*ray.o.x + ray.o.y*ray.o.y - radius*radius; + + // Solve quadratic equation for _t_ values + float t0, t1; + if (!Quadratic(A, B, C, &t0, &t1)) + return false; + + // Compute intersection distance along ray + if (t0 > ray.maxt || t1 < ray.mint) + return false; + float thit = t0; + if (t0 < ray.mint) { + thit = t1; + if (thit > ray.maxt) return false; + } + + // Compute cylinder hit point and $\phi$ + phit = ray(thit); + phi = atan2f(phit.y, phit.x); + if (phi < 0.) phi += 2.f*M_PI; + + // Test cylinder intersection against clipping parameters + if (phit.z < zmin || phit.z > zmax || phi > phiMax) { + if (thit == t1) return false; + thit = t1; + if (t1 > ray.maxt) return false; + // Compute cylinder hit point and $\phi$ + phit = ray(thit); + phi = atan2f(phit.y, phit.x); + if (phi < 0.) phi += 2.f*M_PI; + if (phit.z < zmin || phit.z > zmax || phi > phiMax) + return false; + } + return true; +} + + +float Cylinder::Area() const { + return (zmax-zmin) * phiMax * radius; +} + + +Cylinder *CreateCylinderShape(const Transform *o2w, const Transform *w2o, + bool reverseOrientation, const ParamSet ¶ms) { + float radius = params.FindOneFloat("radius", 1); + float zmin = params.FindOneFloat("zmin", -1); + float zmax = params.FindOneFloat("zmax", 1); + float phimax = params.FindOneFloat("phimax", 360); + return new Cylinder(o2w, w2o, reverseOrientation, radius, zmin, zmax, phimax); +} + + +Point Cylinder::Sample(float u1, float u2, Normal *Ns) const { + float z = Lerp(u1, zmin, zmax); + float t = u2 * phiMax; + Point p = Point(radius * cosf(t), radius * sinf(t), z); + *Ns = Normalize((*ObjectToWorld)(Normal(p.x, p.y, 0.))); + if (ReverseOrientation) *Ns *= -1.f; + return (*ObjectToWorld)(p); +} + + diff --git a/shapes/cylinder.h b/shapes/cylinder.h new file mode 100644 index 0000000..b5ef2a5 --- /dev/null +++ b/shapes/cylinder.h @@ -0,0 +1,55 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_SHAPES_CYLINDER_H +#define PBRT_SHAPES_CYLINDER_H + +// shapes/cylinder.h* +#include "shape.h" + +// Cylinder Declarations +class Cylinder : public Shape { +public: + // Cylinder Public Methods + Cylinder(const Transform *o2w, const Transform *w2o, bool ro, float rad, + float zmin, float zmax, float phiMax); + BBox ObjectBound() const; + bool Intersect(const Ray &ray, float *tHit, float *rayEpsilon, + DifferentialGeometry *dg) const; + bool IntersectP(const Ray &ray) const; + float Area() const; + Point Sample(float u1, float u2, Normal *Ns) const; +protected: + // Cylinder Private Data + float radius, zmin, zmax, phiMax; +}; + + +Cylinder *CreateCylinderShape(const Transform *o2w, const Transform *w2o, + bool reverseOrientation, const ParamSet ¶ms); + +#endif // PBRT_SHAPES_CYLINDER_H diff --git a/shapes/disk.cpp b/shapes/disk.cpp new file mode 100644 index 0000000..2292230 --- /dev/null +++ b/shapes/disk.cpp @@ -0,0 +1,151 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// shapes/disk.cpp* +#include "stdafx.h" +#include "shapes/disk.h" +#include "paramset.h" +#include "montecarlo.h" + +// Disk Method Definitions +Disk::Disk(const Transform *o2w, const Transform *w2o, bool ro, + float ht, float r, float ri, float tmax) + : Shape(o2w, w2o, ro) { + height = ht; + radius = r; + innerRadius = ri; + phiMax = Radians(Clamp(tmax, 0.0f, 360.0f)); +} + + +BBox Disk::ObjectBound() const { + return BBox(Point(-radius, -radius, height), + Point( radius, radius, height)); +} + + +bool Disk::Intersect(const Ray &r, float *tHit, float *rayEpsilon, + DifferentialGeometry *dg) const { + // Transform _Ray_ to object space + Ray ray; + (*WorldToObject)(r, &ray); + + // Compute plane intersection for disk + if (fabsf(ray.d.z) < 1e-7) return false; + float thit = (height - ray.o.z) / ray.d.z; + if (thit < ray.mint || thit > ray.maxt) + return false; + + // See if hit point is inside disk radii and $\phimax$ + Point phit = ray(thit); + float dist2 = phit.x * phit.x + phit.y * phit.y; + if (dist2 > radius * radius || dist2 < innerRadius * innerRadius) + return false; + + // Test disk $\phi$ value against $\phimax$ + float phi = atan2f(phit.y, phit.x); + if (phi < 0) phi += 2. * M_PI; + if (phi > phiMax) + return false; + + // Find parametric representation of disk hit + float u = phi / phiMax; + float oneMinusV = ((sqrtf(dist2)-innerRadius) / + (radius-innerRadius)); + float invOneMinusV = (oneMinusV > 0.f) ? (1.f / oneMinusV) : 0.f; + float v = 1.f - oneMinusV; + Vector dpdu(-phiMax * phit.y, phiMax * phit.x, 0.); + Vector dpdv(-phit.x * invOneMinusV, -phit.y * invOneMinusV, 0.); + dpdu *= phiMax * INV_TWOPI; + dpdv *= (radius - innerRadius) / radius; + Normal dndu(0,0,0), dndv(0,0,0); + + // Initialize _DifferentialGeometry_ from parametric information + const Transform &o2w = *ObjectToWorld; + *dg = DifferentialGeometry(o2w(phit), o2w(dpdu), o2w(dpdv), + o2w(dndu), o2w(dndv), u, v, this); + + // Update _tHit_ for quadric intersection + *tHit = thit; + + // Compute _rayEpsilon_ for quadric intersection + *rayEpsilon = 5e-4f * *tHit; + return true; +} + + +bool Disk::IntersectP(const Ray &r) const { + // Transform _Ray_ to object space + Ray ray; + (*WorldToObject)(r, &ray); + + // Compute plane intersection for disk + if (fabsf(ray.d.z) < 1e-7) return false; + float thit = (height - ray.o.z) / ray.d.z; + if (thit < ray.mint || thit > ray.maxt) + return false; + + // See if hit point is inside disk radii and $\phimax$ + Point phit = ray(thit); + float dist2 = phit.x * phit.x + phit.y * phit.y; + if (dist2 > radius * radius || dist2 < innerRadius * innerRadius) + return false; + + // Test disk $\phi$ value against $\phimax$ + float phi = atan2f(phit.y, phit.x); + if (phi < 0) phi += 2. * M_PI; + if (phi > phiMax) + return false; + return true; +} + + +float Disk::Area() const { + return phiMax * 0.5f * + (radius * radius - innerRadius * innerRadius); +} + + +Disk *CreateDiskShape(const Transform *o2w, const Transform *w2o, + bool reverseOrientation, const ParamSet ¶ms) { + float height = params.FindOneFloat("height", 0.); + float radius = params.FindOneFloat("radius", 1); + float inner_radius = params.FindOneFloat("innerradius", 0); + float phimax = params.FindOneFloat("phimax", 360); + return new Disk(o2w, w2o, reverseOrientation, height, radius, inner_radius, phimax); +} + + +Point Disk::Sample(float u1, float u2, Normal *Ns) const { + Point p; + ConcentricSampleDisk(u1, u2, &p.x, &p.y); + p.x *= radius; + p.y *= radius; + p.z = height; + *Ns = Normalize((*ObjectToWorld)(Normal(0,0,1))); + if (ReverseOrientation) *Ns *= -1.f; + return (*ObjectToWorld)(p); +} + + diff --git a/shapes/disk.h b/shapes/disk.h new file mode 100644 index 0000000..a867962 --- /dev/null +++ b/shapes/disk.h @@ -0,0 +1,55 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_SHAPES_DISK_H +#define PBRT_SHAPES_DISK_H + +// shapes/disk.h* +#include "shape.h" + +// Disk Declarations +class Disk : public Shape { +public: + // Disk Public Methods + Disk(const Transform *o2w, const Transform *w2o, bool ro, float height, + float radius, float innerRadius, float phiMax); + BBox ObjectBound() const; + bool Intersect(const Ray &ray, float *tHit, float *rayEpsilon, + DifferentialGeometry *dg) const; + bool IntersectP(const Ray &ray) const; + float Area() const; + Point Sample(float u1, float u2, Normal *Ns) const; +private: + // Disk Private Data + float height, radius, innerRadius, phiMax; +}; + + +Disk *CreateDiskShape(const Transform *o2w, const Transform *w2o, + bool reverseOrientation, const ParamSet ¶ms); + +#endif // PBRT_SHAPES_DISK_H diff --git a/shapes/heightfield.cpp b/shapes/heightfield.cpp new file mode 100644 index 0000000..d5987cc --- /dev/null +++ b/shapes/heightfield.cpp @@ -0,0 +1,371 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// shapes/heightfield.cpp* +#include "stdafx.h" +#include "shapes/heightfield.h" +#include "paramset.h" +#include +using std::cout; +using std::endl; + + +// Heightfield Method Definitions +Heightfield::Heightfield(const Transform *o2w, const Transform *w2o, + bool ro, int nx, int ny, const float *zs) + : Shape(o2w, w2o, ro) { + this->nx = nx; + this->ny = ny; + z = new float[nx*ny]; + memcpy(z, zs, nx*ny*sizeof(float)); + + tmesh.reserve((nx-1)*(ny-1)); + + // Construct triangular meshes + int x, y; + for (y = 0; y < ny-1; ++y) { + for (x = 0; x < nx-1; ++x) { + + int *verts = new int[6]; + Point *P = new Point[4]; + Normal *N = new Normal[4]; + float *uvs = new float[8]; + + int pos = 0; + int dy, dx; + for (dy = 0; dy <= 1; ++dy) { + for (dx = 0; dx <= 1; ++dx) { + P[pos].x = uvs[2*pos] = (float)(x+dx) / (float)(nx-1); + P[pos].y = uvs[2*pos+1] = (float)(y+dy) / (float)(ny-1); + P[pos].z = z[(x+dx)+(y+dy)*nx]; + ++pos; + } + } + + // Compute average normals at each vertex + Vector V0 = Cross(P[1]-P[0], P[3]-P[0]) + Cross(P[3]-P[0], P[2]-P[0]); + Vector V1 = Cross(P[3]-P[1], P[0]-P[1]); + Vector V2 = Cross(P[0]-P[2], P[3]-P[2]); + Vector V3 = Cross(P[2]-P[3], P[0]-P[3]) + Cross(P[0]-P[3], P[1]-P[3]); + + Point *Pp = new Point[10]; + if (x > 0) { + Pp[9] = Point((float)(x-1)/(float)(nx-1), (float)(y+1)/(float)(ny-1), z[x-1+(y+1)*nx]); + Pp[0] = Point((float)(x-1)/(float)(nx-1), (float)y/(float)(ny-1), z[x-1+y*nx]); + V2 += Cross(Pp[9]-P[2], Pp[0]-P[2]); + V2 += Cross(Pp[0]-P[2], P[0]-P[2]); + V0 += Cross(P[2]-P[0], Pp[0]-P[0]); + } + if (y > 0) { + Pp[2] = Point((float)x/(float)(nx-1), (float)(y-1)/(float)(ny-1), z[x+(y-1)*nx]); + Pp[3] = Point((float)(x+1)/(float)(nx-1), (float)(y-1)/(float)(ny-1), z[x+1+(y-1)*nx]); + V0 += Cross(Pp[2]-P[0], P[1]-P[0]); + V1 += Cross(P[0]-P[1], Pp[2]-P[1]); + V1 += Cross(Pp[2]-P[1], Pp[3]-P[1]); + } + if (x > 0 && y > 0) { + Pp[1] = Point((float)(x-1)/(float)(nx-1), (float)(y-1)/(float)(ny-1), z[x-1+(y-1)*nx]); + V0 += Cross(Pp[0]-P[0], Pp[1]-P[0]); + V0 += Cross(Pp[1]-P[0], Pp[2]-P[0]); + } + if (x < nx-2) { + Pp[4] = Point((float)(x+2)/(float)(nx-1), (float)y/(float)(ny-1), z[x+2+y*nx]); + Pp[5] = Point((float)(x+2)/(float)(nx-1), (float)(y+1)/(float)(ny-1), z[x+2+(y+1)*nx]); + V1 += Cross(Pp[4]-P[1], Pp[5]-P[1]); + V1 += Cross(Pp[5]-P[1], P[3]-P[1]); + V3 += Cross(P[1]-P[3], Pp[5]-P[3]); + } + if (x < nx-2 && y > 0) { + V1 += Cross(Pp[3]-P[1], Pp[4]-P[1]); + } + if (y < ny-2) { + Pp[7] = Point((float)(x+1)/(float)(nx-1), (float)(y+2)/(float)(ny-1), z[x+1+(y+2)*nx]); + Pp[8] = Point((float)x/(float)(nx-1), (float)(y+2)/(float)(ny-1), z[x+(y+2)*nx]); + V3 += Cross(Pp[7]-P[3], P[2]-P[3]); + V2 += Cross(P[3]-P[2], Pp[7]-P[2]); + V2 += Cross(Pp[7]-P[2], Pp[8]-P[2]); + } + if (x < nx-2 && y < ny-2) { + Pp[6] = Point((float)(x+2)/(float)(nx-1), (float)(y+2)/(float)(ny-1), z[x+2+(y+2)*nx]); + V3 += Cross(Pp[5]-P[3], Pp[6]-P[3]); + V3 += Cross(Pp[6]-P[3], Pp[7]-P[3]); + } + if (x > 0 && y < ny-2) { + V2 += Cross(Pp[8]-P[2], Pp[9]-P[2]); + } + + N[0] = Normal(V0); + N[1] = Normal(V1); + N[2] = Normal(V2); + N[3] = Normal(V3); + + // Each mesh contains 2 connected triangles + int *vp = verts; + *vp++ = 0; + *vp++ = 1; + *vp++ = 3; + *vp++ = 0; + *vp++ = 3; + *vp++ = 2; + + ParamSet paramSet; + paramSet.AddInt("indices", verts, 6); + paramSet.AddFloat("uv", uvs, 8); + paramSet.AddPoint("P", P, 4); + paramSet.AddNormal("N", N, 4); + tmesh.push_back(CreateTriangleMeshShape(ObjectToWorld, WorldToObject, ReverseOrientation, paramSet)); + + delete[] P; + delete[] uvs; + delete[] verts; + } + } + + // Construct acceleration structure + quadTree = new QuadNode(); + ConstructQuadTree(quadTree, tmesh); +} + + +Heightfield::~Heightfield() { + delete[] z; +} + + +void Heightfield::GetShadingGeometry(const Transform &obj2world, + const DifferentialGeometry &dg, + DifferentialGeometry *dgShading) const { + + dg.shape->GetShadingGeometry(obj2world, dg, dgShading); +} + + +void Heightfield::ConstructQuadTree(QuadNode* current, vector meshes) { + + // Base case, construct leaf node + if (meshes.size() == 1) { + meshes[0]->Refine(current->triangles); + current->isLeaf = true; + current->worldBound = meshes[0]->WorldBound(); + return; + } + + // Compute bounding boxes for current set of meshes + BBox objectBound = meshes[0]->ObjectBound(); + BBox worldBound = meshes[0]->WorldBound(); + vector::const_iterator it; + for (it=meshes.begin(); it < meshes.end(); ++it) { + objectBound = Union(objectBound, (*it)->ObjectBound()); + worldBound = Union(worldBound, (*it)->WorldBound()); + } + float x = (objectBound.pMax.x-objectBound.pMin.x)/2.f + objectBound.pMin.x; + float y = (objectBound.pMax.y-objectBound.pMin.y)/2.f + objectBound.pMin.y; + current->worldBound = worldBound; + + // Partition meshes into 4 distinct containers + float eps = 0.0001; + vector NEmeshes, SEmeshes, SWmeshes, NWmeshes; + for (it=meshes.begin(); it < meshes.end(); ++it) { + BBox bound = (*it)->ObjectBound(); + if (bound.pMax.x > x+eps && bound.pMax.y > y+eps) + NEmeshes.push_back(*it); + else if (bound.pMax.x > x+eps && bound.pMin.y < y-eps) + SEmeshes.push_back(*it); + else if (bound.pMin.x < x-eps && bound.pMin.y < y-eps) + SWmeshes.push_back(*it); + else if (bound.pMin.x < x-eps && bound.pMax.y > y+eps) + NWmeshes.push_back(*it); + } + + // Construct child nodes with corresponding meshes + if (NEmeshes.size() > 0) { + QuadNode* NEchild = new QuadNode(); + ConstructQuadTree(NEchild, NEmeshes); + current->NEchild = NEchild; + } + if (SEmeshes.size() > 0) { + QuadNode* SEchild = new QuadNode(); + ConstructQuadTree(SEchild, SEmeshes); + current->SEchild = SEchild; + } + if (SWmeshes.size() > 0) { + QuadNode* SWchild = new QuadNode(); + ConstructQuadTree(SWchild, SWmeshes); + current->SWchild = SWchild; + } + if (NWmeshes.size() > 0) { + QuadNode* NWchild = new QuadNode(); + ConstructQuadTree(NWchild, NWmeshes); + current->NWchild = NWchild; + } +} + + +BBox Heightfield::ObjectBound() const { + float minz = z[0], maxz = z[0]; + for (int i = 1; i < nx*ny; ++i) { + if (z[i] < minz) minz = z[i]; + if (z[i] > maxz) maxz = z[i]; + } + return BBox(Point(0,0,minz), Point(1,1,maxz)); +} + + +bool Heightfield::CanIntersect() const { + return true; +} + + +bool Heightfield::IntersectAccel(QuadNode* node, const Ray &ray, float *tHit, float *rayEpsilon, + DifferentialGeometry *dg) const { + + bool hit = false; + + // Base case, check if ray intersects with either triangle + if (node->isLeaf) { + vector >::const_iterator triIt; + for (triIt=node->triangles.begin(); triIt < node->triangles.end(); ++triIt) { + if ((*triIt)->IntersectP(ray)) { + float tHitTemp; + float epsTemp; + DifferentialGeometry *dgTemp = new DifferentialGeometry(); + (*triIt)->Intersect(ray, &tHitTemp, &epsTemp, dgTemp); + if (tHitTemp < *tHit) { + *tHit = tHitTemp; + *rayEpsilon = epsTemp; + *dg = *dgTemp; + hit = true; + } + delete dgTemp; + } + } + return hit; + } + + // If ray intersects current bounding box, check for ray intersections on each child node + if (node->worldBound.IntersectP(ray)) { + if (node->NEchild && IntersectAccel(node->NEchild, ray, tHit, rayEpsilon, dg)) hit = true; + if (node->SEchild && IntersectAccel(node->SEchild, ray, tHit, rayEpsilon, dg)) hit = true; + if (node->SWchild && IntersectAccel(node->SWchild, ray, tHit, rayEpsilon, dg)) hit = true; + if (node->NWchild && IntersectAccel(node->NWchild, ray, tHit, rayEpsilon, dg)) hit = true; + } + return hit; +} + + +bool Heightfield::IntersectAccelP(QuadNode* node, const Ray &ray) const { + + // Base case, return true if ray intersects with either triangle + if (node->isLeaf) { + vector >::const_iterator triIt; + for (triIt=node->triangles.begin(); triIt < node->triangles.end(); ++triIt) { + if ((*triIt)->IntersectP(ray)) { + return true; + } + } + return false; + } + + // If ray intersects current bounding box, check for ray intersections on each child node + if (node->worldBound.IntersectP(ray)) { + if (node->NEchild && IntersectAccelP(node->NEchild, ray)) return true; + if (node->SEchild && IntersectAccelP(node->SEchild, ray)) return true; + if (node->SWchild && IntersectAccelP(node->SWchild, ray)) return true; + if (node->NWchild && IntersectAccelP(node->NWchild, ray)) return true; + } + return false; +} + + +bool Heightfield::Intersect(const Ray &ray, float *tHit, float *rayEpsilon, + DifferentialGeometry *dg) const { + + *tHit = ray.maxt; + return IntersectAccel(quadTree, ray, tHit, rayEpsilon, dg); +} + + +bool Heightfield::IntersectP(const Ray &ray) const { + + return IntersectAccelP(quadTree, ray); +} + + +void Heightfield::Refine(vector > &refined) const { + int ntris = 2*(nx-1)*(ny-1); + refined.reserve(ntris); + int *verts = new int[3*ntris]; + Point *P = new Point[nx*ny]; + float *uvs = new float[2*nx*ny]; + int nverts = nx*ny; + int x, y; + // Compute heightfield vertex positions + int pos = 0; + for (y = 0; y < ny; ++y) { + for (x = 0; x < nx; ++x) { + P[pos].x = uvs[2*pos] = (float)x / (float)(nx-1); + P[pos].y = uvs[2*pos+1] = (float)y / (float)(ny-1); + P[pos].z = z[pos]; + ++pos; + } + } + + // Fill in heightfield vertex offset array + int *vp = verts; + for (y = 0; y < ny-1; ++y) { + for (x = 0; x < nx-1; ++x) { +#define VERT(x,y) ((x)+(y)*nx) + *vp++ = VERT(x, y); + *vp++ = VERT(x+1, y); + *vp++ = VERT(x+1, y+1); + + *vp++ = VERT(x, y); + *vp++ = VERT(x+1, y+1); + *vp++ = VERT(x, y+1); + } +#undef VERT + } + ParamSet paramSet; + paramSet.AddInt("indices", verts, 3*ntris); + paramSet.AddFloat("uv", uvs, 2 * nverts); + paramSet.AddPoint("P", P, nverts); + refined.push_back(CreateTriangleMeshShape(ObjectToWorld, WorldToObject, ReverseOrientation, paramSet)); + delete[] P; + delete[] uvs; + delete[] verts; +} + + +Heightfield *CreateHeightfieldShape(const Transform *o2w, const Transform *w2o, + bool reverseOrientation, const ParamSet ¶ms) { + int nu = params.FindOneInt("nu", -1); + int nv = params.FindOneInt("nv", -1); + int nitems; + const float *Pz = params.FindFloat("Pz", &nitems); + Assert(nitems == nu*nv); + Assert(nu != -1 && nv != -1 && Pz != NULL); + return new Heightfield(o2w, w2o, reverseOrientation, nu, nv, Pz); +} + + diff --git a/shapes/heightfield.h b/shapes/heightfield.h new file mode 100644 index 0000000..d70ab7a --- /dev/null +++ b/shapes/heightfield.h @@ -0,0 +1,82 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_SHAPES_HEIGHTFIELD_H +#define PBRT_SHAPES_HEIGHTFIELD_H + +// shapes/heightfield.h* +#include "shape.h" +#include "shapes/trianglemesh.h" +#include +using std::vector; + +// Heightfield Declarations +class Heightfield : public Shape { +public: + // Heightfield Public Methods + Heightfield(const Transform *o2, const Transform *w2o, bool ro, int nu, int nv, const float *zs); + ~Heightfield(); + bool CanIntersect() const; + bool Intersect(const Ray &ray, float *tHit, float *rayEpsilon, + DifferentialGeometry *dg) const; + bool IntersectP(const Ray &ray) const; + void Refine(vector > &refined) const; + BBox ObjectBound() const; + virtual void GetShadingGeometry(const Transform &obj2world, + const DifferentialGeometry &dg, + DifferentialGeometry *dgShading) const; +private: + class QuadNode { + public: + QuadNode() { + isLeaf = false; + NEchild = SEchild = SWchild = NWchild = NULL; + } + bool isLeaf; + BBox worldBound; + vector > triangles; + QuadNode* NEchild; + QuadNode* SEchild; + QuadNode* SWchild; + QuadNode* NWchild; + }; + void ConstructQuadTree(QuadNode* current, vector meshes); + bool IntersectAccel(QuadNode* node, const Ray &ray, float *tHit, float *rayEpsilon, + DifferentialGeometry *dg) const; + bool IntersectAccelP(QuadNode* node, const Ray &ray) const; + // Heightfield Private Data + float *z; + int nx, ny; + vector tmesh; + QuadNode *quadTree; +}; + + +Heightfield *CreateHeightfieldShape(const Transform *o2w, const Transform *w2o, + bool reverseOrientation, const ParamSet ¶ms); + +#endif // PBRT_SHAPES_HEIGHTFIELD_H diff --git a/shapes/hyperboloid.cpp b/shapes/hyperboloid.cpp new file mode 100644 index 0000000..eade68a --- /dev/null +++ b/shapes/hyperboloid.cpp @@ -0,0 +1,259 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// shapes/hyperboloid.cpp* +#include "stdafx.h" +#include "shapes/hyperboloid.h" +#include "paramset.h" + +// Hyperboloid Method Definitions +Hyperboloid::Hyperboloid(const Transform *o2w, const Transform *w2o, bool ro, + const Point &point1, const Point &point2, float tm) + : Shape(o2w, w2o, ro) { + p1 = point1; + p2 = point2; + phiMax = Radians(Clamp(tm, 0.0f, 360.0f)); + float radius1 = sqrtf(p1.x*p1.x + p1.y*p1.y); + float radius2 = sqrtf(p2.x*p2.x + p2.y*p2.y); + rmax = max(radius1, radius2); + zmin = min(p1.z, p2.z); + zmax = max(p1.z, p2.z); + // Compute implicit function coefficients for hyperboloid + if (p2.z == 0.) swap(p1, p2); + Point pp = p1; + float xy1, xy2; + do { + pp += 2.f * (p2-p1); + xy1 = pp.x*pp.x + pp.y*pp.y; + xy2 = p2.x*p2.x + p2.y*p2.y; + a = (1.f/xy1 - (pp.z*pp.z)/(xy1*p2.z*p2.z)) / + (1 - (xy2*pp.z*pp.z)/(xy1*p2.z*p2.z)); + c = (a * xy2 - 1) / (p2.z*p2.z); + } while (isinf(a) || isnan(a)); +} + + +BBox Hyperboloid::ObjectBound() const { + Point p1 = Point( -rmax, -rmax, zmin ); + Point p2 = Point( rmax, rmax, zmax ); + return BBox( p1, p2 ); +} + + +bool Hyperboloid::Intersect(const Ray &r, float *tHit, + float *rayEpsilon, DifferentialGeometry *dg) const { + float phi, v; + Point phit; + // Transform _Ray_ to object space + Ray ray; + (*WorldToObject)(r, &ray); + + // Compute quadratic hyperboloid coefficients + float A = a*ray.d.x*ray.d.x + + a*ray.d.y*ray.d.y - + c*ray.d.z*ray.d.z; + float B = 2.f * (a*ray.d.x*ray.o.x + + a*ray.d.y*ray.o.y - + c*ray.d.z*ray.o.z); + float C = a*ray.o.x*ray.o.x + + a*ray.o.y*ray.o.y - + c*ray.o.z*ray.o.z - 1; + + // Solve quadratic equation for _t_ values + float t0, t1; + if (!Quadratic(A, B, C, &t0, &t1)) + return false; + + // Compute intersection distance along ray + if (t0 > ray.maxt || t1 < ray.mint) + return false; + float thit = t0; + if (t0 < ray.mint) { + thit = t1; + if (thit > ray.maxt) return false; + } + + // Compute hyperboloid inverse mapping + phit = ray(thit); + v = (phit.z - p1.z)/(p2.z - p1.z); + Point pr = (1.f-v) * p1 + v * p2; + phi = atan2f(pr.x*phit.y - phit.x*pr.y, + phit.x*pr.x + phit.y*pr.y); + if (phi < 0) + phi += 2*M_PI; + + // Test hyperboloid intersection against clipping parameters + if (phit.z < zmin || phit.z > zmax || phi > phiMax) { + if (thit == t1) return false; + thit = t1; + if (t1 > ray.maxt) return false; + // Compute hyperboloid inverse mapping + phit = ray(thit); + v = (phit.z - p1.z)/(p2.z - p1.z); + Point pr = (1.f-v) * p1 + v * p2; + phi = atan2f(pr.x*phit.y - phit.x*pr.y, + phit.x*pr.x + phit.y*pr.y); + if (phi < 0) + phi += 2*M_PI; + if (phit.z < zmin || phit.z > zmax || phi > phiMax) + return false; + } + + // Compute parametric representation of hyperboloid hit + float u = phi / phiMax; + + // Compute hyperboloid $\dpdu$ and $\dpdv$ + float cosphi = cosf(phi), sinphi = sinf(phi); + Vector dpdu(-phiMax * phit.y, phiMax * phit.x, 0.); + Vector dpdv((p2.x-p1.x) * cosphi - (p2.y-p1.y) * sinphi, + (p2.x-p1.x) * sinphi + (p2.y-p1.y) * cosphi, + p2.z-p1.z); + + // Compute hyperboloid $\dndu$ and $\dndv$ + Vector d2Pduu = -phiMax * phiMax * + Vector(phit.x, phit.y, 0); + Vector d2Pduv = phiMax * + Vector(-dpdv.y, dpdv.x, 0.); + Vector d2Pdvv(0, 0, 0); + + // Compute coefficients for fundamental forms + float E = Dot(dpdu, dpdu); + float F = Dot(dpdu, dpdv); + float G = Dot(dpdv, dpdv); + Vector N = Normalize(Cross(dpdu, dpdv)); + float e = Dot(N, d2Pduu); + float f = Dot(N, d2Pduv); + float g = Dot(N, d2Pdvv); + + // Compute $\dndu$ and $\dndv$ from fundamental form coefficients + float invEGF2 = 1.f / (E*G - F*F); + Normal dndu = Normal((f*F - e*G) * invEGF2 * dpdu + + (e*F - f*E) * invEGF2 * dpdv); + Normal dndv = Normal((g*F - f*G) * invEGF2 * dpdu + + (f*F - g*E) * invEGF2 * dpdv); + + // Initialize _DifferentialGeometry_ from parametric information + const Transform &o2w = *ObjectToWorld; + *dg = DifferentialGeometry(o2w(phit), o2w(dpdu), o2w(dpdv), + o2w(dndu), o2w(dndv), u, v, this); + + // Update _tHit_ for quadric intersection + *tHit = thit; + + // Compute _rayEpsilon_ for quadric intersection + *rayEpsilon = 5e-4f * *tHit; + return true; +} + + +bool Hyperboloid::IntersectP(const Ray &r) const { + float phi, v; + Point phit; + // Transform _Ray_ to object space + Ray ray; + (*WorldToObject)(r, &ray); + + // Compute quadratic hyperboloid coefficients + float A = a*ray.d.x*ray.d.x + + a*ray.d.y*ray.d.y - + c*ray.d.z*ray.d.z; + float B = 2.f * (a*ray.d.x*ray.o.x + + a*ray.d.y*ray.o.y - + c*ray.d.z*ray.o.z); + float C = a*ray.o.x*ray.o.x + + a*ray.o.y*ray.o.y - + c*ray.o.z*ray.o.z - 1; + + // Solve quadratic equation for _t_ values + float t0, t1; + if (!Quadratic(A, B, C, &t0, &t1)) + return false; + + // Compute intersection distance along ray + if (t0 > ray.maxt || t1 < ray.mint) + return false; + float thit = t0; + if (t0 < ray.mint) { + thit = t1; + if (thit > ray.maxt) return false; + } + + // Compute hyperboloid inverse mapping + phit = ray(thit); + v = (phit.z - p1.z)/(p2.z - p1.z); + Point pr = (1.f-v) * p1 + v * p2; + phi = atan2f(pr.x*phit.y - phit.x*pr.y, + phit.x*pr.x + phit.y*pr.y); + if (phi < 0) + phi += 2*M_PI; + + // Test hyperboloid intersection against clipping parameters + if (phit.z < zmin || phit.z > zmax || phi > phiMax) { + if (thit == t1) return false; + thit = t1; + if (t1 > ray.maxt) return false; + // Compute hyperboloid inverse mapping + phit = ray(thit); + v = (phit.z - p1.z)/(p2.z - p1.z); + Point pr = (1.f-v) * p1 + v * p2; + phi = atan2f(pr.x*phit.y - phit.x*pr.y, + phit.x*pr.x + phit.y*pr.y); + if (phi < 0) + phi += 2*M_PI; + if (phit.z < zmin || phit.z > zmax || phi > phiMax) + return false; + } + return true; +} + + +#define SQR(a) ((a)*(a)) +#define QUAD(a) ((SQR(a))*(SQR(a))) +float Hyperboloid::Area() const { + return phiMax/6.f * + (2.f*QUAD(p1.x) - 2.f*p1.x*p1.x*p1.x*p2.x + + 2.f*QUAD(p2.x) + + 2.f*(p1.y*p1.y + p1.y*p2.y + p2.y*p2.y)* + (SQR(p1.y - p2.y) + SQR(p1.z - p2.z)) + + p2.x*p2.x*(5.f*p1.y*p1.y + 2.f*p1.y*p2.y - + 4.f*p2.y*p2.y + 2.f*SQR(p1.z - p2.z)) + + p1.x*p1.x*(-4.f*p1.y*p1.y + 2.f*p1.y*p2.y + + 5.f*p2.y*p2.y + 2.f*SQR(p1.z - p2.z)) - + 2.f*p1.x*p2.x*(p2.x*p2.x - p1.y*p1.y + + 5.f*p1.y*p2.y - p2.y*p2.y - p1.z*p1.z + + 2.f*p1.z*p2.z - p2.z*p2.z)); +} + + +#undef SQR +#undef QUAD +Shape *CreateHyperboloidShape(const Transform *o2w, const Transform *w2o, + bool reverseOrientation, const ParamSet ¶ms) { + Point p1 = params.FindOnePoint("p1", Point(0,0,0)); + Point p2 = params.FindOnePoint("p2", Point(1,1,1)); + float phimax = params.FindOneFloat("phimax", 360); + return new Hyperboloid(o2w, w2o, reverseOrientation, p1, p2, phimax); +} + + diff --git a/shapes/hyperboloid.h b/shapes/hyperboloid.h new file mode 100644 index 0000000..d3094a1 --- /dev/null +++ b/shapes/hyperboloid.h @@ -0,0 +1,59 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_SHAPES_HYPERBOLOID_H +#define PBRT_SHAPES_HYPERBOLOID_H + +// shapes/hyperboloid.h* +#include "shape.h" + +// Hyperboloid Declarations +class Hyperboloid : public Shape { +public: + // Hyperboloid Public Methods + Hyperboloid(const Transform *o2w, const Transform *w2o, bool ro, + const Point &point1, const Point &point2, + float tm); + BBox ObjectBound() const; + bool Intersect(const Ray &ray, float *tHit, float *rayEpsilon, + DifferentialGeometry *dg) const; + bool IntersectP(const Ray &ray) const; + float Area() const; +protected: + // Hyperboloid Private Data + Point p1, p2; + float zmin, zmax; + float phiMax; + float rmax; + float a, c; +}; + + +Shape *CreateHyperboloidShape(const Transform *o2w, const Transform *w2o, + bool reverseOrientation, const ParamSet ¶ms); + +#endif // PBRT_SHAPES_HYPERBOLOID_H diff --git a/shapes/loopsubdiv.cpp b/shapes/loopsubdiv.cpp new file mode 100644 index 0000000..abe3054 --- /dev/null +++ b/shapes/loopsubdiv.cpp @@ -0,0 +1,502 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// shapes/loopsubdiv.cpp* +#include "stdafx.h" +#include "shapes/loopsubdiv.h" +#include "shapes/trianglemesh.h" +#include "paramset.h" +#include +#include +using std::set; +using std::map; + +// LoopSubdiv Macros +#define NEXT(i) (((i)+1)%3) +#define PREV(i) (((i)+2)%3) + +// LoopSubdiv Local Structures +struct SDFace; +struct SDFace; +struct SDVertex { + // SDVertex Constructor + SDVertex(Point pt = Point(0,0,0)) + : P(pt), startFace(NULL), child(NULL), + regular(false), boundary(false) { } + + // SDVertex Methods + int valence(); + void oneRing(Point *P); + Point P; + SDFace *startFace; + SDVertex *child; + bool regular, boundary; +}; + + +struct SDFace { + // SDFace Constructor + SDFace() { + int i; + for (i = 0; i < 3; ++i) { + v[i] = NULL; + f[i] = NULL; + } + for (i = 0; i < 4; ++i) + children[i] = NULL; + } + + // SDFace Methods + int vnum(SDVertex *vert) const { + for (int i = 0; i < 3; ++i) + if (v[i] == vert) return i; + Severe("Basic logic error in SDFace::vnum()"); + return -1; + } + SDFace *nextFace(SDVertex *vert) { + return f[vnum(vert)]; + } + SDFace *prevFace(SDVertex *vert) { + return f[PREV(vnum(vert))]; + } + SDVertex *nextVert(SDVertex *vert) { + return v[NEXT(vnum(vert))]; + } + SDVertex *prevVert(SDVertex *vert) { + return v[PREV(vnum(vert))]; + } + SDVertex *otherVert(SDVertex *v0, SDVertex *v1) { + for (int i = 0; i < 3; ++i) + if (v[i] != v0 && v[i] != v1) + return v[i]; + Severe("Basic logic error in SDVertex::otherVert()"); + return NULL; + } + SDVertex *v[3]; + SDFace *f[3]; + SDFace *children[4]; +}; + + +struct SDEdge { + // SDEdge Constructor + SDEdge(SDVertex *v0 = NULL, SDVertex *v1 = NULL) { + v[0] = min(v0, v1); + v[1] = max(v0, v1); + f[0] = f[1] = NULL; + f0edgeNum = -1; + } + + // SDEdge Comparison Function + bool operator<(const SDEdge &e2) const { + if (v[0] == e2.v[0]) return v[1] < e2.v[1]; + return v[0] < e2.v[0]; + } + SDVertex *v[2]; + SDFace *f[2]; + int f0edgeNum; +}; + + + +// LoopSubdiv Inline Functions +inline int SDVertex::valence() { + SDFace *f = startFace; + if (!boundary) { + // Compute valence of interior vertex + int nf = 1; + while ((f = f->nextFace(this)) != startFace) + ++nf; + return nf; + } + else { + // Compute valence of boundary vertex + int nf = 1; + while ((f = f->nextFace(this)) != NULL) + ++nf; + f = startFace; + while ((f = f->prevFace(this)) != NULL) + ++nf; + return nf+1; + } +} + + + +// LoopSubdiv Method Definitions +LoopSubdiv::LoopSubdiv(const Transform *o2w, const Transform *w2o, + bool ro, int nfaces, int nvertices, + const int *vertexIndices, const Point *P, int nl) + : Shape(o2w, w2o, ro) { + nLevels = nl; + // Allocate _LoopSubdiv_ vertices and faces + int i; + SDVertex *verts = new SDVertex[nvertices]; + for (i = 0; i < nvertices; ++i) { + verts[i] = SDVertex(P[i]); + vertices.push_back(&verts[i]); + } + SDFace *fs = new SDFace[nfaces]; + for (i = 0; i < nfaces; ++i) + faces.push_back(&fs[i]); + + // Set face to vertex pointers + const int *vp = vertexIndices; + for (i = 0; i < nfaces; ++i) { + SDFace *f = faces[i]; + for (int j = 0; j < 3; ++j) { + SDVertex *v = vertices[vp[j]]; + f->v[j] = v; + v->startFace = f; + } + vp += 3; + } + + // Set neighbor pointers in _faces_ + set edges; + for (i = 0; i < nfaces; ++i) { + SDFace *f = faces[i]; + for (int edgeNum = 0; edgeNum < 3; ++edgeNum) { + // Update neighbor pointer for _edgeNum_ + int v0 = edgeNum, v1 = NEXT(edgeNum); + SDEdge e(f->v[v0], f->v[v1]); + if (edges.find(e) == edges.end()) { + // Handle new edge + e.f[0] = f; + e.f0edgeNum = edgeNum; + edges.insert(e); + } + else { + // Handle previously seen edge + e = *edges.find(e); + e.f[0]->f[e.f0edgeNum] = f; + f->f[edgeNum] = e.f[0]; + edges.erase(e); + } + } + } + + // Finish vertex initialization + for (i = 0; i < nvertices; ++i) { + SDVertex *v = vertices[i]; + SDFace *f = v->startFace; + do { + f = f->nextFace(v); + } while (f && f != v->startFace); + v->boundary = (f == NULL); + if (!v->boundary && v->valence() == 6) + v->regular = true; + else if (v->boundary && v->valence() == 4) + v->regular = true; + else + v->regular = false; + } +} + + +LoopSubdiv::~LoopSubdiv() { + delete[] vertices[0]; + delete[] faces[0]; +} + + +BBox LoopSubdiv::ObjectBound() const { + BBox b; + for (uint32_t i = 0; i < vertices.size(); i++) + b = Union(b, vertices[i]->P); + return b; +} + + +BBox LoopSubdiv::WorldBound() const { + BBox b; + for (uint32_t i = 0; i < vertices.size(); i++) + b = Union(b, (*ObjectToWorld)(vertices[i]->P)); + return b; +} + + +bool LoopSubdiv::CanIntersect() const { + return false; +} + + +void LoopSubdiv::Refine(vector > &refined) const { + vector f = faces; + vector v = vertices; + MemoryArena arena; + for (int i = 0; i < nLevels; ++i) { + // Update _f_ and _v_ for next level of subdivision + vector newFaces; + vector newVertices; + + // Allocate next level of children in mesh tree + for (uint32_t j = 0; j < v.size(); ++j) { + v[j]->child = arena.Alloc(); + v[j]->child->regular = v[j]->regular; + v[j]->child->boundary = v[j]->boundary; + newVertices.push_back(v[j]->child); + } + for (uint32_t j = 0; j < f.size(); ++j) + for (int k = 0; k < 4; ++k) { + f[j]->children[k] = arena.Alloc(); + newFaces.push_back(f[j]->children[k]); + } + + // Update vertex positions and create new edge vertices + + // Update vertex positions for even vertices + for (uint32_t j = 0; j < v.size(); ++j) { + if (!v[j]->boundary) { + // Apply one-ring rule for even vertex + if (v[j]->regular) + v[j]->child->P = weightOneRing(v[j], 1.f/16.f); + else + v[j]->child->P = weightOneRing(v[j], beta(v[j]->valence())); + } + else { + // Apply boundary rule for even vertex + v[j]->child->P = weightBoundary(v[j], 1.f/8.f); + } + } + + // Compute new odd edge vertices + map edgeVerts; + for (uint32_t j = 0; j < f.size(); ++j) { + SDFace *face = f[j]; + for (int k = 0; k < 3; ++k) { + // Compute odd vertex on _k_th edge + SDEdge edge(face->v[k], face->v[NEXT(k)]); + SDVertex *vert = edgeVerts[edge]; + if (!vert) { + // Create and initialize new odd vertex + vert = arena.Alloc(); + newVertices.push_back(vert); + vert->regular = true; + vert->boundary = (face->f[k] == NULL); + vert->startFace = face->children[3]; + + // Apply edge rules to compute new vertex position + if (vert->boundary) { + vert->P = 0.5f * edge.v[0]->P; + vert->P += 0.5f * edge.v[1]->P; + } + else { + vert->P = 3.f/8.f * edge.v[0]->P; + vert->P += 3.f/8.f * edge.v[1]->P; + vert->P += 1.f/8.f * face->otherVert(edge.v[0], edge.v[1])->P; + vert->P += 1.f/8.f * + face->f[k]->otherVert(edge.v[0], edge.v[1])->P; + } + edgeVerts[edge] = vert; + } + } + } + + // Update new mesh topology + + // Update even vertex face pointers + for (uint32_t j = 0; j < v.size(); ++j) { + SDVertex *vert = v[j]; + int vertNum = vert->startFace->vnum(vert); + vert->child->startFace = + vert->startFace->children[vertNum]; + } + + // Update face neighbor pointers + for (uint32_t j = 0; j < f.size(); ++j) { + SDFace *face = f[j]; + for (int k = 0; k < 3; ++k) { + // Update children _f_ pointers for siblings + face->children[3]->f[k] = face->children[NEXT(k)]; + face->children[k]->f[NEXT(k)] = face->children[3]; + + // Update children _f_ pointers for neighbor children + SDFace *f2 = face->f[k]; + face->children[k]->f[k] = + f2 ? f2->children[f2->vnum(face->v[k])] : NULL; + f2 = face->f[PREV(k)]; + face->children[k]->f[PREV(k)] = + f2 ? f2->children[f2->vnum(face->v[k])] : NULL; + } + } + + // Update face vertex pointers + for (uint32_t j = 0; j < f.size(); ++j) { + SDFace *face = f[j]; + for (int k = 0; k < 3; ++k) { + // Update child vertex pointer to new even vertex + face->children[k]->v[k] = face->v[k]->child; + + // Update child vertex pointer to new odd vertex + SDVertex *vert = edgeVerts[SDEdge(face->v[k], face->v[NEXT(k)])]; + face->children[k]->v[NEXT(k)] = vert; + face->children[NEXT(k)]->v[k] = vert; + face->children[3]->v[k] = vert; + } + } + + // Prepare for next level of subdivision + f = newFaces; + v = newVertices; + } + // Push vertices to limit surface + Point *Plimit = new Point[v.size()]; + for (uint32_t i = 0; i < v.size(); ++i) { + if (v[i]->boundary) + Plimit[i] = weightBoundary(v[i], 1.f/5.f); + else + Plimit[i] = weightOneRing(v[i], gamma(v[i]->valence())); + } + for (uint32_t i = 0; i < v.size(); ++i) + v[i]->P = Plimit[i]; + + // Compute vertex tangents on limit surface + vector Ns; + Ns.reserve(v.size()); + vector Pring(16, Point()); + for (uint32_t i = 0; i < v.size(); ++i) { + SDVertex *vert = v[i]; + Vector S(0,0,0), T(0,0,0); + int valence = vert->valence(); + if (valence > (int)Pring.size()) + Pring.resize(valence); + vert->oneRing(&Pring[0]); + if (!vert->boundary) { + // Compute tangents of interior face + for (int k = 0; k < valence; ++k) { + S += cosf(2.f*M_PI*k/valence) * Vector(Pring[k]); + T += sinf(2.f*M_PI*k/valence) * Vector(Pring[k]); + } + } else { + // Compute tangents of boundary face + S = Pring[valence-1] - Pring[0]; + if (valence == 2) + T = Vector(Pring[0] + Pring[1] - 2 * vert->P); + else if (valence == 3) + T = Pring[1] - vert->P; + else if (valence == 4) // regular + T = Vector(-1*Pring[0] + 2*Pring[1] + 2*Pring[2] + + -1*Pring[3] + -2*vert->P); + else { + float theta = M_PI / float(valence-1); + T = Vector(sinf(theta) * (Pring[0] + Pring[valence-1])); + for (int k = 1; k < valence-1; ++k) { + float wt = (2*cosf(theta) - 2) * sinf((k) * theta); + T += Vector(wt * Pring[k]); + } + T = -T; + } + } + Ns.push_back(Normal(Cross(S, T))); + } + + // Create _TriangleMesh_ from subdivision mesh + uint32_t ntris = uint32_t(f.size()); + int *verts = new int[3*ntris]; + int *vp = verts; + uint32_t totVerts = uint32_t(v.size()); + map usedVerts; + for (uint32_t i = 0; i < totVerts; ++i) + usedVerts[v[i]] = i; + for (uint32_t i = 0; i < ntris; ++i) { + for (int j = 0; j < 3; ++j) { + *vp = usedVerts[f[i]->v[j]]; + ++vp; + } + } + ParamSet paramSet; + paramSet.AddInt("indices", verts, 3*ntris); + paramSet.AddPoint("P", Plimit, totVerts); + paramSet.AddNormal("N", &Ns[0], int(Ns.size())); + refined.push_back(CreateTriangleMeshShape(ObjectToWorld, + WorldToObject, ReverseOrientation, paramSet)); + delete[] verts; + delete[] Plimit; +} + + +Point LoopSubdiv::weightOneRing(SDVertex *vert, float beta) { + // Put _vert_ one-ring in _Pring_ + int valence = vert->valence(); + Point *Pring = ALLOCA(Point, valence); + vert->oneRing(Pring); + Point P = (1 - valence * beta) * vert->P; + for (int i = 0; i < valence; ++i) + P += beta * Pring[i]; + return P; +} + + +void SDVertex::oneRing(Point *P) { + if (!boundary) { + // Get one-ring vertices for interior vertex + SDFace *face = startFace; + do { + *P++ = face->nextVert(this)->P; + face = face->nextFace(this); + } while (face != startFace); + } + else { + // Get one-ring vertices for boundary vertex + SDFace *face = startFace, *f2; + while ((f2 = face->nextFace(this)) != NULL) + face = f2; + *P++ = face->nextVert(this)->P; + do { + *P++ = face->prevVert(this)->P; + face = face->prevFace(this); + } while (face != NULL); + } +} + + +Point LoopSubdiv::weightBoundary(SDVertex *vert, float beta) { + // Put _vert_ one-ring in _Pring_ + int valence = vert->valence(); + Point *Pring = ALLOCA(Point, valence); + vert->oneRing(Pring); + Point P = (1-2*beta) * vert->P; + P += beta * Pring[0]; + P += beta * Pring[valence-1]; + return P; +} + + +LoopSubdiv *CreateLoopSubdivShape(const Transform *o2w, const Transform *w2o, + bool reverseOrientation, const ParamSet ¶ms) { + int nlevels = params.FindOneInt("nlevels", 3); + int nps, nIndices; + const int *vi = params.FindInt("indices", &nIndices); + const Point *P = params.FindPoint("P", &nps); + if (!vi || !P) return NULL; + + // don't actually use this for now... + string scheme = params.FindOneString("scheme", "loop"); + + return new LoopSubdiv(o2w, w2o, reverseOrientation, nIndices/3, nps, + vi, P, nlevels); +} + + diff --git a/shapes/loopsubdiv.h b/shapes/loopsubdiv.h new file mode 100644 index 0000000..5237427 --- /dev/null +++ b/shapes/loopsubdiv.h @@ -0,0 +1,70 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_SHAPES_LOOPSUBDIV_H +#define PBRT_SHAPES_LOOPSUBDIV_H + +// shapes/loopsubdiv.h* +#include "shape.h" +struct SDVertex; +struct SDFace; + +// LoopSubdiv Declarations +class LoopSubdiv : public Shape { +public: + // LoopSubdiv Public Methods + LoopSubdiv(const Transform *o2w, const Transform *w2o, bool ro, + int nt, int nv, const int *vi, + const Point *P, int nlevels); + ~LoopSubdiv(); + bool CanIntersect() const; + void Refine(vector > &refined) const; + BBox ObjectBound() const; + BBox WorldBound() const; +private: + // LoopSubdiv Private Methods + static float beta(int valence) { + if (valence == 3) return 3.f/16.f; + else return 3.f / (8.f * valence); + } + static Point weightOneRing(SDVertex *vert, float beta); + static Point weightBoundary(SDVertex *vert, float beta); + static float gamma(int valence) { + return 1.f / (valence + 3.f / (8.f * beta(valence))); + } + + // LoopSubdiv Private Data + int nLevels; + vector vertices; + vector faces; +}; + + +LoopSubdiv *CreateLoopSubdivShape(const Transform *o2w, const Transform *w2o, + bool reverseOrientation, const ParamSet ¶ms); + +#endif // PBRT_SHAPES_LOOPSUBDIV_H diff --git a/shapes/nurbs.cpp b/shapes/nurbs.cpp new file mode 100644 index 0000000..6d87133 --- /dev/null +++ b/shapes/nurbs.cpp @@ -0,0 +1,349 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// shapes/nurbs.cpp* +#include "stdafx.h" +#include "shapes/nurbs.h" +#include "shapes/trianglemesh.h" +#include "paramset.h" +#include "texture.h" + +// NURBS Evaluation Functions +static int KnotOffset(const float *knot, int order, int np, float t) { + int firstKnot = order - 1; + + int knotOffset = firstKnot; + while (t > knot[knotOffset+1]) + ++knotOffset; + Assert(knotOffset < np); // np == lastKnot + Assert(t >= knot[knotOffset] && t <= knot[knotOffset + 1]); + return knotOffset; +} + + + +// doesn't handle flat out discontinuities in the curve... + +struct Homogeneous3 { +Homogeneous3() { x = y = z = w = 0.; } +Homogeneous3(float xx, float yy, float zz, float ww) { + x = xx; y = yy; z = zz; w = ww; +} + + +float x, y, z, w; +}; + + +static Homogeneous3 +NURBSEvaluate(int order, const float *knot, const Homogeneous3 *cp, int np, + int cpStride, float t, Vector *deriv = NULL) { +// int nKnots = np + order; + float alpha; + + int knotOffset = KnotOffset(knot, order, np, t); + knot += knotOffset; + + int cpOffset = knotOffset - order + 1; + Assert(cpOffset >= 0 && cpOffset < np); + + Homogeneous3 *cpWork = ALLOCA(Homogeneous3, order); + for (int i = 0; i < order; ++i) + cpWork[i] = cp[(cpOffset+i) * cpStride]; + + for (int i = 0; i < order - 2; ++i) + for (int j = 0; j < order - 1 - i; ++j) { + alpha = (knot[1 + j] - t) / + (knot[1 + j] - knot[j + 2 - order + i]); + Assert(alpha >= 0. && alpha <= 1.); + + cpWork[j].x = cpWork[j].x * alpha + cpWork[j+1].x * (1 - alpha); + cpWork[j].y = cpWork[j].y * alpha + cpWork[j+1].y * (1 - alpha); + cpWork[j].z = cpWork[j].z * alpha + cpWork[j+1].z * (1 - alpha); + cpWork[j].w = cpWork[j].w * alpha + cpWork[j+1].w * (1 - alpha); + } + + alpha = (knot[1] - t) / (knot[1] - knot[0]); + Assert(alpha >= 0. && alpha <= 1.); + + Homogeneous3 val(cpWork[0].x * alpha + cpWork[1].x * (1 - alpha), + cpWork[0].y * alpha + cpWork[1].y * (1 - alpha), + cpWork[0].z * alpha + cpWork[1].z * (1 - alpha), + cpWork[0].w * alpha + cpWork[1].w * (1 - alpha)); + + if (deriv) { + float factor = (order - 1) / (knot[1] - knot[0]); + Homogeneous3 delta((cpWork[1].x - cpWork[0].x) * factor, + (cpWork[1].y - cpWork[0].y) * factor, + (cpWork[1].z - cpWork[0].z) * factor, + (cpWork[1].w - cpWork[0].w) * factor); + + deriv->x = delta.x / val.w - (val.x * delta.w / (val.w * val.w)); + deriv->y = delta.y / val.w - (val.y * delta.w / (val.w * val.w)); + deriv->z = delta.z / val.w - (val.z * delta.w / (val.w * val.w)); + } + + return val; +} + + + +static Point +NURBSEvaluateSurface(int uOrder, const float *uKnot, int ucp, float u, + int vOrder, const float *vKnot, int vcp, float v, + const Homogeneous3 *cp, Vector *dPdu, Vector *dPdv) { + Homogeneous3 *iso = ALLOCA(Homogeneous3, max(uOrder, vOrder)); + + int uOffset = KnotOffset(uKnot, uOrder, ucp, u); + int uFirstCp = uOffset - uOrder + 1; + Assert(uFirstCp >= 0 && uFirstCp + uOrder - 1 < ucp); + + for (int i = 0; i < uOrder; ++i) + iso[i] = NURBSEvaluate(vOrder, vKnot, &cp[uFirstCp + i], vcp, + ucp, v); + + int vOffset = KnotOffset(vKnot, vOrder, vcp, v); + int vFirstCp = vOffset - vOrder + 1; + Assert(vFirstCp >= 0 && vFirstCp + vOrder - 1 < vcp); + + Homogeneous3 P = NURBSEvaluate(uOrder, uKnot, iso - uFirstCp, ucp, + 1, u, dPdu); + + if (dPdv) { + for (int i = 0; i < vOrder; ++i) + iso[i] = NURBSEvaluate(uOrder, uKnot, &cp[(vFirstCp+i)*ucp], ucp, + 1, u); + (void)NURBSEvaluate(vOrder, vKnot, iso - vFirstCp, vcp, 1, v, dPdv); + } + return Point(P.x/P.w, P.y/P.w, P.z/P.w);; +} + + + + +// NURBS Method Definitions +NURBS::NURBS(const Transform *o2w, const Transform *w2o, + bool ro, int numu, int uo, const float *uk, + float u0, float u1, int numv, int vo, const float *vk, + float v0, float v1, const float *p, bool homogeneous) + : Shape(o2w, w2o, ro) { + nu = numu; uorder = uo; + umin = u0; umax = u1; + nv = numv; vorder = vo; + vmin = v0; vmax = v1; + isHomogeneous = homogeneous; + if (isHomogeneous) { + P = new float[4*nu*nv]; + memcpy(P, p, 4*nu*nv*sizeof(float)); + } else { + P = new float[3*nu*nv]; + memcpy(P, p, 3*nu*nv*sizeof(float)); + } + uknot = new float[nu + uorder]; + memcpy(uknot, uk, (nu + uorder) * sizeof(float)); + vknot = new float[nv + vorder]; + memcpy(vknot, vk, (nv + vorder) * sizeof(float)); +} + + +NURBS::~NURBS() { + delete[] P; + delete[] uknot; + delete[] vknot; +} + + +BBox NURBS::ObjectBound() const { + if (!isHomogeneous) { + // Compute object-space bound of non-homogeneous NURBS + float *pp = P; + BBox bound; + for (int i = 0; i < nu*nv; ++i, pp += 3) + bound = Union(bound, Point(pp[0], pp[1], pp[2])); + return bound; + } else { + // Compute object-space bound of homogeneous NURBS + float *pp = P; + BBox bound; + for (int i = 0; i < nu*nv; ++i, pp += 4) + bound = Union(bound, Point(pp[0] / pp[3], pp[1] / pp[3], pp[2] / pp[3])); + return bound; + } +} + + +BBox NURBS::WorldBound() const { + if (!isHomogeneous) { + // Compute world-space bound of non-homogeneous NURBS + float *pp = P; + BBox bound; + for (int i = 0; i < nu*nv; ++i, pp += 3) { + Point pt = (*ObjectToWorld)(Point(pp[0], pp[1], pp[2])); + bound = Union(bound, pt); + } + return bound; + } else { + // Compute world-space bound of homogeneous NURBS + float *pp = P; + BBox bound; + for (int i = 0; i < nu*nv; ++i, pp += 4) { + Point pt = (*ObjectToWorld)(Point(pp[0]/pp[3], + pp[1]/pp[3], pp[2]/pp[3])); + bound = Union(bound, pt); + } + return bound; + } +} + + + +void NURBS::Refine(vector > &refined) const { + // Compute NURBS dicing rates + int diceu = 30, dicev = 30; + float *ueval = new float[diceu]; + float *veval = new float[dicev]; + Point *evalPs = new Point[diceu*dicev]; + Normal *evalNs = new Normal[diceu*dicev]; + int i; + for (i = 0; i < diceu; ++i) + ueval[i] = Lerp((float)i / (float)(diceu-1), umin, umax); + for (i = 0; i < dicev; ++i) + veval[i] = Lerp((float)i / (float)(dicev-1), vmin, vmax); + // Evaluate NURBS over grid of points + memset(evalPs, 0, diceu*dicev*sizeof(Point)); + memset(evalNs, 0, diceu*dicev*sizeof(Point)); + float *uvs = new float[2*diceu*dicev]; + // Turn NURBS into triangles + Homogeneous3 *Pw = (Homogeneous3 *)P; + if (!isHomogeneous) { + Pw = new Homogeneous3[nu * nv]; + for (int i = 0; i < nu*nv; ++i) { + Pw[i].x = P[3*i]; + Pw[i].y = P[3*i+1]; + Pw[i].z = P[3*i+2]; + Pw[i].w = 1.; + } + } + for (int v = 0; v < dicev; ++v) { + for (int u = 0; u < diceu; ++u) { + uvs[2*(v*diceu+u)] = ueval[u]; + uvs[2*(v*diceu+u)+1] = veval[v]; + + Vector dPdu, dPdv; + Point pt = NURBSEvaluateSurface(uorder, uknot, nu, ueval[u], + vorder, vknot, nv, veval[v], Pw, &dPdu, &dPdv); + evalPs[v*diceu + u].x = pt.x; + evalPs[v*diceu + u].y = pt.y; + evalPs[v*diceu + u].z = pt.z; + evalNs[v*diceu + u] = Normal(Normalize(Cross(dPdu, dPdv))); + } + } + // Generate points-polygons mesh + int nTris = 2*(diceu-1)*(dicev-1); + int *vertices = new int[3 * nTris]; + int *vertp = vertices; + // Compute the vertex offset numbers for the triangles + for (int v = 0; v < dicev-1; ++v) { + for (int u = 0; u < diceu-1; ++u) { + #define VN(u,v) ((v)*diceu+(u)) + *vertp++ = VN(u, v); + *vertp++ = VN(u+1, v); + *vertp++ = VN(u+1, v+1); + + *vertp++ = VN(u, v); + *vertp++ = VN(u+1, v+1); + *vertp++ = VN(u, v+1); + #undef VN + } + } + int nVerts = diceu*dicev; + ParamSet paramSet; + paramSet.AddInt("indices", vertices, 3*nTris); + paramSet.AddPoint("P", evalPs, nVerts); + paramSet.AddFloat("uv", uvs, 2 * nVerts); + paramSet.AddNormal("N", evalNs, nVerts); + refined.push_back(CreateTriangleMeshShape(ObjectToWorld, WorldToObject, + ReverseOrientation, paramSet)); + // Cleanup from NURBS refinement + if (Pw != (Homogeneous3 *)P) delete[] Pw; + delete[] uvs; + delete[] ueval; + delete[] veval; + delete[] evalPs; + delete[] evalNs; + delete[] vertices; +} + + + +NURBS *CreateNURBSShape(const Transform *o2w, const Transform *w2o, + bool ReverseOrientation, const ParamSet ¶ms) { + int nu = params.FindOneInt("nu", -1); + int uorder = params.FindOneInt("uorder", -1); + int nuknots, nvknots; + const float *uknots = params.FindFloat("uknots", &nuknots); + Assert(nu != -1 && uorder != -1 && uknots != NULL); + Assert(nuknots == nu + uorder); + float u0 = params.FindOneFloat("u0", uknots[uorder-1]); + float u1 = params.FindOneFloat("u1", uknots[nu]); + + int nv = params.FindOneInt("nv", -1); + int vorder = params.FindOneInt("vorder", -1); + const float *vknots = params.FindFloat("vknots", &nvknots); + Assert(nv != -1 && vorder != -1 && vknots != NULL); + Assert(nvknots == nv + vorder); + float v0 = params.FindOneFloat("v0", vknots[vorder-1]); + float v1 = params.FindOneFloat("v1", vknots[nv]); + + bool isHomogeneous = false; + int npts; + const float *P = (const float *)params.FindPoint("P", &npts); + if (!P) { + P = params.FindFloat("Pw", &npts); + if (!P) { + Error("Must provide control points via \"P\" or \"Pw\" parameter to " + "NURBS shape."); + return NULL; + } + if ((npts % 4) != 0) { + Error("Number of \"Pw\" control points provided to NURBS shape must be " + "multiple of four"); + return NULL; + } + + npts /= 4; + isHomogeneous = true; + } + if (npts != nu*nv) { + Error("NURBS shape was expecting %dx%d=%d control points, was given %d", + nu, nv, nu*nv, npts); + return NULL; + } + + return new NURBS(o2w, w2o, ReverseOrientation, nu, uorder, uknots, u0, u1, + nv, vorder, vknots, v0, v1, (float *)P, + isHomogeneous); +} + + diff --git a/shapes/nurbs.h b/shapes/nurbs.h new file mode 100644 index 0000000..f2f9374 --- /dev/null +++ b/shapes/nurbs.h @@ -0,0 +1,67 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_SHAPES_NURBS_H +#define PBRT_SHAPES_NURBS_H + +// shapes/nurbs.h* +#include "pbrt.h" +#include "shape.h" +#include "geometry.h" + + +// NURBS Declarations +class NURBS : public Shape { +public: + // NURBS Methods + NURBS(const Transform *o2w, const Transform *w2o, + bool ReverseOrientation, int nu, int uorder, + const float *uknot, float umin, float umax, + int nv, int vorder, const float *vknot, float vmin, float vmax, + const float *P, bool isHomogeneous); + ~NURBS(); + BBox ObjectBound() const; + BBox WorldBound() const; + bool CanIntersect() const { return false; } + void Refine(vector > &refined) const; +private: + // NURBS Data + int nu, uorder, nv, vorder; + float umin, umax, vmin, vmax; + float *uknot, *vknot; + bool isHomogeneous; + float *P; +}; + + + + +extern NURBS *CreateNURBSShape(const Transform *o2w, const Transform *w2o, + bool ReverseOrientation, const ParamSet ¶ms); + + +#endif // PBRT_SHAPES_NURBS_H diff --git a/shapes/paraboloid.cpp b/shapes/paraboloid.cpp new file mode 100644 index 0000000..d7f4628 --- /dev/null +++ b/shapes/paraboloid.cpp @@ -0,0 +1,214 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// shapes/paraboloid.cpp* +#include "stdafx.h" +#include "shapes/paraboloid.h" +#include "paramset.h" + +// Paraboloid Method Definitions +Paraboloid::Paraboloid(const Transform *o2w, const Transform *w2o, bool ro, + float rad, float z0, float z1, + float tm) + : Shape(o2w, w2o, ro) { + radius = rad; + zmin = min(z0,z1); + zmax = max(z0,z1); + phiMax = Radians(Clamp(tm, 0.0f, 360.0f)); +} + + +BBox Paraboloid::ObjectBound() const { + Point p1 = Point( -radius, -radius, zmin ); + Point p2 = Point( radius, radius, zmax ); + return BBox( p1, p2 ); +} + + +bool Paraboloid::Intersect(const Ray &r, float *tHit, + float *rayEpsilon, DifferentialGeometry *dg) const { + float phi; + Point phit; + // Transform _Ray_ to object space + Ray ray; + (*WorldToObject)(r, &ray); + + // Compute quadratic paraboloid coefficients + float k = zmax/(radius*radius); + float A = k*(ray.d.x * ray.d.x + ray.d.y * ray.d.y); + float B = 2*k*(ray.d.x * ray.o.x + ray.d.y * ray.o.y) - + ray.d.z; + float C = k*(ray.o.x * ray.o.x + ray.o.y * ray.o.y) - + ray.o.z; + + // Solve quadratic equation for _t_ values + float t0, t1; + if (!Quadratic(A, B, C, &t0, &t1)) + return false; + + // Compute intersection distance along ray + if (t0 > ray.maxt || t1 < ray.mint) + return false; + float thit = t0; + if (t0 < ray.mint) { + thit = t1; + if (thit > ray.maxt) return false; + } + + // Compute paraboloid inverse mapping + phit = ray(thit); + phi = atan2f(phit.y, phit.x); + if (phi < 0.) phi += 2.f*M_PI; + + // Test paraboloid intersection against clipping parameters + if (phit.z < zmin || phit.z > zmax || phi > phiMax) { + if (thit == t1) return false; + thit = t1; + if (t1 > ray.maxt) return false; + // Compute paraboloid inverse mapping + phit = ray(thit); + phi = atan2f(phit.y, phit.x); + if (phi < 0.) phi += 2.f*M_PI; + if (phit.z < zmin || phit.z > zmax || phi > phiMax) + return false; + } + + // Find parametric representation of paraboloid hit + float u = phi / phiMax; + float v = (phit.z-zmin) / (zmax-zmin); + + // Compute parabaloid $\dpdu$ and $\dpdv$ + Vector dpdu(-phiMax * phit.y, phiMax * phit.x, 0.); + Vector dpdv = (zmax - zmin) * + Vector(phit.x / (2.f * phit.z), phit.y / (2.f * phit.z), 1.); + + // Compute parabaloid $\dndu$ and $\dndv$ + Vector d2Pduu = -phiMax * phiMax * + Vector(phit.x, phit.y, 0); + Vector d2Pduv = (zmax - zmin) * phiMax * + Vector(-phit.y / (2.f * phit.z), + phit.x / (2.f * phit.z), + 0); + Vector d2Pdvv = -(zmax - zmin) * (zmax - zmin) * + Vector(phit.x / (4.f * phit.z * phit.z), + phit.y / (4.f * phit.z * phit.z), + 0.); + + // Compute coefficients for fundamental forms + float E = Dot(dpdu, dpdu); + float F = Dot(dpdu, dpdv); + float G = Dot(dpdv, dpdv); + Vector N = Normalize(Cross(dpdu, dpdv)); + float e = Dot(N, d2Pduu); + float f = Dot(N, d2Pduv); + float g = Dot(N, d2Pdvv); + + // Compute $\dndu$ and $\dndv$ from fundamental form coefficients + float invEGF2 = 1.f / (E*G - F*F); + Normal dndu = Normal((f*F - e*G) * invEGF2 * dpdu + + (e*F - f*E) * invEGF2 * dpdv); + Normal dndv = Normal((g*F - f*G) * invEGF2 * dpdu + + (f*F - g*E) * invEGF2 * dpdv); + + // Initialize _DifferentialGeometry_ from parametric information + const Transform &o2w = *ObjectToWorld; + *dg = DifferentialGeometry(o2w(phit), o2w(dpdu), o2w(dpdv), + o2w(dndu), o2w(dndv), u, v, this); + + // Update _tHit_ for quadric intersection + *tHit = thit; + + // Compute _rayEpsilon_ for quadric intersection + *rayEpsilon = 5e-4f * *tHit; + return true; +} + + + +bool Paraboloid::IntersectP(const Ray &r) const { + float phi; + Point phit; + // Transform _Ray_ to object space + Ray ray; + (*WorldToObject)(r, &ray); + + // Compute quadratic paraboloid coefficients + float k = zmax/(radius*radius); + float A = k*(ray.d.x * ray.d.x + ray.d.y * ray.d.y); + float B = 2*k*(ray.d.x * ray.o.x + ray.d.y * ray.o.y) - + ray.d.z; + float C = k*(ray.o.x * ray.o.x + ray.o.y * ray.o.y) - + ray.o.z; + + // Solve quadratic equation for _t_ values + float t0, t1; + if (!Quadratic(A, B, C, &t0, &t1)) + return false; + + // Compute intersection distance along ray + if (t0 > ray.maxt || t1 < ray.mint) + return false; + float thit = t0; + if (t0 < ray.mint) { + thit = t1; + if (thit > ray.maxt) return false; + } + + // Compute paraboloid inverse mapping + phit = ray(thit); + phi = atan2f(phit.y, phit.x); + if (phi < 0.) phi += 2.f*M_PI; + + // Test paraboloid intersection against clipping parameters + if (phit.z < zmin || phit.z > zmax || phi > phiMax) { + if (thit == t1) return false; + thit = t1; + if (t1 > ray.maxt) return false; + // Compute paraboloid inverse mapping + phit = ray(thit); + phi = atan2f(phit.y, phit.x); + if (phi < 0.) phi += 2.f*M_PI; + if (phit.z < zmin || phit.z > zmax || phi > phiMax) + return false; + } + return true; +} + + +float Paraboloid::Area() const { + return phiMax/12.0f * + (powf(1+4*zmin, 1.5f) - powf(1+4*zmax, 1.5f)); +} + + +Paraboloid *CreateParaboloidShape(const Transform *o2w, const Transform *w2o, + bool reverseOrientation, const ParamSet ¶ms) { + float radius = params.FindOneFloat("radius", 1); + float zmin = params.FindOneFloat("zmin", 0); + float zmax = params.FindOneFloat("zmax", 1); + float phimax = params.FindOneFloat("phimax", 360); + return new Paraboloid(o2w, w2o, reverseOrientation, radius, zmin, zmax, phimax); +} + + diff --git a/shapes/paraboloid.h b/shapes/paraboloid.h new file mode 100644 index 0000000..d913643 --- /dev/null +++ b/shapes/paraboloid.h @@ -0,0 +1,56 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_SHAPES_PARABOLOID_H +#define PBRT_SHAPES_PARABOLOID_H + +// shapes/paraboloid.h* +#include "shape.h" + +// Paraboloid Declarations +class Paraboloid : public Shape { +public: + // Paraboloid Public Methods + Paraboloid(const Transform *o2w, const Transform *w2o, bool ro, float rad, + float z0, float z1, float tm ); + BBox ObjectBound() const; + bool Intersect(const Ray &ray, float *tHit, float *rayEpsilon, + DifferentialGeometry *dg) const; + bool IntersectP(const Ray &ray) const; + float Area() const; +protected: + // Paraboloid Private Data + float radius; + float zmin, zmax; + float phiMax; +}; + + +Paraboloid *CreateParaboloidShape(const Transform *o2w, const Transform *w2o, + bool reverseOrientation, const ParamSet ¶ms); + +#endif // PBRT_SHAPES_PARABOLOID_H diff --git a/shapes/sphere.cpp b/shapes/sphere.cpp new file mode 100644 index 0000000..b70cde6 --- /dev/null +++ b/shapes/sphere.cpp @@ -0,0 +1,268 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// shapes/sphere.cpp* +#include "stdafx.h" +#include "shapes/sphere.h" +#include "montecarlo.h" +#include "paramset.h" + +// Sphere Method Definitions +Sphere::Sphere(const Transform *o2w, const Transform *w2o, bool ro, + float rad, float z0, float z1, float pm) + : Shape(o2w, w2o, ro) { + radius = rad; + zmin = Clamp(min(z0, z1), -radius, radius); + zmax = Clamp(max(z0, z1), -radius, radius); + thetaMin = acosf(Clamp(zmin/radius, -1.f, 1.f)); + thetaMax = acosf(Clamp(zmax/radius, -1.f, 1.f)); + phiMax = Radians(Clamp(pm, 0.0f, 360.0f)); +} + + +BBox Sphere::ObjectBound() const { + return BBox(Point(-radius, -radius, zmin), + Point( radius, radius, zmax)); +} + + +bool Sphere::Intersect(const Ray &r, float *tHit, float *rayEpsilon, + DifferentialGeometry *dg) const { + float phi; + Point phit; + // Transform _Ray_ to object space + Ray ray; + (*WorldToObject)(r, &ray); + + // Compute quadratic sphere coefficients + float A = ray.d.x*ray.d.x + ray.d.y*ray.d.y + ray.d.z*ray.d.z; + float B = 2 * (ray.d.x*ray.o.x + ray.d.y*ray.o.y + ray.d.z*ray.o.z); + float C = ray.o.x*ray.o.x + ray.o.y*ray.o.y + + ray.o.z*ray.o.z - radius*radius; + + // Solve quadratic equation for _t_ values + float t0, t1; + if (!Quadratic(A, B, C, &t0, &t1)) + return false; + + // Compute intersection distance along ray + if (t0 > ray.maxt || t1 < ray.mint) + return false; + float thit = t0; + if (t0 < ray.mint) { + thit = t1; + if (thit > ray.maxt) return false; + } + + // Compute sphere hit position and $\phi$ + phit = ray(thit); + if (phit.x == 0.f && phit.y == 0.f) phit.x = 1e-5f * radius; + phi = atan2f(phit.y, phit.x); + if (phi < 0.) phi += 2.f*M_PI; + + // Test sphere intersection against clipping parameters + if ((zmin > -radius && phit.z < zmin) || + (zmax < radius && phit.z > zmax) || phi > phiMax) { + if (thit == t1) return false; + if (t1 > ray.maxt) return false; + thit = t1; + // Compute sphere hit position and $\phi$ + phit = ray(thit); + if (phit.x == 0.f && phit.y == 0.f) phit.x = 1e-5f * radius; + phi = atan2f(phit.y, phit.x); + if (phi < 0.) phi += 2.f*M_PI; + if ((zmin > -radius && phit.z < zmin) || + (zmax < radius && phit.z > zmax) || phi > phiMax) + return false; + } + + // Find parametric representation of sphere hit + float u = phi / phiMax; + float theta = acosf(Clamp(phit.z / radius, -1.f, 1.f)); + float v = (theta - thetaMin) / (thetaMax - thetaMin); + + // Compute sphere $\dpdu$ and $\dpdv$ + float zradius = sqrtf(phit.x*phit.x + phit.y*phit.y); + float invzradius = 1.f / zradius; + float cosphi = phit.x * invzradius; + float sinphi = phit.y * invzradius; + Vector dpdu(-phiMax * phit.y, phiMax * phit.x, 0); + Vector dpdv = (thetaMax-thetaMin) * + Vector(phit.z * cosphi, phit.z * sinphi, + -radius * sinf(theta)); + + // Compute sphere $\dndu$ and $\dndv$ + Vector d2Pduu = -phiMax * phiMax * Vector(phit.x, phit.y, 0); + Vector d2Pduv = (thetaMax - thetaMin) * phit.z * phiMax * + Vector(-sinphi, cosphi, 0.); + Vector d2Pdvv = -(thetaMax - thetaMin) * (thetaMax - thetaMin) * + Vector(phit.x, phit.y, phit.z); + + // Compute coefficients for fundamental forms + float E = Dot(dpdu, dpdu); + float F = Dot(dpdu, dpdv); + float G = Dot(dpdv, dpdv); + Vector N = Normalize(Cross(dpdu, dpdv)); + float e = Dot(N, d2Pduu); + float f = Dot(N, d2Pduv); + float g = Dot(N, d2Pdvv); + + // Compute $\dndu$ and $\dndv$ from fundamental form coefficients + float invEGF2 = 1.f / (E*G - F*F); + Normal dndu = Normal((f*F - e*G) * invEGF2 * dpdu + + (e*F - f*E) * invEGF2 * dpdv); + Normal dndv = Normal((g*F - f*G) * invEGF2 * dpdu + + (f*F - g*E) * invEGF2 * dpdv); + + // Initialize _DifferentialGeometry_ from parametric information + const Transform &o2w = *ObjectToWorld; + *dg = DifferentialGeometry(o2w(phit), o2w(dpdu), o2w(dpdv), + o2w(dndu), o2w(dndv), u, v, this); + + // Update _tHit_ for quadric intersection + *tHit = thit; + + // Compute _rayEpsilon_ for quadric intersection + *rayEpsilon = 5e-4f * *tHit; + return true; +} + + +bool Sphere::IntersectP(const Ray &r) const { + float phi; + Point phit; + // Transform _Ray_ to object space + Ray ray; + (*WorldToObject)(r, &ray); + + // Compute quadratic sphere coefficients + float A = ray.d.x*ray.d.x + ray.d.y*ray.d.y + ray.d.z*ray.d.z; + float B = 2 * (ray.d.x*ray.o.x + ray.d.y*ray.o.y + ray.d.z*ray.o.z); + float C = ray.o.x*ray.o.x + ray.o.y*ray.o.y + + ray.o.z*ray.o.z - radius*radius; + + // Solve quadratic equation for _t_ values + float t0, t1; + if (!Quadratic(A, B, C, &t0, &t1)) + return false; + + // Compute intersection distance along ray + if (t0 > ray.maxt || t1 < ray.mint) + return false; + float thit = t0; + if (t0 < ray.mint) { + thit = t1; + if (thit > ray.maxt) return false; + } + + // Compute sphere hit position and $\phi$ + phit = ray(thit); + if (phit.x == 0.f && phit.y == 0.f) phit.x = 1e-5f * radius; + phi = atan2f(phit.y, phit.x); + if (phi < 0.) phi += 2.f*M_PI; + + // Test sphere intersection against clipping parameters + if ((zmin > -radius && phit.z < zmin) || + (zmax < radius && phit.z > zmax) || phi > phiMax) { + if (thit == t1) return false; + if (t1 > ray.maxt) return false; + thit = t1; + // Compute sphere hit position and $\phi$ + phit = ray(thit); + if (phit.x == 0.f && phit.y == 0.f) phit.x = 1e-5f * radius; + phi = atan2f(phit.y, phit.x); + if (phi < 0.) phi += 2.f*M_PI; + if ((zmin > -radius && phit.z < zmin) || + (zmax < radius && phit.z > zmax) || phi > phiMax) + return false; + } + return true; +} + + +float Sphere::Area() const { + return phiMax * radius * (zmax-zmin); +} + + +Sphere *CreateSphereShape(const Transform *o2w, const Transform *w2o, + bool reverseOrientation, const ParamSet ¶ms) { + float radius = params.FindOneFloat("radius", 1.f); + float zmin = params.FindOneFloat("zmin", -radius); + float zmax = params.FindOneFloat("zmax", radius); + float phimax = params.FindOneFloat("phimax", 360.f); + return new Sphere(o2w, w2o, reverseOrientation, radius, + zmin, zmax, phimax); +} + + +Point Sphere::Sample(float u1, float u2, Normal *ns) const { + Point p = Point(0,0,0) + radius * UniformSampleSphere(u1, u2); + *ns = Normalize((*ObjectToWorld)(Normal(p.x, p.y, p.z))); + if (ReverseOrientation) *ns *= -1.f; + return (*ObjectToWorld)(p); +} + + +Point Sphere::Sample(const Point &p, float u1, float u2, + Normal *ns) const { + // Compute coordinate system for sphere sampling + Point Pcenter = (*ObjectToWorld)(Point(0,0,0)); + Vector wc = Normalize(Pcenter - p); + Vector wcX, wcY; + CoordinateSystem(wc, &wcX, &wcY); + + // Sample uniformly on sphere if $\pt{}$ is inside it + if (DistanceSquared(p, Pcenter) - radius*radius < 1e-4f) + return Sample(u1, u2, ns); + + // Sample sphere uniformly inside subtended cone + float sinThetaMax2 = radius*radius / DistanceSquared(p, Pcenter); + float cosThetaMax = sqrtf(max(0.f, 1.f - sinThetaMax2)); + DifferentialGeometry dgSphere; + float thit, rayEpsilon; + Point ps; + Ray r(p, UniformSampleCone(u1, u2, cosThetaMax, wcX, wcY, wc), 1e-3f); + if (!Intersect(r, &thit, &rayEpsilon, &dgSphere)) + thit = Dot(Pcenter - p, Normalize(r.d)); + ps = r(thit); + *ns = Normal(Normalize(ps - Pcenter)); + if (ReverseOrientation) *ns *= -1.f; + return ps; +} + + +float Sphere::Pdf(const Point &p, const Vector &wi) const { + Point Pcenter = (*ObjectToWorld)(Point(0,0,0)); + // Return uniform weight if point inside sphere + if (DistanceSquared(p, Pcenter) - radius*radius < 1e-4f) + return Shape::Pdf(p, wi); + + // Compute general sphere weight + float sinThetaMax2 = radius*radius / DistanceSquared(p, Pcenter); + float cosThetaMax = sqrtf(max(0.f, 1.f - sinThetaMax2)); + return UniformConePdf(cosThetaMax); +} + + diff --git a/shapes/sphere.h b/shapes/sphere.h new file mode 100644 index 0000000..81858ca --- /dev/null +++ b/shapes/sphere.h @@ -0,0 +1,60 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_SHAPES_SPHERE_H +#define PBRT_SHAPES_SPHERE_H + +// shapes/sphere.h* +#include "shape.h" + +// Sphere Declarations +class Sphere : public Shape { +public: + // Sphere Public Methods + Sphere(const Transform *o2w, const Transform *w2o, bool ro, float rad, + float zmin, float zmax, float phiMax); + BBox ObjectBound() const; + bool Intersect(const Ray &ray, float *tHit, float *rayEpsilon, + DifferentialGeometry *dg) const; + bool IntersectP(const Ray &ray) const; + float Area() const; + Point Sample(float u1, float u2, Normal *ns) const; + Point Sample(const Point &p, float u1, float u2, Normal *ns) const; + float Pdf(const Point &p, const Vector &wi) const; +private: + // Sphere Private Data + float radius; + float phiMax; + float zmin, zmax; + float thetaMin, thetaMax; +}; + + +Sphere *CreateSphereShape(const Transform *o2w, const Transform *w2o, + bool reverseOrientation, const ParamSet ¶ms); + +#endif // PBRT_SHAPES_SPHERE_H diff --git a/shapes/trianglemesh.cpp b/shapes/trianglemesh.cpp new file mode 100644 index 0000000..23b00b4 --- /dev/null +++ b/shapes/trianglemesh.cpp @@ -0,0 +1,455 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// shapes/trianglemesh.cpp* +#include "stdafx.h" +#include "shapes/trianglemesh.h" +#include "texture.h" +#include "textures/constant.h" +#include "paramset.h" +#include "montecarlo.h" +#include +using std::cout; +using std::endl; + +// TriangleMesh Method Definitions +TriangleMesh::TriangleMesh(const Transform *o2w, const Transform *w2o, + bool ro, int nt, int nv, const int *vi, const Point *P, + const Normal *N, const Vector *S, const float *uv, + const Reference > &atex) + : Shape(o2w, w2o, ro), alphaTexture(atex) { + ntris = nt; + nverts = nv; + vertexIndex = new int[3 * ntris]; + memcpy(vertexIndex, vi, 3 * ntris * sizeof(int)); + // Copy _uv_, _N_, and _S_ vertex data, if present + if (uv) { + uvs = new float[2*nverts]; + memcpy(uvs, uv, 2*nverts*sizeof(float)); + } + else uvs = NULL; + p = new Point[nverts]; + if (N) { + n = new Normal[nverts]; + memcpy(n, N, nverts*sizeof(Normal)); + } + else n = NULL; + if (S) { + s = new Vector[nverts]; + memcpy(s, S, nverts*sizeof(Vector)); + } + else s = NULL; + + // Transform mesh vertices to world space + for (int i = 0; i < nverts; ++i) + p[i] = (*ObjectToWorld)(P[i]); +} + + +TriangleMesh::~TriangleMesh() { + delete[] vertexIndex; + delete[] p; + delete[] s; + delete[] n; + delete[] uvs; +} + + +BBox TriangleMesh::ObjectBound() const { + BBox objectBounds; + for (int i = 0; i < nverts; i++) + objectBounds = Union(objectBounds, (*WorldToObject)(p[i])); + return objectBounds; +} + + +BBox TriangleMesh::WorldBound() const { + BBox worldBounds; + for (int i = 0; i < nverts; i++) + worldBounds = Union(worldBounds, p[i]); + return worldBounds; +} + + +void TriangleMesh::Refine(vector > &refined) const { + for (int i = 0; i < ntris; ++i) + refined.push_back(new Triangle(ObjectToWorld, + WorldToObject, ReverseOrientation, + (TriangleMesh *)this, i)); +} + + +BBox Triangle::ObjectBound() const { + // Get triangle vertices in _p1_, _p2_, and _p3_ + const Point &p1 = mesh->p[v[0]]; + const Point &p2 = mesh->p[v[1]]; + const Point &p3 = mesh->p[v[2]]; + return Union(BBox((*WorldToObject)(p1), (*WorldToObject)(p2)), + (*WorldToObject)(p3)); +} + + +BBox Triangle::WorldBound() const { + // Get triangle vertices in _p1_, _p2_, and _p3_ + const Point &p1 = mesh->p[v[0]]; + const Point &p2 = mesh->p[v[1]]; + const Point &p3 = mesh->p[v[2]]; + return Union(BBox(p1, p2), p3); +} + + +bool Triangle::Intersect(const Ray &ray, float *tHit, float *rayEpsilon, + DifferentialGeometry *dg) const { + + PBRT_RAY_TRIANGLE_INTERSECTION_TEST(const_cast(&ray), const_cast(this)); + // Compute $\VEC{s}_1$ + + // Get triangle vertices in _p1_, _p2_, and _p3_ + const Point &p1 = mesh->p[v[0]]; + const Point &p2 = mesh->p[v[1]]; + const Point &p3 = mesh->p[v[2]]; + Vector e1 = p2 - p1; + Vector e2 = p3 - p1; + Vector s1 = Cross(ray.d, e2); + float divisor = Dot(s1, e1); + + if (divisor == 0.) + return false; + float invDivisor = 1.f / divisor; + + // Compute first barycentric coordinate + Vector d = ray.o - p1; + float b1 = Dot(d, s1) * invDivisor; + if (b1 < 0. || b1 > 1.) + return false; + + // Compute second barycentric coordinate + Vector s2 = Cross(d, e1); + float b2 = Dot(ray.d, s2) * invDivisor; + if (b2 < 0. || b1 + b2 > 1.) + return false; + + // Compute _t_ to intersection point + float t = Dot(e2, s2) * invDivisor; + if (t < ray.mint || t > ray.maxt) + return false; + + // Compute triangle partial derivatives + Vector dpdu, dpdv; + float uvs[3][2]; + GetUVs(uvs); + + // Compute deltas for triangle partial derivatives + float du1 = uvs[0][0] - uvs[2][0]; + float du2 = uvs[1][0] - uvs[2][0]; + float dv1 = uvs[0][1] - uvs[2][1]; + float dv2 = uvs[1][1] - uvs[2][1]; + Vector dp1 = p1 - p3, dp2 = p2 - p3; + float determinant = du1 * dv2 - dv1 * du2; + if (determinant == 0.f) { + // Handle zero determinant for triangle partial derivative matrix + CoordinateSystem(Normalize(Cross(e2, e1)), &dpdu, &dpdv); + } + else { + float invdet = 1.f / determinant; + dpdu = ( dv2 * dp1 - dv1 * dp2) * invdet; + dpdv = (-du2 * dp1 + du1 * dp2) * invdet; + } + + // Interpolate $(u,v)$ triangle parametric coordinates + float b0 = 1 - b1 - b2; + float tu = b0*uvs[0][0] + b1*uvs[1][0] + b2*uvs[2][0]; + float tv = b0*uvs[0][1] + b1*uvs[1][1] + b2*uvs[2][1]; + + // Test intersection against alpha texture, if present + if (ray.depth != -1) { + if (mesh->alphaTexture) { + DifferentialGeometry dgLocal(ray(t), dpdu, dpdv, + Normal(0,0,0), Normal(0,0,0), + tu, tv, this); + if (mesh->alphaTexture->Evaluate(dgLocal) == 0.f) + return false; + } + } + + // Fill in _DifferentialGeometry_ from triangle hit + *dg = DifferentialGeometry(ray(t), dpdu, dpdv, + Normal(0,0,0), Normal(0,0,0), + tu, tv, this); + *tHit = t; + *rayEpsilon = 1e-3f * *tHit; + PBRT_RAY_TRIANGLE_INTERSECTION_HIT(const_cast(&ray), t); + + return true; +} + + +bool Triangle::IntersectP(const Ray &ray) const { + PBRT_RAY_TRIANGLE_INTERSECTIONP_TEST(const_cast(&ray), const_cast(this)); + // Compute $\VEC{s}_1$ + + // Get triangle vertices in _p1_, _p2_, and _p3_ + const Point &p1 = mesh->p[v[0]]; + const Point &p2 = mesh->p[v[1]]; + const Point &p3 = mesh->p[v[2]]; + Vector e1 = p2 - p1; + Vector e2 = p3 - p1; + Vector s1 = Cross(ray.d, e2); + float divisor = Dot(s1, e1); + + if (divisor == 0.) + return false; + float invDivisor = 1.f / divisor; + + // Compute first barycentric coordinate + Vector d = ray.o - p1; + float b1 = Dot(d, s1) * invDivisor; + if (b1 < 0. || b1 > 1.) + return false; + + // Compute second barycentric coordinate + Vector s2 = Cross(d, e1); + float b2 = Dot(ray.d, s2) * invDivisor; + if (b2 < 0. || b1 + b2 > 1.) + return false; + + // Compute _t_ to intersection point + float t = Dot(e2, s2) * invDivisor; + if (t < ray.mint || t > ray.maxt) + return false; + + // Test shadow ray intersection against alpha texture, if present + if (ray.depth != -1 && mesh->alphaTexture) { + // Compute triangle partial derivatives + Vector dpdu, dpdv; + float uvs[3][2]; + GetUVs(uvs); + + // Compute deltas for triangle partial derivatives + float du1 = uvs[0][0] - uvs[2][0]; + float du2 = uvs[1][0] - uvs[2][0]; + float dv1 = uvs[0][1] - uvs[2][1]; + float dv2 = uvs[1][1] - uvs[2][1]; + Vector dp1 = p1 - p3, dp2 = p2 - p3; + float determinant = du1 * dv2 - dv1 * du2; + if (determinant == 0.f) { + // Handle zero determinant for triangle partial derivative matrix + CoordinateSystem(Normalize(Cross(e2, e1)), &dpdu, &dpdv); + } + else { + float invdet = 1.f / determinant; + dpdu = ( dv2 * dp1 - dv1 * dp2) * invdet; + dpdv = (-du2 * dp1 + du1 * dp2) * invdet; + } + + // Interpolate $(u,v)$ triangle parametric coordinates + float b0 = 1 - b1 - b2; + float tu = b0*uvs[0][0] + b1*uvs[1][0] + b2*uvs[2][0]; + float tv = b0*uvs[0][1] + b1*uvs[1][1] + b2*uvs[2][1]; + DifferentialGeometry dgLocal(ray(t), dpdu, dpdv, + Normal(0,0,0), Normal(0,0,0), + tu, tv, this); + if (mesh->alphaTexture->Evaluate(dgLocal) == 0.f) + return false; + } + PBRT_RAY_TRIANGLE_INTERSECTIONP_HIT(const_cast(&ray), t); + return true; +} + + +float Triangle::Area() const { + // Get triangle vertices in _p1_, _p2_, and _p3_ + const Point &p1 = mesh->p[v[0]]; + const Point &p2 = mesh->p[v[1]]; + const Point &p3 = mesh->p[v[2]]; + return 0.5f * Cross(p2-p1, p3-p1).Length(); +} + + +void Triangle::GetShadingGeometry(const Transform &obj2world, + const DifferentialGeometry &dg, + DifferentialGeometry *dgShading) const { + if (!mesh->n && !mesh->s) { + *dgShading = dg; + return; + } + // Initialize _Triangle_ shading geometry with _n_ and _s_ + + // Compute barycentric coordinates for point + float b[3]; + + // Initialize _A_ and _C_ matrices for barycentrics + float uv[3][2]; + GetUVs(uv); + float A[2][2] = + { { uv[1][0] - uv[0][0], uv[2][0] - uv[0][0] }, + { uv[1][1] - uv[0][1], uv[2][1] - uv[0][1] } }; + float C[2] = { dg.u - uv[0][0], dg.v - uv[0][1] }; + if (!SolveLinearSystem2x2(A, C, &b[1], &b[2])) { + // Handle degenerate parametric mapping + b[0] = b[1] = b[2] = 1.f/3.f; + } + else + b[0] = 1.f - b[1] - b[2]; + + // Use _n_ and _s_ to compute shading tangents for triangle, _ss_ and _ts_ + Normal ns; + Vector ss, ts; + if (mesh->n) ns = Normalize(obj2world(b[0] * mesh->n[v[0]] + + b[1] * mesh->n[v[1]] + + b[2] * mesh->n[v[2]])); + else ns = dg.nn; + if (mesh->s) ss = Normalize(obj2world(b[0] * mesh->s[v[0]] + + b[1] * mesh->s[v[1]] + + b[2] * mesh->s[v[2]])); + else ss = Normalize(dg.dpdu); + + ts = Cross(ss, ns); + if (ts.LengthSquared() > 0.f) { + ts = Normalize(ts); + ss = Cross(ts, ns); + } + else + CoordinateSystem((Vector)ns, &ss, &ts); + Normal dndu, dndv; + + // Compute $\dndu$ and $\dndv$ for triangle shading geometry + if (mesh->n) { + float uvs[3][2]; + GetUVs(uvs); + // Compute deltas for triangle partial derivatives of normal + float du1 = uvs[0][0] - uvs[2][0]; + float du2 = uvs[1][0] - uvs[2][0]; + float dv1 = uvs[0][1] - uvs[2][1]; + float dv2 = uvs[1][1] - uvs[2][1]; + Normal dn1 = mesh->n[v[0]] - mesh->n[v[2]]; + Normal dn2 = mesh->n[v[1]] - mesh->n[v[2]]; + float determinant = du1 * dv2 - dv1 * du2; + if (determinant == 0.f) + dndu = dndv = Normal(0,0,0); + else { + float invdet = 1.f / determinant; + dndu = ( dv2 * dn1 - dv1 * dn2) * invdet; + dndv = (-du2 * dn1 + du1 * dn2) * invdet; + } + } + else + dndu = dndv = Normal(0,0,0); + *dgShading = DifferentialGeometry(dg.p, ss, ts, + (*ObjectToWorld)(dndu), (*ObjectToWorld)(dndv), + dg.u, dg.v, dg.shape); + dgShading->dudx = dg.dudx; dgShading->dvdx = dg.dvdx; + dgShading->dudy = dg.dudy; dgShading->dvdy = dg.dvdy; + dgShading->dpdx = dg.dpdx; dgShading->dpdy = dg.dpdy; +} + + +TriangleMesh *CreateTriangleMeshShape(const Transform *o2w, const Transform *w2o, + bool reverseOrientation, const ParamSet ¶ms, + map > > *floatTextures) { + int nvi, npi, nuvi, nsi, nni; + const int *vi = params.FindInt("indices", &nvi); + const Point *P = params.FindPoint("P", &npi); + const float *uvs = params.FindFloat("uv", &nuvi); + if (!uvs) uvs = params.FindFloat("st", &nuvi); + bool discardDegnerateUVs = params.FindOneBool("discarddegenerateUVs", false); + // XXX should complain if uvs aren't an array of 2... + if (uvs) { + if (nuvi < 2 * npi) { + Error("Not enough of \"uv\"s for triangle mesh. Expencted %d, " + "found %d. Discarding.", 2*npi, nuvi); + uvs = NULL; + } + else if (nuvi > 2 * npi) + Warning("More \"uv\"s provided than will be used for triangle " + "mesh. (%d expcted, %d found)", 2*npi, nuvi); + } + if (!vi || !P) return NULL; + const Vector *S = params.FindVector("S", &nsi); + if (S && nsi != npi) { + Error("Number of \"S\"s for triangle mesh must match \"P\"s"); + S = NULL; + } + const Normal *N = params.FindNormal("N", &nni); + if (N && nni != npi) { + Error("Number of \"N\"s for triangle mesh must match \"P\"s"); + N = NULL; + } + if (discardDegnerateUVs && uvs && N) { + // if there are normals, check for bad uv's that + // give degenerate mappings; discard them if so + const int *vp = vi; + for (int i = 0; i < nvi; i += 3, vp += 3) { + float area = .5f * Cross(P[vp[0]]-P[vp[1]], P[vp[2]]-P[vp[1]]).Length(); + if (area < 1e-7) continue; // ignore degenerate tris. + if ((uvs[2*vp[0]] == uvs[2*vp[1]] && + uvs[2*vp[0]+1] == uvs[2*vp[1]+1]) || + (uvs[2*vp[1]] == uvs[2*vp[2]] && + uvs[2*vp[1]+1] == uvs[2*vp[2]+1]) || + (uvs[2*vp[2]] == uvs[2*vp[0]] && + uvs[2*vp[2]+1] == uvs[2*vp[0]+1])) { + Warning("Degenerate uv coordinates in triangle mesh. Discarding all uvs."); + uvs = NULL; + break; + } + } + } + for (int i = 0; i < nvi; ++i) + if (vi[i] >= npi) { + Error("trianglemesh has out of-bounds vertex index %d (%d \"P\" values were given", + vi[i], npi); + return NULL; + } + + Reference > alphaTex = NULL; + string alphaTexName = params.FindTexture("alpha"); + if (alphaTexName != "") { + if (floatTextures->find(alphaTexName) != floatTextures->end()) + alphaTex = (*floatTextures)[alphaTexName]; + else + Error("Couldn't find float texture \"%s\" for \"alpha\" parameter", + alphaTexName.c_str()); + } + else if (params.FindOneFloat("alpha", 1.f) == 0.f) + alphaTex = new ConstantTexture(0.f); + return new TriangleMesh(o2w, w2o, reverseOrientation, nvi/3, npi, vi, P, + N, S, uvs, alphaTex); +} + + +Point Triangle::Sample(float u1, float u2, Normal *Ns) const { + float b1, b2; + UniformSampleTriangle(u1, u2, &b1, &b2); + // Get triangle vertices in _p1_, _p2_, and _p3_ + const Point &p1 = mesh->p[v[0]]; + const Point &p2 = mesh->p[v[1]]; + const Point &p3 = mesh->p[v[2]]; + Point p = b1 * p1 + b2 * p2 + (1.f - b1 - b2) * p3; + Normal n = Normal(Cross(p2-p1, p3-p1)); + *Ns = Normalize(n); + if (ReverseOrientation) *Ns *= -1.f; + return p; +} + + diff --git a/shapes/trianglemesh.h b/shapes/trianglemesh.h new file mode 100644 index 0000000..44f02e7 --- /dev/null +++ b/shapes/trianglemesh.h @@ -0,0 +1,109 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_SHAPES_TRIANGLEMESH_H +#define PBRT_SHAPES_TRIANGLEMESH_H + +// shapes/trianglemesh.h* +#include "shape.h" +#include +using std::map; + +// TriangleMesh Declarations +class TriangleMesh : public Shape { +public: + // TriangleMesh Public Methods + TriangleMesh(const Transform *o2w, const Transform *w2o, bool ro, + int ntris, int nverts, const int *vptr, + const Point *P, const Normal *N, const Vector *S, + const float *uv, const Reference > &atex); + ~TriangleMesh(); + BBox ObjectBound() const; + BBox WorldBound() const; + bool CanIntersect() const { return false; } + void Refine(vector > &refined) const; + friend class Triangle; + template friend class VertexTexture; +protected: + // TriangleMesh Protected Data + int ntris, nverts; + int *vertexIndex; + Point *p; + Normal *n; + Vector *s; + float *uvs; + Reference > alphaTexture; +}; + + +class Triangle : public Shape { +public: + // Triangle Public Methods + Triangle(const Transform *o2w, const Transform *w2o, bool ro, + TriangleMesh *m, int n) + : Shape(o2w, w2o, ro) { + mesh = m; + v = &mesh->vertexIndex[3*n]; + PBRT_CREATED_TRIANGLE(this); + } + BBox ObjectBound() const; + BBox WorldBound() const; + bool Intersect(const Ray &ray, float *tHit, float *rayEpsilon, + DifferentialGeometry *dg) const; + bool IntersectP(const Ray &ray) const; + void GetUVs(float uv[3][2]) const { + if (mesh->uvs) { + uv[0][0] = mesh->uvs[2*v[0]]; + uv[0][1] = mesh->uvs[2*v[0]+1]; + uv[1][0] = mesh->uvs[2*v[1]]; + uv[1][1] = mesh->uvs[2*v[1]+1]; + uv[2][0] = mesh->uvs[2*v[2]]; + uv[2][1] = mesh->uvs[2*v[2]+1]; + } + else { + uv[0][0] = 0.; uv[0][1] = 0.; + uv[1][0] = 1.; uv[1][1] = 0.; + uv[2][0] = 1.; uv[2][1] = 1.; + } + } + float Area() const; + virtual void GetShadingGeometry(const Transform &obj2world, + const DifferentialGeometry &dg, + DifferentialGeometry *dgShading) const; + Point Sample(float u1, float u2, Normal *Ns) const; +private: + // Triangle Private Data + Reference mesh; + int *v; +}; + + +TriangleMesh *CreateTriangleMeshShape(const Transform *o2w, const Transform *w2o, + bool reverseOrientation, const ParamSet ¶ms, + map > > *floatTextures = NULL); + +#endif // PBRT_SHAPES_TRIANGLEMESH_H diff --git a/telephoto.250mm.dat b/telephoto.250mm.dat new file mode 100644 index 0000000..dd6ae2e --- /dev/null +++ b/telephoto.250mm.dat @@ -0,0 +1,10 @@ +# SIGLER Super achromate telephoto, EFL=254mm, F/5.6" +# MLD, Page 175" +# Scaled to 250 mm from 100 mm +54.6275 12.52 1.529 47.5 +-86.365 3.755 1.599 44.5 +271.7625 2.8175 1 41.5 +0 67.4125 0 40.5 +-32.13 3.755 1.613 31.5 +49.5325 12.52 1.603 33.5 +-50.945 0 1 37 diff --git a/test.dat b/test.dat new file mode 100644 index 0000000..5e43b62 --- /dev/null +++ b/test.dat @@ -0,0 +1,6 @@ +# D-GAUSS F/2 22deg HFOV +# US patent 2,673,491 Tronnier" +# Moden Lens Design, p.312" +# Scaled to 50 mm from 100 mm +# radius axpos N aperture +-10 1 1.6 10 \ No newline at end of file diff --git a/test.exr b/test.exr new file mode 100644 index 0000000..7614143 Binary files /dev/null and b/test.exr differ diff --git a/textures/bilerp.cpp b/textures/bilerp.cpp new file mode 100644 index 0000000..70a5f44 --- /dev/null +++ b/textures/bilerp.cpp @@ -0,0 +1,86 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// textures/bilerp.cpp* +#include "stdafx.h" +#include "textures/bilerp.h" + +// BilerpTexture Method Definitions +BilerpTexture *CreateBilerpFloatTexture(const Transform &tex2world, + const TextureParams &tp) { + // Initialize 2D texture mapping _map_ from _tp_ + TextureMapping2D *map = NULL; + string type = tp.FindString("mapping", "uv"); + if (type == "uv") { + float su = tp.FindFloat("uscale", 1.); + float sv = tp.FindFloat("vscale", 1.); + float du = tp.FindFloat("udelta", 0.); + float dv = tp.FindFloat("vdelta", 0.); + map = new UVMapping2D(su, sv, du, dv); + } + else if (type == "spherical") map = new SphericalMapping2D(Inverse(tex2world)); + else if (type == "cylindrical") map = new CylindricalMapping2D(Inverse(tex2world)); + else if (type == "planar") + map = new PlanarMapping2D(tp.FindVector("v1", Vector(1,0,0)), + tp.FindVector("v2", Vector(0,1,0)), + tp.FindFloat("udelta", 0.f), tp.FindFloat("vdelta", 0.f)); + else { + Error("2D texture mapping \"%s\" unknown", type.c_str()); + map = new UVMapping2D; + } + return new BilerpTexture(map, + tp.FindFloat("v00", 0.f), tp.FindFloat("v01", 1.f), + tp.FindFloat("v10", 0.f), tp.FindFloat("v11", 1.f)); +} + + + +BilerpTexture *CreateBilerpSpectrumTexture(const Transform &tex2world, + const TextureParams &tp) { + // Initialize 2D texture mapping _map_ from _tp_ + TextureMapping2D *map = NULL; + string type = tp.FindString("mapping", "uv"); + if (type == "uv") { + float su = tp.FindFloat("uscale", 1.); + float sv = tp.FindFloat("vscale", 1.); + float du = tp.FindFloat("udelta", 0.); + float dv = tp.FindFloat("vdelta", 0.); + map = new UVMapping2D(su, sv, du, dv); + } + else if (type == "spherical") map = new SphericalMapping2D(Inverse(tex2world)); + else if (type == "cylindrical") map = new CylindricalMapping2D(Inverse(tex2world)); + else if (type == "planar") + map = new PlanarMapping2D(tp.FindVector("v1", Vector(1,0,0)), + tp.FindVector("v2", Vector(0,1,0)), + tp.FindFloat("udelta", 0.f), tp.FindFloat("vdelta", 0.f)); + else { + Error("2D texture mapping \"%s\" unknown", type.c_str()); + map = new UVMapping2D; + } + return new BilerpTexture(map, + tp.FindSpectrum("v00", 0.f), tp.FindSpectrum("v01", 1.f), + tp.FindSpectrum("v10", 0.f), tp.FindSpectrum("v11", 1.f)); +} + + diff --git a/textures/bilerp.h b/textures/bilerp.h new file mode 100644 index 0000000..600a731 --- /dev/null +++ b/textures/bilerp.h @@ -0,0 +1,65 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_TEXTURES_BILERP_H +#define PBRT_TEXTURES_BILERP_H + +// textures/bilerp.h* +#include "pbrt.h" +#include "texture.h" +#include "paramset.h" + +// BilerpTexture Declarations +template class BilerpTexture : public Texture { +public: + // BilerpTexture Public Methods + BilerpTexture(TextureMapping2D *m, const T &t00, const T &t01, + const T &t10, const T &t11) + : mapping(m), v00(t00), v01(t01), v10(t10), v11(t11) { + } + ~BilerpTexture() { + delete mapping; + } + T Evaluate(const DifferentialGeometry &dg) const { + float s, t, dsdx, dtdx, dsdy, dtdy; + mapping->Map(dg, &s, &t, &dsdx, &dtdx, &dsdy, &dtdy); + return (1-s)*(1-t) * v00 + (1-s)*( t) * v01 + + ( s)*(1-t) * v10 + ( s)*( t) * v11; + } +private: + // BilerpTexture Private Data + TextureMapping2D *mapping; + T v00, v01, v10, v11; +}; + + +BilerpTexture *CreateBilerpFloatTexture(const Transform &tex2world, + const TextureParams &tp); +BilerpTexture *CreateBilerpSpectrumTexture(const Transform &tex2world, + const TextureParams &tp); + +#endif // PBRT_TEXTURES_BILERP_H diff --git a/textures/checkerboard.cpp b/textures/checkerboard.cpp new file mode 100644 index 0000000..b12c68b --- /dev/null +++ b/textures/checkerboard.cpp @@ -0,0 +1,112 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// textures/checkerboard.cpp* +#include "stdafx.h" +#include "textures/checkerboard.h" + +// CheckerboardTexture Method Definitions +Texture *CreateCheckerboardFloatTexture(const Transform &tex2world, + const TextureParams &tp) { + int dim = tp.FindInt("dimension", 2); + if (dim != 2 && dim != 3) { + Error("%d dimensional checkerboard texture not supported", dim); + return NULL; + } + Reference > tex1 = tp.GetFloatTexture("tex1", 1.f); + Reference > tex2 = tp.GetFloatTexture("tex2", 0.f); + if (dim == 2) { + // Initialize 2D texture mapping _map_ from _tp_ + TextureMapping2D *map = NULL; + string type = tp.FindString("mapping", "uv"); + if (type == "uv") { + float su = tp.FindFloat("uscale", 1.); + float sv = tp.FindFloat("vscale", 1.); + float du = tp.FindFloat("udelta", 0.); + float dv = tp.FindFloat("vdelta", 0.); + map = new UVMapping2D(su, sv, du, dv); + } + else if (type == "spherical") map = new SphericalMapping2D(Inverse(tex2world)); + else if (type == "cylindrical") map = new CylindricalMapping2D(Inverse(tex2world)); + else if (type == "planar") + map = new PlanarMapping2D(tp.FindVector("v1", Vector(1,0,0)), + tp.FindVector("v2", Vector(0,1,0)), + tp.FindFloat("udelta", 0.f), tp.FindFloat("vdelta", 0.f)); + else { + Error("2D texture mapping \"%s\" unknown", type.c_str()); + map = new UVMapping2D; + } + string aamode = tp.FindString("aamode", "closedform"); + return new Checkerboard2DTexture(map, tex1, tex2, aamode); + } + else { + // Initialize 3D texture mapping _map_ from _tp_ + TextureMapping3D *map = new IdentityMapping3D(tex2world); + return new Checkerboard3DTexture(map, tex1, tex2); + } +} + + + +Texture *CreateCheckerboardSpectrumTexture(const Transform &tex2world, + const TextureParams &tp) { + int dim = tp.FindInt("dimension", 2); + if (dim != 2 && dim != 3) { + Error("%d dimensional checkerboard texture not supported", dim); + return NULL; + } + Reference > tex1 = tp.GetSpectrumTexture("tex1", 1.f); + Reference > tex2 = tp.GetSpectrumTexture("tex2", 0.f); + if (dim == 2) { + // Initialize 2D texture mapping _map_ from _tp_ + TextureMapping2D *map = NULL; + string type = tp.FindString("mapping", "uv"); + if (type == "uv") { + float su = tp.FindFloat("uscale", 1.); + float sv = tp.FindFloat("vscale", 1.); + float du = tp.FindFloat("udelta", 0.); + float dv = tp.FindFloat("vdelta", 0.); + map = new UVMapping2D(su, sv, du, dv); + } + else if (type == "spherical") map = new SphericalMapping2D(Inverse(tex2world)); + else if (type == "cylindrical") map = new CylindricalMapping2D(Inverse(tex2world)); + else if (type == "planar") + map = new PlanarMapping2D(tp.FindVector("v1", Vector(1,0,0)), + tp.FindVector("v2", Vector(0,1,0)), + tp.FindFloat("udelta", 0.f), tp.FindFloat("vdelta", 0.f)); + else { + Error("2D texture mapping \"%s\" unknown", type.c_str()); + map = new UVMapping2D; + } + string aamode = tp.FindString("aamode", "closedform"); + return new Checkerboard2DTexture(map, tex1, tex2, aamode); + } + else { + // Initialize 3D texture mapping _map_ from _tp_ + TextureMapping3D *map = new IdentityMapping3D(tex2world); + return new Checkerboard3DTexture(map, tex1, tex2); + } +} + + diff --git a/textures/checkerboard.h b/textures/checkerboard.h new file mode 100644 index 0000000..a385fa8 --- /dev/null +++ b/textures/checkerboard.h @@ -0,0 +1,134 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_TEXTURES_CHECKERBOARD_H +#define PBRT_TEXTURES_CHECKERBOARD_H + +// textures/checkerboard.h* +#include "pbrt.h" +#include "texture.h" +#include "paramset.h" +#include "montecarlo.h" +#include "shape.h" +#include "parallel.h" +#include "progressreporter.h" + +// CheckerboardTexture Declarations +template class Checkerboard2DTexture : public Texture { +public: + // Checkerboard2DTexture Public Methods + Checkerboard2DTexture(TextureMapping2D *m, Reference > c1, + Reference > c2, const string &aa) + : mapping(m), tex1(c1), tex2(c2) { + // Select antialiasing method for _Checkerboard2DTexture_ + if (aa == "none") aaMethod = NONE; + else if (aa == "closedform") aaMethod = CLOSEDFORM; + else { + Warning("Antialiasing mode \"%s\" not understood by " + "Checkerboard2DTexture; using \"closedform\"", aa.c_str()); + aaMethod = CLOSEDFORM; + } + } + ~Checkerboard2DTexture() { + delete mapping; + } + T Evaluate(const DifferentialGeometry &dg) const { + float s, t, dsdx, dtdx, dsdy, dtdy; + mapping->Map(dg, &s, &t, &dsdx, &dtdx, &dsdy, &dtdy); + if (aaMethod == NONE) { + // Point sample _Checkerboard2DTexture_ + if ((Floor2Int(s) + Floor2Int(t)) % 2 == 0) + return tex1->Evaluate(dg); + return tex2->Evaluate(dg); + } + else { + // Compute closed-form box-filtered _Checkerboard2DTexture_ value + + // Evaluate single check if filter is entirely inside one of them + float ds = max(fabsf(dsdx), fabsf(dsdy)); + float dt = max(fabsf(dtdx), fabsf(dtdy)); + float s0 = s - ds, s1 = s + ds; + float t0 = t - dt, t1 = t + dt; + if (Floor2Int(s0) == Floor2Int(s1) && Floor2Int(t0) == Floor2Int(t1)) { + // Point sample _Checkerboard2DTexture_ + if ((Floor2Int(s) + Floor2Int(t)) % 2 == 0) + return tex1->Evaluate(dg); + return tex2->Evaluate(dg); + } + + // Apply box filter to checkerboard region +#define BUMPINT(x) \ + (Floor2Int((x)/2) + \ + 2.f * max((x/2)-Floor2Int(x/2) - .5f, 0.f)) + float sint = (BUMPINT(s1) - BUMPINT(s0)) / (2.f * ds); + float tint = (BUMPINT(t1) - BUMPINT(t0)) / (2.f * dt); + float area2 = sint + tint - 2.f * sint * tint; + if (ds > 1.f || dt > 1.f) + area2 = .5f; + return (1.f - area2) * tex1->Evaluate(dg) + + area2 * tex2->Evaluate(dg); + } + } +private: + // Checkerboard2DTexture Private Data + TextureMapping2D *mapping; + Reference > tex1, tex2; + enum { NONE, CLOSEDFORM } aaMethod; +}; + + +template class Checkerboard3DTexture : public Texture { +public: + // Checkerboard3DTexture Public Methods + Checkerboard3DTexture(TextureMapping3D *m, Reference > c1, + Reference > c2) + : mapping(m), tex1(c1), tex2(c2) { + } + ~Checkerboard3DTexture() { + delete mapping; + } + T Evaluate(const DifferentialGeometry &dg) const { + Vector dpdx, dpdy; + Point p = mapping->Map(dg, &dpdx, &dpdy); + if ((Floor2Int(p.x) + Floor2Int(p.y) + Floor2Int(p.z)) % 2 == 0) + return tex1->Evaluate(dg); + else + return tex2->Evaluate(dg); + } +private: + // Checkerboard3DTexture Private Data + TextureMapping3D *mapping; + Reference > tex1, tex2; +}; + + +Texture *CreateCheckerboardFloatTexture(const Transform &tex2world, + const TextureParams &tp); +Texture *CreateCheckerboardSpectrumTexture(const Transform &tex2world, + const TextureParams &tp); + +#endif // PBRT_TEXTURES_CHECKERBOARD_H diff --git a/textures/constant.cpp b/textures/constant.cpp new file mode 100644 index 0000000..45dff43 --- /dev/null +++ b/textures/constant.cpp @@ -0,0 +1,42 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// textures/constant.cpp* +#include "stdafx.h" +#include "textures/constant.h" + +// ConstantTexture Method Definitions +ConstantTexture *CreateConstantFloatTexture(const Transform &tex2world, + const TextureParams &tp) { + return new ConstantTexture(tp.FindFloat("value", 1.f)); +} + + + +ConstantTexture *CreateConstantSpectrumTexture(const Transform &tex2world, + const TextureParams &tp) { + return new ConstantTexture(tp.FindSpectrum("value", Spectrum(1.f))); +} + + diff --git a/textures/constant.h b/textures/constant.h new file mode 100644 index 0000000..d1424b6 --- /dev/null +++ b/textures/constant.h @@ -0,0 +1,54 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_TEXTURES_CONSTANT_H +#define PBRT_TEXTURES_CONSTANT_H + +// textures/constant.h* +#include "pbrt.h" +#include "texture.h" +#include "paramset.h" + +// ConstantTexture Declarations +template class ConstantTexture : public Texture { +public: + // ConstantTexture Public Methods + ConstantTexture(const T &v) { value = v; } + T Evaluate(const DifferentialGeometry &) const { + return value; + } +private: + T value; +}; + + +ConstantTexture *CreateConstantFloatTexture(const Transform &tex2world, + const TextureParams &tp); +ConstantTexture *CreateConstantSpectrumTexture(const Transform &tex2world, + const TextureParams &tp); + +#endif // PBRT_TEXTURES_CONSTANT_H diff --git a/textures/dots.cpp b/textures/dots.cpp new file mode 100644 index 0000000..df7c90e --- /dev/null +++ b/textures/dots.cpp @@ -0,0 +1,86 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// textures/dots.cpp* +#include "stdafx.h" +#include "textures/dots.h" + +// DotsTexture Method Definitions +DotsTexture *CreateDotsFloatTexture(const Transform &tex2world, + const TextureParams &tp) { + // Initialize 2D texture mapping _map_ from _tp_ + TextureMapping2D *map = NULL; + string type = tp.FindString("mapping", "uv"); + if (type == "uv") { + float su = tp.FindFloat("uscale", 1.); + float sv = tp.FindFloat("vscale", 1.); + float du = tp.FindFloat("udelta", 0.); + float dv = tp.FindFloat("vdelta", 0.); + map = new UVMapping2D(su, sv, du, dv); + } + else if (type == "spherical") map = new SphericalMapping2D(Inverse(tex2world)); + else if (type == "cylindrical") map = new CylindricalMapping2D(Inverse(tex2world)); + else if (type == "planar") + map = new PlanarMapping2D(tp.FindVector("v1", Vector(1,0,0)), + tp.FindVector("v2", Vector(0,1,0)), + tp.FindFloat("udelta", 0.f), tp.FindFloat("vdelta", 0.f)); + else { + Error("2D texture mapping \"%s\" unknown", type.c_str()); + map = new UVMapping2D; + } + return new DotsTexture(map, + tp.GetFloatTexture("inside", 1.f), + tp.GetFloatTexture("outside", 0.f)); +} + + + +DotsTexture *CreateDotsSpectrumTexture(const Transform &tex2world, + const TextureParams &tp) { + // Initialize 2D texture mapping _map_ from _tp_ + TextureMapping2D *map = NULL; + string type = tp.FindString("mapping", "uv"); + if (type == "uv") { + float su = tp.FindFloat("uscale", 1.); + float sv = tp.FindFloat("vscale", 1.); + float du = tp.FindFloat("udelta", 0.); + float dv = tp.FindFloat("vdelta", 0.); + map = new UVMapping2D(su, sv, du, dv); + } + else if (type == "spherical") map = new SphericalMapping2D(Inverse(tex2world)); + else if (type == "cylindrical") map = new CylindricalMapping2D(Inverse(tex2world)); + else if (type == "planar") + map = new PlanarMapping2D(tp.FindVector("v1", Vector(1,0,0)), + tp.FindVector("v2", Vector(0,1,0)), + tp.FindFloat("udelta", 0.f), tp.FindFloat("vdelta", 0.f)); + else { + Error("2D texture mapping \"%s\" unknown", type.c_str()); + map = new UVMapping2D; + } + return new DotsTexture(map, + tp.GetSpectrumTexture("inside", 1.f), + tp.GetSpectrumTexture("outside", 0.f)); +} + + diff --git a/textures/dots.h b/textures/dots.h new file mode 100644 index 0000000..4b57988 --- /dev/null +++ b/textures/dots.h @@ -0,0 +1,79 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_TEXTURES_DOTS_H +#define PBRT_TEXTURES_DOTS_H + +// textures/dots.h* +#include "pbrt.h" +#include "texture.h" +#include "paramset.h" + +// DotsTexture Declarations +template class DotsTexture : public Texture { +public: + // DotsTexture Public Methods + ~DotsTexture() { + delete mapping; + } + DotsTexture(TextureMapping2D *m, Reference > t1, + Reference > t2) + : mapping(m), outsideDot(t1), insideDot(t2) { + } + T Evaluate(const DifferentialGeometry &dg) const { + // Compute cell indices for dots + float s, t, dsdx, dtdx, dsdy, dtdy; + mapping->Map(dg, &s, &t, &dsdx, &dtdx, &dsdy, &dtdy); + int sCell = Floor2Int(s + .5f), tCell = Floor2Int(t + .5f); + + // Return _insideDot_ result if point is inside dot + if (Noise(sCell+.5f, tCell+.5f) > 0) { + float radius = .35f; + float maxShift = 0.5f - radius; + float sCenter = sCell + maxShift * + Noise(sCell + 1.5f, tCell + 2.8f); + float tCenter = tCell + maxShift * + Noise(sCell + 4.5f, tCell + 9.8f); + float ds = s - sCenter, dt = t - tCenter; + if (ds*ds + dt*dt < radius*radius) + return insideDot->Evaluate(dg); + } + return outsideDot->Evaluate(dg); + } +private: + // DotsTexture Private Data + TextureMapping2D *mapping; + Reference > outsideDot, insideDot; +}; + + +DotsTexture *CreateDotsFloatTexture(const Transform &tex2world, + const TextureParams &tp); +DotsTexture *CreateDotsSpectrumTexture(const Transform &tex2world, + const TextureParams &tp); + +#endif // PBRT_TEXTURES_DOTS_H diff --git a/textures/fbm.cpp b/textures/fbm.cpp new file mode 100644 index 0000000..3a4b8db --- /dev/null +++ b/textures/fbm.cpp @@ -0,0 +1,48 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// textures/fbm.cpp* +#include "stdafx.h" +#include "textures/fbm.h" + +// FBmTexture Method Definitions +FBmTexture *CreateFBmFloatTexture(const Transform &tex2world, + const TextureParams &tp) { + // Initialize 3D texture mapping _map_ from _tp_ + TextureMapping3D *map = new IdentityMapping3D(tex2world); + return new FBmTexture(tp.FindInt("octaves", 8), + tp.FindFloat("roughness", .5f), map); +} + + + +FBmTexture *CreateFBmSpectrumTexture(const Transform &tex2world, + const TextureParams &tp) { + // Initialize 3D texture mapping _map_ from _tp_ + TextureMapping3D *map = new IdentityMapping3D(tex2world); + return new FBmTexture(tp.FindInt("octaves", 8), + tp.FindFloat("roughness", .5f), map); +} + + diff --git a/textures/fbm.h b/textures/fbm.h new file mode 100644 index 0000000..5c3d3a6 --- /dev/null +++ b/textures/fbm.h @@ -0,0 +1,63 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_TEXTURES_FBM_H +#define PBRT_TEXTURES_FBM_H + +// textures/fbm.h* +#include "pbrt.h" +#include "texture.h" +#include "paramset.h" + +// FBmTexture Declarations +template class FBmTexture : public Texture { +public: + // FBmTexture Public Methods + ~FBmTexture() { + delete mapping; + } + FBmTexture(int oct, float roughness, TextureMapping3D *map) + : omega(roughness), octaves(oct), mapping(map) { } + T Evaluate(const DifferentialGeometry &dg) const { + Vector dpdx, dpdy; + Point P = mapping->Map(dg, &dpdx, &dpdy); + return FBm(P, dpdx, dpdy, omega, octaves); + } +private: + // FBmTexture Private Data + float omega; + int octaves; + TextureMapping3D *mapping; +}; + + +FBmTexture *CreateFBmFloatTexture(const Transform &tex2world, + const TextureParams &tp); +FBmTexture *CreateFBmSpectrumTexture(const Transform &tex2world, + const TextureParams &tp); + +#endif // PBRT_TEXTURES_FBM_H diff --git a/textures/imagemap.cpp b/textures/imagemap.cpp new file mode 100644 index 0000000..1d182e2 --- /dev/null +++ b/textures/imagemap.cpp @@ -0,0 +1,170 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// textures/imagemap.cpp* +#include "stdafx.h" +#include "textures/imagemap.h" +#include "imageio.h" + +// ImageTexture Method Definitions +template +ImageTexture::ImageTexture(TextureMapping2D *m, + const string &filename, bool doTrilinear, float maxAniso, + ImageWrap wrapMode, float scale, float gamma) { + mapping = m; + mipmap = GetTexture(filename, doTrilinear, maxAniso, + wrapMode, scale, gamma); +} + + +template + ImageTexture::~ImageTexture() { + delete mapping; +} + + +template MIPMap * +ImageTexture::GetTexture(const string &filename, + bool doTrilinear, float maxAniso, ImageWrap wrap, + float scale, float gamma) { + // Look for texture in texture cache + TexInfo texInfo(filename, doTrilinear, maxAniso, wrap, scale, gamma); + if (textures.find(texInfo) != textures.end()) + return textures[texInfo]; + int width, height; + RGBSpectrum *texels = ReadImage(filename, &width, &height); + MIPMap *ret = NULL; + if (texels) { + // Convert texels to type _Tmemory_ and create _MIPMap_ + Tmemory *convertedTexels = new Tmemory[width*height]; + for (int i = 0; i < width*height; ++i) + convertIn(texels[i], &convertedTexels[i], scale, gamma); + ret = new MIPMap(width, height, convertedTexels, doTrilinear, + maxAniso, wrap); + delete[] texels; + delete[] convertedTexels; + } + else { + // Create one-valued _MIPMap_ + Tmemory *oneVal = new Tmemory[1]; + oneVal[0] = powf(scale, gamma); + ret = new MIPMap(1, 1, oneVal); + delete[] oneVal; + } + textures[texInfo] = ret; + PBRT_LOADED_IMAGE_MAP(const_cast(filename.c_str()), width, height, sizeof(Tmemory), ret); + return ret; +} + + +template + std::map *> ImageTexture::textures; +template Treturn +ImageTexture::Evaluate(const DifferentialGeometry &dg) const { + float s, t, dsdx, dtdx, dsdy, dtdy; + mapping->Map(dg, &s, &t, &dsdx, &dtdx, &dsdy, &dtdy); + Tmemory mem = mipmap->Lookup(s, t, dsdx, dtdx, dsdy, dtdy); + Treturn ret; + convertOut(mem, &ret); + return ret; +} + + +ImageTexture *CreateImageFloatTexture(const Transform &tex2world, + const TextureParams &tp) { + // Initialize 2D texture mapping _map_ from _tp_ + TextureMapping2D *map = NULL; + string type = tp.FindString("mapping", "uv"); + if (type == "uv") { + float su = tp.FindFloat("uscale", 1.); + float sv = tp.FindFloat("vscale", 1.); + float du = tp.FindFloat("udelta", 0.); + float dv = tp.FindFloat("vdelta", 0.); + map = new UVMapping2D(su, sv, du, dv); + } + else if (type == "spherical") map = new SphericalMapping2D(Inverse(tex2world)); + else if (type == "cylindrical") map = new CylindricalMapping2D(Inverse(tex2world)); + else if (type == "planar") + map = new PlanarMapping2D(tp.FindVector("v1", Vector(1,0,0)), + tp.FindVector("v2", Vector(0,1,0)), + tp.FindFloat("udelta", 0.f), tp.FindFloat("vdelta", 0.f)); + else { + Error("2D texture mapping \"%s\" unknown", type.c_str()); + map = new UVMapping2D; + } + + // Initialize _ImageTexture_ parameters + float maxAniso = tp.FindFloat("maxanisotropy", 8.f); + bool trilerp = tp.FindBool("trilinear", false); + string wrap = tp.FindString("wrap", "repeat"); + ImageWrap wrapMode = TEXTURE_REPEAT; + if (wrap == "black") wrapMode = TEXTURE_BLACK; + else if (wrap == "clamp") wrapMode = TEXTURE_CLAMP; + float scale = tp.FindFloat("scale", 1.f); + float gamma = tp.FindFloat("gamma", 1.f); + return new ImageTexture(map, tp.FindFilename("filename"), + trilerp, maxAniso, wrapMode, scale, gamma); +} + + + +ImageTexture *CreateImageSpectrumTexture(const Transform &tex2world, + const TextureParams &tp) { + // Initialize 2D texture mapping _map_ from _tp_ + TextureMapping2D *map = NULL; + string type = tp.FindString("mapping", "uv"); + if (type == "uv") { + float su = tp.FindFloat("uscale", 1.); + float sv = tp.FindFloat("vscale", 1.); + float du = tp.FindFloat("udelta", 0.); + float dv = tp.FindFloat("vdelta", 0.); + map = new UVMapping2D(su, sv, du, dv); + } + else if (type == "spherical") map = new SphericalMapping2D(Inverse(tex2world)); + else if (type == "cylindrical") map = new CylindricalMapping2D(Inverse(tex2world)); + else if (type == "planar") + map = new PlanarMapping2D(tp.FindVector("v1", Vector(1,0,0)), + tp.FindVector("v2", Vector(0,1,0)), + tp.FindFloat("udelta", 0.f), tp.FindFloat("vdelta", 0.f)); + else { + Error("2D texture mapping \"%s\" unknown", type.c_str()); + map = new UVMapping2D; + } + + // Initialize _ImageTexture_ parameters + float maxAniso = tp.FindFloat("maxanisotropy", 8.f); + bool trilerp = tp.FindBool("trilinear", false); + string wrap = tp.FindString("wrap", "repeat"); + ImageWrap wrapMode = TEXTURE_REPEAT; + if (wrap == "black") wrapMode = TEXTURE_BLACK; + else if (wrap == "clamp") wrapMode = TEXTURE_CLAMP; + float scale = tp.FindFloat("scale", 1.f); + float gamma = tp.FindFloat("gamma", 1.f); + return new ImageTexture(map, tp.FindFilename("filename"), + trilerp, maxAniso, wrapMode, scale, gamma); +} + + diff --git a/textures/imagemap.h b/textures/imagemap.h new file mode 100644 index 0000000..267ba34 --- /dev/null +++ b/textures/imagemap.h @@ -0,0 +1,110 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_TEXTURES_IMAGEMAP_H +#define PBRT_TEXTURES_IMAGEMAP_H + +// textures/imagemap.h* +#include "pbrt.h" +#include "texture.h" +#include "mipmap.h" +#include "paramset.h" +#include + +// TexInfo Declarations +struct TexInfo { + TexInfo(const string &f, bool dt, float ma, ImageWrap wm, float sc, float ga) + : filename(f), doTrilinear(dt), maxAniso(ma), wrapMode(wm), scale(sc), gamma(ga) { } + string filename; + bool doTrilinear; + float maxAniso; + ImageWrap wrapMode; + float scale, gamma; + bool operator<(const TexInfo &t2) const { + if (filename != t2.filename) return filename < t2.filename; + if (doTrilinear != t2.doTrilinear) return doTrilinear < t2.doTrilinear; + if (maxAniso != t2.maxAniso) return maxAniso < t2.maxAniso; + if (scale != t2.scale) return scale < t2.scale; + if (gamma != t2.gamma) return gamma < t2.gamma; + return wrapMode < t2.wrapMode; + } +}; + + + +// ImageTexture Declarations +template + class ImageTexture : public Texture { +public: + // ImageTexture Public Methods + ImageTexture(TextureMapping2D *m, const string &filename, bool doTri, + float maxAniso, ImageWrap wm, float scale, float gamma); + Treturn Evaluate(const DifferentialGeometry &) const; + ~ImageTexture(); + static void ClearCache() { + typename std::map *>::iterator iter; + iter = textures.begin(); + while (iter != textures.end()) { + delete iter->second; + ++iter; + } + textures.erase(textures.begin(), textures.end()); + } +private: + // ImageTexture Private Methods + static MIPMap *GetTexture(const string &filename, + bool doTrilinear, float maxAniso, ImageWrap wm, float scale, float gamma); + static void convertIn(const RGBSpectrum &from, RGBSpectrum *to, + float scale, float gamma) { + *to = Pow(scale * from, gamma); + } + static void convertIn(const RGBSpectrum &from, float *to, + float scale, float gamma) { + *to = powf(scale * from.y(), gamma); + } + static void convertOut(const RGBSpectrum &from, Spectrum *to) { + float rgb[3]; + from.ToRGB(rgb); + *to = Spectrum::FromRGB(rgb); + } + static void convertOut(float from, float *to) { + *to = from; + } + + // ImageTexture Private Data + MIPMap *mipmap; + TextureMapping2D *mapping; + static std::map *> textures; +}; + + +ImageTexture *CreateImageFloatTexture(const Transform &tex2world, + const TextureParams &tp); +ImageTexture *CreateImageSpectrumTexture(const Transform &tex2world, + const TextureParams &tp); + +#endif // PBRT_TEXTURES_IMAGEMAP_H diff --git a/textures/marble.cpp b/textures/marble.cpp new file mode 100644 index 0000000..02d0052 --- /dev/null +++ b/textures/marble.cpp @@ -0,0 +1,48 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// textures/marble.cpp* +#include "stdafx.h" +#include "textures/marble.h" + +// MarbleTexture Method Definitions +Texture *CreateMarbleFloatTexture(const Transform &tex2world, + const TextureParams &tp) { + return NULL; +} + + + +MarbleTexture *CreateMarbleSpectrumTexture(const Transform &tex2world, + const TextureParams &tp) { + // Initialize 3D texture mapping _map_ from _tp_ + TextureMapping3D *map = new IdentityMapping3D(tex2world); + return new MarbleTexture(tp.FindInt("octaves", 8), + tp.FindFloat("roughness", .5f), + tp.FindFloat("scale", 1.f), + tp.FindFloat("variation", .2f), + map); +} + + diff --git a/textures/marble.h b/textures/marble.h new file mode 100644 index 0000000..7c6e5b6 --- /dev/null +++ b/textures/marble.h @@ -0,0 +1,88 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_TEXTURES_MARBLE_H +#define PBRT_TEXTURES_MARBLE_H + +// textures/marble.h* +#include "pbrt.h" +#include "texture.h" +#include "paramset.h" + +// MarbleTexture Declarations +class MarbleTexture : public Texture { +public: + // MarbleTexture Public Methods + ~MarbleTexture() { + delete mapping; + } + MarbleTexture(int oct, float roughness, float sc, float var, + TextureMapping3D *map) + : octaves(oct), omega(roughness), scale(sc), variation(var), + mapping(map) { } + Spectrum Evaluate(const DifferentialGeometry &dg) const { + Vector dpdx, dpdy; + Point P = mapping->Map(dg, &dpdx, &dpdy); + P *= scale; + float marble = P.y + variation * + FBm(P, scale * dpdx, scale * dpdy, omega, octaves); + float t = .5f + .5f * sinf(marble); + // Evaluate marble spline at _t_ + static float c[][3] = { { .58f, .58f, .6f }, { .58f, .58f, .6f }, { .58f, .58f, .6f }, + { .5f, .5f, .5f }, { .6f, .59f, .58f }, { .58f, .58f, .6f }, + { .58f, .58f, .6f }, {.2f, .2f, .33f }, { .58f, .58f, .6f }, }; +#define NC sizeof(c) / sizeof(c[0]) +#define NSEG (NC-3) + int first = Floor2Int(t * NSEG); + t = (t * NSEG - first); + Spectrum c0 = Spectrum::FromRGB(c[first]); + Spectrum c1 = Spectrum::FromRGB(c[first+1]); + Spectrum c2 = Spectrum::FromRGB(c[first+2]); + Spectrum c3 = Spectrum::FromRGB(c[first+3]); + // Bezier spline evaluated with de Castilejau's algorithm + Spectrum s0 = (1.f - t) * c0 + t * c1; + Spectrum s1 = (1.f - t) * c1 + t * c2; + Spectrum s2 = (1.f - t) * c2 + t * c3; + s0 = (1.f - t) * s0 + t * s1; + s1 = (1.f - t) * s1 + t * s2; + // Extra scale of 1.5 to increase variation among colors + return 1.5f * ((1.f - t) * s0 + t * s1); + } +private: + // MarbleTexture Private Data + int octaves; + float omega, scale, variation; + TextureMapping3D *mapping; +}; + + +Texture *CreateMarbleFloatTexture(const Transform &tex2world, + const TextureParams &tp); +MarbleTexture *CreateMarbleSpectrumTexture(const Transform &tex2world, + const TextureParams &tp); + +#endif // PBRT_TEXTURES_MARBLE_H diff --git a/textures/mix.cpp b/textures/mix.cpp new file mode 100644 index 0000000..fcc718e --- /dev/null +++ b/textures/mix.cpp @@ -0,0 +1,48 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// textures/mix.cpp* +#include "stdafx.h" +#include "textures/mix.h" + +// MixTexture Method Definitions +MixTexture *CreateMixFloatTexture(const Transform &tex2world, + const TextureParams &tp) { + return new MixTexture( + tp.GetFloatTexture("tex1", 0.f), + tp.GetFloatTexture("tex2", 1.f), + tp.GetFloatTexture("amount", 0.5f)); +} + + + +MixTexture *CreateMixSpectrumTexture(const Transform &tex2world, + const TextureParams &tp) { + return new MixTexture( + tp.GetSpectrumTexture("tex1", 0.f), + tp.GetSpectrumTexture("tex2", 1.f), + tp.GetFloatTexture("amount", 0.5f)); +} + + diff --git a/textures/mix.h b/textures/mix.h new file mode 100644 index 0000000..bb8c58a --- /dev/null +++ b/textures/mix.h @@ -0,0 +1,59 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_TEXTURES_MIX_H +#define PBRT_TEXTURES_MIX_H + +// textures/mix.h* +#include "pbrt.h" +#include "texture.h" +#include "paramset.h" + +// MixTexture Declarations +template class MixTexture : public Texture { +public: + // MixTexture Public Methods + MixTexture(Reference > t1, Reference > t2, + Reference > amt) + : tex1(t1), tex2(t2), amount(amt) { } + T Evaluate(const DifferentialGeometry &dg) const { + T t1 = tex1->Evaluate(dg), t2 = tex2->Evaluate(dg); + float amt = amount->Evaluate(dg); + return (1.f - amt) * t1 + amt * t2; + } +private: + Reference > tex1, tex2; + Reference > amount; +}; + + +MixTexture *CreateMixFloatTexture(const Transform &tex2world, + const TextureParams &tp); +MixTexture *CreateMixSpectrumTexture(const Transform &tex2world, + const TextureParams &tp); + +#endif // PBRT_TEXTURES_MIX_H diff --git a/textures/scale.cpp b/textures/scale.cpp new file mode 100644 index 0000000..2338a30 --- /dev/null +++ b/textures/scale.cpp @@ -0,0 +1,45 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// textures/scale.cpp* +#include "stdafx.h" +#include "textures/scale.h" + +// ScaleTexture Method Definitions +ScaleTexture *CreateScaleFloatTexture(const Transform &tex2world, + const TextureParams &tp) { + return new ScaleTexture(tp.GetFloatTexture("tex1", 1.f), + tp.GetFloatTexture("tex2", 1.f)); +} + + + +ScaleTexture *CreateScaleSpectrumTexture(const Transform &tex2world, + const TextureParams &tp) { + return new ScaleTexture( + tp.GetSpectrumTexture("tex1", Spectrum(1.f)), + tp.GetSpectrumTexture("tex2", Spectrum(1.f))); +} + + diff --git a/textures/scale.h b/textures/scale.h new file mode 100644 index 0000000..4ea77f3 --- /dev/null +++ b/textures/scale.h @@ -0,0 +1,57 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_TEXTURES_SCALE_H +#define PBRT_TEXTURES_SCALE_H + +// textures/scale.h* +#include "pbrt.h" +#include "texture.h" +#include "paramset.h" + +// ScaleTexture Declarations +template +class ScaleTexture : public Texture { +public: + // ScaleTexture Public Methods + ScaleTexture(Reference > t1, Reference > t2) + : tex1(t1), tex2(t2) { } + T2 Evaluate(const DifferentialGeometry &dg) const { + return tex1->Evaluate(dg) * tex2->Evaluate(dg); + } +private: + Reference > tex1; + Reference > tex2; +}; + + +ScaleTexture *CreateScaleFloatTexture(const Transform &tex2world, + const TextureParams &tp); +ScaleTexture *CreateScaleSpectrumTexture(const Transform &tex2world, + const TextureParams &tp); + +#endif // PBRT_TEXTURES_SCALE_H diff --git a/textures/uv.cpp b/textures/uv.cpp new file mode 100644 index 0000000..43d7d6e --- /dev/null +++ b/textures/uv.cpp @@ -0,0 +1,62 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// textures/uv.cpp* +#include "stdafx.h" +#include "textures/uv.h" + +// UVTexture Method Definitions +Texture *CreateUVFloatTexture(const Transform &tex2world, + const TextureParams &tp) { + return NULL; +} + + + +UVTexture *CreateUVSpectrumTexture(const Transform &tex2world, + const TextureParams &tp) { + // Initialize 2D texture mapping _map_ from _tp_ + TextureMapping2D *map = NULL; + string type = tp.FindString("mapping", "uv"); + if (type == "uv") { + float su = tp.FindFloat("uscale", 1.); + float sv = tp.FindFloat("vscale", 1.); + float du = tp.FindFloat("udelta", 0.); + float dv = tp.FindFloat("vdelta", 0.); + map = new UVMapping2D(su, sv, du, dv); + } + else if (type == "spherical") map = new SphericalMapping2D(Inverse(tex2world)); + else if (type == "cylindrical") map = new CylindricalMapping2D(Inverse(tex2world)); + else if (type == "planar") + map = new PlanarMapping2D(tp.FindVector("v1", Vector(1,0,0)), + tp.FindVector("v2", Vector(0,1,0)), + tp.FindFloat("udelta", 0.f), tp.FindFloat("vdelta", 0.f)); + else { + Error("2D texture mapping \"%s\" unknown", type.c_str()); + map = new UVMapping2D; + } + return new UVTexture(map); +} + + diff --git a/textures/uv.h b/textures/uv.h new file mode 100644 index 0000000..018bb05 --- /dev/null +++ b/textures/uv.h @@ -0,0 +1,62 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_TEXTURES_UV_H +#define PBRT_TEXTURES_UV_H + +// textures/uv.h* +#include "pbrt.h" +#include "texture.h" +#include "paramset.h" + +// UVTexture Declarations +class UVTexture : public Texture { +public: + // UVTexture Public Methods + UVTexture(TextureMapping2D *m) { + mapping = m; + } + ~UVTexture() { + delete mapping; + } + Spectrum Evaluate(const DifferentialGeometry &dg) const { + float s, t, dsdx, dtdx, dsdy, dtdy; + mapping->Map(dg, &s, &t, &dsdx, &dtdx, &dsdy, &dtdy); + float rgb[3] = { s - Floor2Int(s), t - Floor2Int(t), 0.f }; + return Spectrum::FromRGB(rgb); + } +private: + TextureMapping2D *mapping; +}; + + +Texture *CreateUVFloatTexture(const Transform &tex2world, + const TextureParams &tp); +UVTexture *CreateUVSpectrumTexture(const Transform &tex2world, + const TextureParams &tp); + +#endif // PBRT_TEXTURES_UV_H diff --git a/textures/windy.cpp b/textures/windy.cpp new file mode 100644 index 0000000..545d76d --- /dev/null +++ b/textures/windy.cpp @@ -0,0 +1,46 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// textures/windy.cpp* +#include "stdafx.h" +#include "textures/windy.h" + +// WindyTexture Method Definitions +WindyTexture *CreateWindyFloatTexture(const Transform &tex2world, + const TextureParams &tp) { + // Initialize 3D texture mapping _map_ from _tp_ + TextureMapping3D *map = new IdentityMapping3D(tex2world); + return new WindyTexture(map); +} + + + +WindyTexture *CreateWindySpectrumTexture(const Transform &tex2world, + const TextureParams &tp) { + // Initialize 3D texture mapping _map_ from _tp_ + TextureMapping3D *map = new IdentityMapping3D(tex2world); + return new WindyTexture(map); +} + + diff --git a/textures/windy.h b/textures/windy.h new file mode 100644 index 0000000..c6d1dc3 --- /dev/null +++ b/textures/windy.h @@ -0,0 +1,62 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_TEXTURES_WINDY_H +#define PBRT_TEXTURES_WINDY_H + +// textures/windy.h* +#include "pbrt.h" +#include "texture.h" +#include "paramset.h" + +// WindyTexture Declarations +template class WindyTexture : public Texture { +public: + // WindyTexture Public Methods + ~WindyTexture() { + delete mapping; + } + WindyTexture(TextureMapping3D *map) : mapping(map) { } + T Evaluate(const DifferentialGeometry &dg) const { + Vector dpdx, dpdy; + Point P = mapping->Map(dg, &dpdx, &dpdy); + float windStrength = FBm(.1f * P, .1f * dpdx, .1f * dpdy, .5f, 3); + float waveHeight = FBm(P, dpdx, dpdy, .5f, 6); + return fabsf(windStrength) * waveHeight; + } +private: + // WindyTexture Private Data + TextureMapping3D *mapping; +}; + + +WindyTexture *CreateWindyFloatTexture(const Transform &tex2world, + const TextureParams &tp); +WindyTexture *CreateWindySpectrumTexture(const Transform &tex2world, + const TextureParams &tp); + +#endif // PBRT_TEXTURES_WINDY_H diff --git a/textures/wrinkled.cpp b/textures/wrinkled.cpp new file mode 100644 index 0000000..0d6ac6e --- /dev/null +++ b/textures/wrinkled.cpp @@ -0,0 +1,48 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// textures/wrinkled.cpp* +#include "stdafx.h" +#include "textures/wrinkled.h" + +// WrinkledTexture Method Definitions +WrinkledTexture *CreateWrinkledFloatTexture(const Transform &tex2world, + const TextureParams &tp) { + // Initialize 3D texture mapping _map_ from _tp_ + TextureMapping3D *map = new IdentityMapping3D(tex2world); + return new WrinkledTexture(tp.FindInt("octaves", 8), + tp.FindFloat("roughness", .5f), map); +} + + + +WrinkledTexture *CreateWrinkledSpectrumTexture(const Transform &tex2world, + const TextureParams &tp) { + // Initialize 3D texture mapping _map_ from _tp_ + TextureMapping3D *map = new IdentityMapping3D(tex2world); + return new WrinkledTexture(tp.FindInt("octaves", 8), + tp.FindFloat("roughness", .5f), map); +} + + diff --git a/textures/wrinkled.h b/textures/wrinkled.h new file mode 100644 index 0000000..2bf9229 --- /dev/null +++ b/textures/wrinkled.h @@ -0,0 +1,66 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_TEXTURES_WRINKLED_H +#define PBRT_TEXTURES_WRINKLED_H + +// textures/wrinkled.h* +#include "pbrt.h" +#include "texture.h" +#include "paramset.h" + +// WrinkledTexture Declarations +template class WrinkledTexture : public Texture { +public: + // WrinkledTexture Public Methods + ~WrinkledTexture() { + delete mapping; + } + WrinkledTexture(int oct, float roughness, TextureMapping3D *map) { + omega = roughness; + octaves = oct; + mapping = map; + } + T Evaluate(const DifferentialGeometry &dg) const { + Vector dpdx, dpdy; + Point P = mapping->Map(dg, &dpdx, &dpdy); + return Turbulence(P, dpdx, dpdy, omega, octaves); + } +private: + // WrinkledTexture Private Data + int octaves; + float omega; + TextureMapping3D *mapping; +}; + + +WrinkledTexture *CreateWrinkledFloatTexture(const Transform &tex2world, + const TextureParams &tp); +WrinkledTexture *CreateWrinkledSpectrumTexture(const Transform &tex2world, + const TextureParams &tp); + +#endif // PBRT_TEXTURES_WRINKLED_H diff --git a/tools/bsdftest.cpp b/tools/bsdftest.cpp new file mode 100644 index 0000000..7f5094d --- /dev/null +++ b/tools/bsdftest.cpp @@ -0,0 +1,498 @@ +// Kevin Egan + +#include +#include + +#include "pbrt.h" +#include "reflection.h" +#include "montecarlo.h" +#include "memory.h" +#include "api.h" +#include "paramset.h" +#include "shapes/disk.h" + +static MemoryArena arena; +static RNG rng; + +// extract the red channel from a Spectrum class +double spectrumRedValue(const Spectrum & s) +{ + return ((float*) (& s))[0]; +} + +typedef void (*CreateBSDFFunc)(BSDF* bsdf); + +void createBlinn0(BSDF* bsdf); +void createBlinn05(BSDF* bsdf); +void createBlinn2(BSDF* bsdf); +void createBlinn30and0(BSDF* bsdf); +void createAniso0_0(BSDF* bsdf); +void createAniso10_10(BSDF* bsdf); +void createAniso30_30(BSDF* bsdf); +void createLambertian(BSDF* bsdf); +void createOrenNayar0(BSDF* bsdf); +void createOrenNayar20(BSDF* bsdf); +void createFresnelBlend0(BSDF* bsdf); +void createFresnelBlend30(BSDF* bsdf); +void createPlastic(BSDF* bsdf); +void createSubstrate(BSDF* bsdf); + + +typedef void (*GenSampleFunc)(BSDF* bsdf, + const Vector & wo, Vector* wi, float* pdf, Spectrum* f); + +void Gen_Sample_f(BSDF* bsdf, + const Vector & wo, Vector* wi, float* pdf, Spectrum* f); +void Gen_CosHemisphere(BSDF* bsdf, + const Vector & wo, Vector* wi, float* pdf, Spectrum* f); +void Gen_UniformHemisphere(BSDF* bsdf, + const Vector & wo, Vector* wi, float* pdf, Spectrum* f); + + +int main(int argc, char *argv[]) +{ + Options opt; + pbrtInit(opt); + + // number of monte carlo estimates + //const int estimates = 1; + const int estimates = 100000000; + + // radiance of uniform environment map + const double environmentRadiance = 1.0; + + + fprintf(stderr, "outgoing radiance from a surface viewed\n" + "straight on with uniform lighting\n\n" + " uniform incoming radiance = %.3f\n" + " monte carlo samples = %d\n\n\n", + environmentRadiance, estimates); + + + CreateBSDFFunc BSDFFuncArray[] = { + createBlinn0, + createBlinn05, + createBlinn2, + createBlinn30and0, + createAniso0_0, + createAniso10_10, + createAniso30_30, +//CO createLambertian, +//CO createOrenNayar0, +//CO createOrenNayar20, +//CO createFresnelBlend0, +//CO createFresnelBlend30, +//CO createPlastic, +//CO createSubstrate, + }; + + const char* BSDFFuncDescripArray[] = { + "Blinn (exponent 0)", + "Blinn (exponent 0.5)", + "Blinn (exponent 2)", + "Blinn (exponent 30 and 0)", + "Anisotropic (exponent 0, 0)", + "Anisotropic (exponent 10, 10)", + "Anisotropic (exponent 30, 30)", +//CO "Lambertian", +//CO "Oren Nayar (sigma 0)", +//CO "Oren Nayar (sigma 20)", +//CO "FresnelBlend (Blinn exponent 0)", +//CO "FresnelBlend (Blinn exponent 30)", +//CO "Plastic", +//CO "Substrate", + }; + + GenSampleFunc SampleFuncArray[] = { + Gen_Sample_f, + Gen_CosHemisphere, +//CO Gen_UniformHemisphere, + }; + + const char* SampleFuncDescripArray[] = { + "BSDF Importance Sampling", + "Cos Hemisphere", +//CO "Uniform Hemisphere", + }; + + int numModels = sizeof(BSDFFuncArray) / sizeof(BSDFFuncArray[0]); + int numModelsDescrip = sizeof(BSDFFuncDescripArray) / + sizeof(BSDFFuncDescripArray[0]); + int numGenerators = sizeof(SampleFuncArray) / sizeof(SampleFuncArray[0]); + int numGeneratorsDescrip = sizeof(SampleFuncDescripArray) / + sizeof(SampleFuncDescripArray[0]); + + if (numModels != numModelsDescrip) { + fprintf(stderr, "BSDFFuncArray and BSDFFuncDescripArray out of sync!\n"); + exit(1); + } + + if (numGenerators != numGeneratorsDescrip) { + fprintf(stderr, "SampleFuncArray and SampleFuncDescripArray out of sync!\n"); + exit(1); + } + + // for each bsdf model + for (int model = 0; model < numModels; model++) { + + BSDF* bsdf; + + // create BSDF which requires creating a Shape, casting a Ray + // that hits the shape to get a DifferentialGeometry object, + // and passing the DifferentialGeometry object into the BSDF + { + Transform t = RotateX(-90); + bool reverseOrientation = false; + ParamSet p; + + Reference disk = new Disk(new Transform(t), new Transform(Inverse(t)), + reverseOrientation, 0., 1., 0, 360.); + if (!disk) { + fprintf(stderr, "Could not load disk plugin\n" + " make sure the PBRT_SEARCHPATH environment variable is set\n"); + exit(1); + } + + Point origin(0.1, 1, 0); // offset slightly so we don't hit center of disk + Vector direction(0, -1, 0); + float tHit, rayEps; + Ray r(origin, direction, 1e-3, INFINITY); + DifferentialGeometry* dg = BSDF_ALLOC(arena, DifferentialGeometry)(); + disk->Intersect(r, &tHit, &rayEps, dg); + + bsdf = BSDF_ALLOC(arena, BSDF)(*dg, dg->nn); + (BSDFFuncArray[model])(bsdf); + } + + + // facing directly at normal + Vector woL = Normalize(Vector(0, 0, 1)); + Vector wo = bsdf->LocalToWorld(woL); + const Normal &n = bsdf->dgShading.nn; + + // for each method of generating samples over the hemisphere + for (int gen = 0; gen < numGenerators; gen++) { + double redSum = 0.0; + + const int numHistoBins = 10; + double histogram[numHistoBins][numHistoBins]; + for (int i = 0; i < numHistoBins; i++) { + for (int j = 0; j < numHistoBins; j++) { + histogram[i][j] = 0; + } + } + int badSamples = 0; + int outsideSamples = 0; + + int warningTarget = 1; + for (int sample = 0; sample < estimates; sample++) { + Vector wi; + float pdf; + Spectrum f; + + // sample hemisphere around bsdf, wo is fixed + (SampleFuncArray[gen])(bsdf, wo, & wi, & pdf, & f); + + double redF = spectrumRedValue(f); + + // add hemisphere sample to histogram + Vector wiL = bsdf->WorldToLocal(wi); + float x = Clamp(wiL.x, -1.f, 1.f); + float y = Clamp(wiL.y, -1.f, 1.f); + float wiPhi = (atan2(y, x) + M_PI) / (2.0 * M_PI); + float wiCosTheta = wiL.z; + bool validSample = (wiCosTheta > 1e-7); + if (wiPhi < -0.0001 || wiPhi > 1.0001 || wiCosTheta > 1.0001) { + // wiCosTheta can be less than 0 + fprintf(stderr, "bad wi! %.3f %.3f %.3f, (%.3f %.3f)\n", + wiL[0], wiL[1], wiL[2], wiPhi, wiCosTheta); + } else if (validSample) { + int histoPhi = (int) (wiPhi * numHistoBins); + int histoCosTheta = (int) (wiCosTheta * numHistoBins); + histogram[histoCosTheta][histoPhi] += 1.0 / pdf; + } + + if (!validSample) { + outsideSamples++; + } else if (pdf == 0.f || isnan(pdf) || redF < 0 || isnan(redF)) { + if (badSamples == warningTarget) { + fprintf(stderr, "warning %d, bad sample %d! " + "pdf: %.3f, redF: %.3f\n", + warningTarget, sample, pdf, redF); + warningTarget *= 10; + } + badSamples++; + } else { + // outgoing radiance estimate = + // bsdf * incomingRadiance * cos(wi) / pdf + redSum += redF * environmentRadiance * AbsDot(wi, n) / pdf; + } + } + int goodSamples = estimates - badSamples; + + // print results + fprintf(stderr, "*** BRDF: '%s', Samples: '%s'\n\n" + "wi histogram showing the relative weight in each bin\n" + " all entries should be close to 2pi = %.5f:\n" + " (%d bad samples, %d outside samples)\n\n" + " cos(theta) bins\n", + BSDFFuncDescripArray[model], SampleFuncDescripArray[gen], + M_PI * 2.0, badSamples, outsideSamples); + double totalSum = 0.0; + for (int i = 0; i < numHistoBins; i++) { + fprintf(stderr, " phi bin %02d:", i); + for (int j = 0; j < numHistoBins; j++) { + fprintf(stderr, " %5.2f", histogram[i][j] * + numHistoBins * numHistoBins / goodSamples); + totalSum += histogram[i][j]; + } + fprintf(stderr, "\n"); + } + fprintf(stderr, "\n final average : %.5f (error %.5f)\n\n" + " radiance = %.5f\n\n", + totalSum / goodSamples, totalSum / goodSamples - M_PI * 2.0, + redSum / goodSamples); + } + } + + pbrtCleanup(); + return 0; +} + + + + + + + + + +void Gen_Sample_f(BSDF* bsdf, + const Vector & wo, Vector* wi, float* pdf, Spectrum* f) +{ + // only glossy or diffuse reflections (no specular reflections) + BxDFType inflags = BxDFType(BSDF_REFLECTION | BSDF_DIFFUSE | BSDF_GLOSSY); + BxDFType outflags; + BSDFSample sample(rng); + *f = bsdf->Sample_f(wo, wi, sample, pdf, inflags, &outflags); + + // double check bsdf->Pdf() gives us the same answer + Vector wiL = bsdf->WorldToLocal(*wi); + float wiCosTheta = wiL.z; + bool validSample = (wiCosTheta > 1e-7); + + if (validSample) { + float verifyPdf = bsdf->Pdf(wo, *wi, inflags); + if (fabs(verifyPdf - *pdf) > 1e-4) { + fprintf(stderr, "BSDF::Pdf() doesn't match BSDF::Sample_f() !\n" + " Sample_f pdf %.3f, Pdf pdf %.3f\n" + " wo %.3f %.3f %.3f, wi %.3f %.3f %.3f\n", + *pdf, verifyPdf, wo[0], wo[1], wo[2], (*wi)[0], (*wi)[1], (*wi)[2]); + fprintf(stderr, "blah! validSample %d, wiCosTheta %.3f, wiL %.3f %.3f %.3f\n", + validSample, wiCosTheta, wiL[0], wiL[1], wiL[2]); + } + } +} + +void Gen_CosHemisphere(BSDF* bsdf, + const Vector & wo, Vector* wi, float* pdf, Spectrum* f) +{ + float u1 = rng.RandomFloat(); + float u2 = rng.RandomFloat(); + Vector wiL = CosineSampleHemisphere(u1, u2); + *wi = bsdf->LocalToWorld(wiL); + float cosTheta = wiL.z; + *pdf = CosineHemispherePdf(cosTheta, u2); + + *f = bsdf->f(wo, *wi); +} + +void Gen_UniformHemisphere(BSDF* bsdf, + const Vector & wo, Vector* wi, float* pdf, Spectrum* f) +{ + float u1 = rng.RandomFloat(); + float u2 = rng.RandomFloat(); + Vector wiL = UniformSampleHemisphere(u1, u2); + *wi = bsdf->LocalToWorld(wiL); + *pdf = UniformHemispherePdf(); + + *f = bsdf->f(wo, *wi); +} + + + + + + + + + +void createBlinn0(BSDF* bsdf) +{ + const float blinnExponent = 0.0; + Spectrum Ks(1); + MicrofacetDistribution* distribution = BSDF_ALLOC(arena, Blinn)(blinnExponent); + Fresnel* fresnel = BSDF_ALLOC(arena, FresnelNoOp)(); + BxDF* bxdf = BSDF_ALLOC(arena, Microfacet)(Ks, fresnel, distribution); + bsdf->Add(bxdf); +} + + +void createBlinn05(BSDF* bsdf) +{ + const float blinnExponent = 0.5; + Spectrum Ks(1); + MicrofacetDistribution* distribution = BSDF_ALLOC(arena, Blinn)(blinnExponent); + Fresnel* fresnel = BSDF_ALLOC(arena, FresnelNoOp)(); + BxDF* bxdf = BSDF_ALLOC(arena, Microfacet)(Ks, fresnel, distribution); + bsdf->Add(bxdf); +} + + +void createBlinn2(BSDF* bsdf) +{ + const float blinnExponent = 2.0; + Spectrum Ks(1); + MicrofacetDistribution* distribution = BSDF_ALLOC(arena, Blinn)(blinnExponent); + Fresnel* fresnel = BSDF_ALLOC(arena, FresnelNoOp)(); + BxDF* bxdf = BSDF_ALLOC(arena, Microfacet)(Ks, fresnel, distribution); + bsdf->Add(bxdf); +} + + +void createBlinn30and0(BSDF* bsdf) +{ + const float blinnExponent1 = 30.0; + Spectrum Ks(0.5); + MicrofacetDistribution* distribution1 = BSDF_ALLOC(arena, Blinn)(blinnExponent1); + Fresnel* fresnel = BSDF_ALLOC(arena, FresnelNoOp)(); + BxDF* bxdf1 = BSDF_ALLOC(arena, Microfacet)(Ks, fresnel, distribution1); + bsdf->Add(bxdf1); + + const float blinnExponent2 = 0.0; + MicrofacetDistribution* distribution2 = BSDF_ALLOC(arena, Blinn)(blinnExponent2); + BxDF* bxdf2 = BSDF_ALLOC(arena, Microfacet)(Ks, fresnel, distribution2); + bsdf->Add(bxdf2); +} + + +void createAniso0_0(BSDF* bsdf) +{ + const float aniso1 = 0.0; + const float aniso2 = 0.0; + Spectrum Ks(1); + MicrofacetDistribution* distribution = + BSDF_ALLOC(arena, Anisotropic(aniso1, aniso2)); + Fresnel* fresnel = BSDF_ALLOC(arena, FresnelNoOp)(); + BxDF* bxdf = BSDF_ALLOC(arena, Microfacet)(Ks, fresnel, distribution); + bsdf->Add(bxdf); +} + + +void createAniso10_10(BSDF* bsdf) +{ + const float aniso1 = 10.0; + const float aniso2 = 10.0; + Spectrum Ks(1); + MicrofacetDistribution* distribution = + BSDF_ALLOC(arena, Anisotropic(aniso1, aniso2)); + Fresnel* fresnel = BSDF_ALLOC(arena, FresnelNoOp)(); + BxDF* bxdf = BSDF_ALLOC(arena, Microfacet)(Ks, fresnel, distribution); + bsdf->Add(bxdf); +} + +void createAniso30_30(BSDF* bsdf) +{ + const float aniso1 = 30.0; + const float aniso2 = 30.0; + Spectrum Ks(1); + MicrofacetDistribution* distribution = + BSDF_ALLOC(arena, Anisotropic(aniso1, aniso2)); + Fresnel* fresnel = BSDF_ALLOC(arena, FresnelNoOp)(); + BxDF* bxdf = BSDF_ALLOC(arena, Microfacet)(Ks, fresnel, distribution); + bsdf->Add(bxdf); +} + + +void createLambertian(BSDF* bsdf) +{ + Spectrum Kd(1); + BxDF* bxdf = BSDF_ALLOC(arena, Lambertian)(Kd); + bsdf->Add(bxdf); +} + + +void createOrenNayar0(BSDF* bsdf) +{ + Spectrum Kd(1); + float sigma = 20.0; + BxDF* bxdf = BSDF_ALLOC(arena, OrenNayar)(Kd, sigma); + bsdf->Add(bxdf); +} + + +void createOrenNayar20(BSDF* bsdf) +{ + Spectrum Kd(1); + float sigma = 0.0; + BxDF* bxdf = BSDF_ALLOC(arena, OrenNayar)(Kd, sigma); + bsdf->Add(bxdf); +} + + +void createFresnelBlend0(BSDF* bsdf) +{ + Spectrum d(0.5); + Spectrum s(0.5); + float exponent = 0.0; + + MicrofacetDistribution* distribution = BSDF_ALLOC(arena, Blinn)(exponent); + BxDF* bxdf = BSDF_ALLOC(arena, FresnelBlend)(d, s, distribution); + bsdf->Add(bxdf); +} + + +void createFresnelBlend30(BSDF* bsdf) +{ + Spectrum d(0.5); + Spectrum s(0.5); + float exponent = 30.0; + + MicrofacetDistribution* distribution = BSDF_ALLOC(arena, Blinn)(exponent); + BxDF* bxdf = BSDF_ALLOC(arena, FresnelBlend)(d, s, distribution); + bsdf->Add(bxdf); +} + + +void createPlastic(BSDF* bsdf) +{ + // Taken from plastic.cpp + + Spectrum kd(0.5); + BxDF *diff = BSDF_ALLOC(arena, Lambertian)(kd); + Fresnel *fresnel = BSDF_ALLOC(arena, FresnelDielectric)(1.5f, 1.f); + Spectrum ks = (0.5); + float rough = 0.1; + BxDF *spec = BSDF_ALLOC(arena, Microfacet)(ks, fresnel, + BSDF_ALLOC(arena, Blinn)(1.f / rough)); + bsdf->Add(diff); + bsdf->Add(spec); +} + + + +void createSubstrate(BSDF* bsdf) +{ + // Taken from substrate.cpp + + Spectrum d(0.5); + Spectrum s(0.5); + float u = 0.1; + float v = 0.1; + + bsdf->Add(BSDF_ALLOC(arena, FresnelBlend)(d, s, + BSDF_ALLOC(arena, Anisotropic)(1.f/u, 1.f/v))); +} + + + diff --git a/tools/exravg.cpp b/tools/exravg.cpp new file mode 100644 index 0000000..7cc1427 --- /dev/null +++ b/tools/exravg.cpp @@ -0,0 +1,82 @@ + +#include +#include +#include +#include +#include +#include + +using namespace Imf; +using namespace Imath; + +static bool ReadEXR(const char *name, float *&rgba, int &xRes, int &yRes, bool &hasAlpha); + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + fprintf(stderr, "usage: exravg [file1.exr] ...\n"); + return 1; + } + + float *rgba, *orig_rgba = NULL; + int xRes = 0, yRes = 0; + bool hasAlpha = false; + float a = 0; + int file; + + for (file = 1 ; file < argc ; file++) { + if (ReadEXR(argv[file], rgba, xRes, yRes, hasAlpha)) { + orig_rgba = rgba; + a = 0; + for (int i = 0; i < xRes*yRes; ++i) { + for (int j = 0; j < 3; ++j) + a += rgba[j]; + rgba += hasAlpha ? 4 : 3; + } + } + printf("%s: Average value %f\n", argv[file], a / (3.f * xRes * yRes)); + delete [] orig_rgba; + } + return 0; +} + +static bool ReadEXR(const char *name, float *&rgba, int &xRes, int &yRes, bool &hasAlpha) +{ + try { + InputFile file(name); + Box2i dw = file.header().dataWindow(); + xRes = dw.max.x - dw.min.x + 1; + yRes = dw.max.y - dw.min.y + 1; + + half *hrgba = new half[4 * xRes * yRes]; + + // for now... + hasAlpha = true; + int nChannels = 4; + + hrgba -= 4 * (dw.min.x + dw.min.y * xRes); + FrameBuffer frameBuffer; + frameBuffer.insert("R", Slice(HALF, (char *)hrgba, + 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 0.0)); + frameBuffer.insert("G", Slice(HALF, (char *)hrgba+sizeof(half), + 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 0.0)); + frameBuffer.insert("B", Slice(HALF, (char *)hrgba+2*sizeof(half), + 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 0.0)); + frameBuffer.insert("A", Slice(HALF, (char *)hrgba+3*sizeof(half), + 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 1.0)); + + file.setFrameBuffer(frameBuffer); + file.readPixels(dw.min.y, dw.max.y); + + hrgba += 4 * (dw.min.x + dw.min.y * xRes); + rgba = new float[nChannels * xRes * yRes]; + for (int i = 0; i < nChannels * xRes * yRes; ++i) + rgba[i] = hrgba[i]; + delete[] hrgba; + } catch (const std::exception &e) { + fprintf(stderr, "Unable to read image file \"%s\": %s", name, e.what()); + return NULL; + } + + return rgba; +} diff --git a/tools/exrdiff.cpp b/tools/exrdiff.cpp new file mode 100644 index 0000000..b0c1f76 --- /dev/null +++ b/tools/exrdiff.cpp @@ -0,0 +1,172 @@ +/* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Imf; +using namespace Imath; + +static bool ReadEXR(const char *name, float *&rgba, int &xRes, int &yRes, bool &hasAlpha); +static void WriteEXR(const char *name, float *pixels, int xRes, int yRes); + +static void usage() { + fprintf(stderr, "usage: exrdiff [-o difffile.exr] [-d diff tolerance %%] \n"); + exit(1); +} + +int main(int argc, char *argv[]) +{ + const char *outfile = NULL; + const char *imageFile1 = NULL, *imageFile2 = NULL; + float tol = 0.f; + + if (argc == 1) usage(); + for (int i = 1; i < argc; ++i) { + if (!strcmp(argv[i], "-o")) { + if (!argv[i+1]) usage(); + outfile = argv[i+1]; + ++i; + } + else if (!strcmp(argv[i], "-d")) { + if (!argv[i+1]) usage(); + tol = atof(argv[i+1]); + ++i; + } + else if (!imageFile1) + imageFile1 = argv[i]; + else if (!imageFile2) + imageFile2 = argv[i]; + else + usage(); + } + + float *im1, *im2; + int r1[2], r2[2]; + bool hasAlpha; + if (!ReadEXR(imageFile1, im1, r1[0], r1[1], hasAlpha)) { + printf("couldn't read image %s\n", imageFile1); + return 1; + } + assert(hasAlpha); + if (!ReadEXR(imageFile2, im2, r2[0], r2[1], hasAlpha)) { + printf("couldn't read image %s\n", imageFile2); + return 1; + } + assert(hasAlpha); + if (r1[0] != r2[0] || r1[1] != r2[1]) { + printf("%s/%s:\n\tresolutions don't match! (%d,%d) vs (%d,%d)\n", + imageFile1, imageFile2, r1[0], r1[1], r2[0], r2[1]); + return 1; + } + + float *diffImage = NULL; + if (outfile != NULL) + diffImage = new float[4 * r1[0] * r1[1]]; + + double sum1 = 0.f, sum2 = 0.f; + int smallDiff = 0, bigDiff = 0; + double mse = 0.f; + for (int i = 0; i < 4*r1[0]*r1[1]; ++i) { + if (diffImage) diffImage[i] = fabsf(im1[i] - im2[i]); + if (im1[i] == 0 && im2[i] == 0) + continue; + if ((i % 4) == 0) // alpha channel + continue; + + sum1 += im1[i]; + sum2 += im2[i]; + float d = fabsf(im1[i] - im2[i]) / im1[i]; + mse += (im1[i] - im2[i]) * (im1[i] - im2[i]); + if (d > .005) ++smallDiff; + if (d > .05) ++bigDiff; + } + double avg1 = sum1 / (3. * r1[0] * r1[1]); + double avg2 = sum2 / (3. * r1[0] * r1[1]); + double avgDelta = (avg1-avg2) / std::min(avg1, avg2); + if ((tol == 0. && (bigDiff > 0 || smallDiff > 0)) || + (tol > 0. && 100.f * fabs(avgDelta) > tol)) { + // printf("%s %s\n\tImages differ: %d big (%.2f%%), %d small (%.2f%%)\n" + // "\tavg 1 = %g, avg2 = %g (%f%% delta)\n" + // "\tMSE = %g\n", + // imageFile1, imageFile2, + // bigDiff, 100.f * float(bigDiff) / (3 * r1[0] * r1[1]), + // smallDiff, 100.f * float(smallDiff) / (3 * r1[0] * r1[1]), + // avg1, avg2, 100. * avgDelta, + // mse / (3. * r1[0] * r1[1])); + printf("%g\n", mse / (3. * r1[0] * r1[1])); + if (outfile) + WriteEXR(outfile, diffImage, r1[0], r1[1]); + return 1; + } + + return 0; +} + +static bool ReadEXR(const char *name, float *&rgba, int &xRes, int &yRes, bool &hasAlpha) +{ + try { + InputFile file(name); + Box2i dw = file.header().dataWindow(); + xRes = dw.max.x - dw.min.x + 1; + yRes = dw.max.y - dw.min.y + 1; + + half *hrgba = new half[4 * xRes * yRes]; + + // for now... + hasAlpha = true; + int nChannels = 4; + + hrgba -= 4 * (dw.min.x + dw.min.y * xRes); + FrameBuffer frameBuffer; + frameBuffer.insert("R", Slice(HALF, (char *)hrgba, + 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 0.0)); + frameBuffer.insert("G", Slice(HALF, (char *)hrgba+sizeof(half), + 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 0.0)); + frameBuffer.insert("B", Slice(HALF, (char *)hrgba+2*sizeof(half), + 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 0.0)); + frameBuffer.insert("A", Slice(HALF, (char *)hrgba+3*sizeof(half), + 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 1.0)); + + file.setFrameBuffer(frameBuffer); + file.readPixels(dw.min.y, dw.max.y); + + hrgba += 4 * (dw.min.x + dw.min.y * xRes); + rgba = new float[nChannels * xRes * yRes]; + for (int i = 0; i < nChannels * xRes * yRes; ++i) + rgba[i] = hrgba[i]; + delete[] hrgba; + } catch (const std::exception &e) { + fprintf(stderr, "Unable to read image file \"%s\": %s", name, e.what()); + return NULL; + } + + return rgba; +} + +static void WriteEXR(const char *name, float *pixels, int xRes, int yRes) { + Rgba *hrgba = new Rgba[xRes * yRes]; + for (int i = 0; i < xRes * yRes; ++i) + hrgba[i] = Rgba(pixels[4*i], pixels[4*i+1], pixels[4*i+2], 1.); + + Box2i displayWindow(V2i(0,0), V2i(xRes-1, yRes-1)); + Box2i dataWindow = displayWindow; + + RgbaOutputFile file(name, displayWindow, dataWindow, WRITE_RGBA); + file.setFrameBuffer(hrgba, 1, xRes); + try { + file.writePixels(yRes); + } + catch (const std::exception &e) { + fprintf(stderr, "Unable to write image file \"%s\": %s", name, + e.what()); + } + + delete[] hrgba; +} diff --git a/tools/exrtotiff.cpp b/tools/exrtotiff.cpp new file mode 100644 index 0000000..1f1f0c1 --- /dev/null +++ b/tools/exrtotiff.cpp @@ -0,0 +1,296 @@ +/* + * exrtoiff.cpp + * + * $Id: exrtotiff.cpp 1063 2004-05-14 01:23:50Z mmp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using std::min; +using std::max; + +using namespace Imf; +using namespace Imath; + +static bool ReadEXR(const char *name, float *&rgba, int &xRes, int &yRes, bool &hasAlpha); +static void WriteTIFF(const char *name, float *rgba, int xRes, int yRes, bool hasAlpha); + +static void usage() { + fprintf( stderr, "usage: exrtotiff [options] \n" ); + fprintf( stderr, "Supported options:\n"); + fprintf( stderr, "\t-scale scale\n" ); + fprintf( stderr, "\t-bloom\n" ); + fprintf( stderr, "\t-bloomscale scale [default: 0.1]\n" ); + fprintf( stderr, "\t-bloomradius radius [default: 0.01]\n" ); + fprintf( stderr, "\t-tonemap\n" ); + fprintf( stderr, "\t-repeatpix [count]\n" ); + fprintf( stderr, "\t-gamma gamma\n" ); + fprintf( stderr, "\t-bg bg-grey color\n"); + exit(1); +} + +void reinhard(float *d, int xRes, int yRes) { + const float yw[3] = { 0.212671f, 0.715160f, 0.072169f }; + // Compute world adaptation luminance, _Ywa_ + float Ywa = 0.; + for (int i = 0; i < xRes * yRes; ++i) { + float y = yw[0] * d[3*i] + yw[1] * d[3*i+1] + yw[2] * d[3*i+2]; +//CO if ((i % 1000) == 1) fprintf(stderr, "%f,%f,%f -> %f\n", +//CO d[3*i], d[3*i+1], d[3*i+2], y); + if (y > 1e-4f) Ywa += logf(y); + } + Ywa = expf(Ywa / (xRes * yRes)); +//CO Ywa /= 683.f; +//CO fprintf(stderr, "YWA = %f\n", Ywa); + float invY2 = 1.f / (Ywa * Ywa); +//CO float invY2 = 1.f / (maxY * maxY); + + for (int i = 0; i < xRes * yRes; ++i) { + float y = yw[0] * d[3*i] + yw[1] * d[3*i+1] + yw[2] * d[3*i+2]; + + float s = (1.f + y * invY2) / (1.f + y); +//CO if ((i % 1000) == 1) fprintf(stderr, "%f %f -> %f\n", y, invY2, s); + d[3*i] *= s; + d[3*i+1] *= s; + d[3*i+2] *= s; + } +} + +inline float Lerp(float t, float a, float b) { + return (1.f - t) * a + t * b; +} + +void bloom(float *rgb, int xResolution, int yResolution, float bloomRadius, + float bloomWeight) { + int nPix = xResolution * yResolution; + // Possibly apply bloom effect to image + if (bloomRadius > 0.f && bloomWeight > 0.f) { + // Compute image-space extent of bloom effect + int bloomSupport = int(ceilf(bloomRadius * + max(xResolution, yResolution))); + int bloomWidth = bloomSupport / 2; + // Initialize bloom filter table + float *bloomFilter = new float[bloomWidth * bloomWidth]; + for (int i = 0; i < bloomWidth * bloomWidth; ++i) { + float dist = sqrtf(float(i)) / float(bloomWidth); + bloomFilter[i] = powf(max(0.f, 1.f - dist), 4.f); + } + // Apply bloom filter to image pixels + float *bloomImage = new float[3*nPix]; + for (int y = 0; y < yResolution; ++y) { + for (int x = 0; x < xResolution; ++x) { + // Compute bloom for pixel _(x,y)_ + // Compute extent of pixels contributing bloom + int x0 = max(0, x - bloomWidth); + int x1 = min(x + bloomWidth, xResolution - 1); + int y0 = max(0, y - bloomWidth); + int y1 = min(y + bloomWidth, yResolution - 1); + int offset = y * xResolution + x; + float sumWt = 0.; + for (int by = y0; by <= y1; ++by) + for (int bx = x0; bx <= x1; ++bx) { + // Accumulate bloom from pixel $(bx,by)$ + int dx = x - bx, dy = y - by; + if (dx == 0 && dy == 0) continue; + int dist2 = dx*dx + dy*dy; + if (dist2 < bloomWidth * bloomWidth) { + int bloomOffset = bx + by * xResolution; + float wt = bloomFilter[dist2]; + sumWt += wt; + for (int j = 0; j < 3; ++j) + bloomImage[3*offset+j] += wt * rgb[3*bloomOffset+j]; + } + } + bloomImage[3*offset ] /= sumWt; + bloomImage[3*offset+1] /= sumWt; + bloomImage[3*offset+2] /= sumWt; + } + } + // Mix bloom effect into each pixel + for (int i = 0; i < 3 * nPix; ++i) + rgb[i] = Lerp(bloomWeight, rgb[i], bloomImage[i]); + // Free memory allocated for bloom effect + delete[] bloomFilter; + delete[] bloomImage; + } +} + +int main(int argc, char *argv[]) +{ + float scale = 1.f, gamma = 2.2f; + float bggray = -1.f; + bool tonemap = false, bloom = false; + float bloomRadius = .01f, bloomScale = .1f; + int repeat = 1; + float rp = 1; + + int argNum = 1; + while (argNum < argc && argv[argNum][0] == '-') { +#define ARG(name, var) \ + else if (!strcmp(argv[argNum], "-" name)) { \ + if (argNum+1 == argc) \ + usage(); \ + var = atof(argv[argNum+1]); \ + ++argNum; \ + } + if (!strcmp(argv[argNum], "-tonemap")) tonemap = true; + else if (!strcmp(argv[argNum], "-bloom")) bloom = true; + ARG("bloomscale", bloomScale) + ARG("bloomradius", bloomRadius) + ARG("repeatpix", rp) + ARG("scale", scale) + ARG("gamma", gamma) + ARG("bg", bggray) + else + usage(); + ++argNum; + + } + if (argNum + 2 > argc) usage(); + repeat = int(rp); + + char *inFile = argv[argNum], *outFile = argv[argNum+1]; + float *rgba; + int xRes, yRes; + bool hasAlpha; + + if (ReadEXR(inFile, rgba, xRes, yRes, hasAlpha)) { + if (repeat > 1) { + assert(hasAlpha != 0); + float *rscale = new float[4 * repeat * xRes * repeat * yRes]; + float *rsp = rscale; + for (int y = 0; y < repeat * yRes; ++y) { + int yy = y / repeat; + for (int x = 0; x < repeat * xRes; ++x) { + int xx = x / repeat; + for (int c = 0; c < 4; ++c) + *rsp++ = rgba[4 * (yy * xRes + xx) + c]; + } + } + xRes *= repeat; + yRes *= repeat; + rgba = rscale; + } + + float *rgb = new float[xRes*yRes*3]; + for (int i = 0; i < xRes*yRes; ++i) { + for (int j = 0; j < 3; ++j) { + rgb[3*i+j] = scale * rgba[4*i+j]; + if (bggray > 0) + rgb[3*i+j] = rgba[4*i+3] * rgb[3*i+j] + (1.f - rgba[4*i+3]) * bggray; + } + if (bggray > 0) + rgba[4*i+3] = 1.f; + } + + if (bloom) ::bloom(rgb, xRes, yRes, bloomRadius, bloomScale); + if (tonemap) reinhard(rgb, xRes, yRes); + + for (int i = 0; i < xRes*yRes; ++i) { + float m = 0.f; + for (int j = 0; j < 3; ++j) { + rgba[4*i+j] = 255.f * powf(std::max(0.f, rgb[3*i+j]), 1.f / gamma); + m = std::max(m, rgba[4*i+j]); + } + if (m > 255.f) { + for (int j = 0; j < 3; ++j) + rgba[4*i+j] = 255.f * (rgba[4*i+j] / m); + } +//CO if (rgba[4*i+j] < 0.f) rgba[4*i+j] = 0.f; +//CO if (rgba[4*i+j] > 255.f) rgba[4*i+j] = 255.f; + + rgba[4*i+3] *= 255.f; + } + + WriteTIFF(outFile, rgba, xRes, yRes, hasAlpha); + } + return 0; +} + +void WriteTIFF(const char *name, float *rgba, int XRes, int YRes, bool hasAlpha) +{ + // Open 8-bit TIFF file for writing + TIFF *tiff = TIFFOpen(name, "w"); + if (!tiff) { + fprintf(stderr, "Unable to open TIFF %s for writing", name); + return; + } + + int nChannels = hasAlpha ? 4 : 3; + TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, nChannels); + if (hasAlpha) { + short int extra[] = { EXTRASAMPLE_ASSOCALPHA }; + TIFFSetField(tiff, TIFFTAG_EXTRASAMPLES, (short)1, extra); + } + // Write image resolution information + TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, XRes); + TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, YRes); + TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8); + TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + // Set Generic TIFF Fields + TIFFSetField(tiff, TIFFTAG_ROWSPERSTRIP, 1); + TIFFSetField(tiff, TIFFTAG_XRESOLUTION, 1.f); + TIFFSetField(tiff, TIFFTAG_YRESOLUTION, 1.f); + TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, (short)1); + TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tiff, TIFFTAG_ORIENTATION, (int)ORIENTATION_TOPLEFT); + // Write 8-bit scanlines + unsigned char *buf = new unsigned char[nChannels * XRes]; + for (int y = 0; y < YRes; ++y) { + unsigned char *bufp = buf; + for (int x = 0; x < XRes; ++x) { + // Pack 8-bit pixels samples into buf + for (int s = 0; s < nChannels; ++s) + *bufp++ = (unsigned char)*rgba++; + } + TIFFWriteScanline(tiff, buf, y, 1); + } + // Close 8-bit TIFF file + delete[] buf; + TIFFClose(tiff); +} + +static bool ReadEXR(const char *name, float *&rgba, int &xRes, int &yRes, bool &hasAlpha) +{ + InputFile file(name); + Box2i dw = file.header().dataWindow(); + xRes = dw.max.x - dw.min.x + 1; + yRes = dw.max.y - dw.min.y + 1; + + half *hrgba = new half[4 * xRes * yRes]; + + // for now... + hasAlpha = true; + int nChannels = 4; + + half *hp = hrgba - nChannels * (dw.min.x + dw.min.y * xRes); + + FrameBuffer frameBuffer; + frameBuffer.insert("R", Slice(HALF, (char *)hp, + 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 0.0)); + frameBuffer.insert("G", Slice(HALF, (char *)hp+sizeof(half), + 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 0.0)); + frameBuffer.insert("B", Slice(HALF, (char *)hp+2*sizeof(half), + 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 0.0)); + frameBuffer.insert("A", Slice(HALF, (char *)hp+3*sizeof(half), + 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 1.0)); + + file.setFrameBuffer(frameBuffer); + file.readPixels(dw.min.y, dw.max.y); + + rgba = new float[nChannels * xRes * yRes]; + for (int i = 0; i < nChannels * xRes * yRes; ++i) + rgba[i] = hrgba[i]; + delete[] hrgba; + + return rgba; +} diff --git a/tools/ply.c b/tools/ply.c new file mode 100644 index 0000000..adafd09 --- /dev/null +++ b/tools/ply.c @@ -0,0 +1,3300 @@ +/* + +The interface routines for reading and writing PLY polygon files. + +Greg Turk + +--------------------------------------------------------------- + +A PLY file contains a single polygonal _object_. + +An object is composed of lists of _elements_. Typical elements are +vertices, faces, edges and materials. + +Each type of element for a given object has one or more _properties_ +associated with the element type. For instance, a vertex element may +have as properties the floating-point values x,y,z and the three unsigned +chars representing red, green and blue. + +----------------------------------------------------------------------- + +Copyright (c) 1998 Georgia Institute of Technology. All rights reserved. + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose is hereby granted without fee, provided +that the above copyright notice and this permission notice appear in +all copies of this software and that you do not sell the software. + +THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, +EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +*/ + +#include +#include +#include +#include +#include + +char *type_names[] = { /* names of scalar types */ +"invalid", +"int8", "int16", "int32", "uint8", "uint16", "uint32", "float32", "float64", +}; + +char *old_type_names[] = { /* old names of types for backward compatability */ +"invalid", +"char", "short", "int", "uchar", "ushort", "uint", "float", "double", +}; + +int ply_type_size[] = { + 0, 1, 2, 4, 1, 2, 4, 4, 8 +}; + +#define NO_OTHER_PROPS -1 + +#define DONT_STORE_PROP 0 +#define STORE_PROP 1 + +#define OTHER_PROP 0 +#define NAMED_PROP 1 + +/* returns 1 if strings are equal, 0 if not */ +int equal_strings(char *, char *); + +/* find an element in a plyfile's list */ +PlyElement *find_element(PlyFile *, char *); + +/* find a property in an element's list */ +PlyProperty *find_property(PlyElement *, char *, int *); + +/* write to a file the word describing a PLY file data type */ +void write_scalar_type (FILE *, int); + +/* read a line from a file and break it up into separate words */ +char **get_words(FILE *, int *, char **); + +/* write an item to a file */ +void write_binary_item(FILE *, int, unsigned int, double, int); +void write_ascii_item(FILE *, int, unsigned int, double, int); + +/* add information to a PLY file descriptor */ +void add_element(PlyFile *, char **, int); +void add_property(PlyFile *, char **, int); +void add_comment(PlyFile *, char *); +void add_obj_info(PlyFile *, char *); + +/* copy a property */ +void copy_property(PlyProperty *, PlyProperty *); + +/* store a value into where a pointer and a type specify */ +void store_item(char *, int, int, unsigned int, double); + +/* return the value of a stored item */ +void get_stored_item( void *, int, int *, unsigned int *, double *); + +/* return the value stored in an item, given ptr to it and its type */ +double get_item_value(char *, int); + +/* get binary or ascii item and store it according to ptr and type */ +void get_ascii_item(char *, int, int *, unsigned int *, double *); +void get_binary_item(FILE *, int, int *, unsigned int *, double *); + +/* get a bunch of elements from a file */ +void ascii_get_element(PlyFile *, char *); +void binary_get_element(PlyFile *, char *); + +/* memory allocation */ +static char *my_alloc(int, int, char *); + + +/*************/ +/* Writing */ +/*************/ + + +/****************************************************************************** +Given a file pointer, get ready to write PLY data to the file. + +Entry: + fp - the given file pointer + nelems - number of elements in object + elem_names - list of element names + file_type - file type, either ascii or binary + +Exit: + returns a pointer to a PlyFile, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_write( + FILE *fp, + int nelems, + char **elem_names, + int file_type +) +{ + int i; + PlyFile *plyfile; + PlyElement *elem; + + /* check for NULL file pointer */ + if (fp == NULL) + return (NULL); + + /* create a record for this object */ + + plyfile = (PlyFile *) myalloc (sizeof (PlyFile)); + plyfile->file_type = file_type; + plyfile->num_comments = 0; + plyfile->num_obj_info = 0; + plyfile->num_elem_types = nelems; + plyfile->version = 1.0; + plyfile->fp = fp; + plyfile->other_elems = NULL; + + /* tuck aside the names of the elements */ + + plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *) * nelems); + for (i = 0; i < nelems; i++) { + elem = (PlyElement *) myalloc (sizeof (PlyElement)); + plyfile->elems[i] = elem; + elem->name = strdup (elem_names[i]); + elem->num = 0; + elem->nprops = 0; + } + + /* return pointer to the file descriptor */ + return (plyfile); +} + + +/****************************************************************************** +Open a polygon file for writing. + +Entry: + filename - name of file to read from + nelems - number of elements in object + elem_names - list of element names + file_type - file type, either ascii or binary + +Exit: + returns a file identifier, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *open_for_writing_ply( + char *filename, + int nelems, + char **elem_names, + int file_type +) +{ + PlyFile *plyfile; + char *name; + FILE *fp; + + /* tack on the extension .ply, if necessary */ + + name = (char *) myalloc (sizeof (char) * (strlen (filename) + 5)); + strcpy (name, filename); + if (strlen (name) < 4 || + strcmp (name + strlen (name) - 4, ".ply") != 0) + strcat (name, ".ply"); + + /* open the file for writing */ + + fp = fopen (name, "w"); + if (fp == NULL) { + return (NULL); + } + + /* create the actual PlyFile structure */ + + plyfile = ply_write (fp, nelems, elem_names, file_type); + if (plyfile == NULL) + return (NULL); + + /* return pointer to the file descriptor */ + return (plyfile); +} + + +/****************************************************************************** +Describe an element, including its properties and how many will be written +to the file. + +Entry: + plyfile - file identifier + elem_name - name of element that information is being specified about + nelems - number of elements of this type to be written + nprops - number of properties contained in the element + prop_list - list of properties +******************************************************************************/ + +void element_layout_ply( + PlyFile *plyfile, + char *elem_name, + int nelems, + int nprops, + PlyProperty *prop_list +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr,"element_layout_ply: can't find element '%s'\n",elem_name); + exit (-1); + } + + elem->num = nelems; + + /* copy the list of properties */ + + elem->nprops = nprops; + elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *) * nprops); + elem->store_prop = (char *) myalloc (sizeof (char) * nprops); + + for (i = 0; i < nprops; i++) { + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + elem->props[i] = prop; + elem->store_prop[i] = NAMED_PROP; + copy_property (prop, &prop_list[i]); + } +} + + +/****************************************************************************** +Describe a property of an element. + +Entry: + plyfile - file identifier + elem_name - name of element that information is being specified about + prop - the new property +******************************************************************************/ + +void ply_describe_property( + PlyFile *plyfile, + char *elem_name, + PlyProperty *prop +) +{ + PlyElement *elem; + PlyProperty *elem_prop; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr, "ply_describe_property: can't find element '%s'\n", + elem_name); + return; + } + + /* create room for new property */ + + if (elem->nprops == 0) { + elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *)); + elem->store_prop = (char *) myalloc (sizeof (char)); + elem->nprops = 1; + } + else { + elem->nprops++; + elem->props = (PlyProperty **) + realloc (elem->props, sizeof (PlyProperty *) * elem->nprops); + elem->store_prop = (char *) + realloc (elem->store_prop, sizeof (char) * elem->nprops); + } + + /* copy the new property */ + + elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + elem->props[elem->nprops - 1] = elem_prop; + elem->store_prop[elem->nprops - 1] = NAMED_PROP; + copy_property (elem_prop, prop); +} + + +/****************************************************************************** +State how many of a given element will be written. + +Entry: + plyfile - file identifier + elem_name - name of element that information is being specified about + nelems - number of elements of this type to be written +******************************************************************************/ + +void element_count_ply( + PlyFile *plyfile, + char *elem_name, + int nelems +) +{ + PlyElement *elem; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr,"element_count_ply: can't find element '%s'\n",elem_name); + exit (-1); + } + + elem->num = nelems; +} + + +/****************************************************************************** +Signal that we've described everything a PLY file's header and that the +header should be written to the file. + +Entry: + plyfile - file identifier +******************************************************************************/ + +void header_complete_ply(PlyFile *plyfile) +{ + int i,j; + FILE *fp = plyfile->fp; + PlyElement *elem; + PlyProperty *prop; + + fprintf (fp, "ply\n"); + + switch (plyfile->file_type) { + case PLY_ASCII: + fprintf (fp, "format ascii 1.0\n"); + break; + case PLY_BINARY_BE: + fprintf (fp, "format binary_big_endian 1.0\n"); + break; + case PLY_BINARY_LE: + fprintf (fp, "format binary_little_endian 1.0\n"); + break; + default: + fprintf (stderr, "ply_header_complete: bad file type = %d\n", + plyfile->file_type); + exit (-1); + } + + /* write out the comments */ + + for (i = 0; i < plyfile->num_comments; i++) + fprintf (fp, "comment %s\n", plyfile->comments[i]); + + /* write out object information */ + + for (i = 0; i < plyfile->num_obj_info; i++) + fprintf (fp, "obj_info %s\n", plyfile->obj_info[i]); + + /* write out information about each element */ + + for (i = 0; i < plyfile->num_elem_types; i++) { + + elem = plyfile->elems[i]; + fprintf (fp, "element %s %d\n", elem->name, elem->num); + + /* write out each property */ + for (j = 0; j < elem->nprops; j++) { + prop = elem->props[j]; + if (prop->is_list == PLY_LIST) { + fprintf (fp, "property list "); + write_scalar_type (fp, prop->count_external); + fprintf (fp, " "); + write_scalar_type (fp, prop->external_type); + fprintf (fp, " %s\n", prop->name); + } + else if (prop->is_list == PLY_STRING) { + fprintf (fp, "property string"); + fprintf (fp, " %s\n", prop->name); + } + else { + fprintf (fp, "property "); + write_scalar_type (fp, prop->external_type); + fprintf (fp, " %s\n", prop->name); + } + } + } + + fprintf (fp, "end_header\n"); +} + + +/****************************************************************************** +Specify which elements are going to be written. This should be called +before a call to the routine ply_put_element(). + +Entry: + plyfile - file identifier + elem_name - name of element we're talking about +******************************************************************************/ + +void put_element_setup_ply(PlyFile *plyfile, char *elem_name) +{ + PlyElement *elem; + + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr, "put_element_setup_ply: can't find element '%s'\n", elem_name); + exit (-1); + } + + plyfile->which_elem = elem; +} + + +/****************************************************************************** +Write an element to the file. This routine assumes that we're +writing the type of element specified in the last call to the routine +put_element_setup_ply(). + +Entry: + plyfile - file identifier + elem_ptr - pointer to the element +******************************************************************************/ + +void put_element_ply(PlyFile *plyfile, void *elem_ptr) +{ + int j,k; + FILE *fp = plyfile->fp; + PlyElement *elem; + PlyProperty *prop; + char *item; + char *elem_data; + char **item_ptr; + int list_count; + int item_size; + int int_val; + unsigned int uint_val; + double double_val; + char **other_ptr; + + elem = plyfile->which_elem; + elem_data = (char *) elem_ptr; + other_ptr = (char **) (((char *) elem_ptr) + elem->other_offset); + + /* write out either to an ascii or binary file */ + + if (plyfile->file_type == PLY_ASCII) { + + /* write an ascii file */ + + /* write out each property of the element */ + for (j = 0; j < elem->nprops; j++) { + + prop = elem->props[j]; + + if (elem->store_prop[j] == OTHER_PROP) + elem_data = *other_ptr; + else + elem_data = (char *) elem_ptr; + + if (prop->is_list == PLY_LIST) { /* list */ + item = elem_data + prop->count_offset; + get_stored_item ((void *) item, prop->count_internal, + &int_val, &uint_val, &double_val); + write_ascii_item (fp, int_val, uint_val, double_val, + prop->count_external); + list_count = uint_val; + item_ptr = (char **) (elem_data + prop->offset); + item = item_ptr[0]; + item_size = ply_type_size[prop->internal_type]; + for (k = 0; k < list_count; k++) { + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_ascii_item (fp, int_val, uint_val, double_val, + prop->external_type); + item += item_size; + } + } + else if (prop->is_list == PLY_STRING) { /* string */ + char **str; + item = elem_data + prop->offset; + str = (char **) item; + fprintf (fp, "\"%s\"", *str); + } + else { /* scalar */ + item = elem_data + prop->offset; + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_ascii_item (fp, int_val, uint_val, double_val, + prop->external_type); + } + } + + fprintf (fp, "\n"); + } + else { + + /* write a binary file */ + + /* write out each property of the element */ + for (j = 0; j < elem->nprops; j++) { + prop = elem->props[j]; + if (elem->store_prop[j] == OTHER_PROP) + elem_data = *other_ptr; + else + elem_data = (char *) elem_ptr; + if (prop->is_list == PLY_LIST) { /* list */ + item = elem_data + prop->count_offset; + item_size = ply_type_size[prop->count_internal]; + get_stored_item ((void *) item, prop->count_internal, + &int_val, &uint_val, &double_val); + write_binary_item (fp, int_val, uint_val, double_val, + prop->count_external); + list_count = uint_val; + item_ptr = (char **) (elem_data + prop->offset); + item = item_ptr[0]; + item_size = ply_type_size[prop->internal_type]; + for (k = 0; k < list_count; k++) { + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_binary_item (fp, int_val, uint_val, double_val, + prop->external_type); + item += item_size; + } + } + else if (prop->is_list == PLY_STRING) { /* string */ + int len; + char **str; + item = elem_data + prop->offset; + str = (char **) item; + + /* write the length */ + len = strlen(*str) + 1; + fwrite (&len, sizeof(int), 1, fp); + + /* write the string, including the null character */ + fwrite (*str, len, 1, fp); + } + else { /* scalar */ + item = elem_data + prop->offset; + item_size = ply_type_size[prop->internal_type]; + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_binary_item (fp, int_val, uint_val, double_val, + prop->external_type); + } + } + + } +} + + + + + + +/*************/ +/* Reading */ +/*************/ + + + +/****************************************************************************** +Given a file pointer, get ready to read PLY data from the file. + +Entry: + fp - the given file pointer + +Exit: + nelems - number of elements in object + elem_names - list of element names + returns a pointer to a PlyFile, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_read(FILE *fp, int *nelems, char ***elem_names) +{ + int i,j; + PlyFile *plyfile; + int nwords; + char **words; + int found_format = 0; + char **elist; + PlyElement *elem; + char *orig_line; + + /* check for NULL file pointer */ + if (fp == NULL) + return (NULL); + + /* create record for this object */ + + plyfile = (PlyFile *) myalloc (sizeof (PlyFile)); + plyfile->num_elem_types = 0; + plyfile->comments = NULL; + plyfile->num_comments = 0; + plyfile->obj_info = NULL; + plyfile->num_obj_info = 0; + plyfile->fp = fp; + plyfile->other_elems = NULL; + plyfile->rule_list = NULL; + + /* read and parse the file's header */ + + words = get_words (plyfile->fp, &nwords, &orig_line); + if (!words || !equal_strings (words[0], "ply")) + return (NULL); + + while (words) { + + /* parse words */ + + if (equal_strings (words[0], "format")) { + if (nwords != 3) + return (NULL); + if (equal_strings (words[1], "ascii")) + plyfile->file_type = PLY_ASCII; + else if (equal_strings (words[1], "binary_big_endian")) + plyfile->file_type = PLY_BINARY_BE; + else if (equal_strings (words[1], "binary_little_endian")) + plyfile->file_type = PLY_BINARY_LE; + else + return (NULL); + plyfile->version = atof (words[2]); + found_format = 1; + } + else if (equal_strings (words[0], "element")) + add_element (plyfile, words, nwords); + else if (equal_strings (words[0], "property")) + add_property (plyfile, words, nwords); + else if (equal_strings (words[0], "comment")) + add_comment (plyfile, orig_line); + else if (equal_strings (words[0], "obj_info")) + add_obj_info (plyfile, orig_line); + else if (equal_strings (words[0], "end_header")) + break; + + /* free up words space */ + free (words); + + words = get_words (plyfile->fp, &nwords, &orig_line); + } + + /* create tags for each property of each element, to be used */ + /* later to say whether or not to store each property for the user */ + + for (i = 0; i < plyfile->num_elem_types; i++) { + elem = plyfile->elems[i]; + elem->store_prop = (char *) myalloc (sizeof (char) * elem->nprops); + for (j = 0; j < elem->nprops; j++) + elem->store_prop[j] = DONT_STORE_PROP; + elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */ + } + + /* set return values about the elements */ + + elist = (char **) myalloc (sizeof (char *) * plyfile->num_elem_types); + for (i = 0; i < plyfile->num_elem_types; i++) + elist[i] = strdup (plyfile->elems[i]->name); + + *elem_names = elist; + *nelems = plyfile->num_elem_types; + + /* return a pointer to the file's information */ + + return (plyfile); +} + + +/****************************************************************************** +Open a polygon file for reading. + +Entry: + filename - name of file to read from + +Exit: + nelems - number of elements in object + elem_names - list of element names + file_type - file type, either ascii or binary + version - version number of PLY file + returns a file identifier, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_open_for_reading( + char *filename, + int *nelems, + char ***elem_names, + int *file_type, + float *version +) +{ + FILE *fp; + PlyFile *plyfile; + char *name; + + /* tack on the extension .ply, if necessary */ + + name = (char *) myalloc (sizeof (char) * (strlen (filename) + 5)); + strcpy (name, filename); + if (strlen (name) < 4 || + strcmp (name + strlen (name) - 4, ".ply") != 0) + strcat (name, ".ply"); + + /* open the file for reading */ + + fp = fopen (name, "r"); + if (fp == NULL) + return (NULL); + + /* create the PlyFile data structure */ + + plyfile = ply_read (fp, nelems, elem_names); + + /* determine the file type and version */ + + *file_type = plyfile->file_type; + *version = plyfile->version; + + /* return a pointer to the file's information */ + + return (plyfile); +} + + +/****************************************************************************** +Get information about a particular element. + +Entry: + plyfile - file identifier + elem_name - name of element to get information about + +Exit: + nelems - number of elements of this type in the file + nprops - number of properties + returns a list of properties, or NULL if the file doesn't contain that elem +******************************************************************************/ + +PlyProperty **get_element_description_ply( + PlyFile *plyfile, + char *elem_name, + int *nelems, + int *nprops +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + PlyProperty **prop_list; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) + return (NULL); + + *nelems = elem->num; + *nprops = elem->nprops; + + /* make a copy of the element's property list */ + prop_list = (PlyProperty **) myalloc (sizeof (PlyProperty *) * elem->nprops); + for (i = 0; i < elem->nprops; i++) { + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + copy_property (prop, elem->props[i]); + prop_list[i] = prop; + } + + /* return this duplicate property list */ + return (prop_list); +} + + +/****************************************************************************** +Specify which properties of an element are to be returned. This should be +called before a call to the routine get_element_ply(). + +Entry: + plyfile - file identifier + elem_name - which element we're talking about + nprops - number of properties + prop_list - list of properties +******************************************************************************/ + +void get_element_setup_ply( + PlyFile *plyfile, + char *elem_name, + int nprops, + PlyProperty *prop_list +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + int index; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + plyfile->which_elem = elem; + + /* deposit the property information into the element's description */ + for (i = 0; i < nprops; i++) { + + /* look for actual property */ + prop = find_property (elem, prop_list[i].name, &index); + if (prop == NULL) { + fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n", + prop_list[i].name, elem_name); + continue; + } + + /* store its description */ + prop->internal_type = prop_list[i].internal_type; + prop->offset = prop_list[i].offset; + prop->count_internal = prop_list[i].count_internal; + prop->count_offset = prop_list[i].count_offset; + + /* specify that the user wants this property */ + elem->store_prop[index] = STORE_PROP; + } +} + + +/****************************************************************************** +Specify a property of an element that is to be returned. This should be +called (usually multiple times) before a call to the routine ply_get_element(). +This routine should be used in preference to the less flexible old routine +called ply_get_element_setup(). + +Entry: + plyfile - file identifier + elem_name - which element we're talking about + prop - property to add to those that will be returned +******************************************************************************/ + +void ply_get_property( + PlyFile *plyfile, + char *elem_name, + PlyProperty *prop +) +{ + PlyElement *elem; + PlyProperty *prop_ptr; + int index; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + plyfile->which_elem = elem; + + /* deposit the property information into the element's description */ + + prop_ptr = find_property (elem, prop->name, &index); + if (prop_ptr == NULL) { + fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n", + prop->name, elem_name); + return; + } + prop_ptr->internal_type = prop->internal_type; + prop_ptr->offset = prop->offset; + prop_ptr->count_internal = prop->count_internal; + prop_ptr->count_offset = prop->count_offset; + + /* specify that the user wants this property */ + elem->store_prop[index] = STORE_PROP; +} + + +/****************************************************************************** +Read one element from the file. This routine assumes that we're reading +the type of element specified in the last call to the routine +ply_get_element_setup(). + +Entry: + plyfile - file identifier + elem_ptr - pointer to location where the element information should be put +******************************************************************************/ + +void ply_get_element(PlyFile *plyfile, void *elem_ptr) +{ + if (plyfile->file_type == PLY_ASCII) + ascii_get_element (plyfile, (char *) elem_ptr); + else + binary_get_element (plyfile, (char *) elem_ptr); +} + + +/****************************************************************************** +Extract the comments from the header information of a PLY file. + +Entry: + plyfile - file identifier + +Exit: + num_comments - number of comments returned + returns a pointer to a list of comments +******************************************************************************/ + +char **get_comments_ply(PlyFile *plyfile, int *num_comments) +{ + *num_comments = plyfile->num_comments; + return (plyfile->comments); +} + + +/****************************************************************************** +Extract the object information (arbitrary text) from the header information +of a PLY file. + +Entry: + plyfile - file identifier + +Exit: + num_obj_info - number of lines of text information returned + returns a pointer to a list of object info lines +******************************************************************************/ + +char **get_obj_info_ply(PlyFile *plyfile, int *num_obj_info) +{ + *num_obj_info = plyfile->num_obj_info; + return (plyfile->obj_info); +} + + +/****************************************************************************** +Make ready for "other" properties of an element-- those properties that +the user has not explicitly asked for, but that are to be stashed away +in a special structure to be carried along with the element's other +information. + +Entry: + plyfile - file identifier + elem - element for which we want to save away other properties +******************************************************************************/ + +void setup_other_props(PlyFile *plyfile, PlyElement *elem) +{ + int i; + PlyProperty *prop; + int size = 0; + int type_size; + + /* Examine each property in decreasing order of size. */ + /* We do this so that all data types will be aligned by */ + /* word, half-word, or whatever within the structure. */ + + for (type_size = 8; type_size > 0; type_size /= 2) { + + /* add up the space taken by each property, and save this information */ + /* away in the property descriptor */ + + for (i = 0; i < elem->nprops; i++) { + + /* don't bother with properties we've been asked to store explicitly */ + if (elem->store_prop[i]) + continue; + + prop = elem->props[i]; + + /* internal types will be same as external */ + prop->internal_type = prop->external_type; + prop->count_internal = prop->count_external; + + /* list case */ + if (prop->is_list == PLY_LIST) { + + /* pointer to list */ + if (type_size == sizeof (void *)) { + prop->offset = size; + size += sizeof (void *); /* always use size of a pointer here */ + } + + /* count of number of list elements */ + if (type_size == ply_type_size[prop->count_external]) { + prop->count_offset = size; + size += ply_type_size[prop->count_external]; + } + } + /* string */ + else if (prop->is_list == PLY_STRING) { + /* pointer to string */ + if (type_size == sizeof (char *)) { + prop->offset = size; + size += sizeof (char *); + } + } + /* scalar */ + else if (type_size == ply_type_size[prop->external_type]) { + prop->offset = size; + size += ply_type_size[prop->external_type]; + } + } + + } + + /* save the size for the other_props structure */ + elem->other_size = size; +} + + +/****************************************************************************** +Specify that we want the "other" properties of an element to be tucked +away within the user's structure. + +Entry: + plyfile - file identifier + elem - the element that we want to store other_props in + offset - offset to where other_props will be stored inside user's structure + +Exit: + returns pointer to structure containing description of other_props +******************************************************************************/ + +static PlyOtherProp *get_other_properties( + PlyFile *plyfile, + PlyElement *elem, + int offset +) +{ + int i; + PlyOtherProp *other; + PlyProperty *prop; + int nprops; + + /* remember that this is the "current" element */ + plyfile->which_elem = elem; + + /* save the offset to where to store the other_props */ + elem->other_offset = offset; + + /* place the appropriate pointers, etc. in the element's property list */ + setup_other_props (plyfile, elem); + + /* create structure for describing other_props */ + other = (PlyOtherProp *) myalloc (sizeof (PlyOtherProp)); + other->name = strdup (elem->name); +#if 0 + if (elem->other_offset == NO_OTHER_PROPS) { + other->size = 0; + other->props = NULL; + other->nprops = 0; + return (other); + } +#endif + other->size = elem->other_size; + other->props = (PlyProperty **) myalloc (sizeof(PlyProperty) * elem->nprops); + + /* save descriptions of each "other" property */ + nprops = 0; + for (i = 0; i < elem->nprops; i++) { + if (elem->store_prop[i]) + continue; + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + copy_property (prop, elem->props[i]); + other->props[nprops] = prop; + nprops++; + } + other->nprops = nprops; + + /* set other_offset pointer appropriately if there are NO other properties */ + if (other->nprops == 0) { + elem->other_offset = NO_OTHER_PROPS; + } + + /* return structure */ + return (other); +} + + +/****************************************************************************** +Specify that we want the "other" properties of an element to be tucked +away within the user's structure. The user needn't be concerned for how +these properties are stored. + +Entry: + plyfile - file identifier + elem_name - name of element that we want to store other_props in + offset - offset to where other_props will be stored inside user's structure + +Exit: + returns pointer to structure containing description of other_props +******************************************************************************/ + +PlyOtherProp *ply_get_other_properties( + PlyFile *plyfile, + char *elem_name, + int offset +) +{ + PlyElement *elem; + PlyOtherProp *other; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf (stderr, "ply_get_other_properties: Can't find element '%s'\n", + elem_name); + return (NULL); + } + + other = get_other_properties (plyfile, elem, offset); + return (other); +} + + + + +/*************************/ +/* Other Element Stuff */ +/*************************/ + + + + + +/****************************************************************************** +Grab all the data for the current element that a user does not want to +explicitly read in. Stores this in the PLY object's data structure. + +Entry: + plyfile - pointer to file + +Exit: + returns pointer to ALL the "other" element data for this PLY file +******************************************************************************/ + +PlyOtherElems *get_other_element_ply (PlyFile *plyfile) +{ + int i; + PlyElement *elem; + char *elem_name; + int elem_count; + PlyOtherElems *other_elems; + OtherElem *other; + + elem = plyfile->which_elem; + elem_name = elem->name; + elem_count = elem->num; + + /* create room for the new "other" element, initializing the */ + /* other data structure if necessary */ + + if (plyfile->other_elems == NULL) { + plyfile->other_elems = (PlyOtherElems *) myalloc (sizeof (PlyOtherElems)); + other_elems = plyfile->other_elems; + other_elems->other_list = (OtherElem *) myalloc (sizeof (OtherElem)); + other = &(other_elems->other_list[0]); + other_elems->num_elems = 1; + } + else { + other_elems = plyfile->other_elems; + other_elems->other_list = (OtherElem *) realloc (other_elems->other_list, + sizeof (OtherElem) * other_elems->num_elems + 1); + other = &(other_elems->other_list[other_elems->num_elems]); + other_elems->num_elems++; + } + + /* count of element instances in file */ + other->elem_count = elem_count; + + /* save name of element */ + other->elem_name = strdup (elem_name); + + /* create a list to hold all the current elements */ + other->other_data = (OtherData **) + malloc (sizeof (OtherData *) * other->elem_count); + + /* set up for getting elements */ + other->other_props = ply_get_other_properties (plyfile, elem_name, + offsetof(OtherData,other_props)); + + /* grab all these elements */ + for (i = 0; i < other->elem_count; i++) { + /* grab and element from the file */ + other->other_data[i] = (OtherData *) malloc (sizeof (OtherData)); + ply_get_element (plyfile, (void *) other->other_data[i]); + } + + /* return pointer to the other elements data */ + return (other_elems); +} + + +/****************************************************************************** +Write out the "other" elements specified for this PLY file. + +Entry: + plyfile - pointer to PLY file to write out other elements for +******************************************************************************/ + +void put_other_elements_ply (PlyFile *plyfile) +{ + int i,j; + OtherElem *other; + + /* make sure we have other elements to write */ + if (plyfile->other_elems == NULL) + return; + + /* write out the data for each "other" element */ + + for (i = 0; i < plyfile->other_elems->num_elems; i++) { + + other = &(plyfile->other_elems->other_list[i]); + put_element_setup_ply (plyfile, other->elem_name); + + /* write out each instance of the current element */ + for (j = 0; j < other->elem_count; j++) + put_element_ply (plyfile, (void *) other->other_data[j]); + } +} + + +/****************************************************************************** +Free up storage used by an "other" elements data structure. + +Entry: + other_elems - data structure to free up +******************************************************************************/ + +void free_other_elements_ply (PlyOtherElems *other_elems) +{ + +} + + + +/*******************/ +/* Miscellaneous */ +/*******************/ + + + +/****************************************************************************** +Close a PLY file. + +Entry: + plyfile - identifier of file to close +******************************************************************************/ + +void ply_close(PlyFile *plyfile) +{ + fclose (plyfile->fp); + + /* free up memory associated with the PLY file */ + free (plyfile); +} + + +/****************************************************************************** +Get version number and file type of a PlyFile. + +Entry: + ply - pointer to PLY file + +Exit: + version - version of the file + file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE +******************************************************************************/ + +void get_info_ply(PlyFile *ply, float *version, int *file_type) +{ + if (ply == NULL) + return; + + *version = ply->version; + *file_type = ply->file_type; +} + + +/****************************************************************************** +Compare two strings. Returns 1 if they are the same, 0 if not. +******************************************************************************/ + +int equal_strings(char *s1, char *s2) +{ + while (*s1 && *s2) + if (*s1++ != *s2++) + return (0); + + if (*s1 != *s2) + return (0); + else + return (1); +} + + +/****************************************************************************** +Re-create the command line that was used to invoke this program. + +Entry: + argc - number of words in argv + argv - array of words in command line +******************************************************************************/ + +char *recreate_command_line (int argc, char *argv[]) +{ + int i; + char *line; + int len = 0; + + /* count total number of characters needed, including separating spaces */ + for (i = 0; i < argc; i++) + len += strlen(argv[i]) + 1; + + /* create empty line */ + line = (char *) malloc (sizeof(char) * len); + line[0] = '\0'; + + /* repeatedly append argv */ + for (i = 0; i < argc; i++) { + strcat (line, argv[i]); + if (i != argc - 1) + strcat (line, " "); + } + + return (line); +} + + +/****************************************************************************** +Find an element from the element list of a given PLY object. + +Entry: + plyfile - file id for PLY file + element - name of element we're looking for + +Exit: + returns the element, or NULL if not found +******************************************************************************/ + +PlyElement *find_element(PlyFile *plyfile, char *element) +{ + int i; + + for (i = 0; i < plyfile->num_elem_types; i++) + if (equal_strings (element, plyfile->elems[i]->name)) + return (plyfile->elems[i]); + + return (NULL); +} + + +/****************************************************************************** +Find a property in the list of properties of a given element. + +Entry: + elem - pointer to element in which we want to find the property + prop_name - name of property to find + +Exit: + index - index to position in list + returns a pointer to the property, or NULL if not found +******************************************************************************/ + +PlyProperty *find_property(PlyElement *elem, char *prop_name, int *index) +{ + int i; + + for (i = 0; i < elem->nprops; i++) + if (equal_strings (prop_name, elem->props[i]->name)) { + *index = i; + return (elem->props[i]); + } + + *index = -1; + return (NULL); +} + + +/****************************************************************************** +Read an element from an ascii file. + +Entry: + plyfile - file identifier + elem_ptr - pointer to element +******************************************************************************/ + +void ascii_get_element(PlyFile *plyfile, char *elem_ptr) +{ + int j,k; + PlyElement *elem; + PlyProperty *prop; + char **words; + int nwords; + int which_word; + char *elem_data,*item = NULL; + char *item_ptr; + int item_size; + int int_val; + unsigned int uint_val; + double double_val; + int list_count; + int store_it; + char **store_array; + char *orig_line; + char *other_data = NULL; + int other_flag; + + /* the kind of element we're reading currently */ + elem = plyfile->which_elem; + + /* do we need to setup for other_props? */ + + if (elem->other_offset != NO_OTHER_PROPS) { + char **ptr; + other_flag = 1; + /* make room for other_props */ + other_data = (char *) myalloc (elem->other_size); + /* store pointer in user's structure to the other_props */ + ptr = (char **) (elem_ptr + elem->other_offset); + *ptr = other_data; + } + else + other_flag = 0; + + /* read in the element */ + + words = get_words (plyfile->fp, &nwords, &orig_line); + if (words == NULL) { + fprintf (stderr, "ply_get_element: unexpected end of file\n"); + exit (-1); + } + + which_word = 0; + + for (j = 0; j < elem->nprops; j++) { + + prop = elem->props[j]; + store_it = (elem->store_prop[j] | other_flag); + + /* store either in the user's structure or in other_props */ + if (elem->store_prop[j]) + elem_data = elem_ptr; + else + elem_data = other_data; + + if (prop->is_list == PLY_LIST) { /* a list */ + + /* get and store the number of items in the list */ + get_ascii_item (words[which_word++], prop->count_external, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->count_offset; + store_item(item, prop->count_internal, int_val, uint_val, double_val); + } + + /* allocate space for an array of items and store a ptr to the array */ + list_count = int_val; + item_size = ply_type_size[prop->internal_type]; + store_array = (char **) (elem_data + prop->offset); + + if (list_count == 0) { + if (store_it) + *store_array = NULL; + } + else { + if (store_it) { + item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count); + item = item_ptr; + *store_array = item_ptr; + } + + /* read items and store them into the array */ + for (k = 0; k < list_count; k++) { + get_ascii_item (words[which_word++], prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + store_item (item, prop->internal_type, + int_val, uint_val, double_val); + item += item_size; + } + } + } + + } + else if (prop->is_list == PLY_STRING) { /* a string */ + if (store_it) { + char *str; + char **str_ptr; + str = strdup (words[which_word++]); + item = elem_data + prop->offset; + str_ptr = (char **) item; + *str_ptr = str; + } + else { + which_word++; + } + } + else { /* a scalar */ + get_ascii_item (words[which_word++], prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->offset; + store_item (item, prop->internal_type, int_val, uint_val, double_val); + } + } + + } + + free (words); +} + + +/****************************************************************************** +Read an element from a binary file. + +Entry: + plyfile - file identifier + elem_ptr - pointer to an element +******************************************************************************/ + +void binary_get_element(PlyFile *plyfile, char *elem_ptr) +{ + int j,k; + PlyElement *elem; + PlyProperty *prop; + FILE *fp = plyfile->fp; + char *elem_data; + char *item = NULL; + char *item_ptr; + int item_size; + int int_val; + unsigned int uint_val; + double double_val; + int list_count; + int store_it; + char **store_array; + char *other_data = NULL; + int other_flag; + + /* the kind of element we're reading currently */ + elem = plyfile->which_elem; + + /* do we need to setup for other_props? */ + + if (elem->other_offset != NO_OTHER_PROPS) { + char **ptr; + other_flag = 1; + /* make room for other_props */ + other_data = (char *) myalloc (elem->other_size); + /* store pointer in user's structure to the other_props */ + ptr = (char **) (elem_ptr + elem->other_offset); + *ptr = other_data; + } + else + other_flag = 0; + + /* read in a number of elements */ + + for (j = 0; j < elem->nprops; j++) { + + prop = elem->props[j]; + store_it = (elem->store_prop[j] | other_flag); + + /* store either in the user's structure or in other_props */ + if (elem->store_prop[j]) + elem_data = elem_ptr; + else + elem_data = other_data; + + if (prop->is_list == PLY_LIST) { /* list */ + + /* get and store the number of items in the list */ + get_binary_item (fp, prop->count_external, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->count_offset; + store_item(item, prop->count_internal, int_val, uint_val, double_val); + } + + /* allocate space for an array of items and store a ptr to the array */ + list_count = int_val; + item_size = ply_type_size[prop->internal_type]; + store_array = (char **) (elem_data + prop->offset); + if (list_count == 0) { + if (store_it) + *store_array = NULL; + } + else { + if (store_it) { + item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count); + item = item_ptr; + *store_array = item_ptr; + } + + /* read items and store them into the array */ + for (k = 0; k < list_count; k++) { + get_binary_item (fp, prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + store_item (item, prop->internal_type, + int_val, uint_val, double_val); + item += item_size; + } + } + } + + } + else if (prop->is_list == PLY_STRING) { /* string */ + int len; + char *str; + fread (&len, sizeof(int), 1, fp); + str = (char *) myalloc (len); + fread (str, len, 1, fp); + if (store_it) { + char **str_ptr; + item = elem_data + prop->offset; + str_ptr = (char **) item; + *str_ptr = str; + } + } + else { /* scalar */ + get_binary_item (fp, prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->offset; + store_item (item, prop->internal_type, int_val, uint_val, double_val); + } + } + + } +} + + +/****************************************************************************** +Write to a file the word that represents a PLY data type. + +Entry: + fp - file pointer + code - code for type +******************************************************************************/ + +void write_scalar_type (FILE *fp, int code) +{ + /* make sure this is a valid code */ + + if (code <= StartType || code >= EndType) { + fprintf (stderr, "write_scalar_type: bad data code = %d\n", code); + exit (-1); + } + + /* write the code to a file */ + + fprintf (fp, "%s", type_names[code]); +} + + +/****************************************************************************** +Get a text line from a file and break it up into words. + +IMPORTANT: The calling routine should call "free" on the returned pointer once +finished with it. + +Entry: + fp - file to read from + +Exit: + nwords - number of words returned + orig_line - the original line of characters + returns a list of words from the line, or NULL if end-of-file +******************************************************************************/ + +char **get_words(FILE *fp, int *nwords, char **orig_line) +{ +#define BIG_STRING 4096 + static char str[BIG_STRING]; + static char str_copy[BIG_STRING]; + char **words; + int max_words = 10; + int num_words = 0; + char *ptr,*ptr2; + char *result; + + words = (char **) myalloc (sizeof (char *) * max_words); + + /* read in a line */ + result = fgets (str, BIG_STRING, fp); + if (result == NULL) { + *nwords = 0; + *orig_line = NULL; + return (NULL); + } + + /* convert line-feed and tabs into spaces */ + /* (this guarentees that there will be a space before the */ + /* null character at the end of the string) */ + + str[BIG_STRING-2] = ' '; + str[BIG_STRING-1] = '\0'; + + for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) { + *ptr2 = *ptr; + if (*ptr == '\t') { + *ptr = ' '; + *ptr2 = ' '; + } + else if (*ptr == '\n') { + *ptr = ' '; + *ptr2 = '\0'; + break; + } + } + + /* find the words in the line */ + + ptr = str; + while (*ptr != '\0') { + + /* jump over leading spaces */ + while (*ptr == ' ') + ptr++; + + /* break if we reach the end */ + if (*ptr == '\0') + break; + + /* allocate more room for words if necessary */ + if (num_words >= max_words) { + max_words += 10; + words = (char **) realloc (words, sizeof (char *) * max_words); + } + + if (*ptr == '\"') { /* a quote indidicates that we have a string */ + + /* skip over leading quote */ + ptr++; + + /* save pointer to beginning of word */ + words[num_words++] = ptr; + + /* find trailing quote or end of line */ + while (*ptr != '\"' && *ptr != '\0') + ptr++; + + /* replace quote with a null character to mark the end of the word */ + /* if we are not already at the end of the line */ + if (*ptr != '\0') + *ptr++ = '\0'; + } + else { /* non-string */ + + /* save pointer to beginning of word */ + words[num_words++] = ptr; + + /* jump over non-spaces */ + while (*ptr != ' ') + ptr++; + + /* place a null character here to mark the end of the word */ + *ptr++ = '\0'; + } + } + + /* return the list of words */ + *nwords = num_words; + *orig_line = str_copy; + return (words); +} + + +/****************************************************************************** +Return the value of an item, given a pointer to it and its type. + +Entry: + item - pointer to item + type - data type that "item" points to + +Exit: + returns a double-precision float that contains the value of the item +******************************************************************************/ + +double get_item_value(char *item, int type) +{ + unsigned char *puchar; + char *pchar; + short int *pshort; + unsigned short int *pushort; + int *pint; + unsigned int *puint; + float *pfloat; + double *pdouble; + int int_value; + unsigned int uint_value; + double double_value; + + switch (type) { + case Int8: + pchar = (char *) item; + int_value = *pchar; + return ((double) int_value); + case Uint8: + puchar = (unsigned char *) item; + int_value = *puchar; + return ((double) int_value); + case Int16: + pshort = (short int *) item; + int_value = *pshort; + return ((double) int_value); + case Uint16: + pushort = (unsigned short int *) item; + int_value = *pushort; + return ((double) int_value); + case Int32: + pint = (int *) item; + int_value = *pint; + return ((double) int_value); + case Uint32: + puint = (unsigned int *) item; + uint_value = *puint; + return ((double) uint_value); + case Float32: + pfloat = (float *) item; + double_value = *pfloat; + return (double_value); + case Float64: + pdouble = (double *) item; + double_value = *pdouble; + return (double_value); + default: + fprintf (stderr, "get_item_value: bad type = %d\n", type); + exit (-1); + } + + return (0.0); /* never actually gets here */ +} + + +/****************************************************************************** +Write out an item to a file as raw binary bytes. + +Entry: + fp - file to write to + int_val - integer version of item + uint_val - unsigned integer version of item + double_val - double-precision float version of item + type - data type to write out +******************************************************************************/ + +void write_binary_item( + FILE *fp, + int int_val, + unsigned int uint_val, + double double_val, + int type +) +{ + unsigned char uchar_val; + char char_val; + unsigned short ushort_val; + short short_val; + float float_val; + + switch (type) { + case Int8: + char_val = int_val; + fwrite (&char_val, 1, 1, fp); + break; + case Int16: + short_val = int_val; + fwrite (&short_val, 2, 1, fp); + break; + case Int32: + fwrite (&int_val, 4, 1, fp); + break; + case Uint8: + uchar_val = uint_val; + fwrite (&uchar_val, 1, 1, fp); + break; + case Uint16: + ushort_val = uint_val; + fwrite (&ushort_val, 2, 1, fp); + break; + case Uint32: + fwrite (&uint_val, 4, 1, fp); + break; + case Float32: + float_val = double_val; + fwrite (&float_val, 4, 1, fp); + break; + case Float64: + fwrite (&double_val, 8, 1, fp); + break; + default: + fprintf (stderr, "write_binary_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Write out an item to a file as ascii characters. + +Entry: + fp - file to write to + int_val - integer version of item + uint_val - unsigned integer version of item + double_val - double-precision float version of item + type - data type to write out +******************************************************************************/ + +void write_ascii_item( + FILE *fp, + int int_val, + unsigned int uint_val, + double double_val, + int type +) +{ + switch (type) { + case Int8: + case Int16: + case Int32: + fprintf (fp, "%d ", int_val); + break; + case Uint8: + case Uint16: + case Uint32: + fprintf (fp, "%u ", uint_val); + break; + case Float32: + case Float64: + fprintf (fp, "%g ", double_val); + break; + default: + fprintf (stderr, "write_ascii_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Get the value of an item that is in memory, and place the result +into an integer, an unsigned integer and a double. + +Entry: + ptr - pointer to the item + type - data type supposedly in the item + +Exit: + int_val - integer value + uint_val - unsigned integer value + double_val - double-precision floating point value +******************************************************************************/ + +void get_stored_item( + void *ptr, + int type, + int *int_val, + unsigned int *uint_val, + double *double_val +) +{ + switch (type) { + case Int8: + *int_val = *((char *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case Uint8: + *uint_val = *((unsigned char *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case Int16: + *int_val = *((short int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case Uint16: + *uint_val = *((unsigned short int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case Int32: + *int_val = *((int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case Uint32: + *uint_val = *((unsigned int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case Float32: + *double_val = *((float *) ptr); + *int_val = *double_val; + *uint_val = *double_val; + break; + case Float64: + *double_val = *((double *) ptr); + *int_val = *double_val; + *uint_val = *double_val; + break; + default: + fprintf (stderr, "get_stored_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Get the value of an item from a binary file, and place the result +into an integer, an unsigned integer and a double. + +Entry: + fp - file to get item from + type - data type supposedly in the word + +Exit: + int_val - integer value + uint_val - unsigned integer value + double_val - double-precision floating point value +******************************************************************************/ + +void get_binary_item( + FILE *fp, + int type, + int *int_val, + unsigned int *uint_val, + double *double_val +) +{ + char c[8]; + void *ptr; + + ptr = (void *) c; + + switch (type) { + case Int8: + fread (ptr, 1, 1, fp); + *int_val = *((char *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case Uint8: + fread (ptr, 1, 1, fp); + *uint_val = *((unsigned char *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case Int16: + fread (ptr, 2, 1, fp); + *int_val = *((short int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case Uint16: + fread (ptr, 2, 1, fp); + *uint_val = *((unsigned short int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case Int32: + fread (ptr, 4, 1, fp); + *int_val = *((int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case Uint32: + fread (ptr, 4, 1, fp); + *uint_val = *((unsigned int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case Float32: + fread (ptr, 4, 1, fp); + *double_val = *((float *) ptr); + *int_val = *double_val; + *uint_val = *double_val; + break; + case Float64: + fread (ptr, 8, 1, fp); + *double_val = *((double *) ptr); + *int_val = *double_val; + *uint_val = *double_val; + break; + default: + fprintf (stderr, "get_binary_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Extract the value of an item from an ascii word, and place the result +into an integer, an unsigned integer and a double. + +Entry: + word - word to extract value from + type - data type supposedly in the word + +Exit: + int_val - integer value + uint_val - unsigned integer value + double_val - double-precision floating point value +******************************************************************************/ + +void get_ascii_item( + char *word, + int type, + int *int_val, + unsigned int *uint_val, + double *double_val +) +{ + switch (type) { + case Int8: + case Uint8: + case Int16: + case Uint16: + case Int32: + *int_val = atoi (word); + *uint_val = *int_val; + *double_val = *int_val; + break; + + case Uint32: + *uint_val = strtoul (word, (char **) NULL, 10); + *int_val = *uint_val; + *double_val = *uint_val; + break; + + case Float32: + case Float64: + *double_val = atof (word); + *int_val = (int) *double_val; + *uint_val = (unsigned int) *double_val; + break; + + default: + fprintf (stderr, "get_ascii_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Store a value into a place being pointed to, guided by a data type. + +Entry: + item - place to store value + type - data type + int_val - integer version of value + uint_val - unsigned integer version of value + double_val - double version of value + +Exit: + item - pointer to stored value +******************************************************************************/ + +void store_item ( + char *item, + int type, + int int_val, + unsigned int uint_val, + double double_val +) +{ + unsigned char *puchar; + short int *pshort; + unsigned short int *pushort; + int *pint; + unsigned int *puint; + float *pfloat; + double *pdouble; + + switch (type) { + case Int8: + *item = int_val; + break; + case Uint8: + puchar = (unsigned char *) item; + *puchar = uint_val; + break; + case Int16: + pshort = (short *) item; + *pshort = int_val; + break; + case Uint16: + pushort = (unsigned short *) item; + *pushort = uint_val; + break; + case Int32: + pint = (int *) item; + *pint = int_val; + break; + case Uint32: + puint = (unsigned int *) item; + *puint = uint_val; + break; + case Float32: + pfloat = (float *) item; + *pfloat = double_val; + break; + case Float64: + pdouble = (double *) item; + *pdouble = double_val; + break; + default: + fprintf (stderr, "store_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Add an element to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + words - list of words describing the element + nwords - number of words in the list +******************************************************************************/ + +void add_element (PlyFile *plyfile, char **words, int nwords) +{ + PlyElement *elem; + + /* create the new element */ + elem = (PlyElement *) myalloc (sizeof (PlyElement)); + elem->name = strdup (words[1]); + elem->num = atoi (words[2]); + elem->nprops = 0; + + /* make room for new element in the object's list of elements */ + if (plyfile->num_elem_types == 0) + plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *)); + else + plyfile->elems = (PlyElement **) realloc (plyfile->elems, + sizeof (PlyElement *) * (plyfile->num_elem_types + 1)); + + /* add the new element to the object's list */ + plyfile->elems[plyfile->num_elem_types] = elem; + plyfile->num_elem_types++; +} + + +/****************************************************************************** +Return the type of a property, given the name of the property. + +Entry: + name - name of property type + +Exit: + returns integer code for property, or 0 if not found +******************************************************************************/ + +int get_prop_type(char *type_name) +{ + int i; + + /* try to match the type name */ + for (i = StartType + 1; i < EndType; i++) + if (equal_strings (type_name, type_names[i])) + return (i); + + /* see if we can match an old type name */ + for (i = StartType + 1; i < EndType; i++) + if (equal_strings (type_name, old_type_names[i])) + return (i); + + /* if we get here, we didn't find the type */ + return (0); +} + + +/****************************************************************************** +Add a property to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + words - list of words describing the property + nwords - number of words in the list +******************************************************************************/ + +void add_property (PlyFile *plyfile, char **words, int nwords) +{ + PlyProperty *prop; + PlyElement *elem; + + /* create the new property */ + + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + + if (equal_strings (words[1], "list")) { /* list */ + prop->count_external = get_prop_type (words[2]); + prop->external_type = get_prop_type (words[3]); + prop->name = strdup (words[4]); + prop->is_list = PLY_LIST; + } + else if (equal_strings (words[1], "string")) { /* string */ + prop->count_external = Int8; + prop->external_type = Int8; + prop->name = strdup (words[2]); + prop->is_list = PLY_STRING; + } + else { /* scalar */ + prop->external_type = get_prop_type (words[1]); + prop->name = strdup (words[2]); + prop->is_list = PLY_SCALAR; + } + + /* add this property to the list of properties of the current element */ + + elem = plyfile->elems[plyfile->num_elem_types - 1]; + + if (elem->nprops == 0) + elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *)); + else + elem->props = (PlyProperty **) realloc (elem->props, + sizeof (PlyProperty *) * (elem->nprops + 1)); + + elem->props[elem->nprops] = prop; + elem->nprops++; +} + + +/****************************************************************************** +Add a comment to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + line - line containing comment +******************************************************************************/ + +void add_comment (PlyFile *plyfile, char *line) +{ + int i; + + /* skip over "comment" and leading spaces and tabs */ + i = 7; + while (line[i] == ' ' || line[i] == '\t') + i++; + + append_comment_ply (plyfile, &line[i]); +} + + +/****************************************************************************** +Add a some object information to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + line - line containing text info +******************************************************************************/ + +void add_obj_info (PlyFile *plyfile, char *line) +{ + int i; + + /* skip over "obj_info" and leading spaces and tabs */ + i = 8; + while (line[i] == ' ' || line[i] == '\t') + i++; + + append_obj_info_ply (plyfile, &line[i]); +} + + +/****************************************************************************** +Copy a property. +******************************************************************************/ + +void copy_property(PlyProperty *dest, PlyProperty *src) +{ + dest->name = strdup (src->name); + dest->external_type = src->external_type; + dest->internal_type = src->internal_type; + dest->offset = src->offset; + + dest->is_list = src->is_list; + dest->count_external = src->count_external; + dest->count_internal = src->count_internal; + dest->count_offset = src->count_offset; +} + + +/****************************************************************************** +Allocate some memory. + +Entry: + size - amount of memory requested (in bytes) + lnum - line number from which memory was requested + fname - file name from which memory was requested +******************************************************************************/ + +static char *my_alloc(int size, int lnum, char *fname) +{ + char *ptr; + + ptr = (char *) malloc (size); + + if (ptr == 0) { + fprintf(stderr, "Memory allocation bombed on line %d in %s\n", lnum, fname); + } + + return (ptr); +} + + +/**** NEW STUFF ****/ +/**** NEW STUFF ****/ +/**** NEW STUFF ****/ +/**** NEW STUFF ****/ + + + +/****************************************************************************** +Given a file pointer, get ready to read PLY data from the file. + +Entry: + fp - the given file pointer + +Exit: + nelems - number of elements in object + elem_names - list of element names + returns a pointer to a PlyFile, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *read_ply(FILE *fp) +{ + PlyFile *ply; + int num_elems; + char **elem_names; + + ply = ply_read (fp, &num_elems, &elem_names); + + return (ply); +} + + +/****************************************************************************** +Given a file pointer, get ready to write PLY data to the file. + +Entry: + fp - the given file pointer + nelems - number of elements in object + elem_names - list of element names + file_type - file type, either ascii or binary + +Exit: + returns a pointer to a PlyFile, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *write_ply( + FILE *fp, + int nelems, + char **elem_names, + int file_type +) +{ + PlyFile *ply; + + ply = ply_write (fp, nelems, elem_names, file_type); + + return (ply); +} + + +/****************************************************************************** +Return a list of the names of the elements in a particular PLY file. + +Entry: + ply - PLY file whose element name list we want + +Exit: + num_elems - the number of element names in the list + returns the list of names +******************************************************************************/ + +char **get_element_list_ply(PlyFile *ply, int *num_elems) +{ + int i; + char **elist; + + /* create the list of element names */ + + elist = (char **) myalloc (sizeof (char *) * ply->num_elem_types); + for (i = 0; i < ply->num_elem_types; i++) + elist[i] = strdup (ply->elems[i]->name); + + /* return the number of elements and the list of element names */ + *num_elems = ply->num_elem_types; + return (elist); +} + + +/****************************************************************************** +Append a comment to a PLY file. + +Entry: + ply - file to append comment to + comment - the comment to append +******************************************************************************/ + +void append_comment_ply(PlyFile *ply, char *comment) +{ + /* (re)allocate space for new comment */ + if (ply->num_comments == 0) + ply->comments = (char **) myalloc (sizeof (char *)); + else + ply->comments = (char **) realloc (ply->comments, + sizeof (char *) * (ply->num_comments + 1)); + + /* add comment to list */ + ply->comments[ply->num_comments] = strdup (comment); + ply->num_comments++; +} + + +/****************************************************************************** +Copy the comments from one PLY file to another. + +Entry: + out_ply - destination file to copy comments to + in_ply - the source of the comments +******************************************************************************/ + +void copy_comments_ply(PlyFile *out_ply, PlyFile *in_ply) +{ + int i; + + for (i = 0; i < in_ply->num_comments; i++) + append_comment_ply (out_ply, in_ply->comments[i]); +} + + +/****************************************************************************** +Append object information (arbitrary text) to a PLY file. + +Entry: + ply - file to append object info to + obj_info - the object info to append +******************************************************************************/ + +void append_obj_info_ply(PlyFile *ply, char *obj_info) +{ + /* (re)allocate space for new info */ + if (ply->num_obj_info == 0) + ply->obj_info = (char **) myalloc (sizeof (char *)); + else + ply->obj_info = (char **) realloc (ply->obj_info, + sizeof (char *) * (ply->num_obj_info + 1)); + + /* add info to list */ + ply->obj_info[ply->num_obj_info] = strdup (obj_info); + ply->num_obj_info++; +} + + +/****************************************************************************** +Copy the object information from one PLY file to another. + +Entry: + out_ply - destination file to copy object information to + in_ply - the source of the object information +******************************************************************************/ + +void copy_obj_info_ply(PlyFile *out_ply, PlyFile *in_ply) +{ + int i; + + for (i = 0; i < in_ply->num_obj_info; i++) + append_obj_info_ply (out_ply, in_ply->obj_info[i]); +} + + +/****************************************************************************** +Close a PLY file. + +Entry: + plyfile - identifier of file to close +******************************************************************************/ + +void close_ply(PlyFile *plyfile) +{ + fclose (plyfile->fp); +} + + +/****************************************************************************** +Free the memory used by a PLY file. + +Entry: + plyfile - identifier of file +******************************************************************************/ + +void free_ply(PlyFile *plyfile) +{ + /* free up memory associated with the PLY file */ + free (plyfile); +} + + +/****************************************************************************** +Specify the index of the next element to be read in from a PLY file. + +Entry: + ply - file to read from + index - index of the element to be read + +Exit: + elem_count - the number of elements in the file + returns pointer to the name of this next element +******************************************************************************/ + +char *setup_element_read_ply (PlyFile *ply, int index, int *elem_count) +{ + PlyElement *elem; + + if (index < 0 || index > ply->num_elem_types) { + fprintf (stderr, "Warning: No element with index %d\n", index); + return (0); + } + + elem = ply->elems[index]; + + /* set this to be the current element */ + ply->which_elem = elem; + + /* return the number of such elements in the file and the element's name */ + *elem_count = elem->num; + return (elem->name); +} + + +/****************************************************************************** +Read one element from the file. This routine assumes that we're reading +the type of element specified in the last call to the routine +setup_element_read_ply(). + +Entry: + plyfile - file identifier + elem_ptr - pointer to location where the element information should be put +******************************************************************************/ + +void get_element_ply (PlyFile *plyfile, void *elem_ptr) +{ + if (plyfile->file_type == PLY_ASCII) + ascii_get_element (plyfile, (char *) elem_ptr); + else + binary_get_element (plyfile, (char *) elem_ptr); +} + + +/****************************************************************************** +Specify one of several properties of the current element that is to be +read from a file. This should be called (usually multiple times) before a +call to the routine get_element_ply(). + +Entry: + plyfile - file identifier + prop - property to add to those that will be returned +******************************************************************************/ + +void setup_property_ply( + PlyFile *plyfile, + PlyProperty *prop +) +{ + PlyElement *elem; + PlyProperty *prop_ptr; + int index; + + elem = plyfile->which_elem; + + /* deposit the property information into the element's description */ + + prop_ptr = find_property (elem, prop->name, &index); + if (prop_ptr == NULL) { + fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n", + prop->name, elem->name); + return; + } + prop_ptr->internal_type = prop->internal_type; + prop_ptr->offset = prop->offset; + prop_ptr->count_internal = prop->count_internal; + prop_ptr->count_offset = prop->count_offset; + + /* specify that the user wants this property */ + elem->store_prop[index] = STORE_PROP; +} + + +/****************************************************************************** +Specify that we want the "other" properties of the current element to be tucked +away within the user's structure. + +Entry: + plyfile - file identifier + offset - offset to where other_props will be stored inside user's structure + +Exit: + returns pointer to structure containing description of other_props +******************************************************************************/ + +PlyOtherProp *get_other_properties_ply( + PlyFile *plyfile, + int offset +) +{ + PlyOtherProp *other; + + other = get_other_properties (plyfile, plyfile->which_elem, offset); + return (other); +} + + +/****************************************************************************** +Describe which element is to be written next and state how many of them will +be written. + +Entry: + plyfile - file identifier + elem_name - name of element that information is being described + nelems - number of elements of this type to be written +******************************************************************************/ + +void describe_element_ply( + PlyFile *plyfile, + char *elem_name, + int nelems +) +{ + PlyElement *elem; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr,"describe_element_ply: can't find element '%s'\n",elem_name); + exit (-1); + } + + elem->num = nelems; + + /* now this element is the current element */ + plyfile->which_elem = elem; +} + + +/****************************************************************************** +Describe a property of an element. + +Entry: + plyfile - file identifier + prop - the new property +******************************************************************************/ + +void describe_property_ply( + PlyFile *plyfile, + PlyProperty *prop +) +{ + PlyElement *elem; + PlyProperty *elem_prop; + + elem = plyfile->which_elem; + + /* create room for new property */ + + if (elem->nprops == 0) { + elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *)); + elem->store_prop = (char *) myalloc (sizeof (char)); + elem->nprops = 1; + } + else { + elem->nprops++; + elem->props = (PlyProperty **) + realloc (elem->props, sizeof (PlyProperty *) * elem->nprops); + elem->store_prop = (char *) + realloc (elem->store_prop, sizeof (char) * elem->nprops); + } + + /* copy the new property */ + + elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + elem->props[elem->nprops - 1] = elem_prop; + elem->store_prop[elem->nprops - 1] = NAMED_PROP; + copy_property (elem_prop, prop); +} + + +/****************************************************************************** +Describe what the "other" properties are that are to be stored, and where +they are in an element. +******************************************************************************/ + +void describe_other_properties_ply( + PlyFile *plyfile, + PlyOtherProp *other, + int offset +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + + /* look for appropriate element */ + elem = find_element (plyfile, other->name); + if (elem == NULL) { + fprintf(stderr, "describe_other_properties_ply: can't find element '%s'\n", + other->name); + return; + } + + /* create room for other properties */ + + if (elem->nprops == 0) { + elem->props = (PlyProperty **) + myalloc (sizeof (PlyProperty *) * other->nprops); + elem->store_prop = (char *) myalloc (sizeof (char) * other->nprops); + elem->nprops = 0; + } + else { + int newsize; + newsize = elem->nprops + other->nprops; + elem->props = (PlyProperty **) + realloc (elem->props, sizeof (PlyProperty *) * newsize); + elem->store_prop = (char *) + realloc (elem->store_prop, sizeof (char) * newsize); + } + + /* copy the other properties */ + + for (i = 0; i < other->nprops; i++) { + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + copy_property (prop, other->props[i]); + elem->props[elem->nprops] = prop; + elem->store_prop[elem->nprops] = OTHER_PROP; + elem->nprops++; + } + + /* save other info about other properties */ + elem->other_size = other->size; + elem->other_offset = offset; +} + + +/****************************************************************************** +Pass along a pointer to "other" elements that we want to save in a given +PLY file. These other elements were presumably read from another PLY file. + +Entry: + plyfile - file pointer in which to store this other element info + other_elems - info about other elements that we want to store +******************************************************************************/ + +void describe_other_elements_ply ( + PlyFile *plyfile, + PlyOtherElems *other_elems +) +{ + int i; + OtherElem *other; + + /* ignore this call if there is no other element */ + if (other_elems == NULL) + return; + + /* save pointer to this information */ + plyfile->other_elems = other_elems; + + /* describe the other properties of this element */ + + for (i = 0; i < other_elems->num_elems; i++) { + other = &(other_elems->other_list[i]); + element_count_ply (plyfile, other->elem_name, other->elem_count); + describe_other_properties_ply (plyfile, other->other_props, + offsetof(OtherData,other_props)); + } +} + + + +/**** Property Propagation Rules ****/ + + +typedef struct RuleName { + int code; + char *name; +} RuleName; + +RuleName rule_name_list[] = { + { AVERAGE_RULE, "avg", }, + { RANDOM_RULE, "rnd", }, + { MINIMUM_RULE, "max", }, + { MAXIMUM_RULE, "min", }, + { MAJORITY_RULE, "major", }, + { SAME_RULE, "same", }, + { -1, "end_marker", }, +}; + + + +/****************************************************************************** +Initialize the property propagation rules for an element. Default is to +use averaging (AVERAGE_RULE) for creating all new properties. + +Entry: + ply - PLY object that this is for + elem_name - name of the element that we're making the rules for + +Exit: + returns pointer to the default rules +******************************************************************************/ + +PlyPropRules *init_rule_ply (PlyFile *ply, char *elem_name) +{ + int i,j; + PlyElement *elem; + PlyPropRules *rules; + PlyRuleList *list; + int found_prop; + + elem = find_element (ply, elem_name); + if (elem == NULL) { + fprintf (stderr, "init_rule_ply: Can't find element '%s'\n", elem_name); + exit (-1); + } + + rules = (PlyPropRules *) myalloc (sizeof (PlyPropRules)); + rules->elem = elem; + rules->rule_list = (int *) myalloc (sizeof(int) * elem->nprops); + rules->max_props = 0; + rules->nprops = 0; + + /* default is to use averaging rule */ + for (i = 0; i < elem->nprops; i++) + rules->rule_list[i] = AVERAGE_RULE; + + /* see if there are other rules we should use */ + + if (ply->rule_list == NULL) + return (rules); + + /* try to match the element, property and rule name */ + + for (list = ply->rule_list; list != NULL; list = list->next) { + + if (!equal_strings (list->element, elem->name)) + continue; + + found_prop = 0; + + for (i = 0; i < elem->nprops; i++) + if (equal_strings (list->property, elem->props[i]->name)) { + + found_prop = 1; + + /* look for matching rule name */ + for (j = 0; rule_name_list[j].code != -1; j++) + if (equal_strings (list->name, rule_name_list[j].name)) { + rules->rule_list[i] = rule_name_list[j].code; + break; + } + } + + if (!found_prop) { + fprintf (stderr, "Can't find property '%s' for rule '%s'\n", + list->property, list->name); + continue; + } + } + + return (rules); +} + + +/****************************************************************************** +Modify a property propagation rule. + +Entry: + rules - rules for the element + prop_name - name of the property whose rule we're modifying + rule_type - type of rule (MAXIMUM_RULE, MINIMUM_RULE, MAJORITY_RULE, etc.) +******************************************************************************/ + +void modify_rule_ply (PlyPropRules *rules, char *prop_name, int rule_type) +{ + int i; + PlyElement *elem = rules->elem; + + /* find the property and modify its rule type */ + + for (i = 0; i < elem->nprops; i++) + if (equal_strings (elem->props[i]->name, prop_name)) { + rules->rule_list[i] = rule_type; + return; + } + + /* we didn't find the property if we get here */ + fprintf (stderr, "modify_rule_ply: Can't find property '%s'\n", prop_name); + exit (-1); +} + + +/****************************************************************************** +Begin to create a set of properties from a set of propagation rules. + +Entry: + ply - PLY object whose rules we're preparing to use + rules - rules for the element +******************************************************************************/ + +void start_props_ply (PlyFile *ply, PlyPropRules *rules) +{ + /* save pointer to the rules in the PLY object */ + ply->current_rules = rules; + + /* get ready for new sets of properties to combine */ + rules->nprops = 0; +} + + +/****************************************************************************** +Remember a set of properties and their weights for creating a new set of +properties. + +Entry: + weight - weights for this set of properties + other_props - the properties to use +******************************************************************************/ + +void weight_props_ply (PlyFile *ply, float weight, void *other_props) +{ + PlyPropRules *rules = ply->current_rules; + + /* allocate space for properties and weights, if necessary */ + if (rules->max_props == 0) { + rules->max_props = 6; + rules->props = (void **) myalloc (sizeof (void *) * rules->max_props); + rules->weights = (float *) myalloc (sizeof (float) * rules->max_props); + } + if (rules->nprops == rules->max_props) { + rules->max_props *= 2; + rules->props = (void **) realloc (rules->props, + sizeof (void *) * rules->max_props); + rules->weights = (float *) realloc (rules->weights, + sizeof (float) * rules->max_props); + } + + /* remember these new properties and their weights */ + + rules->props[rules->nprops] = other_props; + rules->weights[rules->nprops] = weight; + rules->nprops++; +} + + +/****************************************************************************** +Return a pointer to a new set of properties that have been created using +a specified set of property combination rules and a given collection of +"other" properties. + +Exit: + returns a pointer to the new properties +******************************************************************************/ + +void *get_new_props_ply(PlyFile *ply) +{ + int i,j; + static double *vals; + static int max_vals = 0; + PlyPropRules *rules = ply->current_rules; + PlyElement *elem = rules->elem; + PlyProperty *prop; + char *data; + char *new_data; + void *ptr; + int offset; + int type; + double double_val; + int int_val; + unsigned int uint_val; + int random_pick; + + /* return NULL if we've got no "other" properties */ + if (elem->other_size == 0) { + return (NULL); + } + + /* create room for combined other properties */ + new_data = (char *) myalloc (sizeof (char) * elem->other_size); + + /* make sure there is enough room to store values we're to combine */ + + if (max_vals == 0) { + max_vals = rules->nprops; + vals = (double *) myalloc (sizeof (double) * rules->nprops); + } + if (rules->nprops >= max_vals) { + max_vals = rules->nprops; + vals = (double *) realloc (vals, sizeof (double) * rules->nprops); + } + + /* in case we need a random choice */ +#ifdef WIN32 +#define drand48(x) (rand(x)/(float)RAND_MAX) +#endif + random_pick = (int) floor (rules->nprops * drand48()); + + /* calculate the combination for each "other" property of the element */ + + for (i = 0; i < elem->nprops; i++) { + + /* don't bother with properties we've been asked to store explicitly */ + if (elem->store_prop[i]) + continue; + + prop = elem->props[i]; + offset = prop->offset; + type = prop->external_type; + + /* collect together all the values we're to combine */ + + for (j = 0; j < rules->nprops; j++) { + data = (char *) rules->props[j]; + ptr = (void *) (data + offset); + get_stored_item ((void *) ptr, type, &int_val, &uint_val, &double_val); + vals[j] = double_val; + } + + /* calculate the combined value */ + + switch (rules->rule_list[i]) { + case AVERAGE_RULE: { + double sum = 0; + double weight_sum = 0; + for (j = 0; j < rules->nprops; j++) { + sum += vals[j] * rules->weights[j]; + weight_sum += rules->weights[j]; + } + double_val = sum / weight_sum; + break; + } + case MINIMUM_RULE: { + double_val = vals[0]; + for (j = 1; j < rules->nprops; j++) + if (double_val > vals[j]) + double_val = vals[j]; + break; + } + case MAXIMUM_RULE: { + double_val = vals[0]; + for (j = 1; j < rules->nprops; j++) + if (double_val < vals[j]) + double_val = vals[j]; + break; + } + case RANDOM_RULE: { + double_val = vals[random_pick]; + break; + } + case SAME_RULE: { + double_val = vals[0]; + for (j = 1; j < rules->nprops; j++) + if (double_val != vals[j]) { + fprintf (stderr, + "get_new_props_ply: Error combining properties that should be the same.\n"); + exit (-1); + } + break; + } + default: + fprintf (stderr, "get_new_props_ply: Bad rule = %d\n", + rules->rule_list[i]); + exit (-1); + } + + /* store the combined value */ + + int_val = (int) double_val; + uint_val = (unsigned int) double_val; + ptr = (void *) (new_data + offset); + store_item ((char *) ptr, type, int_val, uint_val, double_val); + } + + return ((void *) new_data); +} + + +/****************************************************************************** +Set the list of user-specified property combination rules. +******************************************************************************/ + +void set_prop_rules_ply (PlyFile *ply, PlyRuleList *prop_rules) +{ + ply->rule_list = prop_rules; +} + + +/****************************************************************************** +Append a property rule to a growing list of user-specified rules. + +Entry: + rule_list - current rule list + name - name of property combination rule + property - "element.property" says which property the rule affects + +Exit: + returns pointer to the new rule list +******************************************************************************/ + +PlyRuleList *append_prop_rule ( + PlyRuleList *rule_list, + char *name, + char *property +) +{ + PlyRuleList *rule; + PlyRuleList *rule_ptr; + char *str,*str2; + char *ptr; + + /* find . */ + str = strdup (property); + for (ptr = str; *ptr != '\0' && *ptr != '.'; ptr++) ; + + /* split string at . */ + if (*ptr == '.') { + *ptr = '\0'; + str2 = ptr + 1; + } + else { + fprintf (stderr, "Can't find property '%s' for rule '%s'\n", + property, name); + return (rule_list); + } + + rule = (PlyRuleList *) malloc (sizeof (PlyRuleList)); + rule->name = name; + rule->element = str; + rule->property = str2; + rule->next = NULL; + + /* either start rule list or append to it */ + + if (rule_list == NULL) + rule_list = rule; + else { /* append new rule to current list */ + rule_ptr = rule_list; + while (rule_ptr->next != NULL) + rule_ptr = rule_ptr->next; + rule_ptr->next = rule; + } + + /* return pointer to list */ + + return (rule_list); +} + + +/****************************************************************************** +See if a name matches the name of any property combination rules. + +Entry: + name - name of rule we're trying to match + +Exit: + returns 1 if we find a match, 0 if not +******************************************************************************/ + +int matches_rule_name (char *name) +{ + int i; + + for (i = 0; rule_name_list[i].code != -1; i++) + if (equal_strings (rule_name_list[i].name, name)) + return (1); + + return (0); +} + diff --git a/tools/ply.h b/tools/ply.h new file mode 100644 index 0000000..127844c --- /dev/null +++ b/tools/ply.h @@ -0,0 +1,233 @@ +/* + +Header for PLY polygon files. + +- Greg Turk + +A PLY file contains a single polygonal _object_. + +An object is composed of lists of _elements_. Typical elements are +vertices, faces, edges and materials. + +Each type of element for a given object has one or more _properties_ +associated with the element type. For instance, a vertex element may +have as properties three floating-point values x,y,z and three unsigned +chars for red, green and blue. + +----------------------------------------------------------------------- + +Copyright (c) 1998 Georgia Institute of Technology. All rights reserved. + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose is hereby granted without fee, provided +that the above copyright notice and this permission notice appear in +all copies of this software and that you do not sell the software. + +THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, +EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +*/ + +#ifndef __PLY_H__ +#define __PLY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define PLY_ASCII 1 /* ascii PLY file */ +#define PLY_BINARY_BE 2 /* binary PLY file, big endian */ +#define PLY_BINARY_LE 3 /* binary PLY file, little endian */ + +#define PLY_OKAY 0 /* ply routine worked okay */ +#define PLY_ERROR -1 /* error in ply routine */ + +/* scalar data types supported by PLY format */ + +#define StartType 0 +#define Int8 1 +#define Int16 2 +#define Int32 3 +#define Uint8 4 +#define Uint16 5 +#define Uint32 6 +#define Float32 7 +#define Float64 8 +#define EndType 9 + +#define PLY_SCALAR 0 +#define PLY_LIST 1 +#define PLY_STRING 2 + + +typedef struct PlyProperty { /* description of a property */ + + char *name; /* property name */ + int external_type; /* file's data type */ + int internal_type; /* program's data type */ + int offset; /* offset bytes of prop in a struct */ + + int is_list; /* 0 = scalar, 1 = list, 2 = char string */ + int count_external; /* file's count type */ + int count_internal; /* program's count type */ + int count_offset; /* offset byte for list count */ + +} PlyProperty; + +typedef struct PlyElement { /* description of an element */ + char *name; /* element name */ + int num; /* number of elements in this object */ + int size; /* size of element (bytes) or -1 if variable */ + int nprops; /* number of properties for this element */ + PlyProperty **props; /* list of properties in the file */ + char *store_prop; /* flags: property wanted by user? */ + int other_offset; /* offset to un-asked-for props, or -1 if none*/ + int other_size; /* size of other_props structure */ +} PlyElement; + +typedef struct PlyOtherProp { /* describes other properties in an element */ + char *name; /* element name */ + int size; /* size of other_props */ + int nprops; /* number of properties in other_props */ + PlyProperty **props; /* list of properties in other_props */ +} PlyOtherProp; + +typedef struct OtherData { /* for storing other_props for an other element */ + void *other_props; +} OtherData; + +typedef struct OtherElem { /* data for one "other" element */ + char *elem_name; /* names of other elements */ + int elem_count; /* count of instances of each element */ + OtherData **other_data; /* actual property data for the elements */ + PlyOtherProp *other_props; /* description of the property data */ +} OtherElem; + +typedef struct PlyOtherElems { /* "other" elements, not interpreted by user */ + int num_elems; /* number of other elements */ + OtherElem *other_list; /* list of data for other elements */ +} PlyOtherElems; + +#define AVERAGE_RULE 1 +#define MAJORITY_RULE 2 +#define MINIMUM_RULE 3 +#define MAXIMUM_RULE 4 +#define SAME_RULE 5 +#define RANDOM_RULE 6 + +typedef struct PlyPropRules { /* rules for combining "other" properties */ + PlyElement *elem; /* element whose rules we are making */ + int *rule_list; /* types of rules (AVERAGE_PLY, MAJORITY_PLY, etc.) */ + int nprops; /* number of properties we're combining so far */ + int max_props; /* maximum number of properties we have room for now */ + void **props; /* list of properties we're combining */ + float *weights; /* list of weights of the properties */ +} PlyPropRules; + +typedef struct PlyRuleList { + char *name; /* name of the rule */ + char *element; /* name of element that rule applies to */ + char *property; /* name of property that rule applies to */ + struct PlyRuleList *next; /* pointer for linked list of rules */ +} PlyRuleList; + +typedef struct PlyFile { /* description of PLY file */ + FILE *fp; /* file pointer */ + int file_type; /* ascii or binary */ + float version; /* version number of file */ + int num_elem_types; /* number of element types of object */ + PlyElement **elems; /* list of elements */ + int num_comments; /* number of comments */ + char **comments; /* list of comments */ + int num_obj_info; /* number of items of object information */ + char **obj_info; /* list of object info items */ + PlyElement *which_elem; /* element we're currently reading or writing */ + PlyOtherElems *other_elems; /* "other" elements from a PLY file */ + PlyPropRules *current_rules; /* current propagation rules */ + PlyRuleList *rule_list; /* rule list from user */ +} PlyFile; + +/* memory allocation */ +/* +extern char *my_alloc(); +*/ +#define myalloc(mem_size) my_alloc((mem_size), __LINE__, __FILE__) + + +/* old routines */ + +#if 0 +extern PlyFile *ply_write(FILE *, int, char **, int); +extern PlyFile *ply_read(FILE *, int *, char ***); +extern PlyFile *ply_open_for_reading( char *, int *, char ***, int *, float *); +extern void ply_close(PlyFile *); +extern PlyOtherProp *ply_get_other_properties(PlyFile *, char *, int); +#endif + +extern void ply_describe_property(PlyFile *, char *, PlyProperty *); +extern void ply_get_property(PlyFile *, char *, PlyProperty *); +extern void ply_get_element(PlyFile *, void *); + + +/*** delcaration of routines ***/ + +PlyOtherElems *get_other_element_ply (PlyFile *); + +PlyFile *read_ply(FILE *); +PlyFile *write_ply(FILE *, int, char **, int); +extern PlyFile *open_for_writing_ply(char *, int, char **, int); +void close_ply(PlyFile *); +void free_ply(PlyFile *); + +void get_info_ply(PlyFile *, float *, int *); +void free_other_elements_ply (PlyOtherElems *); + +void append_comment_ply(PlyFile *, char *); +void append_obj_info_ply(PlyFile *, char *); +void copy_comments_ply(PlyFile *, PlyFile *); +void copy_obj_info_ply(PlyFile *, PlyFile *); +char **get_comments_ply(PlyFile *, int *); +char **get_obj_info_ply(PlyFile *, int *); + +char **get_element_list_ply(PlyFile *, int *); +void setup_property_ply(PlyFile *, PlyProperty *); +void get_element_ply (PlyFile *, void *); +char *setup_element_read_ply (PlyFile *, int, int *); +PlyOtherProp *get_other_properties_ply(PlyFile *, int); + +void element_count_ply(PlyFile *, char *, int); +void describe_element_ply(PlyFile *, char *, int); +void describe_property_ply(PlyFile *, PlyProperty *); +void describe_other_properties_ply(PlyFile *, PlyOtherProp *, int); +void describe_other_elements_ply ( PlyFile *, PlyOtherElems *); +void get_element_setup_ply(PlyFile *, char *, int, PlyProperty *); +PlyProperty **get_element_description_ply(PlyFile *, char *, int*, int*); +void element_layout_ply(PlyFile *, char *, int, int, PlyProperty *); + +void header_complete_ply(PlyFile *); +void put_element_setup_ply(PlyFile *, char *); +void put_element_ply(PlyFile *, void *); +void put_other_elements_ply(PlyFile *); + +PlyPropRules *init_rule_ply (PlyFile *, char *); +void modify_rule_ply (PlyPropRules *, char *, int); +void start_props_ply (PlyFile *, PlyPropRules *); +void weight_props_ply (PlyFile *, float, void *); +void *get_new_props_ply(PlyFile *); +void set_prop_rules_ply (PlyFile *, PlyRuleList *); +PlyRuleList *append_prop_rule (PlyRuleList *, char *, char *); +int matches_rule_name (char *); + +int equal_strings(char *, char *); +char *recreate_command_line (int, char *argv[]); + + +#ifdef __cplusplus +} +#endif +#endif /* !__PLY_H__ */ + diff --git a/tools/ply2pbrt.c b/tools/ply2pbrt.c new file mode 100644 index 0000000..a3f2a13 --- /dev/null +++ b/tools/ply2pbrt.c @@ -0,0 +1,260 @@ +/* + +ply2lrt converter--a trivial modification of: + +ply2iv, Convert a PLY file to an Inventor file. + +Greg Turk + +----------------------------------------------------------------------- + +Copyright (c) 1998 Georgia Institute of Technology. All rights reserved. + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose is hereby granted without fee, provided +that the above copyright notice and this permission notice appear in +all copies of this software and that you do not sell the software. + +THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, +EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +*/ + +#include +#include +#include +#include +#include + + +/* vertex and face definitions for a polygonal object */ + +typedef struct Vertex { + float x,y,z; + float r,g,b; + float nx,ny,nz; + void *other_props; /* other properties */ +} Vertex; + +typedef struct Face { + unsigned char nverts; /* number of vertex indices in list */ + int *verts; /* vertex index list */ + void *other_props; /* other properties */ +} Face; + +char *elem_names[] = { /* list of the elements in the object */ + "vertex", "face" +}; + +PlyProperty vert_props[] = { /* list of property information for a vertex */ + {"x", Float32, Float32, offsetof(Vertex,x), 0, 0, 0, 0}, + {"y", Float32, Float32, offsetof(Vertex,y), 0, 0, 0, 0}, + {"z", Float32, Float32, offsetof(Vertex,z), 0, 0, 0, 0}, + {"r", Float32, Float32, offsetof(Vertex,r), 0, 0, 0, 0}, + {"g", Float32, Float32, offsetof(Vertex,g), 0, 0, 0, 0}, + {"b", Float32, Float32, offsetof(Vertex,b), 0, 0, 0, 0}, + {"nx", Float32, Float32, offsetof(Vertex,nx), 0, 0, 0, 0}, + {"ny", Float32, Float32, offsetof(Vertex,ny), 0, 0, 0, 0}, + {"nz", Float32, Float32, offsetof(Vertex,nz), 0, 0, 0, 0}, +}; + +PlyProperty face_props[] = { /* list of property information for a face */ + {"vertex_indices", Int32, Int32, offsetof(Face,verts), + 1, Uint8, Uint8, offsetof(Face,nverts)}, +}; + + +/*** the PLY object ***/ + +static int nverts,nfaces; +static Vertex **vlist; +static Face **flist; + +static PlyOtherProp *vert_other,*face_other; + +static int per_vertex_color = 0; +static int has_normals = 0; + +void usage(char *progname); +void read_file(void); +void write_lrt(void); + + +/****************************************************************************** +Main program. +******************************************************************************/ + +int +main(int argc, char *argv[]) +{ + char *s; + char *progname; + + progname = argv[0]; + + while (--argc > 0 && (*++argv)[0]=='-') { + for (s = argv[0]+1; *s; s++) + switch (*s) { + default: + usage (progname); + exit (-1); + break; + } + } + + read_file(); + write_lrt(); + return 0; +} + + +/****************************************************************************** +Print out usage information. +******************************************************************************/ + +void +usage(char *progname) +{ + fprintf (stderr, "usage: %s [flags] out.iv\n", progname); +} + + +/****************************************************************************** +Read in the PLY file from standard in. +******************************************************************************/ + +void +read_file(void) +{ + int i,j; + int elem_count; + char *elem_name; + PlyFile *in_ply; + + /*** Read in the original PLY object ***/ + + in_ply = read_ply (stdin); + + for (i = 0; i < in_ply->num_elem_types; i++) { + + /* prepare to read the i'th list of elements */ + elem_name = setup_element_read_ply (in_ply, i, &elem_count); + + if (equal_strings ("vertex", elem_name)) { + + /* create a vertex list to hold all the vertices */ + vlist = (Vertex **) malloc (sizeof (Vertex *) * elem_count); + nverts = elem_count; + + /* set up for getting vertex elements */ + + setup_property_ply (in_ply, &vert_props[0]); + setup_property_ply (in_ply, &vert_props[1]); + setup_property_ply (in_ply, &vert_props[2]); + + for (j = 0; j < in_ply->elems[i]->nprops; j++) { + PlyProperty *prop; + prop = in_ply->elems[i]->props[j]; + if (equal_strings ("r", prop->name)) { + setup_property_ply (in_ply, &vert_props[3]); + per_vertex_color = 1; + } + if (equal_strings ("g", prop->name)) { + setup_property_ply (in_ply, &vert_props[4]); + per_vertex_color = 1; + } + if (equal_strings ("b", prop->name)) { + setup_property_ply (in_ply, &vert_props[5]); + per_vertex_color = 1; + } + if (equal_strings ("nx", prop->name)) { + setup_property_ply (in_ply, &vert_props[6]); + has_normals = 1; + } + if (equal_strings ("ny", prop->name)) { + setup_property_ply (in_ply, &vert_props[7]); + has_normals = 1; + } + if (equal_strings ("nz", prop->name)) { + setup_property_ply (in_ply, &vert_props[8]); + has_normals = 1; + } + } + + vert_other = get_other_properties_ply (in_ply, + offsetof(Vertex,other_props)); + + /* grab all the vertex elements */ + for (j = 0; j < elem_count; j++) { + vlist[j] = (Vertex *) malloc (sizeof (Vertex)); + vlist[j]->r = 1; + vlist[j]->g = 1; + vlist[j]->b = 1; + get_element_ply (in_ply, (void *) vlist[j]); + } + } + else if (equal_strings ("face", elem_name)) { + + /* create a list to hold all the face elements */ + flist = (Face **) malloc (sizeof (Face *) * elem_count); + nfaces = elem_count; + + /* set up for getting face elements */ + + setup_property_ply (in_ply, &face_props[0]); + face_other = get_other_properties_ply (in_ply, + offsetof(Face,other_props)); + + /* grab all the face elements */ + for (j = 0; j < elem_count; j++) { + flist[j] = (Face *) malloc (sizeof (Face)); + get_element_ply (in_ply, (void *) flist[j]); + } + } + else + get_other_element_ply (in_ply); + } + + close_ply (in_ply); + free_ply (in_ply); +} + + +/****************************************************************************** +Write out a lrt file. +******************************************************************************/ + +void +write_lrt(void) +{ + int i,j; + + printf ("Shape \"trianglemesh\" \n"); + printf (" \"vertex point P\" [\n"); + for (i = 0; i < nverts; i++) + printf (" %g %g %g\n", vlist[i]->x, vlist[i]->y, vlist[i]->z); + printf (" ]\n"); + + /* if we have them, write surface normals */ + + if (has_normals) { + printf ("\"vertex normal N\" [\n"); + for (i = 0; i < nverts; i++) + printf (" %g %g %g\n", vlist[i]->nx, vlist[i]->ny, vlist[i]->nz); + printf (" ]\n"); + printf ("\n"); + } + + printf ("\"integer indices\" [\n"); + for (i = 0; i < nfaces; i++) { + /* triangulate the faces... */ + int nv = flist[i]->nverts; + for (j = 0; j < nv-2; ++j) + printf (" %d %d %d\n", flist[i]->verts[0], flist[i]->verts[j+1], flist[i]->verts[j+2]); + } + printf (" ]\n"); + + printf ("\n"); +} + diff --git a/tools/samplepat.cpp b/tools/samplepat.cpp new file mode 100644 index 0000000..10c556b --- /dev/null +++ b/tools/samplepat.cpp @@ -0,0 +1,268 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// tools/samplepat.cpp* +#include "pbrt.h" +#include "sampler.h" +#include "progressreporter.h" +#include "montecarlo.h" + +// BestCandidate Sampling Constants +#define SQRT_SAMPLE_TABLE_SIZE 64 +#define SAMPLE_TABLE_SIZE (SQRT_SAMPLE_TABLE_SIZE * \ + SQRT_SAMPLE_TABLE_SIZE) + +// Sample Pattern Definitions +#define BC_GRID_SIZE 40 +typedef vector SampleGrid[BC_GRID_SIZE][BC_GRID_SIZE]; +#define GRID(v) (int((v) * BC_GRID_SIZE)) + +// Sample Pattern Precomputation +int line_num = 0; // make this link! +string current_file; // ditto. + +// Pattern Precomputation Local Data +static float imageSamples[SAMPLE_TABLE_SIZE][2]; +static float timeSamples[SAMPLE_TABLE_SIZE]; +static float lensSamples[SAMPLE_TABLE_SIZE][2]; + +// Pattern Precomputation Utility Functions +static void addSampleToGrid(float sample[][2], int sampleNum, + SampleGrid *grid) { + int u = GRID(sample[sampleNum][0]); + int v = GRID(sample[sampleNum][1]); + (*grid)[u][v].push_back(sampleNum); +} + + +inline float Wrapped1DDist(float a, float b) { + float d = fabsf(a - b); + if (d < 0.5f) return d; + else return 1.f - max(a, b) + min(a, b); +} + + + +// Pattern Precomputation Forward Declarations +void BestCandidate2D(float table[][2], + int count, RNG &rng, SampleGrid *grid = NULL); +static void +Redistribute2D(float samples[][2], SampleGrid &pixelGrid); +int main() { + RNG rng; + // Compute image sample positions + SampleGrid pixelGrid; + BestCandidate2D(imageSamples, SAMPLE_TABLE_SIZE, rng, &pixelGrid); + + // Compute time samples + ProgressReporter timeProgress(SAMPLE_TABLE_SIZE, "Time samples"); + for (int i = 0; i < SAMPLE_TABLE_SIZE; ++i) + timeSamples[i] = (i + rng.RandomFloat()) / SAMPLE_TABLE_SIZE; + for (int currentSample = 1; + currentSample < SAMPLE_TABLE_SIZE; + ++currentSample) { + // Select best time sample for current image sample + int best = -1; + + // Find best time relative to neighbors + float maxMinDelta = 0.; + for (int t = currentSample; t < SAMPLE_TABLE_SIZE; ++t) { + // Compute min delta for this time + int gu = GRID(imageSamples[currentSample][0]); + int gv = GRID(imageSamples[currentSample][1]); + float minDelta = INFINITY; + for (int du = -1; du <= 1; ++du) { + for (int dv = -1; dv <= 1; ++dv) { + // Check offset from times of nearby samples + + // Compute (u,v) grid cell to check + int u = gu + du, v = gv + dv; + if (u < 0) u += BC_GRID_SIZE; + if (u >= BC_GRID_SIZE) u -= BC_GRID_SIZE; + if (v < 0) v += BC_GRID_SIZE; + if (v >= BC_GRID_SIZE) v -= BC_GRID_SIZE; + for (uint32_t g = 0; g < pixelGrid[u][v].size(); ++g) { + int otherSample = pixelGrid[u][v][g]; + if (otherSample < currentSample) { + float dt = Wrapped1DDist(timeSamples[otherSample], timeSamples[t]); + minDelta = min(minDelta, dt); + } + } + } + } + + // Update _best_ if this is best time so far + if (minDelta > maxMinDelta) { + maxMinDelta = minDelta; + best = t; + } + } + Assert(best != -1); + swap(timeSamples[best], timeSamples[currentSample]); + timeProgress.Update(); + } + timeProgress.Done();; + + // Compute lens samples + BestCandidate2D(lensSamples, SAMPLE_TABLE_SIZE, rng); + Redistribute2D(lensSamples, pixelGrid); + + // Write sample table to disk + FILE *f = fopen("sampledata.out", "w"); + if (f == NULL) + Severe("Couldn't open sampledata.out for writing."); + fprintf(f, "\n/* Automatically generated %dx%d sample " + "table (%s @a %s) */\n\n", + SQRT_SAMPLE_TABLE_SIZE, SQRT_SAMPLE_TABLE_SIZE, + __DATE__, __TIME__); + fprintf(f, "const float " + "BestCandidateSampler::sampleTable[%d][5] = {\n", + SAMPLE_TABLE_SIZE); + for (int i = 0; i < SAMPLE_TABLE_SIZE; ++i) { + fprintf(f, " { "); + fprintf(f, "%10.10ff, %10.10ff, ", imageSamples[i][0], + imageSamples[i][1]); + fprintf(f, "%10.10ff, ", timeSamples[i]); + fprintf(f, "%10.10ff, %10.10ff, ", lensSamples[i][0], + lensSamples[i][1]); + fprintf(f, "},\n"); + } + fprintf(f, "};\n"); + return 0; +} + + +void BestCandidate2D(float table[][2], int totalSamples, + RNG &rng, SampleGrid *grid) { + SampleGrid localGrid; + if (!grid) grid = &localGrid; + ProgressReporter + progress(totalSamples-1, "Throwing Darts"); + // Generate first 2D sample arbitrarily + table[0][0] = rng.RandomFloat(); + table[0][1] = rng.RandomFloat(); + addSampleToGrid(table, 0, grid); + for (int currentSample = 1; currentSample < totalSamples; + ++currentSample) { + // Generate next best 2D image sample + float maxDist2 = 0.; + int numCandidates = 500 * currentSample; + for (int currentCandidate = 0; + currentCandidate < numCandidates; + ++currentCandidate) { + // Generate a random candidate sample + float candidate[2]; + candidate[0] = rng.RandomFloat(); + candidate[1] = rng.RandomFloat(); + + // Loop over neighboring grid cells and check distances + float sampleDist2 = INFINITY; + int gu = GRID(candidate[0]), gv = GRID(candidate[1]); + for (int du = -1; du <= 1; ++du) { + for (int dv = -1; dv <= 1; ++dv) { + // Compute (u,v) grid cell to check + int u = gu + du, v = gv + dv; + if (u < 0) u += BC_GRID_SIZE; + if (u >= BC_GRID_SIZE) u -= BC_GRID_SIZE; + if (v < 0) v += BC_GRID_SIZE; + if (v >= BC_GRID_SIZE) v -= BC_GRID_SIZE; + + // Update minimum squared distance from cell's samples + for (uint32_t g = 0; g < (*grid)[u][v].size(); ++g) { + int s = (*grid)[u][v][g]; + float xdist = Wrapped1DDist(candidate[0], table[s][0]); + float ydist = Wrapped1DDist(candidate[1], table[s][1]); + float d2 = xdist*xdist + ydist*ydist; + sampleDist2 = min(sampleDist2, d2); + } + } + } + + // Keep this sample if it is the best one so far + if (sampleDist2 > maxDist2) { + maxDist2 = sampleDist2; + table[currentSample][0] = candidate[0]; + table[currentSample][1] = candidate[1]; + } + } + addSampleToGrid(table, currentSample, grid); + progress.Update(); + } + progress.Done(); +} + + +static void Redistribute2D(float samples[][2], SampleGrid &pixelGrid) { + ProgressReporter progress(SAMPLE_TABLE_SIZE, "Redistribution"); + for (int currentSample = 1; + currentSample < SAMPLE_TABLE_SIZE; + ++currentSample) { + // Select best lens sample for current image sample + int best = -1; + + // Find best 2D sample relative to neighbors + float maxMinDist2 = 0.f; + for (int samp = currentSample; samp < SAMPLE_TABLE_SIZE; ++samp) { + // Check distance to lens positions at nearby samples + int gu = GRID(imageSamples[currentSample][0]); + int gv = GRID(imageSamples[currentSample][1]); + float minDist2 = INFINITY; + for (int du = -1; du <= 1; ++du) { + for (int dv = -1; dv <= 1; ++dv) { + // Check 2D samples in current grid cell + + // Compute (u,v) grid cell to check + int u = gu + du, v = gv + dv; + if (u < 0) u += BC_GRID_SIZE; + if (u >= BC_GRID_SIZE) u -= BC_GRID_SIZE; + if (v < 0) v += BC_GRID_SIZE; + if (v >= BC_GRID_SIZE) v -= BC_GRID_SIZE; + for (uint32_t g = 0; g < pixelGrid[u][v].size(); ++g) { + int s2 = pixelGrid[u][v][g]; + if (s2 < currentSample) { + float dx = Wrapped1DDist(samples[s2][0], samples[samp][0]); + float dy = Wrapped1DDist(samples[s2][1], samples[samp][1]); + float d2 = dx*dx + dy*dy; + minDist2 = min(d2, minDist2); + } + } + } + } + + // Update _best_ for 2D lens sample if it is best so far + if (minDist2 > maxMinDist2) { + maxMinDist2 = minDist2; + best = samp; + } + } + Assert(best != -1); + swap(samples[best][0], samples[currentSample][0]); + swap(samples[best][1], samples[currentSample][1]); + progress.Update(); + } + fprintf(stderr, "\n"); + progress.Done(); +} + + diff --git a/tools/tifftoexr.cpp b/tools/tifftoexr.cpp new file mode 100644 index 0000000..62d4f94 --- /dev/null +++ b/tools/tifftoexr.cpp @@ -0,0 +1,162 @@ +/* + g++ -g -Wall tifftoexr.cpp -I../../src/tangled_code/OpenEXR/include -ltiff -L../../src/tangled_code/OpenEXR/lib-linux -lIlmImf -lImath -lIex -lHalf + +*/ + +#include +#include +#include +#include +#include +#include +#include + +using namespace Imf; +using namespace Imath; + +#define INV_255 .00392156862745098039f + +static void WriteEXR(const char *name, float *rgba, int xRes, int yRes, bool hasAlpha); +static bool ReadTIFF(const char *name, float *&rgba, int &xRes, int &yRes, bool &hasAlpha); + +int main(int argc, char *argv[]) +{ + if (argc != 3) { + fprintf(stderr, "usage: tifftoexr [foo.tiff] [foo.exr]\n"); + return 1; + } + + float *rgba; + int xRes, yRes; + bool hasAlpha; + if (ReadTIFF(argv[1], rgba, xRes, yRes, hasAlpha)) + WriteEXR(argv[2], rgba, xRes, yRes, hasAlpha); + return 0; +} + +void WriteEXR(const char *name, float *frgba, int xRes, int yRes, bool hasAlpha) +{ + Header header(xRes, yRes); + header.channels().insert("R", Channel (HALF)); + header.channels().insert("G", Channel (HALF)); + header.channels().insert("B", Channel (HALF)); + if (hasAlpha) + header.channels().insert("A", Channel (HALF)); + int stride = hasAlpha ? 4 : 3; + + half *rgba = new half[xRes*yRes * stride]; + for (int i = 0; i < xRes*yRes * stride; ++i) + rgba[i] = frgba[i]; + + FrameBuffer fb; + fb.insert("R", Slice(HALF, (char *)rgba, stride*sizeof(half), + stride*xRes*sizeof(half))); + fb.insert("G", Slice(HALF, (char *)rgba+sizeof(half), stride*sizeof(half), + stride*xRes*sizeof(half))); + fb.insert("B", Slice(HALF, (char *)rgba+2*sizeof(half), stride*sizeof(half), + stride*xRes*sizeof(half))); + if (hasAlpha) + fb.insert("A", Slice(HALF, (char *)rgba+3*sizeof(half), stride*sizeof(half), + stride*xRes*sizeof(half))); + + OutputFile file(name, header); + file.setFrameBuffer(fb); + file.writePixels(yRes); +} + +static bool ReadTIFF(const char *name, float *&rgba, int &xRes, int &yRes, + bool &hasAlpha) +{ + // Try to open TIFF file + TIFF *tiff = TIFFOpen(name, "r"); + if (!tiff) { + fprintf(stderr, "Unable to open TIFF %s", name); + return false; + } + // Get basic information from TIFF header + short int nSamples; + int xSize, ySize; + TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &xSize); + TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &ySize); + TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &nSamples); + if (nSamples != 3 && nSamples != 4) { + fprintf(stderr, "Sorry, only handle 3 and 4 sample TIFFs...\n"); + return false; + } + hasAlpha = (nSamples == 4); + xRes = xSize; + yRes = ySize; + + // Make sure this is a TIFF we can read + short int bitsPerSample, sampleFormat = SAMPLEFORMAT_UINT; + if (!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitsPerSample)) { + fprintf(stderr, "TIFFRead: bits per sample not set in TIFF"); + TIFFClose(tiff); + return false; + } + + if (!TIFFGetField(tiff, TIFFTAG_SAMPLEFORMAT, &sampleFormat)) { + if (bitsPerSample == 32) + sampleFormat = SAMPLEFORMAT_IEEEFP; + else + sampleFormat = SAMPLEFORMAT_UINT; + } + + if (bitsPerSample == 32) { + if (sampleFormat != SAMPLEFORMAT_IEEEFP) { + fprintf(stderr, "TIFFRead: 32 bit TIFF not stored in floating point format"); + TIFFClose(tiff); + return false; + } + } + else { + if (bitsPerSample != 8 && bitsPerSample != 32) { + fprintf(stderr, "TIFFRead: only 8 and 32 bits per sample supported"); + TIFFClose(tiff); + return false; + } + if (sampleFormat != SAMPLEFORMAT_UINT) { + fprintf(stderr, "TIFFRead: 8 bit TIFFs must be stored as unsigned ints"); + TIFFClose(tiff); + return false; + } + } + + int bytesPerSample = bitsPerSample / 8; + if (nSamples * xRes * bytesPerSample != TIFFScanlineSize(tiff)) { + fprintf(stderr, "TIFFRead: RGB not interleaved in TIFF %s", name); + TIFFClose(tiff); + return false; + } + + // Allocate space for [[pixels]] and buffers + rgba = new float[nSamples * xRes * yRes]; + float *p = rgba; + unsigned char *ubuf = NULL; + if (bitsPerSample == 8) ubuf = new unsigned char[nSamples * xRes]; + + for (int y = 0; y < yRes; ++y) { + if (ubuf) { + // Read 8-bit TIFF scanline + if (TIFFReadScanline(tiff, ubuf, y, 1) == -1) { + TIFFClose(tiff); + return false; + } + for (int x = 0; x < nSamples*xRes; ++x) + *p++ = ubuf[x] * INV_255; + } + else { + // Read floating point TIFF scanline + if (TIFFReadScanline(tiff, p, y, 1) == -1) { + TIFFClose(tiff); + return false; + } + p += nSamples * xRes; + } + } + + delete[] ubuf; + TIFFClose(tiff); + return rgba; +} + diff --git a/volumes/exponential.cpp b/volumes/exponential.cpp new file mode 100644 index 0000000..264944b --- /dev/null +++ b/volumes/exponential.cpp @@ -0,0 +1,47 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// volumes/exponential.cpp* +#include "stdafx.h" +#include "volumes/exponential.h" +#include "paramset.h" + +// ExponentialDensity Method Definitions +ExponentialDensity *CreateExponentialVolumeRegion(const Transform &volume2world, + const ParamSet ¶ms) { + // Initialize common volume region parameters + Spectrum sigma_a = params.FindOneSpectrum("sigma_a", 0.); + Spectrum sigma_s = params.FindOneSpectrum("sigma_s", 0.); + float g = params.FindOneFloat("g", 0.); + Spectrum Le = params.FindOneSpectrum("Le", 0.); + Point p0 = params.FindOnePoint("p0", Point(0,0,0)); + Point p1 = params.FindOnePoint("p1", Point(1,1,1)); + float a = params.FindOneFloat("a", 1.); + float b = params.FindOneFloat("b", 1.); + Vector up = params.FindOneVector("updir", Vector(0,1,0)); + return new ExponentialDensity(sigma_a, sigma_s, g, Le, BBox(p0, p1), + volume2world, a, b, up); +} + + diff --git a/volumes/exponential.h b/volumes/exponential.h new file mode 100644 index 0000000..2df0f06 --- /dev/null +++ b/volumes/exponential.h @@ -0,0 +1,66 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_VOLUMES_EXPONENTIAL_H +#define PBRT_VOLUMES_EXPONENTIAL_H + +// volumes/exponential.h* +#include "volume.h" + +// ExponentialDensity Declarations +class ExponentialDensity : public DensityRegion { +public: + // ExponentialDensity Public Methods + ExponentialDensity(const Spectrum &sa, const Spectrum &ss, + float gg, const Spectrum &emit, const BBox &e, + const Transform &v2w, float aa, float bb, + const Vector &up) + : DensityRegion(sa, ss, gg, emit, v2w), extent(e), a(aa), b(bb) { + upDir = Normalize(up); + } + BBox WorldBound() const { return Inverse(WorldToVolume)(extent); } + bool IntersectP(const Ray &r, float *t0, float *t1) const { + Ray ray = WorldToVolume(r); + return extent.IntersectP(ray, t0, t1); + } + float Density(const Point &Pobj) const { + if (!extent.Inside(Pobj)) return 0; + float height = Dot(Pobj - extent.pMin, upDir); + return a * expf(-b * height); + } +private: + // ExponentialDensity Private Data + BBox extent; + float a, b; + Vector upDir; +}; + + +ExponentialDensity *CreateExponentialVolumeRegion(const Transform &volume2world, + const ParamSet ¶ms); + +#endif // PBRT_VOLUMES_EXPONENTIAL_H diff --git a/volumes/homogeneous.cpp b/volumes/homogeneous.cpp new file mode 100644 index 0000000..bc881c8 --- /dev/null +++ b/volumes/homogeneous.cpp @@ -0,0 +1,44 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// volumes/homogeneous.cpp* +#include "stdafx.h" +#include "volumes/homogeneous.h" +#include "paramset.h" + +// HomogeneousVolumeDensity Method Definitions +HomogeneousVolumeDensity *CreateHomogeneousVolumeDensityRegion(const Transform &volume2world, + const ParamSet ¶ms) { + // Initialize common volume region parameters + Spectrum sigma_a = params.FindOneSpectrum("sigma_a", 0.); + Spectrum sigma_s = params.FindOneSpectrum("sigma_s", 0.); + float g = params.FindOneFloat("g", 0.); + Spectrum Le = params.FindOneSpectrum("Le", 0.); + Point p0 = params.FindOnePoint("p0", Point(0,0,0)); + Point p1 = params.FindOnePoint("p1", Point(1,1,1)); + return new HomogeneousVolumeDensity(sigma_a, sigma_s, g, Le, BBox(p0, p1), + volume2world); +} + + diff --git a/volumes/homogeneous.h b/volumes/homogeneous.h new file mode 100644 index 0000000..e9e1fd3 --- /dev/null +++ b/volumes/homogeneous.h @@ -0,0 +1,87 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_VOLUMES_HOMOGENEOUS_H +#define PBRT_VOLUMES_HOMOGENEOUS_H + +// volumes/homogeneous.h* +#include "volume.h" + +// HomogeneousVolumeDensity Declarations +class HomogeneousVolumeDensity : public VolumeRegion { +public: + // HomogeneousVolumeDensity Public Methods + HomogeneousVolumeDensity(const Spectrum &sa, const Spectrum &ss, float gg, + const Spectrum &emit, const BBox &e, const Transform &v2w) { + WorldToVolume = Inverse(v2w); + sig_a = sa; + sig_s = ss; + g = gg; + le = emit; + extent = e; + } + BBox WorldBound() const { + return Inverse(WorldToVolume)(extent); + } + bool IntersectP(const Ray &r, float *t0, float *t1) const { + Ray ray = WorldToVolume(r); + return extent.IntersectP(ray, t0, t1); + } + Spectrum sigma_a(const Point &p, const Vector &, float) const { + return extent.Inside(WorldToVolume(p)) ? sig_a : 0.; + } + Spectrum sigma_s(const Point &p, const Vector &, float) const { + return extent.Inside(WorldToVolume(p)) ? sig_s : 0.; + } + Spectrum sigma_t(const Point &p, const Vector &, float) const { + return extent.Inside(WorldToVolume(p)) ? (sig_a + sig_s) : 0.; + } + Spectrum Lve(const Point &p, const Vector &, float) const { + return extent.Inside(WorldToVolume(p)) ? le : 0.; + } + float p(const Point &p, const Vector &wi, const Vector &wo, float) const { + if (!extent.Inside(WorldToVolume(p))) return 0.; + return PhaseHG(wi, wo, g); + } + Spectrum tau(const Ray &ray, float, float) const { + float t0, t1; + if (!IntersectP(ray, &t0, &t1)) return 0.; + return Distance(ray(t0), ray(t1)) * (sig_a + sig_s); + } +private: + // HomogeneousVolumeDensity Private Data + Spectrum sig_a, sig_s, le; + float g; + BBox extent; + Transform WorldToVolume; +}; + + +HomogeneousVolumeDensity *CreateHomogeneousVolumeDensityRegion(const Transform &volume2world, + const ParamSet ¶ms); + +#endif // PBRT_VOLUMES_HOMOGENEOUS_H diff --git a/volumes/volumegrid.cpp b/volumes/volumegrid.cpp new file mode 100644 index 0000000..95c1465 --- /dev/null +++ b/volumes/volumegrid.cpp @@ -0,0 +1,79 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + + +// volumes/volumegrid.cpp* +#include "stdafx.h" +#include "volumes/volumegrid.h" +#include "paramset.h" + +// VolumeGridDensity Method Definitions +float VolumeGridDensity::Density(const Point &Pobj) const { + if (!extent.Inside(Pobj)) return 0; + // Compute voxel coordinates and offsets for _Pobj_ + Vector vox = extent.Offset(Pobj); + vox.x = vox.x * nx - .5f; + vox.y = vox.y * ny - .5f; + vox.z = vox.z * nz - .5f; + int vx = Floor2Int(vox.x), vy = Floor2Int(vox.y), vz = Floor2Int(vox.z); + float dx = vox.x - vx, dy = vox.y - vy, dz = vox.z - vz; + + // Trilinearly interpolate density values to compute local density + float d00 = Lerp(dx, D(vx, vy, vz), D(vx+1, vy, vz)); + float d10 = Lerp(dx, D(vx, vy+1, vz), D(vx+1, vy+1, vz)); + float d01 = Lerp(dx, D(vx, vy, vz+1), D(vx+1, vy, vz+1)); + float d11 = Lerp(dx, D(vx, vy+1, vz+1), D(vx+1, vy+1, vz+1)); + float d0 = Lerp(dy, d00, d10); + float d1 = Lerp(dy, d01, d11); + return Lerp(dz, d0, d1); +} + + +VolumeGridDensity *CreateGridVolumeRegion(const Transform &volume2world, + const ParamSet ¶ms) { + // Initialize common volume region parameters + Spectrum sigma_a = params.FindOneSpectrum("sigma_a", 0.); + Spectrum sigma_s = params.FindOneSpectrum("sigma_s", 0.); + float g = params.FindOneFloat("g", 0.); + Spectrum Le = params.FindOneSpectrum("Le", 0.); + Point p0 = params.FindOnePoint("p0", Point(0,0,0)); + Point p1 = params.FindOnePoint("p1", Point(1,1,1)); + int nitems; + const float *data = params.FindFloat("density", &nitems); + if (!data) { + Error("No \"density\" values provided for volume grid?"); + return NULL; + } + int nx = params.FindOneInt("nx", 1); + int ny = params.FindOneInt("ny", 1); + int nz = params.FindOneInt("nz", 1); + if (nitems != nx*ny*nz) { + Error("VolumeGridDensity has %d density values but nx*ny*nz = %d", + nitems, nx*ny*nz); + return NULL; + } + return new VolumeGridDensity(sigma_a, sigma_s, g, Le, BBox(p0, p1), + volume2world, nx, ny, nz, data); +} + + diff --git a/volumes/volumegrid.h b/volumes/volumegrid.h new file mode 100644 index 0000000..5c820ad --- /dev/null +++ b/volumes/volumegrid.h @@ -0,0 +1,69 @@ + +/* + pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys. + + This file is part of pbrt. + + pbrt is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Note that the text contents of + the book "Physically Based Rendering" are *not* licensed under the + GNU GPL. + + pbrt is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef PBRT_VOLUMES_VOLUMEGRID_H +#define PBRT_VOLUMES_VOLUMEGRID_H + +// volumes/volumegrid.h* +#include "volume.h" + +// VolumeGridDensity Declarations +class VolumeGridDensity : public DensityRegion { +public: + // VolumeGridDensity Public Methods + VolumeGridDensity(const Spectrum &sa, const Spectrum &ss, float gg, + const Spectrum &emit, const BBox &e, const Transform &v2w, + int x, int y, int z, const float *d) + : DensityRegion(sa, ss, gg, emit, v2w), nx(x), ny(y), nz(z), extent(e) { + density = new float[nx*ny*nz]; + memcpy(density, d, nx*ny*nz*sizeof(float)); + } + ~VolumeGridDensity() { delete[] density; } + BBox WorldBound() const { return Inverse(WorldToVolume)(extent); } + bool IntersectP(const Ray &r, float *t0, float *t1) const { + Ray ray = WorldToVolume(r); + return extent.IntersectP(ray, t0, t1); + } + float Density(const Point &Pobj) const; + float D(int x, int y, int z) const { + x = Clamp(x, 0, nx-1); + y = Clamp(y, 0, ny-1); + z = Clamp(z, 0, nz-1); + return density[z*nx*ny + y*nx + x]; + } +private: + // VolumeGridDensity Private Data + float *density; + const int nx, ny, nz; + const BBox extent; +}; + + +VolumeGridDensity *CreateGridVolumeRegion(const Transform &volume2world, + const ParamSet ¶ms); + +#endif // PBRT_VOLUMES_VOLUMEGRID_H diff --git a/wide.22mm.dat b/wide.22mm.dat new file mode 100644 index 0000000..7ba0790 --- /dev/null +++ b/wide.22mm.dat @@ -0,0 +1,17 @@ +# Wide-angle (38-degree) lens. Nakamura. +# MLD, p. 360" +# Scaled to 22 mm from 100 mm +# radius sep n aperture +35.98738 1.21638 1.54 23.716 +11.69718 9.9957 1 17.996 +13.08714 5.12622 1.772 12.364 +-22.63294 1.76924 1.617 9.812 +71.05802 0.8184 1 9.152 +0 2.27766 0 8.756 +-9.58584 2.43254 1.617 8.184 +-11.28864 0.11506 1 9.152 +-166.7765 3.09606 1.713 10.648 +-7.5911 1.32682 1.805 11.44 +-16.7662 3.98068 1 12.276 +-7.70286 1.21638 1.617 13.42 +-11.97328 0 1 17.996