Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Luc Peurière <jlp@nerim.net>2005-09-18 17:27:12 +0400
committerJean-Luc Peurière <jlp@nerim.net>2005-09-18 17:27:12 +0400
commite2d577de9ee72a4e97b12652984bbba007bec82c (patch)
treefb6f6a447d791685b55f28b95534e9571bba4303
parent9e3468bde2ced17f848c37ddd638829801daa335 (diff)
initial commit of the fluid simulator.
Ton reviewed and gave his blessing. Zr, can you have a look ? see : http://projects.blender.org/tracker/?func=detail&atid=127&aid=3039&group_id=9 for initial comments. N_T : the solver itself (elbeem) needs some works to get rid of warnings
-rw-r--r--intern/Makefile2
-rw-r--r--intern/SConscript1
-rw-r--r--intern/elbeem/COPYING360
-rw-r--r--intern/elbeem/COPYING_trimesh2303
-rw-r--r--intern/elbeem/Makefile58
-rw-r--r--intern/elbeem/SConscript56
-rw-r--r--intern/elbeem/extern/LBM_fluidsim.h68
-rw-r--r--intern/elbeem/intern/Makefile48
-rw-r--r--intern/elbeem/intern/arrays.h290
-rw-r--r--intern/elbeem/intern/attributes.cpp358
-rw-r--r--intern/elbeem/intern/attributes.h143
-rw-r--r--intern/elbeem/intern/blendercall.cpp28
-rw-r--r--intern/elbeem/intern/cfglexer.cpp2561
-rw-r--r--intern/elbeem/intern/cfgparser.cpp2348
-rw-r--r--intern/elbeem/intern/cfgparser.hpp259
-rw-r--r--intern/elbeem/intern/elbeem.cpp51
-rw-r--r--intern/elbeem/intern/factory_fsgr.cpp40
-rw-r--r--intern/elbeem/intern/factory_lbm.h18
-rw-r--r--intern/elbeem/intern/globals.h32
-rw-r--r--intern/elbeem/intern/isosurface.cpp1057
-rw-r--r--intern/elbeem/intern/isosurface.h277
-rw-r--r--intern/elbeem/intern/lbmdimensions.h391
-rw-r--r--intern/elbeem/intern/lbmfsgrsolver.h6519
-rw-r--r--intern/elbeem/intern/lbmfunctions.h351
-rw-r--r--intern/elbeem/intern/lbminterface.cpp716
-rw-r--r--intern/elbeem/intern/lbminterface.h564
-rw-r--r--intern/elbeem/intern/mcubes_tables.h298
-rw-r--r--intern/elbeem/intern/ntl_blenderdumper.cpp216
-rw-r--r--intern/elbeem/intern/ntl_blenderdumper.h34
-rw-r--r--intern/elbeem/intern/ntl_bsptree.cpp668
-rw-r--r--intern/elbeem/intern/ntl_bsptree.h121
-rw-r--r--intern/elbeem/intern/ntl_geometrybox.cpp302
-rw-r--r--intern/elbeem/intern/ntl_geometrybox.h63
-rw-r--r--intern/elbeem/intern/ntl_geometryclass.h92
-rw-r--r--intern/elbeem/intern/ntl_geometrymodel.cpp204
-rw-r--r--intern/elbeem/intern/ntl_geometrymodel.h71
-rw-r--r--intern/elbeem/intern/ntl_geometryobject.cpp128
-rw-r--r--intern/elbeem/intern/ntl_geometryobject.h104
-rw-r--r--intern/elbeem/intern/ntl_geometryshader.h50
-rw-r--r--intern/elbeem/intern/ntl_geometrysphere.cpp229
-rw-r--r--intern/elbeem/intern/ntl_geometrysphere.h65
-rw-r--r--intern/elbeem/intern/ntl_image.cpp13
-rw-r--r--intern/elbeem/intern/ntl_image.h167
-rw-r--r--intern/elbeem/intern/ntl_lightobject.cpp143
-rw-r--r--intern/elbeem/intern/ntl_lightobject.h120
-rw-r--r--intern/elbeem/intern/ntl_material.h203
-rw-r--r--intern/elbeem/intern/ntl_matrices.h658
-rw-r--r--intern/elbeem/intern/ntl_ray.cpp652
-rw-r--r--intern/elbeem/intern/ntl_ray.h234
-rw-r--r--intern/elbeem/intern/ntl_raytracer.cpp726
-rw-r--r--intern/elbeem/intern/ntl_raytracer.h105
-rw-r--r--intern/elbeem/intern/ntl_renderglobals.h371
-rw-r--r--intern/elbeem/intern/ntl_rndstream.h127
-rw-r--r--intern/elbeem/intern/ntl_scene.cpp239
-rw-r--r--intern/elbeem/intern/ntl_scene.h186
-rw-r--r--intern/elbeem/intern/ntl_triangle.h183
-rw-r--r--intern/elbeem/intern/ntl_vector3dim.h1032
-rw-r--r--intern/elbeem/intern/parametrizer.cpp501
-rw-r--r--intern/elbeem/intern/parametrizer.h369
-rw-r--r--intern/elbeem/intern/particletracer.cpp270
-rw-r--r--intern/elbeem/intern/particletracer.h165
-rw-r--r--intern/elbeem/intern/simulation_object.cpp355
-rw-r--r--intern/elbeem/intern/simulation_object.h202
-rw-r--r--intern/elbeem/intern/typeslbm.h260
-rw-r--r--intern/elbeem/intern/utilities.cpp292
-rw-r--r--intern/elbeem/intern/utilities.h170
-rw-r--r--source/Makefile1
-rw-r--r--source/blender/blenkernel/BKE_modifier.h8
-rw-r--r--source/blender/blenkernel/SConscript2
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c386
-rw-r--r--source/blender/blenkernel/intern/Makefile1
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c11
-rw-r--r--source/blender/blenkernel/intern/object.c9
-rw-r--r--source/blender/blenloader/intern/readfile.c6
-rw-r--r--source/blender/blenloader/intern/writefile.c1
-rw-r--r--source/blender/include/butspace.h4
-rw-r--r--source/blender/makesdna/DNA_object_types.h5
-rw-r--r--source/blender/makesdna/intern/makesdna.c2
-rw-r--r--source/blender/src/Makefile1
-rw-r--r--source/blender/src/SConscript4
-rw-r--r--source/blender/src/buttons_object.c186
-rw-r--r--source/nan_definitions.mk1
-rw-r--r--tools/scons/bs/bs_libs.py3
83 files changed, 27913 insertions, 5 deletions
diff --git a/intern/Makefile b/intern/Makefile
index af64e44cdf4..f4ace043414 100644
--- a/intern/Makefile
+++ b/intern/Makefile
@@ -35,7 +35,7 @@ SOURCEDIR = intern
# include nan_subdirs.mk
ALLDIRS = string ghost guardedalloc bmfont moto container memutil
-ALLDIRS += decimation iksolver bsp SoundSystem opennl
+ALLDIRS += decimation iksolver bsp SoundSystem opennl elbeem
all::
@for i in $(ALLDIRS); do \
diff --git a/intern/SConscript b/intern/SConscript
index afbcd24b8be..a9f8196e23e 100644
--- a/intern/SConscript
+++ b/intern/SConscript
@@ -9,6 +9,7 @@ SConscript(['SoundSystem/SConscript',
'memutil/SConscript/',
'decimation/SConscript',
'iksolver/SConscript',
+ 'elbeem/SConscript',
'opennl/SConscript'])
NEW_CSG='false'
diff --git a/intern/elbeem/COPYING b/intern/elbeem/COPYING
new file mode 100644
index 00000000000..d876362de6c
--- /dev/null
+++ b/intern/elbeem/COPYING
@@ -0,0 +1,360 @@
+ All code distributed as part of El'Bemm is covered by the following
+ version of the GNU General Public License, expcept for excerpts of
+ the trimesh2 package in src/isosurface.cpp (see COPYING_trimesh2
+ for details).
+
+ 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.
+
+ Copyright (c) 2003-2005 Nils Thuerey. All rights reserved.
+
+
+
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, 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 Library 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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
+
+
+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.
+
+ <signature of Ty Coon>, 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 Library General
+Public License instead of this License.
diff --git a/intern/elbeem/COPYING_trimesh2 b/intern/elbeem/COPYING_trimesh2
new file mode 100644
index 00000000000..a214195fd60
--- /dev/null
+++ b/intern/elbeem/COPYING_trimesh2
@@ -0,0 +1,303 @@
+This distribution includes source to "miniball", "freeGLUT",
+and "GLUI", which are covered under their own licenses.
+
+All other code distributed as part of trimesh2 is covered
+by the following license:
+
+
+Copyright (c) 2004 Szymon Rusinkiewicz.
+All rights reserved.
+
+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.
+
+
+
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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
diff --git a/intern/elbeem/Makefile b/intern/elbeem/Makefile
new file mode 100644
index 00000000000..3e0333fb3cd
--- /dev/null
+++ b/intern/elbeem/Makefile
@@ -0,0 +1,58 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# 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. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Hans Lambermont
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+# elbeem main makefile.
+#
+
+include nan_definitions.mk
+
+unexport NAN_QUIET
+
+LIBNAME = elbeem
+SOURCEDIR = intern/$(LIBNAME)
+DIR = $(OCGDIR)/$(SOURCEDIR)
+DIRS = intern
+#not ready yet TESTDIRS = test
+
+include nan_subdirs.mk
+
+install: all debug
+ @[ -d $(NAN_ELBEEM) ] || mkdir $(NAN_ELBEEM)
+ @[ -d $(NAN_ELBEEM)/include ] || mkdir $(NAN_ELBEEM)/include
+ @[ -d $(NAN_ELBEEM)/lib ] || mkdir $(NAN_ELBEEM)/lib
+ @[ -d $(NAN_ELBEEM)/lib/debug ] || mkdir $(NAN_ELBEEM)/lib/debug
+ @../tools/cpifdiff.sh $(DIR)/libelbeem.a $(NAN_ELBEEM)/lib/
+ @../tools/cpifdiff.sh $(DIR)/debug/libelbeem.a $(NAN_ELBEEM)/lib/debug/
+ifeq ($(OS),darwin)
+ ranlib $(NAN_ELBEEM)/lib/libelbeem.a
+ ranlib $(NAN_ELBEEM)/lib/debug/libelbeem.a
+endif
+ @../tools/cpifdiff.sh extern/*.h $(NAN_ELBEEM)/include/
+
diff --git a/intern/elbeem/SConscript b/intern/elbeem/SConscript
new file mode 100644
index 00000000000..af6bbb2077c
--- /dev/null
+++ b/intern/elbeem/SConscript
@@ -0,0 +1,56 @@
+#!/usr/bin/python
+Import ('library_env')
+Import('user_options_dict');
+
+print "Including El'Beem Fluid Simulation..."
+elbeem_env = library_env.Copy();
+elbeem_env.Append(CXXFLAGS= ' -DNOGUI -DELBEEM_BLENDER=1 ');
+elbeem_env.Append(CCFLAGS= ' -DNOGUI -DELBEEM_BLENDER=1 ');
+#elbeem_env.Append(CPPPATH= '../src');
+#elbeem_env.Append(CCPATH= '../src');
+
+elbeem_env.Append (CPPPATH = user_options_dict['PNG_INCLUDE'])
+elbeem_env.Append (CPPPATH = user_options_dict['Z_INCLUDE'])
+elbeem_env.Append (CPPPATH = user_options_dict['SDL_INCLUDE'])
+elbeem_env.Append (CCPATH = user_options_dict['PNG_INCLUDE'])
+elbeem_env.Append (CCPATH = user_options_dict['Z_INCLUDE'])
+elbeem_env.Append (CCPATH = user_options_dict['SDL_INCLUDE'])
+
+#Export('elbeem_env');
+#SConscript(['src/SConscript'])
+
+# main build----------------------------------------
+#Import('elbeem_env');
+#srcenv = elbeem_env.Copy();
+
+Sources = [
+
+ "intern/cfgparser.cpp",
+ "intern/cfglexer.cpp",
+
+ "intern/attributes.cpp",
+ "intern/elbeem.cpp",
+ "intern/factory_fsgr.cpp",
+ "intern/isosurface.cpp",
+ "intern/lbminterface.cpp",
+ "intern/ntl_blenderdumper.cpp",
+ "intern/ntl_bsptree.cpp",
+ "intern/ntl_geometrybox.cpp",
+ "intern/ntl_geometrymodel.cpp",
+ "intern/ntl_geometryobject.cpp",
+ "intern/ntl_geometrysphere.cpp",
+ "intern/ntl_image.cpp",
+ "intern/ntl_lightobject.cpp",
+ "intern/ntl_ray.cpp",
+ "intern/ntl_raytracer.cpp",
+ "intern/ntl_scene.cpp",
+ "intern/parametrizer.cpp",
+ "intern/particletracer.cpp",
+ "intern/simulation_object.cpp",
+ "intern/utilities.cpp",
+ "intern/blendercall.cpp"
+
+ ]; # sources
+
+elbeem_env.Library (target='#'+user_options_dict['BUILD_DIR']+'/lib/blender_elbeem', source=Sources)
+
diff --git a/intern/elbeem/extern/LBM_fluidsim.h b/intern/elbeem/extern/LBM_fluidsim.h
new file mode 100644
index 00000000000..27fcc101440
--- /dev/null
+++ b/intern/elbeem/extern/LBM_fluidsim.h
@@ -0,0 +1,68 @@
+/**
+ * BKE_fluidsim.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef LBM_FLUIDSIM_H
+#define LBM_FLUIDSIM_H
+
+struct Mesh;
+struct DerivedMesh;
+struct Object;
+struct fluidsimDerivedMesh;
+
+extern double fluidsimViscosityPreset[6];
+extern char* fluidsimViscosityPresetString[6];
+
+/* allocates and initializes fluidsim data */
+struct FluidsimSettings* fluidsimSettingsNew(struct Object *srcob);
+
+/* frees internal data itself */
+void fluidsimSettingsFree(struct FluidsimSettings* sb);
+
+/* export blender geometry to fluid solver */
+void fluidsimBake(struct Object* ob);
+
+/* read & write bobj / bobj.gz files (e.g. for fluid sim surface meshes) */
+void writeBobjgz(char *filename, struct Object *ob);
+struct Mesh* readBobjgz(char *filename, struct Mesh *orgmesh);
+
+/* create derived mesh for fluid sim objects */
+// WARNING - currently implemented in DerivedMesh.c!
+struct DerivedMesh *getFluidsimDerivedMesh(struct Object *srcob, int useRenderParams, float *extverts, float *nors);
+
+/* run simulation with given config file */
+// WARNING - implemented in intern/elbeem/blendercall.cpp
+int performElbeemSimulation(char *cfgfilename);
+
+#endif
+
+
diff --git a/intern/elbeem/intern/Makefile b/intern/elbeem/intern/Makefile
new file mode 100644
index 00000000000..fb11f1dfb9e
--- /dev/null
+++ b/intern/elbeem/intern/Makefile
@@ -0,0 +1,48 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# 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. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+# elbeem intern Makefile
+#
+
+LIBNAME = elbeem
+DIR = $(OCGDIR)/intern/$(LIBNAME)
+
+include nan_compile.mk
+
+unexport NAN_QUIET
+
+CCFLAGS += $(LEVEL_2_CPP_WARNINGS)
+
+CPPFLAGS += -DNOGUI -DELBEEM_BLENDER
+CPPFLAGS += -I.
+CPPFLAGS += -I../extern
+CPPFLAGS += $(NAN_SDLCFLAGS)
+CPPFLAGS += -I$(NAN_PNG)/include
+CPPFLAGS += -I$(NAN_PNG)/include/libpng
diff --git a/intern/elbeem/intern/arrays.h b/intern/elbeem/intern/arrays.h
new file mode 100644
index 00000000000..9eea34e579f
--- /dev/null
+++ b/intern/elbeem/intern/arrays.h
@@ -0,0 +1,290 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Array class definitions
+ *
+ *****************************************************************************/
+#ifndef ARRAYS_H
+#include <string>
+#include <sstream>
+#include <fstream>
+
+
+/*****************************************************************************/
+/* array handling "cutting off" access along the border */
+template<class T>
+class ArrayCutoffBc {
+ public:
+ //! constructor
+ ArrayCutoffBc() :
+ mpVal( NULL ), mElemSize( sizeof(T) ),
+ mAllocSize(0),
+ mSizex(0), mSizey(0), mSizez(0)
+ { };
+ //! destructor
+ virtual ~ArrayCutoffBc() {
+ if((mpVal)&&(mAllocSize>0)) delete[] mpVal;
+ mpVal = NULL;
+ }
+
+ //! init sizes
+ void initializeArray(int setx, int sety, int setz) {
+ mSizex = setx;
+ mSizey = sety;
+ mSizez = setz;
+ }
+
+ //! allocate a new array
+ inline void allocate() {
+ int size = mSizex*mSizey*mSizez;
+ if(size == mAllocSize) return; // dont reallocate
+ T* newval = new T[size];
+ for(int i=0;i<size;i++) newval[i] = (T)(0.0);
+ mpVal = (unsigned char *)newval;
+ mAllocSize = size;
+ };
+
+ //! set the scalar field pointer
+ inline void setValuePointer(T *pnt, int elem) { mpVal = (unsigned char *)pnt; mElemSize = elem; };
+
+ //! internal array index calculator
+ inline int arrayIndex(int x, int y, int z) {
+ if(x<0) x=0;
+ if(y<0) y=0;
+ if(z<0) z=0;
+ if(x>mSizex-1) x=mSizex-1;
+ if(y>mSizey-1) y=mSizey-1;
+ if(z>mSizez-1) z=mSizez-1;
+ return z*mSizex*mSizey + y*mSizex + x;
+ }
+ //! phi access function
+ inline T& getValue(int x, int y, int z) {
+ unsigned char *bpnt = &mpVal[ arrayIndex(x,y,z)*mElemSize ];
+ return *((T*)bpnt);
+ //return mpPhi[ z*mSizex*mSizey + y*mSizex + x];
+ }
+ //! return relative offset in direction dir (x=0,y=1,z=2)
+ inline T& getOffset(T *base,int off, int dir) {
+ unsigned char *basep = (unsigned char *)base;
+ int multiplier = 1;
+ if(dir==1) multiplier=mSizex;
+ if(dir==2) multiplier=mSizex*mSizey;
+ // check boundary
+ unsigned char *bpnt = (basep+ ((off*multiplier)*mElemSize) );
+ if(bpnt<mpVal) bpnt = basep;
+ if(bpnt>= (unsigned char *)&getValue(mSizex-1,mSizey-1,mSizez-1) ) bpnt = basep;
+ return *((T*)bpnt);
+ }
+
+ //! perform trilinear interpolation of array values
+ inline T interpolateValueAt(LbmFloat x, LbmFloat y, LbmFloat z) {
+ const LbmFloat gsx=1.0, gsy=1.0, gsz=1.0;
+ int i= (int)x;
+ int j= (int)y;
+ int k= (int)z;
+
+ int in = i+1;
+ int jn = j+1;
+ int kn = k+1;
+ if(in>=mSizex) in = mSizex-1;
+ if(jn>=mSizey) jn = mSizey-1;
+ if(kn>=mSizez) kn = mSizez-1;
+
+ LbmVec mStart(0.0); // TODO remove?
+ LbmFloat x1 = mStart[0]+ (LbmFloat)(i)*gsx;
+ LbmFloat x2 = mStart[0]+ (LbmFloat)(in)*gsx;
+ LbmFloat y1 = mStart[1]+ (LbmFloat)(j)*gsy;
+ LbmFloat y2 = mStart[1]+ (LbmFloat)(jn)*gsy;
+ LbmFloat z1 = mStart[2]+ (LbmFloat)(k)*gsz;
+ LbmFloat z2 = mStart[2]+ (LbmFloat)(kn)*gsz;
+
+ if(mSizez==1) {
+ z1=0.0; z2=1.0;
+ k = kn = 0;
+ }
+
+ T v1, v2, v3, v4, v5, v6, v7, v8;
+ v1 = getValue(i ,j ,k );
+ v2 = getValue(in ,j ,k );
+ v3 = getValue(i ,jn ,k );
+ v4 = getValue(in ,jn ,k );
+ v5 = getValue(i ,j ,kn );
+ v6 = getValue(in ,j ,kn );
+ v7 = getValue(i ,jn ,kn );
+ v8 = getValue(in ,jn ,kn );
+
+ T val =
+ ( v1 *(x2-x)* (y2-y)* (z2-z) +
+ v2 *(x-x1)* (y2-y)* (z2-z) +
+ v3 *(x2-x)* (y-y1)* (z2-z) +
+ v4 *(x-x1)* (y-y1)* (z2-z) +
+ v5 *(x2-x)* (y2-y)* (z-z1) +
+ v6 *(x-x1)* (y2-y)* (z-z1) +
+ v7 *(x2-x)* (y-y1)* (z-z1) +
+ v8 *(x-x1)* (y-y1)* (z-z1)
+ ) * (1.0/(gsx*gsy*gsz)) ;
+ return val;
+ }
+
+ //! get size of an element
+ inline int getElementSize(){ return mElemSize; }
+ //! get array sizes
+ inline int getSizeX(){ return mSizex; }
+ inline int getSizeY(){ return mSizey; }
+ inline int getSizeZ(){ return mSizez; }
+ //! get array pointer
+ inline T* getPointer(){ return (T*)mpVal; }
+
+ //! testing, gnuplot dump (XY plane for k=Z/2)
+ void dumpToFile(std::string filebase, int id, int nr) {
+ std::ostringstream filename;
+ filename << filebase << "_"<< id <<"_"<< nr <<".dump";
+ std::ofstream outfile( filename.str().c_str() );
+ for(int k=mSizez/2; k<=mSizez/2; k++) {
+ for(int j=0; j<mSizey; j++) {
+ for(int i=0; i<mSizex; i++) {
+ outfile <<i<<" "<<j<<" " << getValue(i,j,k)<<" " <<std::endl;
+ }
+ outfile << std::endl;
+ }
+ }
+ }
+ //! testing, grid text dump (XY plane for k=Z/2)
+ void dumpToGridFile(std::string filebase, int id, int nr) {
+ std::ostringstream filename;
+ filename << filebase << "_"<< id <<"_"<< nr <<".dump";
+ std::ofstream outfile( filename.str().c_str() );
+ for(int k=mSizez/2; k<=mSizez/2; k++) {
+ for(int j=0; j<mSizey; j++) {
+ for(int i=0; i<mSizex; i++) {
+ outfile <<getValue(i,j,k)<<"\t";
+ }
+ outfile << std::endl;
+ }
+ }
+ }
+
+ protected:
+ //! pointer for the value field (unsigned char for adding element size)
+ unsigned char *mpVal;
+ //! element offset in array
+ int mElemSize;
+ //! store allocated size
+ int mAllocSize;
+
+ //! Sizes of the scal array in each dimension
+ int mSizex,mSizey,mSizez;
+};
+
+/*****************************************************************************/
+/* array handling "cutting off" access along the border */
+template<class T>
+class ArrayPlain {
+ public:
+ //! constructor
+ ArrayPlain() :
+ mpVal( NULL ), mElemSize( sizeof(T) ),
+ mAllocSize(0),
+ mSizex(0), mSizey(0), mSizez(0)
+ { };
+ //! destructor
+ virtual ~ArrayPlain() {
+ if((mpVal)&&(mAllocSize>0)) delete[] mpVal;
+ mpVal = NULL;
+ }
+
+ //! init sizes
+ void initializeArray(int setx, int sety, int setz) {
+ mSizex = setx;
+ mSizey = sety;
+ mSizez = setz;
+ }
+
+ //! allocate a new array
+ inline void allocate() {
+ int size = mSizex*mSizey*mSizez;
+ if(size == mAllocSize) return; // dont reallocate
+ T* newval = new T[size];
+ for(int i=0;i<size;i++) newval[i] = (T)(0.0);
+ mpVal = (unsigned char *)newval;
+ mAllocSize = size;
+ };
+
+ //! set the scalar field pointer
+ inline void setValuePointer(T *pnt, int elem) { mpVal = (unsigned char *)pnt; mElemSize = elem; };
+
+ //! phi access function
+ inline T& getValue(const int x, const int y, const int z) const {
+ unsigned char *bpnt = &mpVal[ (z*mSizex*mSizey + y*mSizex + x)*mElemSize ];
+ return *((T*)bpnt);
+ }
+ //! return relative offset in direction dir (x=0,y=1,z=2)
+ inline T& getOffset(T *base,int off, int dir) {
+ unsigned char *basep = (unsigned char *)base;
+ int multiplier = 1;
+ if(dir==1) multiplier=mSizex;
+ if(dir==2) multiplier=mSizex*mSizey;
+ // check boundary
+ unsigned char *bpnt = (basep+ ((off*multiplier)*mElemSize) );
+ if(bpnt<mpVal) bpnt = basep;
+ if(bpnt>= (unsigned char *)&getValue(mSizex-1,mSizey-1,mSizez-1) ) bpnt = basep;
+ return *((T*)bpnt);
+ }
+
+ //! get size of an element
+ inline int getElementSize(){ return mElemSize; }
+ //! get array sizes
+ inline int getSizeX(){ return mSizex; }
+ inline int getSizeY(){ return mSizey; }
+ inline int getSizeZ(){ return mSizez; }
+ //! get array pointer
+ inline T* getPointer(){ return (T*)mpVal; }
+
+ //! testing, gnuplot dump (XY plane for k=Z/2)
+ void dumpToFile(std::string filebase, int id, int nr) {
+ std::ostringstream filename;
+ filename << filebase << "_"<< id <<"_"<< nr <<".dump";
+ std::ofstream outfile( filename.str().c_str() );
+ for(int k=mSizez/2; k<=mSizez/2; k++) {
+ for(int j=0; j<mSizey; j++) {
+ for(int i=0; i<mSizex; i++) {
+ outfile <<i<<" "<<j<<" " << getValue(i,j,k)<<" " <<std::endl;
+ }
+ outfile << std::endl;
+ }
+ }
+ }
+ //! testing, grid text dump (XY plane for k=Z/2)
+ void dumpToGridFile(std::string filebase, int id, int nr) {
+ std::ostringstream filename;
+ filename << filebase << "_"<< id <<"_"<< nr <<".dump";
+ std::ofstream outfile( filename.str().c_str() );
+ for(int k=mSizez/2; k<=mSizez/2; k++) {
+ for(int j=0; j<mSizey; j++) {
+ for(int i=0; i<mSizex; i++) {
+ outfile <<getValue(i,j,k)<<"\t";
+ }
+ outfile << std::endl;
+ }
+ }
+ }
+
+ protected:
+ //! pointer for the value field (unsigned char for adding element size)
+ unsigned char *mpVal;
+ //! element offset in array
+ int mElemSize;
+ //! store allocated size
+ int mAllocSize;
+
+ //! Sizes of the scal array in each dimension
+ int mSizex,mSizey,mSizez;
+};
+
+
+
+#define ARRAYS_H
+#endif
+
diff --git a/intern/elbeem/intern/attributes.cpp b/intern/elbeem/intern/attributes.cpp
new file mode 100644
index 00000000000..aa013a5b3aa
--- /dev/null
+++ b/intern/elbeem/intern/attributes.cpp
@@ -0,0 +1,358 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * configuration attribute storage class and attribute class
+ *
+ *****************************************************************************/
+
+#include "attributes.h"
+#include <sstream>
+
+
+//! output attribute values? on=1/off=0
+#define DEBUG_ATTRIBUTES 0
+
+
+/******************************************************************************
+ * attribute conversion functions
+ *****************************************************************************/
+
+// get value as string
+string Attribute::getAsString()
+{
+ if(mValue.size()!=1) {
+ //errMsg("Attribute::getAsString", "Attribute \"" << mName << "\" used as string has invalid value '"<< getCompleteString() <<"' ");
+ // for directories etc. , this might be valid! cutoff "..." first
+ string comp = getCompleteString();
+ if(comp.size()<2) return string("");
+ return comp.substr(1, comp.size()-2);
+ }
+ return mValue[0];
+}
+
+// get value as integer value
+int Attribute::getAsInt()
+{
+ bool success = true;
+ int ret = 0;
+ if(mValue.size()!=1) success = false;
+ else {
+ const char *str = mValue[0].c_str();
+ char *endptr;
+ ret = strtol(str, &endptr, 10);
+ if( (str==endptr) ||
+ ((str!=endptr) && (*endptr != '\0')) )success = false;
+ }
+
+ if(!success) {
+ errMsg("Attribute::getAsString", "Attribute \"" << mName << "\" used as int has invalid value '"<< getCompleteString() <<"' ");
+ errMsg("Attribute::getAsString", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
+ errMsg("Attribute::getAsString", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
+ return 0;
+ }
+ return ret;
+}
+
+
+// get value as integer value
+bool Attribute::getAsBool()
+{
+ int val = getAsInt();
+ if(val==0) return false;
+ else return true;
+}
+
+
+// get value as double value
+double Attribute::getAsFloat()
+{
+ bool success = true;
+ double ret = 0.0;
+ if(mValue.size()!=1) success = false;
+ else {
+ const char *str = mValue[0].c_str();
+ char *endptr;
+ ret = strtod(str, &endptr);
+ if((str!=endptr) && (*endptr != '\0')) success = false;
+ }
+
+ if(!success) {
+ errMsg("Attribute::getAsFloat", "Attribute \"" << mName << "\" used as double has invalid value '"<< getCompleteString() <<"' ");
+ errMsg("Attribute::getAsFloat", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
+ errMsg("Attribute::getAsFloat", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
+ return 0.0;
+ }
+ return ret;
+}
+
+// get value as 3d vector
+ntlVec3d Attribute::getAsVec3d()
+{
+ bool success = true;
+ ntlVec3d ret(0.0);
+ if(mValue.size()==1) {
+ const char *str = mValue[0].c_str();
+ char *endptr;
+ double rval = strtod(str, &endptr);
+ if( (str==endptr) ||
+ ((str!=endptr) && (*endptr != '\0')) )success = false;
+ if(success) ret = ntlVec3d( rval );
+ } else if(mValue.size()==3) {
+ char *endptr;
+ const char *str = NULL;
+
+ str = mValue[0].c_str();
+ double rval1 = strtod(str, &endptr);
+ if( (str==endptr) ||
+ ((str!=endptr) && (*endptr != '\0')) )success = false;
+
+ str = mValue[1].c_str();
+ double rval2 = strtod(str, &endptr);
+ if( (str==endptr) ||
+ ((str!=endptr) && (*endptr != '\0')) )success = false;
+
+ str = mValue[2].c_str();
+ double rval3 = strtod(str, &endptr);
+ if( (str==endptr) ||
+ ((str!=endptr) && (*endptr != '\0')) )success = false;
+
+ if(success) ret = ntlVec3d( rval1, rval2, rval3 );
+ } else {
+ success = false;
+ }
+
+ if(!success) {
+ errMsg("Attribute::getAsVec3d", "Attribute \"" << mName << "\" used as Vec3d has invalid value '"<< getCompleteString() <<"' ");
+ errMsg("Attribute::getAsVec3d", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
+ errMsg("Attribute::getAsVec3d", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
+ return ntlVec3d(0.0);
+ }
+ return ret;
+}
+
+// get value as 4x4 matrix
+ntlMat4Gfx Attribute::getAsMat4Gfx()
+{
+ bool success = true;
+ ntlMat4Gfx ret(0.0);
+ char *endptr;
+ const char *str = NULL;
+
+ if(mValue.size()==1) {
+ const char *str = mValue[0].c_str();
+ char *endptr;
+ double rval = strtod(str, &endptr);
+ if( (str==endptr) ||
+ ((str!=endptr) && (*endptr != '\0')) )success = false;
+ if(success) {
+ ret = ntlMat4Gfx( 0.0 );
+ ret.value[0][0] = rval;
+ ret.value[1][1] = rval;
+ ret.value[2][2] = rval;
+ ret.value[3][3] = 1.0;
+ }
+ } else if(mValue.size()==9) {
+ // 3x3
+ for(int i=0; i<3;i++) {
+ for(int j=0; j<3;j++) {
+ str = mValue[i*3+j].c_str();
+ ret.value[i][j] = strtod(str, &endptr);
+ if( (str==endptr) ||
+ ((str!=endptr) && (*endptr != '\0')) ) success = false;
+ }
+ }
+ } else if(mValue.size()==16) {
+ // 4x4
+ for(int i=0; i<4;i++) {
+ for(int j=0; j<4;j++) {
+ str = mValue[i*4+j].c_str();
+ ret.value[i][j] = strtod(str, &endptr);
+ if( (str==endptr) ||
+ ((str!=endptr) && (*endptr != '\0')) ) success = false;
+ }
+ }
+
+ } else {
+ success = false;
+ }
+
+ if(!success) {
+ errMsg("Attribute::getAsMat4Gfx", "Attribute \"" << mName << "\" used as Mat4x4 has invalid value '"<< getCompleteString() <<"' ");
+ errMsg("Attribute::getAsMat4Gfx", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
+ errMsg("Attribute::getAsMat4Gfx", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
+ return ntlMat4Gfx(0.0);
+ }
+ return ret;
+}
+
+
+// get the concatenated string of all value string
+string Attribute::getCompleteString()
+{
+ string ret;
+ for(size_t i=0;i<mValue.size();i++) {
+ ret += mValue[i];
+ if(i<mValue.size()-1) ret += " ";
+ }
+ return ret;
+}
+
+
+/******************************************************************************
+ * check if there were unknown params
+ *****************************************************************************/
+bool AttributeList::checkUnusedParams()
+{
+ bool found = false;
+ for(map<string, Attribute*>::iterator i=mAttrs.begin();
+ i != mAttrs.end(); i++) {
+ if((*i).second) {
+ if(!(*i).second->getUsed()) {
+ errorOut("Attribute "<<mName<<" has unknown parameter '"<<(*i).first<<"' = '"<< mAttrs[(*i).first]->getAsString() <<"' ");
+ found = true;
+ }
+ }
+ }
+ return found;
+}
+//! set all params to used, for invisible objects
+void AttributeList::setAllUsed() {
+ for(map<string, Attribute*>::iterator i=mAttrs.begin();
+ i != mAttrs.end(); i++) {
+ if((*i).second) {
+ (*i).second->setUsed(true);
+ }
+ }
+}
+
+/******************************************************************************
+ * Attribute list read functions
+ *****************************************************************************/
+int AttributeList::readInt(string name, int defaultValue, string source,string target, bool needed) {
+ if(!exists(name)) {
+ if(needed) { errorOut("AttributeList::readInt error: Required attribute '"<<name<<"' for "<< source <<" not set! "); exit(1); }
+ return defaultValue;
+ }
+ if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
+ find(name)->setUsed(true);
+ return find(name)->getAsInt();
+}
+bool AttributeList::readBool(string name, bool defaultValue, string source,string target, bool needed) {
+ if(!exists(name)) {
+ if(needed) { errorOut("AttributeList::readBool error: Required attribute '"<<name<<"' for "<< source <<" not set! "); exit(1); }
+ return defaultValue;
+ }
+ if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
+ find(name)->setUsed(true);
+ return find(name)->getAsBool();
+}
+double AttributeList::readFloat(string name, double defaultValue, string source,string target, bool needed) {
+ if(!exists(name)) {
+ if(needed) { errorOut("AttributeList::readFloat error: Required attribute '"<<name<<"' for "<< source <<" not set! "); exit(1); }
+ return defaultValue;
+ }
+ if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
+ find(name)->setUsed(true);
+ return find(name)->getAsFloat();
+}
+string AttributeList::readString(string name, string defaultValue, string source,string target, bool needed) {
+ if(!exists(name)) {
+ if(needed) { errorOut("AttributeList::readInt error: Required attribute '"<<name<<"' for "<< source <<" not set! "); exit(1); }
+ return defaultValue;
+ }
+ if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
+ find(name)->setUsed(true);
+ return find(name)->getAsString();
+}
+ntlVec3d AttributeList::readVec3d(string name, ntlVec3d defaultValue, string source,string target, bool needed) {
+ if(!exists(name)) {
+ if(needed) { errorOut("AttributeList::readInt error: Required attribute '"<<name<<"' for "<< source <<" not set! "); exit(1); }
+ return defaultValue;
+ }
+ if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
+ find(name)->setUsed(true);
+ return find(name)->getAsVec3d();
+}
+
+ntlMat4Gfx AttributeList::readMat4Gfx(string name, ntlMat4Gfx defaultValue, string source,string target, bool needed) {
+ if(!exists(name)) {
+ if(needed) { errorOut("AttributeList::readInt error: Required attribute '"<<name<<"' for "<< source <<" not set! "); exit(1); }
+ return defaultValue;
+ }
+ if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
+ find(name)->setUsed(true);
+ return find(name)->getAsMat4Gfx();
+}
+
+// set that a parameter can be given, and will be ignored...
+bool AttributeList::ignoreParameter(string name, string source) {
+ if(!exists(name)) return false;
+ find(name)->setUsed(true);
+ if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Param '"<< name <<"' set but ignored... " , 3); }
+ return true;
+}
+
+/******************************************************************************
+ * destructor
+ *****************************************************************************/
+AttributeList::~AttributeList() {
+ for(map<string, Attribute*>::iterator i=mAttrs.begin();
+ i != mAttrs.end(); i++) {
+ if((*i).second) {
+ delete (*i).second;
+ (*i).second = NULL;
+ }
+ }
+};
+
+
+/******************************************************************************
+ * debugging
+ *****************************************************************************/
+
+//! debug function, prints value
+void Attribute::print()
+{
+ std::ostringstream ostr;
+ ostr << " "<< mName <<"= ";
+ for(size_t i=0;i<mValue.size();i++) {
+ ostr <<"'"<< mValue[i]<<"' ";
+ }
+ ostr <<" (at line "<<mLine<<") "; //<< std::endl;
+ debugOut( ostr.str(), 10);
+}
+
+//! debug function, prints all attribs
+void AttributeList::print()
+{
+ debugOut("Attribute "<<mName<<" values:", 10);
+ for(map<string, Attribute*>::iterator i=mAttrs.begin();
+ i != mAttrs.end(); i++) {
+ if((*i).second) {
+ (*i).second->print();
+ }
+ }
+}
+
+
+
+/******************************************************************************
+ * import attributes from other attribute list
+ *****************************************************************************/
+void AttributeList::import(AttributeList *oal)
+{
+ for(map<string, Attribute*>::iterator i=oal->mAttrs.begin();
+ i !=oal->mAttrs.end(); i++) {
+ // FIXME - check freeing of copyied attributes
+ if((*i).second) {
+ Attribute *newAttr = new Attribute( *(*i).second );
+ mAttrs[ (*i).first ] = newAttr;
+ }
+ }
+}
+
+
+
+
diff --git a/intern/elbeem/intern/attributes.h b/intern/elbeem/intern/attributes.h
new file mode 100644
index 00000000000..93793708533
--- /dev/null
+++ b/intern/elbeem/intern/attributes.h
@@ -0,0 +1,143 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * configuration attribute storage class and attribute class
+ *
+ *****************************************************************************/
+
+
+#ifndef NTL_ATTRIBUTES_H
+
+#include "utilities.h"
+#include "ntl_matrices.h"
+
+
+//! A single attribute
+class Attribute
+{
+ public:
+ //! Standard constructor
+ Attribute(string mn, vector<string> &value, int setline) :
+ mName(mn), mValue(value),
+ mLine(setline), mUsed(false) { };
+ //! Copy constructor
+ Attribute(Attribute &a) :
+ mName(a.mName), mValue(a.mValue),
+ mLine(a.mLine), mUsed(false) { };
+ //! Destructor
+ ~Attribute() { /* empty */ };
+
+ //! set used flag
+ void setUsed(bool set){ mUsed = set; }
+ //! get used flag
+ bool getUsed() { return mUsed; }
+
+ //! get value as string
+ string getAsString();
+
+ //! get value as integer value
+ int getAsInt();
+
+ //! get value as boolean
+ bool getAsBool();
+
+ //! get value as double value
+ double getAsFloat();
+
+ //! get value as 3d vector
+ ntlVec3d getAsVec3d();
+
+ //! get value as 4x4 matrix
+ ntlMat4Gfx getAsMat4Gfx();
+
+ //! get the concatenated string of all value string
+ string getCompleteString();
+
+ //! debug function, prints value
+ void print();
+
+ protected:
+
+ /*! the attr name */
+ string mName;
+
+ /*! the attr value */
+ vector<string> mValue;
+
+ /*! line where the value was defined in the config file (for error messages) */
+ int mLine;
+
+ /*! was this attribute used? */
+ bool mUsed;
+};
+
+
+//! The list of configuration attributes
+class AttributeList
+{
+ public:
+ //! Standard constructor
+ AttributeList(string name) :
+ mName(name), mAttrs() { };
+ //! Destructor , delete all contained attribs
+ ~AttributeList();
+
+ /*! add an attribute to this list */
+ void addAttr(string name, vector<string> &value, int line) {
+ if(exists(name)) delete mAttrs[name];
+ mAttrs[name] = new Attribute(name,value,line);
+ }
+
+ /*! check if an attribute is set */
+ bool exists(string name) {
+ if(mAttrs.find(name) == mAttrs.end()) return false;
+ return true;
+ }
+
+ /*! get an attribute */
+ Attribute *find(string name) {
+ if(mAttrs.find(name) == mAttrs.end()) {
+ errorOut("AttributeList::find error: Invalid attribute '"<<name<<"' , not found..." );
+ exit(1);
+ }
+ return mAttrs[name];
+ }
+
+ //! set all params to used, for invisible objects
+ void setAllUsed();
+ //! check if there were unknown params
+ bool checkUnusedParams();
+
+ //! import attributes from other attribute list
+ void import(AttributeList *oal);
+
+ //! read attributes for object initialization
+ int readInt(string name, int defaultValue, string source,string target, bool needed);
+ bool readBool(string name, bool defaultValue, string source,string target, bool needed);
+ double readFloat(string name, double defaultValue, string source,string target, bool needed);
+ string readString(string name, string defaultValue, string source,string target, bool needed);
+ ntlVec3d readVec3d(string name, ntlVec3d defaultValue, string source,string target, bool needed);
+ ntlMat4Gfx readMat4Gfx(string name, ntlMat4Gfx defaultValue, string source,string target, bool needed);
+
+ //! set that a parameter can be given, and will be ignored...
+ bool ignoreParameter(string name, string source);
+
+ //! debug function, prints all attribs
+ void print();
+
+ protected:
+
+ /*! attribute name (form config file) */
+ string mName;
+
+ /*! the global attribute storage */
+ map<string, Attribute*> mAttrs;
+
+};
+
+
+#define NTL_ATTRIBUTES_H
+#endif
+
diff --git a/intern/elbeem/intern/blendercall.cpp b/intern/elbeem/intern/blendercall.cpp
new file mode 100644
index 00000000000..41ddf7d63e1
--- /dev/null
+++ b/intern/elbeem/intern/blendercall.cpp
@@ -0,0 +1,28 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * All code distributed as part of El'Beem is covered by the version 2 of the
+ * GNU General Public License. See the file COPYING for details.
+ * Copyright 2003-2005 Nils Thuerey
+ *
+ * Blender call interface
+ *
+ *****************************************************************************/
+
+#include "globals.h"
+#include "ntl_raytracer.h"
+#include "ntl_blenderdumper.h"
+
+extern "C"
+int performElbeemSimulation(char *cfgfilename) {
+ fprintf(GEN_userstream, "Running El'Beem from Blender with file '%s' ...\n",cfgfilename);
+ // load given file in command line mode
+ ntlBlenderDumper elbeem(cfgfilename, true);
+ myTime_t timestart = getTime();
+ elbeem.renderAnimation();
+ myTime_t timeend = getTime();
+ fprintf(GEN_userstream, "El'Beem simulation done, time: %f seconds.\n", ((timeend-timestart)/(double)1000.0) );
+ return 1;
+};
+
+
diff --git a/intern/elbeem/intern/cfglexer.cpp b/intern/elbeem/intern/cfglexer.cpp
new file mode 100644
index 00000000000..ddd8367eae0
--- /dev/null
+++ b/intern/elbeem/intern/cfglexer.cpp
@@ -0,0 +1,2561 @@
+
+#line 3 "<stdout>"
+
+#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 31
+#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 <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
+#include <inttypes.h>
+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 */
+
+#if __STDC__
+
+#define YY_USE_CONST
+
+#endif /* __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 yy_restart(yy_in )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int yy_leng;
+
+extern FILE *yy_in, *yy_out;
+
+#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 yy_text. */ \
+ 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 yy_text again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef unsigned int yy_size_t;
+#endif
+
+#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.
+ */
+ int 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 yy_restart()), so that the user can continue scanning by
+ * just pointing yy_in 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 yy_text is formed. */
+static char yy_hold_char;
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+int yy_leng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yy_wrap()'s to do buffer switches
+ * instead of setting up a fresh yy_in. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yy_restart (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 yy_push_buffer_state (YY_BUFFER_STATE new_buffer );
+void yy_pop_buffer_state (void );
+
+static void yy_ensure_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,int len );
+
+void *yy_alloc (yy_size_t );
+void *yy_realloc (void *,yy_size_t );
+void yy_free (void * );
+
+#define yy_new_buffer yy__create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yy_ensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy__create_buffer(yy_in,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yy_ensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy__create_buffer(yy_in,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+
+FILE *yy_in = (FILE *) 0, *yy_out = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int yy_lineno;
+
+int yy_lineno = 1;
+
+extern char *yy_text;
+#define yytext_ptr yy_text
+
+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 yy_text.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ yy_leng = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 97
+#define YY_END_OF_BUFFER 98
+/* 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[562] =
+ { 0,
+ 0, 0, 0, 0, 6, 6, 98, 96, 96, 94,
+ 95, 96, 92, 96, 96, 96, 88, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 1, 2, 96, 95, 4,
+ 3, 6, 7, 6, 6, 6, 7, 1, 2, 0,
+ 1, 2, 0, 92, 0, 88, 89, 93, 91, 88,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 84, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 1, 2, 0, 3,
+ 4, 3, 6, 6, 5, 6, 6, 6, 90, 91,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 44,
+ 0, 0, 0, 0, 0, 0, 0, 0, 51, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 85, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 17, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 0, 0, 0, 75, 0,
+ 0, 52, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 86, 43, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 62,
+ 0, 0, 78, 0, 0, 0, 0, 0, 0, 0,
+ 87, 0, 0, 0, 0, 0, 0, 0, 0, 74,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 50,
+ 0, 0, 0, 16, 0, 0, 76, 0, 0, 0,
+
+ 0, 18, 0, 0, 0, 0, 0, 77, 0, 0,
+ 0, 39, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 59, 0, 15, 0, 0, 67, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 45, 0, 0, 0, 0, 55, 0, 64, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 65, 0, 0, 0, 0, 0, 72, 0, 0,
+ 0, 0, 0, 0, 0, 0, 53, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 49, 0, 0, 21, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 14, 58, 25,
+ 8, 0, 42, 0, 60, 0, 0, 0, 46, 0,
+ 79, 0, 0, 0, 0, 0, 0, 66, 34, 0,
+ 0, 0, 0, 0, 0, 22, 0, 13, 38, 0,
+ 0, 0, 0, 0, 0, 0, 0, 10, 0, 0,
+ 0, 24, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 82, 0, 0, 0, 0, 0, 0, 0,
+ 37, 20, 0, 0, 0, 0, 0, 0, 9, 33,
+ 0, 73, 57, 0, 0, 0, 35, 11, 0, 0,
+ 0, 12, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 36, 47, 0, 0, 83, 0, 40, 30, 56, 54,
+ 0, 69, 0, 0, 0, 71, 0, 0, 0, 19,
+ 23, 0, 0, 0, 0, 0, 0, 0, 0, 68,
+ 31, 0, 0, 0, 0, 0, 0, 0, 0, 29,
+ 70, 0, 0, 0, 80, 0, 0, 48, 26, 0,
+ 0, 0, 81, 0, 0, 27, 28, 0, 32, 41,
+ 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 4, 1, 5, 6, 1, 1, 1, 1, 1,
+ 1, 7, 1, 1, 8, 9, 10, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 12, 13, 1,
+ 14, 1, 1, 1, 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, 33,
+ 1, 15, 1, 1, 16, 1, 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, 33, 42, 1, 43, 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[44] =
+ { 0,
+ 1, 2, 3, 4, 1, 1, 1, 5, 6, 5,
+ 6, 5, 2, 1, 5, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[572] =
+ { 0,
+ 0, 0, 43, 86, 128, 170, 699, 700, 60, 700,
+ 63, 0, 0, 43, 687, 53, 50, 47, 53, 78,
+ 47, 39, 87, 676, 43, 82, 54, 80, 117, 92,
+ 93, 112, 116, 664, 99, 123, 138, 149, 152, 0,
+ 141, 0, 700, 690, 156, 101, 700, 157, 160, 163,
+ 175, 180, 689, 0, 682, 176, 681, 700, 0, 177,
+ 655, 672, 153, 657, 652, 668, 101, 646, 161, 46,
+ 175, 178, 665, 663, 655, 654, 644, 642, 186, 648,
+ 640, 646, 653, 644, 168, 640, 644, 643, 645, 648,
+ 639, 700, 647, 636, 174, 625, 192, 648, 131, 647,
+
+ 628, 198, 630, 623, 626, 624, 214, 219, 222, 226,
+ 0, 227, 0, 653, 652, 230, 0, 235, 700, 0,
+ 631, 630, 146, 629, 632, 618, 624, 620, 619, 700,
+ 612, 612, 615, 613, 607, 618, 614, 619, 700, 608,
+ 604, 617, 612, 595, 606, 599, 604, 611, 596, 606,
+ 602, 607, 593, 592, 604, 206, 595, 700, 598, 592,
+ 591, 579, 594, 582, 596, 582, 595, 583, 593, 593,
+ 590, 576, 573, 578, 586, 585, 584, 583, 567, 577,
+ 238, 563, 579, 565, 562, 580, 577, 570, 571, 573,
+ 562, 556, 554, 183, 572, 565, 557, 565, 548, 553,
+
+ 562, 216, 562, 700, 560, 550, 558, 544, 540, 540,
+ 558, 540, 556, 541, 700, 540, 549, 538, 700, 545,
+ 544, 543, 529, 530, 538, 545, 540, 532, 528, 521,
+ 523, 520, 526, 519, 524, 700, 700, 533, 530, 532,
+ 528, 518, 530, 529, 517, 508, 525, 508, 520, 700,
+ 516, 514, 700, 504, 503, 218, 515, 516, 499, 508,
+ 700, 501, 514, 502, 494, 507, 491, 490, 491, 700,
+ 488, 498, 481, 487, 492, 485, 498, 489, 700, 485,
+ 490, 497, 475, 493, 477, 473, 470, 480, 486, 700,
+ 475, 193, 488, 700, 464, 475, 700, 466, 472, 466,
+
+ 474, 700, 461, 466, 462, 478, 475, 700, 472, 461,
+ 466, 474, 453, 467, 457, 466, 456, 466, 456, 454,
+ 447, 700, 458, 700, 462, 458, 700, 436, 440, 454,
+ 457, 443, 441, 452, 449, 444, 449, 431, 437, 448,
+ 700, 444, 213, 446, 422, 700, 440, 432, 438, 422,
+ 440, 420, 418, 437, 433, 227, 424, 431, 410, 432,
+ 414, 700, 411, 425, 424, 415, 418, 700, 401, 424,
+ 412, 418, 415, 412, 408, 399, 700, 404, 408, 397,
+ 401, 413, 404, 411, 393, 405, 405, 388, 389, 221,
+ 700, 397, 218, 700, 386, 399, 389, 382, 386, 382,
+
+ 391, 227, 396, 392, 391, 375, 385, 700, 700, 700,
+ 700, 377, 700, 389, 700, 375, 375, 386, 700, 368,
+ 700, 373, 378, 381, 363, 368, 366, 700, 700, 372,
+ 377, 374, 373, 359, 369, 700, 366, 700, 355, 369,
+ 352, 348, 352, 354, 367, 349, 353, 700, 353, 344,
+ 360, 700, 357, 341, 346, 354, 340, 350, 355, 350,
+ 335, 339, 350, 331, 335, 335, 332, 338, 338, 332,
+ 700, 700, 326, 324, 341, 321, 324, 334, 700, 700,
+ 320, 700, 700, 329, 317, 316, 700, 700, 330, 309,
+ 312, 700, 322, 321, 317, 325, 307, 325, 305, 319,
+
+ 700, 700, 319, 307, 700, 307, 311, 700, 700, 700,
+ 304, 700, 309, 316, 294, 700, 310, 306, 299, 700,
+ 700, 235, 298, 304, 308, 286, 305, 288, 301, 700,
+ 700, 298, 295, 295, 280, 273, 266, 263, 262, 700,
+ 700, 268, 257, 260, 700, 266, 249, 700, 700, 245,
+ 225, 224, 700, 237, 166, 700, 700, 155, 700, 700,
+ 700, 267, 273, 276, 282, 113, 288, 294, 300, 306,
+ 312
+ } ;
+
+static yyconst flex_int16_t yy_def[572] =
+ { 0,
+ 561, 1, 562, 562, 563, 563, 561, 561, 561, 561,
+ 561, 564, 565, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 566,
+ 561, 567, 561, 568, 569, 567, 561, 567, 567, 561,
+ 561, 561, 564, 565, 561, 561, 561, 561, 570, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 566, 561, 567, 568, 568, 569, 567, 571, 561, 570,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 571, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 0, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561
+ } ;
+
+static yyconst flex_int16_t yy_nxt[744] =
+ { 0,
+ 8, 9, 10, 11, 12, 13, 8, 14, 15, 16,
+ 17, 8, 8, 8, 8, 8, 18, 19, 20, 21,
+ 22, 23, 24, 8, 25, 8, 8, 26, 27, 28,
+ 29, 30, 8, 31, 32, 33, 34, 35, 8, 8,
+ 8, 36, 37, 8, 38, 10, 39, 8, 13, 8,
+ 8, 55, 16, 56, 8, 8, 41, 8, 55, 58,
+ 60, 50, 59, 50, 50, 61, 50, 71, 73, 66,
+ 85, 72, 81, 133, 134, 62, 63, 82, 86, 74,
+ 67, 64, 65, 68, 36, 37, 8, 38, 10, 39,
+ 8, 13, 8, 8, 69, 16, 87, 8, 8, 41,
+
+ 8, 51, 52, 75, 51, 52, 83, 117, 70, 96,
+ 118, 76, 84, 97, 77, 94, 88, 78, 111, 105,
+ 79, 128, 95, 106, 107, 129, 107, 36, 37, 9,
+ 43, 11, 44, 45, 89, 98, 101, 46, 90, 108,
+ 47, 108, 112, 99, 112, 91, 92, 100, 93, 102,
+ 109, 170, 109, 109, 171, 109, 103, 54, 107, 54,
+ 107, 108, 110, 108, 50, 110, 50, 184, 54, 48,
+ 49, 9, 43, 11, 44, 45, 107, 123, 107, 46,
+ 185, 108, 47, 108, 55, 55, 56, 60, 124, 560,
+ 51, 52, 135, 51, 52, 131, 136, 132, 137, 138,
+
+ 559, 162, 145, 152, 51, 52, 146, 153, 163, 343,
+ 165, 48, 49, 166, 174, 107, 253, 107, 175, 254,
+ 108, 167, 108, 109, 344, 109, 168, 112, 112, 112,
+ 112, 54, 387, 54, 176, 110, 120, 216, 120, 120,
+ 433, 120, 54, 217, 262, 263, 310, 120, 388, 311,
+ 120, 400, 436, 437, 533, 445, 434, 558, 401, 557,
+ 556, 402, 446, 51, 52, 555, 534, 40, 40, 40,
+ 40, 40, 40, 42, 42, 42, 42, 42, 42, 53,
+ 53, 53, 54, 54, 554, 54, 54, 54, 113, 553,
+ 552, 551, 113, 113, 114, 550, 549, 548, 114, 114,
+
+ 116, 116, 547, 116, 116, 116, 120, 120, 546, 120,
+ 120, 120, 181, 181, 545, 181, 181, 181, 544, 543,
+ 542, 541, 540, 539, 538, 537, 536, 535, 532, 531,
+ 530, 529, 528, 527, 526, 525, 524, 523, 522, 521,
+ 520, 519, 518, 517, 516, 515, 514, 513, 512, 511,
+ 510, 509, 508, 507, 506, 505, 504, 503, 502, 501,
+ 500, 499, 498, 497, 496, 495, 494, 493, 492, 491,
+ 490, 489, 488, 487, 486, 485, 484, 483, 482, 481,
+ 480, 479, 478, 477, 476, 475, 474, 473, 472, 471,
+ 470, 469, 468, 467, 466, 465, 464, 463, 462, 461,
+
+ 460, 459, 458, 457, 456, 455, 454, 453, 452, 451,
+ 450, 449, 448, 447, 444, 443, 442, 441, 440, 439,
+ 438, 435, 432, 431, 430, 429, 428, 427, 426, 425,
+ 424, 423, 422, 421, 420, 419, 418, 417, 416, 415,
+ 414, 413, 412, 411, 410, 409, 408, 407, 406, 405,
+ 404, 403, 399, 398, 397, 396, 395, 394, 393, 392,
+ 391, 390, 389, 386, 385, 384, 383, 382, 381, 380,
+ 379, 378, 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, 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, 309, 308, 307, 306,
+ 305, 304, 303, 302, 301, 300, 299, 298, 297, 296,
+ 295, 294, 293, 292, 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, 261, 260, 259, 258, 257, 256, 255, 252,
+ 251, 250, 249, 248, 247, 246, 245, 244, 243, 242,
+
+ 241, 240, 239, 238, 237, 236, 235, 234, 233, 232,
+ 231, 230, 229, 228, 227, 226, 225, 224, 223, 222,
+ 221, 220, 219, 218, 215, 214, 213, 212, 211, 210,
+ 209, 208, 207, 206, 205, 204, 203, 202, 201, 200,
+ 199, 198, 197, 196, 195, 194, 193, 192, 191, 190,
+ 189, 188, 187, 186, 183, 182, 115, 115, 180, 179,
+ 178, 177, 173, 172, 169, 164, 161, 160, 159, 158,
+ 157, 156, 155, 154, 151, 150, 149, 148, 147, 144,
+ 143, 142, 141, 140, 139, 130, 127, 126, 125, 122,
+ 121, 57, 57, 119, 115, 104, 80, 57, 561, 7,
+
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561
+ } ;
+
+static yyconst flex_int16_t yy_chk[744] =
+ { 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, 3, 3, 3, 3, 3, 3, 3,
+ 3, 14, 3, 14, 3, 3, 3, 3, 17, 16,
+ 17, 9, 16, 9, 11, 18, 11, 21, 22, 19,
+ 27, 21, 25, 70, 70, 18, 18, 25, 27, 22,
+ 19, 18, 18, 19, 3, 3, 4, 4, 4, 4,
+ 4, 4, 4, 4, 20, 4, 28, 4, 4, 4,
+
+ 4, 9, 9, 23, 11, 11, 26, 46, 20, 31,
+ 46, 23, 26, 31, 23, 30, 28, 23, 566, 35,
+ 23, 67, 30, 35, 36, 67, 36, 4, 4, 5,
+ 5, 5, 5, 5, 29, 32, 33, 5, 29, 37,
+ 5, 37, 41, 32, 41, 29, 29, 32, 29, 33,
+ 38, 99, 38, 39, 99, 39, 33, 45, 48, 45,
+ 48, 49, 38, 49, 50, 39, 50, 123, 45, 5,
+ 5, 6, 6, 6, 6, 6, 51, 63, 51, 6,
+ 123, 52, 6, 52, 56, 60, 56, 60, 63, 558,
+ 38, 38, 71, 39, 39, 69, 71, 69, 72, 72,
+
+ 555, 95, 79, 85, 50, 50, 79, 85, 95, 292,
+ 97, 6, 6, 97, 102, 107, 194, 107, 102, 194,
+ 108, 97, 108, 109, 292, 109, 97, 110, 112, 110,
+ 112, 116, 343, 116, 102, 109, 118, 156, 118, 181,
+ 390, 181, 116, 156, 202, 202, 256, 118, 343, 256,
+ 181, 356, 393, 393, 522, 402, 390, 554, 356, 552,
+ 551, 356, 402, 109, 109, 550, 522, 562, 562, 562,
+ 562, 562, 562, 563, 563, 563, 563, 563, 563, 564,
+ 564, 564, 565, 565, 547, 565, 565, 565, 567, 546,
+ 544, 543, 567, 567, 568, 542, 539, 538, 568, 568,
+
+ 569, 569, 537, 569, 569, 569, 570, 570, 536, 570,
+ 570, 570, 571, 571, 535, 571, 571, 571, 534, 533,
+ 532, 529, 528, 527, 526, 525, 524, 523, 519, 518,
+ 517, 515, 514, 513, 511, 507, 506, 504, 503, 500,
+ 499, 498, 497, 496, 495, 494, 493, 491, 490, 489,
+ 486, 485, 484, 481, 478, 477, 476, 475, 474, 473,
+ 470, 469, 468, 467, 466, 465, 464, 463, 462, 461,
+ 460, 459, 458, 457, 456, 455, 454, 453, 451, 450,
+ 449, 447, 446, 445, 444, 443, 442, 441, 440, 439,
+ 437, 435, 434, 433, 432, 431, 430, 427, 426, 425,
+
+ 424, 423, 422, 420, 418, 417, 416, 414, 412, 407,
+ 406, 405, 404, 403, 401, 400, 399, 398, 397, 396,
+ 395, 392, 389, 388, 387, 386, 385, 384, 383, 382,
+ 381, 380, 379, 378, 376, 375, 374, 373, 372, 371,
+ 370, 369, 367, 366, 365, 364, 363, 361, 360, 359,
+ 358, 357, 355, 354, 353, 352, 351, 350, 349, 348,
+ 347, 345, 344, 342, 340, 339, 338, 337, 336, 335,
+ 334, 333, 332, 331, 330, 329, 328, 326, 325, 323,
+ 321, 320, 319, 318, 317, 316, 315, 314, 313, 312,
+ 311, 310, 309, 307, 306, 305, 304, 303, 301, 300,
+
+ 299, 298, 296, 295, 293, 291, 289, 288, 287, 286,
+ 285, 284, 283, 282, 281, 280, 278, 277, 276, 275,
+ 274, 273, 272, 271, 269, 268, 267, 266, 265, 264,
+ 263, 262, 260, 259, 258, 257, 255, 254, 252, 251,
+ 249, 248, 247, 246, 245, 244, 243, 242, 241, 240,
+ 239, 238, 235, 234, 233, 232, 231, 230, 229, 228,
+ 227, 226, 225, 224, 223, 222, 221, 220, 218, 217,
+ 216, 214, 213, 212, 211, 210, 209, 208, 207, 206,
+ 205, 203, 201, 200, 199, 198, 197, 196, 195, 193,
+ 192, 191, 190, 189, 188, 187, 186, 185, 184, 183,
+
+ 182, 180, 179, 178, 177, 176, 175, 174, 173, 172,
+ 171, 170, 169, 168, 167, 166, 165, 164, 163, 162,
+ 161, 160, 159, 157, 155, 154, 153, 152, 151, 150,
+ 149, 148, 147, 146, 145, 144, 143, 142, 141, 140,
+ 138, 137, 136, 135, 134, 133, 132, 131, 129, 128,
+ 127, 126, 125, 124, 122, 121, 115, 114, 106, 105,
+ 104, 103, 101, 100, 98, 96, 94, 93, 91, 90,
+ 89, 88, 87, 86, 84, 83, 82, 81, 80, 78,
+ 77, 76, 75, 74, 73, 68, 66, 65, 64, 62,
+ 61, 57, 55, 53, 44, 34, 24, 15, 7, 561,
+
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561
+ } ;
+
+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 *yy_text;
+#line 1 "src/cfglexer.ll"
+/*---------------------------------------------------------------------------*/
+/* */
+/* Minimal Flex Lexer */
+/* */
+/*---------------------------------------------------------------------------*/
+#line 11 "src/cfglexer.ll"
+
+/*---------------------------------------------------------------------------*/
+/* bison grammar tokens */
+/*---------------------------------------------------------------------------*/
+
+/* this header file is automatically generated by bison
+ * and includes all token definitions, as well as yy_lval */
+#include "cfgparser.hpp"
+#include "utilities.h"
+
+#include <string.h>
+#define CHAR_BUFFER_SIZE 8000
+ char charBuffer[ CHAR_BUFFER_SIZE ];
+
+ int lineCount = 1;
+
+// for windos compiler...
+extern "C" int yy_wrap (void ) { return 1; }
+#define YY_NO_UNISTD_H
+
+/*----------------------------------------------------------------------------*/
+/* definitions */
+/*----------------------------------------------------------------------------*/
+
+
+/*----------------------------------------------------------------------------*/
+/*
+ * rules start
+ */
+/*----------------------------------------------------------------------------*/
+#line 826 "<stdout>"
+
+#define INITIAL 0
+#define ATTR 1
+#define ATTRVALUE 2
+
+#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 <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yy_wrap (void );
+#else
+extern int yy_wrap (void );
+#endif
+#endif
+
+ static void yyunput (int c,char *buf_ptr );
+
+#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 (void) fwrite( yy_text, yy_leng, 1, yy_out )
+#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 = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yy_in )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yy_in ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yy_in))==0 && ferror(yy_in)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yy_in); \
+ } \
+ }\
+\
+
+#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 yy_lex (void);
+
+#define YY_DECL int yy_lex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yy_text and yy_leng
+ * 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 51 "src/cfglexer.ll"
+
+
+
+#line 983 "<stdout>"
+
+ if ( (yy_init) )
+ {
+ (yy_init) = 0;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! yy_in )
+ yy_in = stdin;
+
+ if ( ! yy_out )
+ yy_out = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yy_ensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy__create_buffer(yy_in,YY_BUF_SIZE );
+ }
+
+ yy__load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of yy_text. */
+ *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 >= 562 )
+ 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_current_state != 561 );
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+
+yy_find_action:
+ 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 54 "src/cfglexer.ll"
+{ return KW_PAROPEN; }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 55 "src/cfglexer.ll"
+{ BEGIN(INITIAL); // '}' always closes scopes
+ return KW_PARCLOSE; }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 58 "src/cfglexer.ll"
+{
+ BEGIN(ATTRVALUE);
+ return KW_EQUALS; }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 61 "src/cfglexer.ll"
+{ /* attribute name = normal string */
+ strncpy( charBuffer, yy_text, CHAR_BUFFER_SIZE-2 );
+ yy_lval.charValue = charBuffer;
+ return DT_ATTRNAME; }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 65 "src/cfglexer.ll"
+{ /* quoted string! attribute name = normal string */
+ strncpy( charBuffer, yy_text, CHAR_BUFFER_SIZE-2 );
+ /* get rid of " " */
+ for(unsigned int j=0;j<strlen(charBuffer);j++) charBuffer[j]=charBuffer[j+1];
+ charBuffer[ strlen(charBuffer)-1 ] = 0;
+ yy_lval.charValue = charBuffer;
+ return DT_ATTRVALUE; }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 72 "src/cfglexer.ll"
+{ /* ends at newline or ';' */
+ strncpy( charBuffer, yy_text, CHAR_BUFFER_SIZE-2 );
+ yy_lval.charValue = charBuffer;
+ return DT_ATTRVALUE; }
+ YY_BREAK
+case 7:
+/* rule 7 can match eol */
+YY_RULE_SETUP
+#line 76 "src/cfglexer.ll"
+{ /* return end token... */
+ BEGIN(ATTR);
+ return KW_ATTREND; }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 81 "src/cfglexer.ll"
+{ return KW_LBMSIM; }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 82 "src/cfglexer.ll"
+{ return KW_COMPARELBM; }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 83 "src/cfglexer.ll"
+{ return KW_DEBUGMODE; }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 84 "src/cfglexer.ll"
+{ return KW_RAYTRACING; }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 87 "src/cfglexer.ll"
+{ return KW_RESOLUTION; }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 88 "src/cfglexer.ll"
+{ return KW_ANTIALIAS; }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 89 "src/cfglexer.ll"
+{ return KW_EYEPOINT; }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 90 "src/cfglexer.ll"
+{ return KW_LOOKAT ; }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 91 "src/cfglexer.ll"
+{ return KW_UPVEC ; }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 92 "src/cfglexer.ll"
+{ return KW_FOVY; }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 93 "src/cfglexer.ll"
+{ return KW_ASPECT ; }
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 94 "src/cfglexer.ll"
+{ return KW_AMBIENCE; }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 95 "src/cfglexer.ll"
+{ return KW_BACKGROUND; }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 96 "src/cfglexer.ll"
+{ return KW_ANISTART; }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 97 "src/cfglexer.ll"
+{ return KW_ANIFRAMES; }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 98 "src/cfglexer.ll"
+{ return KW_ANIFRAMETIME; }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 99 "src/cfglexer.ll"
+{ return KW_FRAMESKIP; }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 100 "src/cfglexer.ll"
+{ return KW_FILENAME; }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 101 "src/cfglexer.ll"
+{ return KW_PMCAUSTICS; }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 102 "src/cfglexer.ll"
+{ return KW_CAUSTICDIST; }
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 103 "src/cfglexer.ll"
+{ return KW_CAUSTICPHOT; }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 104 "src/cfglexer.ll"
+{ return KW_SHADOWMAPBIAS; }
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 105 "src/cfglexer.ll"
+{ return KW_MAXRAYDEPTH; }
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 106 "src/cfglexer.ll"
+{ return KW_TREEMAXDEPTH; }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 107 "src/cfglexer.ll"
+{ return KW_TREEMAXTRIANGLES; }
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 108 "src/cfglexer.ll"
+{ return KW_DEBUGPIXEL; }
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 109 "src/cfglexer.ll"
+{ return KW_TESTMODE; }
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 110 "src/cfglexer.ll"
+{ return KW_OPENGLATTR; }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 111 "src/cfglexer.ll"
+{ return KW_BLENDERATTR; }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 113 "src/cfglexer.ll"
+{ return KW_OBJATTR; /* assign attr to obj */ }
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 114 "src/cfglexer.ll"
+{ BEGIN(ATTR); return KW_ATTRIBUTE; /* global attr list */ }
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 115 "src/cfglexer.ll"
+{ BEGIN(ATTR); return KW_DEFINEATTR; /* obj defines new attrs */ }
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 116 "src/cfglexer.ll"
+{ BEGIN(ATTR); return KW_DEFINEATTR; }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 117 "src/cfglexer.ll"
+{ BEGIN(ATTR); return KW_DEFINEATTR; }
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 119 "src/cfglexer.ll"
+{ return KW_GEOMETRY; }
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 120 "src/cfglexer.ll"
+{ return KW_TYPE; }
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 121 "src/cfglexer.ll"
+{ return KW_GEOTYPE_BOX; }
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 122 "src/cfglexer.ll"
+{ return KW_GEOTYPE_SPHERE; }
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 123 "src/cfglexer.ll"
+{ return KW_GEOTYPE_OBJMODEL; }
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 124 "src/cfglexer.ll"
+{ return KW_CASTSHADOWS; }
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 125 "src/cfglexer.ll"
+{ return KW_RECEIVESHADOWS ; }
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 126 "src/cfglexer.ll"
+{ return KW_VISIBLE; }
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 127 "src/cfglexer.ll"
+{ return KW_BOX_START; }
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 128 "src/cfglexer.ll"
+{ return KW_BOX_END; }
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 129 "src/cfglexer.ll"
+{ return KW_POLY ; }
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 130 "src/cfglexer.ll"
+{ return KW_POLY ; }
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 131 "src/cfglexer.ll"
+{ return KW_NUMVERTICES; }
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 132 "src/cfglexer.ll"
+{ return KW_VERTEX; }
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 133 "src/cfglexer.ll"
+{ return KW_NUMPOLYGONS; }
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 134 "src/cfglexer.ll"
+{ return KW_ISOSURF; }
+ YY_BREAK
+case 58:
+YY_RULE_SETUP
+#line 135 "src/cfglexer.ll"
+{ return KW_FILEMODE; }
+ YY_BREAK
+case 59:
+YY_RULE_SETUP
+#line 136 "src/cfglexer.ll"
+{ return KW_INVERT; }
+ YY_BREAK
+case 60:
+YY_RULE_SETUP
+#line 138 "src/cfglexer.ll"
+{ return KW_MATERIAL; }
+ YY_BREAK
+case 61:
+YY_RULE_SETUP
+#line 139 "src/cfglexer.ll"
+{ return KW_MATTYPE_PHONG; }
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 140 "src/cfglexer.ll"
+{ return KW_MATTYPE_BLINN; }
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 141 "src/cfglexer.ll"
+{ return KW_NAME; }
+ YY_BREAK
+case 64:
+YY_RULE_SETUP
+#line 142 "src/cfglexer.ll"
+{ return KW_AMBIENT; }
+ YY_BREAK
+case 65:
+YY_RULE_SETUP
+#line 143 "src/cfglexer.ll"
+{ return KW_DIFFUSE; }
+ YY_BREAK
+case 66:
+YY_RULE_SETUP
+#line 144 "src/cfglexer.ll"
+{ return KW_SPECULAR; }
+ YY_BREAK
+case 67:
+YY_RULE_SETUP
+#line 145 "src/cfglexer.ll"
+{ return KW_MIRROR; }
+ YY_BREAK
+case 68:
+YY_RULE_SETUP
+#line 146 "src/cfglexer.ll"
+{ return KW_TRANSPARENCE; }
+ YY_BREAK
+case 69:
+YY_RULE_SETUP
+#line 147 "src/cfglexer.ll"
+{ return KW_REFRACINDEX; }
+ YY_BREAK
+case 70:
+YY_RULE_SETUP
+#line 148 "src/cfglexer.ll"
+{ return KW_TRANSADDITIVE; }
+ YY_BREAK
+case 71:
+YY_RULE_SETUP
+#line 149 "src/cfglexer.ll"
+{ return KW_TRANSATTCOL; }
+ YY_BREAK
+case 72:
+YY_RULE_SETUP
+#line 150 "src/cfglexer.ll"
+{ return KW_FRESNEL; }
+ YY_BREAK
+case 73:
+YY_RULE_SETUP
+#line 151 "src/cfglexer.ll"
+{ return KW_FRESNEL; }
+ YY_BREAK
+case 74:
+YY_RULE_SETUP
+#line 153 "src/cfglexer.ll"
+{ return KW_LIGHT; }
+ YY_BREAK
+case 75:
+YY_RULE_SETUP
+#line 154 "src/cfglexer.ll"
+{ return KW_LIGHT_OMNI; }
+ YY_BREAK
+case 76:
+YY_RULE_SETUP
+#line 155 "src/cfglexer.ll"
+{ return KW_ACTIVE; }
+ YY_BREAK
+case 77:
+YY_RULE_SETUP
+#line 156 "src/cfglexer.ll"
+{ return KW_COLOUR; }
+ YY_BREAK
+case 78:
+YY_RULE_SETUP
+#line 157 "src/cfglexer.ll"
+{ return KW_COLOUR; }
+ YY_BREAK
+case 79:
+YY_RULE_SETUP
+#line 158 "src/cfglexer.ll"
+{ return KW_POSITION; }
+ YY_BREAK
+case 80:
+YY_RULE_SETUP
+#line 159 "src/cfglexer.ll"
+{ return KW_CAUSTICPHOTONS; }
+ YY_BREAK
+case 81:
+YY_RULE_SETUP
+#line 160 "src/cfglexer.ll"
+{ return KW_CAUSTICSTRENGTH; }
+ YY_BREAK
+case 82:
+YY_RULE_SETUP
+#line 161 "src/cfglexer.ll"
+{ return KW_SHADOWMAP; }
+ YY_BREAK
+case 83:
+YY_RULE_SETUP
+#line 162 "src/cfglexer.ll"
+{ return KW_CAUSTICSMAP; }
+ YY_BREAK
+case 84:
+YY_RULE_SETUP
+#line 164 "src/cfglexer.ll"
+{ yy_lval.intValue = 1; return DT_INTEGER; }
+ YY_BREAK
+case 85:
+YY_RULE_SETUP
+#line 165 "src/cfglexer.ll"
+{ yy_lval.intValue = 0; return DT_INTEGER; }
+ YY_BREAK
+case 86:
+YY_RULE_SETUP
+#line 166 "src/cfglexer.ll"
+{ yy_lval.intValue = 1; return DT_INTEGER; }
+ YY_BREAK
+case 87:
+YY_RULE_SETUP
+#line 167 "src/cfglexer.ll"
+{ yy_lval.intValue = 0; return DT_INTEGER; }
+ YY_BREAK
+case 88:
+YY_RULE_SETUP
+#line 170 "src/cfglexer.ll"
+{ // integer number
+ yy_lval.intValue = atoi( yy_text );
+ return DT_INTEGER; }
+ YY_BREAK
+case 89:
+YY_RULE_SETUP
+#line 174 "src/cfglexer.ll"
+{ // floating point number
+ yy_lval.floatValue = atof( yy_text );
+ return DT_FLOAT; }
+ YY_BREAK
+case 90:
+YY_RULE_SETUP
+#line 178 "src/cfglexer.ll"
+{ /* normal character strings, now also for paths/filenames */
+ strncpy( charBuffer, yy_text, CHAR_BUFFER_SIZE-2 );
+ /* get rid of " " */
+ for(unsigned int j=0;j<strlen(charBuffer);j++) charBuffer[j]=charBuffer[j+1];
+ charBuffer[ strlen(charBuffer)-1 ] = 0;
+ yy_lval.charValue = charBuffer;
+ return DT_STRING; }
+ YY_BREAK
+case 91:
+YY_RULE_SETUP
+#line 186 "src/cfglexer.ll"
+{ /* one line comment */ }
+ YY_BREAK
+case 92:
+YY_RULE_SETUP
+#line 187 "src/cfglexer.ll"
+{ /* one line comment */ }
+ YY_BREAK
+case 93:
+YY_RULE_SETUP
+#line 188 "src/cfglexer.ll"
+{ /* multiline comment */
+ register int c;
+ for ( ; ; ) {
+ while ( (c = yyinput()) != '*' &&
+ c != EOF ) {
+ /* eat up text of comment, count lines */
+ if(c == '\n') lineCount++;
+ }
+
+ if ( c == '*' ) {
+ while ( (c = yyinput()) == '*' ); /* search '*' */
+ if ( c == '/' ) break; /* found the end */
+ if ( c == '\n' ) lineCount++;
+ }
+
+ if ( c == EOF ) {
+ errorOut( "cfgLexer, Line "<<lineCount<<" :End of file found in comment..." );
+ break;
+ }
+ } /* multline comment done */
+ }
+ YY_BREAK
+case 94:
+/* rule 94 can match eol */
+YY_RULE_SETUP
+#line 212 "src/cfglexer.ll"
+{ // count line numbers
+ lineCount++; }
+ YY_BREAK
+case 95:
+YY_RULE_SETUP
+#line 215 "src/cfglexer.ll"
+{ /* do nothing by default... */ }
+ YY_BREAK
+case 96:
+YY_RULE_SETUP
+#line 217 "src/cfglexer.ll"
+{ /*errorOut( "cfgLexer, Line "<<lineCount<<" : Unknown character '"<<(char)yyinput()<<"' " ); exit(1); */ }
+ YY_BREAK
+case 97:
+YY_RULE_SETUP
+#line 220 "src/cfglexer.ll"
+ECHO;
+ YY_BREAK
+#line 1597 "<stdout>"
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(ATTR):
+case YY_STATE_EOF(ATTRVALUE):
+ 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 yy_in at a new source and called
+ * yy_lex(). 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 = yy_in;
+ 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_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( yy_wrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yy_text, 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 yy_lex */
+
+/* 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
+ {
+ 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 )
+ {
+ int 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. */
+ yy_realloc((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;
+ yy_restart(yy_in );
+ }
+
+ 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;
+
+ (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 >= 562 )
+ 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 >= 562 )
+ 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 == 561);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+ static void yyunput (int c, register char * yy_bp )
+{
+ register char *yy_cp;
+
+ yy_cp = (yy_c_buf_p);
+
+ /* undo effects of setting up yy_text */
+ *yy_cp = (yy_hold_char);
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = (yy_n_chars) + 2;
+ register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ register char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ (yytext_ptr) = yy_bp;
+ (yy_hold_char) = *yy_cp;
+ (yy_c_buf_p) = yy_cp;
+}
+
+#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 */
+ int 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. */
+ yy_restart(yy_in );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yy_wrap( ) )
+ return EOF;
+
+ 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 yy_text */
+ (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 yy_restart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yy_ensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy__create_buffer(yy_in,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
+ * yy_pop_buffer_state();
+ * yy_push_buffer_state(new_buffer);
+ */
+ yy_ensure_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 (yy_wrap()) processing, but the only time this flag
+ * is looked at is after yy_wrap() 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;
+ yy_in = 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) yy_alloc(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 *) yy_alloc(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 )
+ yy_free((void *) b->yy_ch_buf );
+
+ yy_free((void *) b );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yy_restart() 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 yy_restart() 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 = 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 yy_push_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ yy_ensure_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 yy_pop_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 yy_ensure_buffer_stack (void)
+{
+ int 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**)yy_alloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+
+ 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**)yy_realloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+
+ /* 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) yy_alloc(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 yy_lex() will
+ * scan from a @e copy of @a str.
+ * @param str 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 * yy_str )
+{
+
+ return yy__scan_bytes(yy_str,strlen(yy_str) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yy_lex() 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 * bytes, int len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = len + 2;
+ buf = (char *) yy_alloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy__scan_bytes()" );
+
+ for ( i = 0; i < len; ++i )
+ buf[i] = bytes[i];
+
+ buf[len] = buf[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 yy_text. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yy_text[yy_leng] = (yy_hold_char); \
+ (yy_c_buf_p) = yy_text + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ yy_leng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int yy_get_lineno (void)
+{
+
+ return yy_lineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *yy_get_in (void)
+{
+ return yy_in;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *yy_get_out (void)
+{
+ return yy_out;
+}
+
+/** Get the length of the current token.
+ *
+ */
+int yy_get_leng (void)
+{
+ return yy_leng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *yy_get_text (void)
+{
+ return yy_text;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void yy_set_lineno (int line_number )
+{
+
+ yy_lineno = 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 yy_set_in (FILE * in_str )
+{
+ yy_in = in_str ;
+}
+
+void yy_set_out (FILE * out_str )
+{
+ yy_out = out_str ;
+}
+
+int yy_get_debug (void)
+{
+ return yy__flex_debug;
+}
+
+void yy_set_debug (int bdebug )
+{
+ yy__flex_debug = bdebug ;
+}
+
+/* yy_lex_destroy is for both reentrant and non-reentrant scanners. */
+int yy_lex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy__delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yy_pop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ yy_free((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ 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 *yy_alloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *yy_realloc (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 yy_free (void * ptr )
+{
+ free( (char *) ptr ); /* see yy_realloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef yytext_ptr
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+#line 220 "src/cfglexer.ll"
diff --git a/intern/elbeem/intern/cfgparser.cpp b/intern/elbeem/intern/cfgparser.cpp
new file mode 100644
index 00000000000..d70fc50ec4c
--- /dev/null
+++ b/intern/elbeem/intern/cfgparser.cpp
@@ -0,0 +1,2348 @@
+/* A Bison parser, made by GNU Bison 1.875d. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 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., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* 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
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+/* If NAME_PREFIX is specified substitute the variables and functions
+ names. */
+#define yyparse yy_parse
+#define yylex yy_lex
+#define yyerror yy_error
+#define yylval yy_lval
+#define yychar yy_char
+#define yydebug yy_debug
+#define yynerrs yy_nerrs
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ DT_INTEGER = 258,
+ DT_FLOAT = 259,
+ DT_STRING = 260,
+ DT_ATTRNAME = 261,
+ DT_ATTRVALUE = 262,
+ KW_LBMSIM = 263,
+ KW_COMPARELBM = 264,
+ KW_ANIFRAMETIME = 265,
+ KW_DEBUGMODE = 266,
+ KW_P_RELAXTIME = 267,
+ KW_P_REYNOLDS = 268,
+ KW_P_VISCOSITY = 269,
+ KW_P_SOUNDSPEED = 270,
+ KW_P_DOMAINSIZE = 271,
+ KW_P_FORCE = 272,
+ KW_P_TIMELENGTH = 273,
+ KW_P_STEPTIME = 274,
+ KW_P_TIMEFACTOR = 275,
+ KW_P_ANIFRAMETIME = 276,
+ KW_P_ANISTART = 277,
+ KW_P_SURFACETENSION = 278,
+ KW_P_ACTIVATE = 279,
+ KW_P_DEACTIVATE = 280,
+ KW_P_DENSITY = 281,
+ KW_P_CELLSIZE = 282,
+ KW_P_GSTAR = 283,
+ KW_PFSPATH = 284,
+ KW_PARTLINELENGTH = 285,
+ KW_PARTICLES = 286,
+ KW_FRAMESPERSEC = 287,
+ KW_RAYTRACING = 288,
+ KW_PAROPEN = 289,
+ KW_PARCLOSE = 290,
+ KW_FILENAME = 291,
+ KW_PMCAUSTICS = 292,
+ KW_MAXRAYDEPTH = 293,
+ KW_CAUSTICDIST = 294,
+ KW_CAUSTICPHOT = 295,
+ KW_SHADOWMAPBIAS = 296,
+ KW_TREEMAXDEPTH = 297,
+ KW_TREEMAXTRIANGLES = 298,
+ KW_RESOLUTION = 299,
+ KW_ANTIALIAS = 300,
+ KW_EYEPOINT = 301,
+ KW_ANISTART = 302,
+ KW_ANIFRAMES = 303,
+ KW_FRAMESKIP = 304,
+ KW_LOOKAT = 305,
+ KW_UPVEC = 306,
+ KW_FOVY = 307,
+ KW_ASPECT = 308,
+ KW_AMBIENCE = 309,
+ KW_BACKGROUND = 310,
+ KW_DEBUGPIXEL = 311,
+ KW_TESTMODE = 312,
+ KW_OPENGLATTR = 313,
+ KW_BLENDERATTR = 314,
+ KW_ATTRIBUTE = 315,
+ KW_OBJATTR = 316,
+ KW_EQUALS = 317,
+ KW_DEFINEATTR = 318,
+ KW_ATTREND = 319,
+ KW_GEOMETRY = 320,
+ KW_TYPE = 321,
+ KW_GEOTYPE_BOX = 322,
+ KW_GEOTYPE_FLUID = 323,
+ KW_GEOTYPE_OBJMODEL = 324,
+ KW_GEOTYPE_SPHERE = 325,
+ KW_CASTSHADOWS = 326,
+ KW_RECEIVESHADOWS = 327,
+ KW_VISIBLE = 328,
+ KW_BOX_END = 329,
+ KW_BOX_START = 330,
+ KW_POLY = 331,
+ KW_NUMVERTICES = 332,
+ KW_VERTEX = 333,
+ KW_NUMPOLYGONS = 334,
+ KW_ISOSURF = 335,
+ KW_FILEMODE = 336,
+ KW_INVERT = 337,
+ KW_MATERIAL = 338,
+ KW_MATTYPE_PHONG = 339,
+ KW_MATTYPE_BLINN = 340,
+ KW_NAME = 341,
+ KW_AMBIENT = 342,
+ KW_DIFFUSE = 343,
+ KW_SPECULAR = 344,
+ KW_MIRROR = 345,
+ KW_TRANSPARENCE = 346,
+ KW_REFRACINDEX = 347,
+ KW_TRANSADDITIVE = 348,
+ KW_TRANSATTCOL = 349,
+ KW_FRESNEL = 350,
+ KW_LIGHT = 351,
+ KW_ACTIVE = 352,
+ KW_COLOUR = 353,
+ KW_POSITION = 354,
+ KW_LIGHT_OMNI = 355,
+ KW_CAUSTICPHOTONS = 356,
+ KW_CAUSTICSTRENGTH = 357,
+ KW_SHADOWMAP = 358,
+ KW_CAUSTICSMAP = 359
+ };
+#endif
+#define DT_INTEGER 258
+#define DT_FLOAT 259
+#define DT_STRING 260
+#define DT_ATTRNAME 261
+#define DT_ATTRVALUE 262
+#define KW_LBMSIM 263
+#define KW_COMPARELBM 264
+#define KW_ANIFRAMETIME 265
+#define KW_DEBUGMODE 266
+#define KW_P_RELAXTIME 267
+#define KW_P_REYNOLDS 268
+#define KW_P_VISCOSITY 269
+#define KW_P_SOUNDSPEED 270
+#define KW_P_DOMAINSIZE 271
+#define KW_P_FORCE 272
+#define KW_P_TIMELENGTH 273
+#define KW_P_STEPTIME 274
+#define KW_P_TIMEFACTOR 275
+#define KW_P_ANIFRAMETIME 276
+#define KW_P_ANISTART 277
+#define KW_P_SURFACETENSION 278
+#define KW_P_ACTIVATE 279
+#define KW_P_DEACTIVATE 280
+#define KW_P_DENSITY 281
+#define KW_P_CELLSIZE 282
+#define KW_P_GSTAR 283
+#define KW_PFSPATH 284
+#define KW_PARTLINELENGTH 285
+#define KW_PARTICLES 286
+#define KW_FRAMESPERSEC 287
+#define KW_RAYTRACING 288
+#define KW_PAROPEN 289
+#define KW_PARCLOSE 290
+#define KW_FILENAME 291
+#define KW_PMCAUSTICS 292
+#define KW_MAXRAYDEPTH 293
+#define KW_CAUSTICDIST 294
+#define KW_CAUSTICPHOT 295
+#define KW_SHADOWMAPBIAS 296
+#define KW_TREEMAXDEPTH 297
+#define KW_TREEMAXTRIANGLES 298
+#define KW_RESOLUTION 299
+#define KW_ANTIALIAS 300
+#define KW_EYEPOINT 301
+#define KW_ANISTART 302
+#define KW_ANIFRAMES 303
+#define KW_FRAMESKIP 304
+#define KW_LOOKAT 305
+#define KW_UPVEC 306
+#define KW_FOVY 307
+#define KW_ASPECT 308
+#define KW_AMBIENCE 309
+#define KW_BACKGROUND 310
+#define KW_DEBUGPIXEL 311
+#define KW_TESTMODE 312
+#define KW_OPENGLATTR 313
+#define KW_BLENDERATTR 314
+#define KW_ATTRIBUTE 315
+#define KW_OBJATTR 316
+#define KW_EQUALS 317
+#define KW_DEFINEATTR 318
+#define KW_ATTREND 319
+#define KW_GEOMETRY 320
+#define KW_TYPE 321
+#define KW_GEOTYPE_BOX 322
+#define KW_GEOTYPE_FLUID 323
+#define KW_GEOTYPE_OBJMODEL 324
+#define KW_GEOTYPE_SPHERE 325
+#define KW_CASTSHADOWS 326
+#define KW_RECEIVESHADOWS 327
+#define KW_VISIBLE 328
+#define KW_BOX_END 329
+#define KW_BOX_START 330
+#define KW_POLY 331
+#define KW_NUMVERTICES 332
+#define KW_VERTEX 333
+#define KW_NUMPOLYGONS 334
+#define KW_ISOSURF 335
+#define KW_FILEMODE 336
+#define KW_INVERT 337
+#define KW_MATERIAL 338
+#define KW_MATTYPE_PHONG 339
+#define KW_MATTYPE_BLINN 340
+#define KW_NAME 341
+#define KW_AMBIENT 342
+#define KW_DIFFUSE 343
+#define KW_SPECULAR 344
+#define KW_MIRROR 345
+#define KW_TRANSPARENCE 346
+#define KW_REFRACINDEX 347
+#define KW_TRANSADDITIVE 348
+#define KW_TRANSATTCOL 349
+#define KW_FRESNEL 350
+#define KW_LIGHT 351
+#define KW_ACTIVE 352
+#define KW_COLOUR 353
+#define KW_POSITION 354
+#define KW_LIGHT_OMNI 355
+#define KW_CAUSTICPHOTONS 356
+#define KW_CAUSTICSTRENGTH 357
+#define KW_SHADOWMAP 358
+#define KW_CAUSTICSMAP 359
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 14 "src/cfgparser.yy"
+
+
+#define YYDEBUG 1
+
+/* library functions */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "attributes.h"
+
+ void yy_warn(char *s);
+ void yy_error(const char *s);
+
+ /* imported from flex... */
+ extern int yy_lex();
+ extern int lineCount;
+ extern FILE *yy_in;
+
+ /* the parse function from bison */
+ int yy_parse( void );
+
+// local variables to access objects
+#include "simulation_object.h"
+#ifdef LBM_INCLUDE_TESTSOLVERS
+#include "simulation_complbm.h"
+#endif // LBM_INCLUDE_TESTSOLVERS
+
+#include "parametrizer.h"
+#include "ntl_renderglobals.h"
+#include "ntl_scene.h"
+
+#include "ntl_lightobject.h"
+#include "ntl_material.h"
+#include "ntl_geometrybox.h"
+#include "ntl_geometrysphere.h"
+#include "ntl_geometrymodel.h"
+#include "globals.h"
+
+ /* global variables */
+ static map<string,AttributeList*> attrs; /* global attribute storage */
+ vector<string> currentAttrValue; /* build string vector */
+
+ // global raytracing settings, stores object,lights,material lists etc.
+ // lists are freed by ntlScene upon deletion
+ static ntlRenderGlobals *reglob; /* raytracing global settings */
+
+ /* light initialization checks */
+ ntlLightObject *currentLight;
+ ntlLightObject *currentLightOmni;
+
+ /* geometry initialization checks */
+ ntlGeometryClass *currentGeoClass;
+ ntlGeometryObject *currentGeoObj;
+ ntlGeometryBox *currentGeometryBox;
+ ntlGeometrySphere *currentGeometrySphere;
+ SimulationObject *currentGeometrySim;
+ ntlGeometryObjModel *currentGeometryModel;
+ AttributeList *currentAttrib;
+ string currentAttrName, currentAttribAddName;
+
+ /* material init checks */
+ ntlMaterial *currentMaterial;
+
+
+
+/* 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
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 85 "src/cfgparser.yy"
+typedef union YYSTYPE {
+ int intValue;
+ float floatValue;
+ char *charValue;
+} YYSTYPE;
+/* Line 191 of yacc.c. */
+#line 364 "bld-std-gcc/src/cfgparser.cpp"
+# 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 214 of yacc.c. */
+#line 376 "bld-std-gcc/src/cfgparser.cpp"
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+# ifndef YYFREE
+# define YYFREE free
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# endif
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# define YYSTACK_ALLOC alloca
+# endif
+# else
+# if defined (alloca) || defined (_ALLOCA_H)
+# define YYSTACK_ALLOC alloca
+# else
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# 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
+{
+ short int 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 (short int) + 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 \
+ { \
+ register YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (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 (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short int yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 12
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 278
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 105
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 77
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 136
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 237
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 359
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned char 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, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned short int yyprhs[] =
+{
+ 0, 0, 3, 6, 8, 10, 12, 14, 17, 22,
+ 25, 27, 29, 31, 33, 35, 37, 39, 41, 43,
+ 45, 47, 49, 51, 53, 55, 57, 59, 61, 63,
+ 65, 67, 69, 71, 73, 75, 77, 80, 83, 86,
+ 89, 93, 96, 101, 106, 111, 114, 117, 122, 127,
+ 130, 133, 136, 139, 143, 146, 149, 152, 159, 162,
+ 164, 166, 168, 170, 172, 174, 177, 180, 185, 190,
+ 191, 199, 202, 204, 206, 208, 210, 212, 214, 216,
+ 218, 220, 222, 224, 226, 228, 230, 232, 235, 238,
+ 241, 244, 247, 252, 257, 260, 265, 272, 275, 277,
+ 279, 281, 283, 285, 287, 289, 291, 293, 295, 297,
+ 299, 301, 304, 309, 314, 318, 321, 324, 327, 330,
+ 335, 338, 339, 346, 349, 351, 352, 353, 360, 363,
+ 365, 367, 369, 371, 373, 375, 377
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const short int yyrhs[] =
+{
+ 106, 0, -1, 106, 107, -1, 107, -1, 109, -1,
+ 169, -1, 108, -1, 11, 3, -1, 33, 34, 110,
+ 35, -1, 110, 111, -1, 111, -1, 114, -1, 112,
+ -1, 113, -1, 115, -1, 116, -1, 117, -1, 118,
+ -1, 119, -1, 120, -1, 121, -1, 122, -1, 123,
+ -1, 124, -1, 125, -1, 126, -1, 127, -1, 128,
+ -1, 129, -1, 130, -1, 131, -1, 132, -1, 133,
+ -1, 141, -1, 172, -1, 155, -1, 47, 180, -1,
+ 10, 180, -1, 48, 179, -1, 49, 181, -1, 44,
+ 179, 179, -1, 45, 3, -1, 46, 178, 178, 178,
+ -1, 50, 178, 178, 178, -1, 51, 178, 178, 178,
+ -1, 52, 178, -1, 53, 178, -1, 54, 178, 178,
+ 178, -1, 55, 178, 178, 178, -1, 36, 5, -1,
+ 42, 179, -1, 43, 179, -1, 38, 179, -1, 56,
+ 3, 3, -1, 57, 181, -1, 58, 5, -1, 59,
+ 5, -1, 96, 34, 66, 135, 134, 35, -1, 134,
+ 136, -1, 136, -1, 100, -1, 137, -1, 138, -1,
+ 139, -1, 140, -1, 97, 181, -1, 71, 181, -1,
+ 98, 178, 178, 178, -1, 99, 178, 178, 178, -1,
+ -1, 65, 34, 66, 144, 142, 143, 35, -1, 143,
+ 145, -1, 145, -1, 67, -1, 70, -1, 69, -1,
+ 8, -1, 9, -1, 146, -1, 147, -1, 148, -1,
+ 149, -1, 150, -1, 151, -1, 152, -1, 153, -1,
+ 154, -1, 86, 5, -1, 83, 5, -1, 71, 181,
+ -1, 72, 181, -1, 73, 181, -1, 75, 178, 178,
+ 178, -1, 74, 178, 178, 178, -1, 61, 5, -1,
+ 63, 34, 171, 35, -1, 83, 34, 66, 157, 156,
+ 35, -1, 156, 158, -1, 158, -1, 84, -1, 85,
+ -1, 159, -1, 160, -1, 161, -1, 162, -1, 163,
+ -1, 165, -1, 164, -1, 166, -1, 167, -1, 168,
+ -1, 86, 5, -1, 87, 176, 176, 176, -1, 88,
+ 176, 176, 176, -1, 89, 178, 178, -1, 90, 177,
+ -1, 91, 177, -1, 92, 178, -1, 93, 177, -1,
+ 94, 178, 178, 178, -1, 95, 180, -1, -1, 60,
+ 6, 34, 170, 171, 35, -1, 171, 172, -1, 172,
+ -1, -1, -1, 6, 62, 173, 175, 174, 64, -1,
+ 175, 7, -1, 7, -1, 177, -1, 178, -1, 4,
+ -1, 3, -1, 3, -1, 3, -1, 3, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned short int yyrline[] =
+{
+ 0, 144, 144, 145, 148, 149, 150, 154, 164, 165,
+ 165, 168, 169, 170, 171, 173, 174, 175, 176, 177,
+ 178, 179, 180, 181, 182, 183, 184, 185, 186, 187,
+ 188, 189, 191, 192, 193, 194, 199, 203, 208, 212,
+ 218, 222, 226, 230, 234, 238, 242, 246, 250, 254,
+ 258, 262, 266, 270, 274, 278, 283, 292, 303, 304,
+ 307, 315, 316, 317, 318, 322, 327, 332, 337, 355,
+ 354, 374, 375, 378, 383, 388, 393, 399, 411, 412,
+ 413, 414, 415, 416, 417, 418, 419, 424, 429, 435,
+ 441, 447, 452, 464, 477, 483, 493, 504, 505, 508,
+ 513, 517, 518, 519, 520, 521, 522, 523, 524, 525,
+ 526, 531, 536, 541, 546, 552, 557, 562, 567, 572,
+ 577, 588, 588, 598, 598, 601, 602, 601, 609, 612,
+ 622, 625, 637, 639, 645, 656, 668
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[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", "DT_INTEGER", "DT_FLOAT", "DT_STRING",
+ "DT_ATTRNAME", "DT_ATTRVALUE", "KW_LBMSIM", "KW_COMPARELBM",
+ "KW_ANIFRAMETIME", "KW_DEBUGMODE", "KW_P_RELAXTIME", "KW_P_REYNOLDS",
+ "KW_P_VISCOSITY", "KW_P_SOUNDSPEED", "KW_P_DOMAINSIZE", "KW_P_FORCE",
+ "KW_P_TIMELENGTH", "KW_P_STEPTIME", "KW_P_TIMEFACTOR",
+ "KW_P_ANIFRAMETIME", "KW_P_ANISTART", "KW_P_SURFACETENSION",
+ "KW_P_ACTIVATE", "KW_P_DEACTIVATE", "KW_P_DENSITY", "KW_P_CELLSIZE",
+ "KW_P_GSTAR", "KW_PFSPATH", "KW_PARTLINELENGTH", "KW_PARTICLES",
+ "KW_FRAMESPERSEC", "KW_RAYTRACING", "KW_PAROPEN", "KW_PARCLOSE",
+ "KW_FILENAME", "KW_PMCAUSTICS", "KW_MAXRAYDEPTH", "KW_CAUSTICDIST",
+ "KW_CAUSTICPHOT", "KW_SHADOWMAPBIAS", "KW_TREEMAXDEPTH",
+ "KW_TREEMAXTRIANGLES", "KW_RESOLUTION", "KW_ANTIALIAS", "KW_EYEPOINT",
+ "KW_ANISTART", "KW_ANIFRAMES", "KW_FRAMESKIP", "KW_LOOKAT", "KW_UPVEC",
+ "KW_FOVY", "KW_ASPECT", "KW_AMBIENCE", "KW_BACKGROUND", "KW_DEBUGPIXEL",
+ "KW_TESTMODE", "KW_OPENGLATTR", "KW_BLENDERATTR", "KW_ATTRIBUTE",
+ "KW_OBJATTR", "KW_EQUALS", "KW_DEFINEATTR", "KW_ATTREND", "KW_GEOMETRY",
+ "KW_TYPE", "KW_GEOTYPE_BOX", "KW_GEOTYPE_FLUID", "KW_GEOTYPE_OBJMODEL",
+ "KW_GEOTYPE_SPHERE", "KW_CASTSHADOWS", "KW_RECEIVESHADOWS", "KW_VISIBLE",
+ "KW_BOX_END", "KW_BOX_START", "KW_POLY", "KW_NUMVERTICES", "KW_VERTEX",
+ "KW_NUMPOLYGONS", "KW_ISOSURF", "KW_FILEMODE", "KW_INVERT",
+ "KW_MATERIAL", "KW_MATTYPE_PHONG", "KW_MATTYPE_BLINN", "KW_NAME",
+ "KW_AMBIENT", "KW_DIFFUSE", "KW_SPECULAR", "KW_MIRROR",
+ "KW_TRANSPARENCE", "KW_REFRACINDEX", "KW_TRANSADDITIVE",
+ "KW_TRANSATTCOL", "KW_FRESNEL", "KW_LIGHT", "KW_ACTIVE", "KW_COLOUR",
+ "KW_POSITION", "KW_LIGHT_OMNI", "KW_CAUSTICPHOTONS",
+ "KW_CAUSTICSTRENGTH", "KW_SHADOWMAP", "KW_CAUSTICSMAP", "$accept",
+ "desc_line", "desc_expression", "toggledebug_expression",
+ "raytrace_section", "raytrace_line", "raytrace_expression",
+ "anistart_expression", "aniframetime_expression", "aniframes_expression",
+ "frameskip_expression", "resolution_expression", "antialias_expression",
+ "eyepoint_expression", "lookat_expression", "upvec_expression",
+ "fovy_expression", "aspect_expression", "ambience_expression",
+ "background_expression", "filename_expression",
+ "treemaxdepth_expression", "treemaxtriangles_expression",
+ "maxraydepth_expression", "debugpixel_expression", "testmode_expression",
+ "openglattr_expr", "blenderattr_expr", "light_expression",
+ "lightsettings_line", "lighttype_expression", "lightsettings_expression",
+ "lightactive_expression", "lightcastshadows_expression",
+ "lightcolor_expression", "lightposition_expression",
+ "geometry_expression", "@1", "geometrysettings_line",
+ "geometrytype_expression", "geometrysettings_expression",
+ "geometryexpression_name", "geometryexpression_propname",
+ "geometryexpression_castshadows", "geometryexpression_recshadows",
+ "geometryexpression_visible", "geometryexpression_boxstart",
+ "geometryexpression_boxend", "geometryexpression_attrib",
+ "geometryexpression_defattrib", "material_expression",
+ "materialsettings_line", "materialtype_expression",
+ "materialsettings_expression", "materialexpression_name",
+ "materialexpression_ambient", "materialexpression_diffuse",
+ "materialexpression_specular", "materialexpression_mirror",
+ "materialexpression_transparence", "materialexpression_refracindex",
+ "materialexpression_transadd", "materialexpression_transattcol",
+ "materialexpression_fresnel", "attribute_section", "@2",
+ "attribute_line", "attribute_expression", "@3", "@4", "attrvalue_list",
+ "DT_COLOR", "DT_ZEROTOONE", "DT_REALVAL", "DT_INTLTZERO", "DT_POSINT",
+ "DT_BOOLEAN", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short int 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,
+ 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
+ 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
+ 325, 326, 327, 328, 329, 330, 331, 332, 333, 334,
+ 335, 336, 337, 338, 339, 340, 341, 342, 343, 344,
+ 345, 346, 347, 348, 349, 350, 351, 352, 353, 354,
+ 355, 356, 357, 358, 359
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned char yyr1[] =
+{
+ 0, 105, 106, 106, 107, 107, 107, 108, 109, 110,
+ 110, 111, 111, 111, 111, 111, 111, 111, 111, 111,
+ 111, 111, 111, 111, 111, 111, 111, 111, 111, 111,
+ 111, 111, 111, 111, 111, 111, 112, 113, 114, 115,
+ 116, 117, 118, 119, 120, 121, 122, 123, 124, 125,
+ 126, 127, 128, 129, 130, 131, 132, 133, 134, 134,
+ 135, 136, 136, 136, 136, 137, 138, 139, 140, 142,
+ 141, 143, 143, 144, 144, 144, 144, 144, 145, 145,
+ 145, 145, 145, 145, 145, 145, 145, 146, 147, 148,
+ 149, 150, 151, 152, 153, 154, 155, 156, 156, 157,
+ 157, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+ 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
+ 168, 170, 169, 171, 171, 173, 174, 172, 175, 175,
+ 176, 177, 178, 178, 179, 180, 181
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 2, 1, 1, 1, 1, 2, 4, 2,
+ 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, 2, 2, 2, 2,
+ 3, 2, 4, 4, 4, 2, 2, 4, 4, 2,
+ 2, 2, 2, 3, 2, 2, 2, 6, 2, 1,
+ 1, 1, 1, 1, 1, 2, 2, 4, 4, 0,
+ 7, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
+ 2, 2, 4, 4, 2, 4, 6, 2, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 4, 3, 2, 2, 2, 2, 4,
+ 2, 0, 6, 2, 1, 0, 0, 6, 2, 1,
+ 1, 1, 1, 1, 1, 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 unsigned char yydefact[] =
+{
+ 0, 0, 0, 0, 0, 3, 6, 4, 5, 7,
+ 0, 0, 1, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 10, 12, 13, 11, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 35, 34, 121, 125, 135, 37,
+ 49, 134, 52, 50, 51, 0, 41, 133, 132, 0,
+ 36, 38, 136, 39, 0, 0, 45, 46, 0, 0,
+ 0, 54, 55, 56, 0, 0, 0, 8, 9, 0,
+ 0, 40, 0, 0, 0, 0, 0, 53, 0, 0,
+ 0, 0, 124, 129, 126, 42, 43, 44, 47, 48,
+ 76, 77, 73, 75, 74, 69, 99, 100, 0, 60,
+ 0, 122, 123, 128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 98, 101, 102,
+ 103, 104, 105, 107, 106, 108, 109, 110, 0, 0,
+ 0, 0, 0, 59, 61, 62, 63, 64, 127, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 72,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 111,
+ 0, 130, 131, 0, 0, 115, 116, 117, 118, 0,
+ 120, 96, 97, 66, 65, 0, 0, 57, 58, 94,
+ 0, 89, 90, 91, 0, 0, 88, 87, 70, 71,
+ 0, 0, 114, 0, 0, 0, 0, 0, 0, 112,
+ 113, 119, 67, 68, 95, 93, 92
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const short int yydefgoto[] =
+{
+ -1, 4, 5, 6, 7, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, 58, 59, 60, 61, 62, 162,
+ 130, 163, 164, 165, 166, 167, 63, 135, 178, 125,
+ 179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
+ 64, 146, 128, 147, 148, 149, 150, 151, 152, 153,
+ 154, 155, 156, 157, 8, 99, 111, 65, 100, 134,
+ 114, 190, 191, 192, 72, 69, 83
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -111
+static const short int yypact[] =
+{
+ 31, 10, -18, 22, 12, -111, -111, -111, -111, -111,
+ 172, -2, -111, -111, -26, 41, 45, 43, 43, 43,
+ 43, 48, 21, 41, 43, 51, 21, 21, 21, 21,
+ 21, 21, 55, 51, 54, 60, 19, 34, 35, 50,
+ -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
+ -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
+ -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
+ -111, -111, -111, -111, -111, 43, -111, -111, -111, 21,
+ -111, -111, -111, -111, 21, 21, -111, -111, 21, 21,
+ 67, -111, -111, -111, -11, 5, 23, -111, -111, 81,
+ 83, -111, 21, 21, 21, 21, 21, -111, 9, -50,
+ 11, 8, -111, -111, 105, -111, -111, -111, -111, -111,
+ -111, -111, -111, -111, -111, -111, -111, -111, 183, -111,
+ 52, -111, -111, -111, 57, 171, 113, 21, 21, 21,
+ 21, 21, 21, 21, 21, 41, 75, -111, -111, -111,
+ -111, -111, -111, -111, -111, -111, -111, -111, 51, 51,
+ 21, 21, -24, -111, -111, -111, -111, -111, -111, 114,
+ 90, 51, 51, 51, 21, 21, 120, 121, -34, -111,
+ -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
+ 21, -111, -111, 21, 21, -111, -111, -111, -111, 21,
+ -111, -111, -111, -111, -111, 21, 21, -111, -111, -111,
+ 81, -111, -111, -111, 21, 21, -111, -111, -111, -111,
+ 21, 21, -111, 21, 21, 21, 13, 21, 21, -111,
+ -111, -111, -111, -111, -111, -111, -111
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yysigned_char yypgoto[] =
+{
+ -111, -111, 125, -111, -111, -111, 92, -111, -111, -111,
+ -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
+ -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
+ -111, -28, -111, -111, -111, -111, -111, -111, -111, -111,
+ -43, -111, -111, -111, -111, -111, -111, -111, -111, -111,
+ -111, -111, -111, -10, -111, -111, -111, -111, -111, -111,
+ -111, -111, -111, -111, -111, -111, -73, -96, -111, -111,
+ -111, -77, -110, -22, 2, -13, -31
+};
+
+/* 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 -1
+static const unsigned char yytable[] =
+{
+ 79, 218, 91, 112, 84, 85, 86, 87, 88, 89,
+ 80, 207, 12, 9, 14, 132, 10, 120, 121, 14,
+ 73, 74, 75, 1, 77, 78, 81, 169, 11, 170,
+ 195, 196, 66, 198, 126, 127, 67, 171, 172, 173,
+ 174, 175, 1, 131, 68, 2, 71, 158, 234, 176,
+ 70, 76, 177, 94, 82, 108, 14, 102, 90, 92,
+ 15, 193, 103, 104, 2, 93, 105, 106, 95, 96,
+ 107, 109, 3, 159, 160, 161, 122, 101, 123, 124,
+ 115, 116, 117, 118, 119, 97, 16, 14, 17, 110,
+ 113, 3, 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 201, 129, 133, 220, 112, 36, 221, 194, 189, 209,
+ 197, 168, 199, 158, 210, 216, 217, 203, 204, 13,
+ 132, 98, 200, 37, 208, 219, 202, 226, 205, 206,
+ 211, 212, 213, 229, 230, 0, 38, 0, 0, 159,
+ 160, 161, 214, 215, 0, 0, 0, 0, 0, 0,
+ 0, 136, 137, 138, 139, 140, 141, 142, 143, 144,
+ 145, 0, 222, 0, 0, 0, 0, 223, 14, 0,
+ 0, 0, 15, 224, 225, 0, 0, 0, 0, 0,
+ 0, 0, 227, 228, 0, 0, 0, 0, 0, 0,
+ 0, 231, 232, 233, 0, 235, 236, 0, 16, 0,
+ 17, 0, 0, 0, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 169, 0, 170, 0, 0, 36, 0, 0,
+ 0, 0, 171, 172, 173, 174, 175, 0, 0, 0,
+ 0, 0, 0, 0, 176, 37, 0, 177, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 38, 136,
+ 137, 138, 139, 140, 141, 142, 143, 144, 145
+};
+
+static const short int yycheck[] =
+{
+ 22, 35, 33, 99, 26, 27, 28, 29, 30, 31,
+ 23, 35, 0, 3, 6, 111, 34, 8, 9, 6,
+ 18, 19, 20, 11, 3, 4, 24, 61, 6, 63,
+ 140, 141, 34, 143, 84, 85, 62, 71, 72, 73,
+ 74, 75, 11, 35, 3, 33, 3, 71, 35, 83,
+ 5, 3, 86, 34, 3, 66, 6, 79, 3, 5,
+ 10, 138, 84, 85, 33, 5, 88, 89, 34, 34,
+ 3, 66, 60, 97, 98, 99, 67, 75, 69, 70,
+ 102, 103, 104, 105, 106, 35, 36, 6, 38, 66,
+ 7, 60, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 35, 100, 7, 190, 210, 65, 193, 139, 5, 5,
+ 142, 64, 144, 71, 34, 5, 5, 158, 159, 4,
+ 226, 39, 145, 83, 162, 178, 146, 210, 160, 161,
+ 171, 172, 173, 220, 221, -1, 96, -1, -1, 97,
+ 98, 99, 174, 175, -1, -1, -1, -1, -1, -1,
+ -1, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, -1, 194, -1, -1, -1, -1, 199, 6, -1,
+ -1, -1, 10, 205, 206, -1, -1, -1, -1, -1,
+ -1, -1, 214, 215, -1, -1, -1, -1, -1, -1,
+ -1, 223, 224, 225, -1, 227, 228, -1, 36, -1,
+ 38, -1, -1, -1, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 61, -1, 63, -1, -1, 65, -1, -1,
+ -1, -1, 71, 72, 73, 74, 75, -1, -1, -1,
+ -1, -1, -1, -1, 83, 83, -1, 86, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 96, 86,
+ 87, 88, 89, 90, 91, 92, 93, 94, 95
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned char yystos[] =
+{
+ 0, 11, 33, 60, 106, 107, 108, 109, 169, 3,
+ 34, 6, 0, 107, 6, 10, 36, 38, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, 58, 59, 65, 83, 96, 110,
+ 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
+ 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
+ 131, 132, 133, 141, 155, 172, 34, 62, 3, 180,
+ 5, 3, 179, 179, 179, 179, 3, 3, 4, 178,
+ 180, 179, 3, 181, 178, 178, 178, 178, 178, 178,
+ 3, 181, 5, 5, 34, 34, 34, 35, 111, 170,
+ 173, 179, 178, 178, 178, 178, 178, 3, 66, 66,
+ 66, 171, 172, 7, 175, 178, 178, 178, 178, 178,
+ 8, 9, 67, 69, 70, 144, 84, 85, 157, 100,
+ 135, 35, 172, 7, 174, 142, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 156, 158, 159, 160,
+ 161, 162, 163, 164, 165, 166, 167, 168, 71, 97,
+ 98, 99, 134, 136, 137, 138, 139, 140, 64, 61,
+ 63, 71, 72, 73, 74, 75, 83, 86, 143, 145,
+ 146, 147, 148, 149, 150, 151, 152, 153, 154, 5,
+ 176, 177, 178, 176, 178, 177, 177, 178, 177, 178,
+ 180, 35, 158, 181, 181, 178, 178, 35, 136, 5,
+ 34, 181, 181, 181, 178, 178, 5, 5, 35, 145,
+ 176, 176, 178, 178, 178, 178, 171, 178, 178, 176,
+ 176, 178, 178, 178, 35, 178, 178
+};
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#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; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror ("syntax error: cannot back up");\
+ YYERROR; \
+ } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+ are run). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ ((Current).first_line = (Rhs)[1].first_line, \
+ (Current).first_column = (Rhs)[1].first_column, \
+ (Current).last_line = (Rhs)[N].last_line, \
+ (Current).last_column = (Rhs)[N].last_column)
+#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 <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YYDSYMPRINT(Args) \
+do { \
+ if (yydebug) \
+ yysymprint Args; \
+} while (0)
+
+# define YYDSYMPRINTF(Title, Token, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Token, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short int *bottom, short int *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short int *bottom;
+ short int *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; 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 (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
+#endif
+{
+ int yyi;
+ unsigned int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+ yyrule - 1, yylno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
+# define YYDSYMPRINTF(Title, Token, 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
+ SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#if defined (YYMAXDEPTH) && YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#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. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ register const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# 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. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ register char *yyd = yydest;
+ register const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (yytype < YYNTOKENS)
+ {
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ }
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yytype, yyvaluep)
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ 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 lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ register int yystate;
+ register int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+
+ /* 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. */
+ short int yyssa[YYINITDEPTH];
+ short int *yyss = yyssa;
+ register short int *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ register YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK (yyvsp--, yyssp--)
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ 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;
+ short int *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 ("parser stack overflow",
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyoverflowlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyoverflowlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ short int *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyoverflowlab;
+ 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 lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead 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);
+ YYDSYMPRINTF ("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;
+
+ /* Shift the lookahead token. */
+ YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ 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 7:
+#line 154 "src/cfgparser.yy"
+ { yy_debug = yyvsp[0].intValue; }
+ break;
+
+ case 36:
+#line 200 "src/cfgparser.yy"
+ { reglob->setAniStart( yyvsp[0].intValue ); }
+ break;
+
+ case 37:
+#line 204 "src/cfgparser.yy"
+ { reglob->setAniFrameTime( yyvsp[0].intValue ); }
+ break;
+
+ case 38:
+#line 209 "src/cfgparser.yy"
+ { reglob->setAniFrames( (yyvsp[0].intValue)-1 ); }
+ break;
+
+ case 39:
+#line 213 "src/cfgparser.yy"
+ { reglob->setFrameSkip( (yyvsp[0].intValue) ); }
+ break;
+
+ case 40:
+#line 219 "src/cfgparser.yy"
+ { reglob->setResX( yyvsp[-1].intValue ); reglob->setResY( yyvsp[0].intValue); }
+ break;
+
+ case 41:
+#line 223 "src/cfgparser.yy"
+ { reglob->setAADepth( yyvsp[0].intValue ); }
+ break;
+
+ case 42:
+#line 227 "src/cfgparser.yy"
+ { reglob->setEye( ntlVec3Gfx(yyvsp[-2].floatValue,yyvsp[-1].floatValue,yyvsp[0].floatValue) ); }
+ break;
+
+ case 43:
+#line 231 "src/cfgparser.yy"
+ { reglob->setLookat( ntlVec3Gfx(yyvsp[-2].floatValue,yyvsp[-1].floatValue,yyvsp[0].floatValue) ); }
+ break;
+
+ case 44:
+#line 235 "src/cfgparser.yy"
+ { reglob->setUpVec( ntlVec3Gfx(yyvsp[-2].floatValue,yyvsp[-1].floatValue,yyvsp[0].floatValue) ); }
+ break;
+
+ case 45:
+#line 239 "src/cfgparser.yy"
+ { reglob->setFovy( yyvsp[0].floatValue ); }
+ break;
+
+ case 46:
+#line 243 "src/cfgparser.yy"
+ { reglob->setAspect( yyvsp[0].floatValue ); }
+ break;
+
+ case 47:
+#line 247 "src/cfgparser.yy"
+ { reglob->setAmbientLight( ntlColor(yyvsp[-2].floatValue,yyvsp[-1].floatValue,yyvsp[0].floatValue) ); }
+ break;
+
+ case 48:
+#line 251 "src/cfgparser.yy"
+ { reglob->setBackgroundCol( ntlColor(yyvsp[-2].floatValue,yyvsp[-1].floatValue,yyvsp[0].floatValue) ); }
+ break;
+
+ case 49:
+#line 255 "src/cfgparser.yy"
+ { reglob->setOutFilename( yyvsp[0].charValue ); }
+ break;
+
+ case 50:
+#line 259 "src/cfgparser.yy"
+ { reglob->setTreeMaxDepth( yyvsp[0].intValue ); }
+ break;
+
+ case 51:
+#line 263 "src/cfgparser.yy"
+ { reglob->setTreeMaxTriangles( yyvsp[0].intValue ); }
+ break;
+
+ case 52:
+#line 267 "src/cfgparser.yy"
+ { reglob->setRayMaxDepth( yyvsp[0].intValue ); }
+ break;
+
+ case 53:
+#line 271 "src/cfgparser.yy"
+ { reglob->setDebugPixel( yyvsp[-1].intValue, yyvsp[0].intValue ); }
+ break;
+
+ case 54:
+#line 275 "src/cfgparser.yy"
+ { reglob->setTestMode( yyvsp[0].intValue ); }
+ break;
+
+ case 55:
+#line 279 "src/cfgparser.yy"
+ { if(attrs[yyvsp[0].charValue] == NULL){ yyerror("OPENGL ATTRIBUTES: The attribute was not found!"); }
+ reglob->getOpenGlAttributes()->import( attrs[yyvsp[0].charValue] ); }
+ break;
+
+ case 56:
+#line 284 "src/cfgparser.yy"
+ { if(attrs[yyvsp[0].charValue] == NULL){ yyerror("BLENDER ATTRIBUTES: The attribute was not found!"); }
+ reglob->getBlenderAttributes()->import( attrs[yyvsp[0].charValue] ); }
+ break;
+
+ case 57:
+#line 296 "src/cfgparser.yy"
+ {
+ /* reset light pointers */
+ currentLightOmni = NULL;
+ }
+ break;
+
+ case 60:
+#line 308 "src/cfgparser.yy"
+ { currentLightOmni = new ntlLightObject( reglob );
+ currentLight = currentLightOmni;
+ reglob->getLightList()->push_back(currentLight);
+ }
+ break;
+
+ case 65:
+#line 322 "src/cfgparser.yy"
+ {
+ currentLight->setActive( yyvsp[0].intValue );
+ }
+ break;
+
+ case 66:
+#line 327 "src/cfgparser.yy"
+ {
+ currentLight->setCastShadows( yyvsp[0].intValue );
+ }
+ break;
+
+ case 67:
+#line 332 "src/cfgparser.yy"
+ {
+ currentLight->setColor( ntlColor(yyvsp[-2].floatValue,yyvsp[-1].floatValue,yyvsp[0].floatValue) );
+ }
+ break;
+
+ case 68:
+#line 337 "src/cfgparser.yy"
+ {
+ int init = 0;
+ if(currentLightOmni != NULL) {
+ currentLightOmni->setPosition( ntlVec3Gfx(yyvsp[-2].floatValue,yyvsp[-1].floatValue,yyvsp[0].floatValue) ); init = 1; }
+ if(!init) yyerror("This property can only be set for omni-directional and rectangular lights!");
+ }
+ break;
+
+ case 69:
+#line 355 "src/cfgparser.yy"
+ {
+ // geo classes have attributes...
+ reglob->getScene()->addGeoClass(currentGeoClass);
+ currentAttrib = currentGeoClass->getAttributeList();
+ }
+ break;
+
+ case 70:
+#line 361 "src/cfgparser.yy"
+ {
+ /* reset geometry object pointers */
+ currentGeoObj = NULL;
+ currentGeoClass = NULL;
+ currentGeometryBox = NULL;
+ currentGeometrySim = NULL;
+ currentGeometryModel = NULL;
+ currentGeometrySphere = NULL;
+ currentAttrib = NULL;
+ }
+ break;
+
+ case 73:
+#line 378 "src/cfgparser.yy"
+ {
+ currentGeometryBox = new ntlGeometryBox( );
+ currentGeoClass = currentGeometryBox;
+ currentGeoObj = (ntlGeometryObject*)( currentGeometryBox );
+ }
+ break;
+
+ case 74:
+#line 383 "src/cfgparser.yy"
+ {
+ currentGeometrySphere = new ntlGeometrySphere( );
+ currentGeoClass = currentGeometrySphere;
+ currentGeoObj = (ntlGeometryObject*)( currentGeometrySphere );
+ }
+ break;
+
+ case 75:
+#line 388 "src/cfgparser.yy"
+ {
+ currentGeometryModel = new ntlGeometryObjModel( );
+ currentGeoClass = currentGeometryModel;
+ currentGeoObj = (ntlGeometryObject*)( currentGeometryModel );
+ }
+ break;
+
+ case 76:
+#line 393 "src/cfgparser.yy"
+ {
+ currentGeometrySim = new SimulationObject();
+ currentGeoClass = currentGeometrySim;
+ reglob->getSims()->push_back(currentGeometrySim);
+ // dont add mcubes to geo list!
+ }
+ break;
+
+ case 77:
+#line 399 "src/cfgparser.yy"
+ {
+#ifdef LBM_INCLUDE_TESTSOLVERS
+ currentGeometrySim = new SimulationCompareLbm();
+ currentGeoClass = currentGeometrySim;
+ reglob->getSims()->push_back(currentGeometrySim);
+#else // LBM_INCLUDE_TESTSOLVERS
+ errMsg("El'Beem::cfg","compare test solver not supported!");
+#endif // LBM_INCLUDE_TESTSOLVERS
+ }
+ break;
+
+ case 87:
+#line 424 "src/cfgparser.yy"
+ {
+ currentGeoClass->setName( yyvsp[0].charValue );
+ }
+ break;
+
+ case 88:
+#line 429 "src/cfgparser.yy"
+ {
+ if(currentGeoObj == NULL){ yyerror(" MATERIAL : This property can only be set for geometry objects!"); }
+ currentGeoObj->setMaterialName( yyvsp[0].charValue );
+ }
+ break;
+
+ case 89:
+#line 435 "src/cfgparser.yy"
+ {
+ if(currentGeoObj == NULL){ yyerror(" CAST_SHADOW : This property can only be set for geometry objects!"); }
+ currentGeoObj->setCastShadows( yyvsp[0].intValue );
+ }
+ break;
+
+ case 90:
+#line 441 "src/cfgparser.yy"
+ {
+ if(currentGeoObj == NULL){ yyerror(" RECEIVE_SHADOW : This property can only be set for geometry objects!"); }
+ currentGeoObj->setReceiveShadows( yyvsp[0].intValue );
+ }
+ break;
+
+ case 91:
+#line 447 "src/cfgparser.yy"
+ {
+ currentGeoClass->setVisible( yyvsp[0].intValue );
+ }
+ break;
+
+ case 92:
+#line 452 "src/cfgparser.yy"
+ {
+ int init = 0;
+ if(currentGeometryBox != NULL){
+ currentGeometryBox->setStart( ntlVec3Gfx(yyvsp[-2].floatValue,yyvsp[-1].floatValue,yyvsp[0].floatValue) ); init=1; }
+ if(currentGeometrySim != NULL){
+ currentGeometrySim->setGeoStart( ntlVec3Gfx(yyvsp[-2].floatValue,yyvsp[-1].floatValue,yyvsp[0].floatValue) ); init=1; }
+ if(currentGeometryModel != NULL){
+ currentGeometryModel->setStart( ntlVec3Gfx(yyvsp[-2].floatValue,yyvsp[-1].floatValue,yyvsp[0].floatValue) ); init=1; }
+ if(!init ){ yyerror("BOXSTART : This property can only be set for box, objmodel, fluid and isosurface objects!"); }
+ }
+ break;
+
+ case 93:
+#line 464 "src/cfgparser.yy"
+ {
+ int init = 0;
+ if(currentGeometryBox != NULL){
+ currentGeometryBox->setEnd( ntlVec3Gfx(yyvsp[-2].floatValue,yyvsp[-1].floatValue,yyvsp[0].floatValue) ); init=1; }
+ if(currentGeometrySim != NULL){
+ currentGeometrySim->setGeoEnd( ntlVec3Gfx(yyvsp[-2].floatValue,yyvsp[-1].floatValue,yyvsp[0].floatValue) ); init=1; }
+ if(currentGeometryModel != NULL){
+ currentGeometryModel->setEnd( ntlVec3Gfx(yyvsp[-2].floatValue,yyvsp[-1].floatValue,yyvsp[0].floatValue) ); init=1; }
+ if(!init ){ yyerror("BOXEND : This property can only be set for box, objmodel, fluid and isosurface objects!"); }
+ }
+ break;
+
+ case 94:
+#line 477 "src/cfgparser.yy"
+ {
+ if(attrs[yyvsp[0].charValue] == NULL){ yyerror("GEO ATTRIBUTES: The attribute was not found!"); }
+ currentGeoClass->getAttributeList()->import( attrs[yyvsp[0].charValue] );
+ }
+ break;
+
+ case 95:
+#line 485 "src/cfgparser.yy"
+ { }
+ break;
+
+ case 96:
+#line 497 "src/cfgparser.yy"
+ {
+ /* reset geometry object pointers */
+ currentMaterial = NULL;
+ }
+ break;
+
+ case 99:
+#line 509 "src/cfgparser.yy"
+ { currentMaterial = new ntlMaterial( );
+ currentMaterial = currentMaterial;
+ reglob->getMaterials()->push_back(currentMaterial);
+ }
+ break;
+
+ case 100:
+#line 513 "src/cfgparser.yy"
+ {
+ yyerror("MATTYPE: Blinn NYI!"); }
+ break;
+
+ case 111:
+#line 531 "src/cfgparser.yy"
+ {
+ currentMaterial->setName( yyvsp[0].charValue );
+ }
+ break;
+
+ case 112:
+#line 536 "src/cfgparser.yy"
+ {
+ currentMaterial->setAmbientRefl( ntlColor(yyvsp[-2].floatValue,yyvsp[-1].floatValue,yyvsp[0].floatValue) );
+ }
+ break;
+
+ case 113:
+#line 541 "src/cfgparser.yy"
+ {
+ currentMaterial->setDiffuseRefl( ntlColor(yyvsp[-2].floatValue,yyvsp[-1].floatValue,yyvsp[0].floatValue) );
+ }
+ break;
+
+ case 114:
+#line 546 "src/cfgparser.yy"
+ {
+ currentMaterial->setSpecular( yyvsp[-1].floatValue );
+ currentMaterial->setSpecExponent( yyvsp[0].floatValue );
+ }
+ break;
+
+ case 115:
+#line 552 "src/cfgparser.yy"
+ {
+ currentMaterial->setMirror( yyvsp[0].floatValue );
+ }
+ break;
+
+ case 116:
+#line 557 "src/cfgparser.yy"
+ {
+ currentMaterial->setTransparence( yyvsp[0].floatValue );
+ }
+ break;
+
+ case 117:
+#line 562 "src/cfgparser.yy"
+ {
+ currentMaterial->setRefracIndex( yyvsp[0].floatValue );
+ }
+ break;
+
+ case 118:
+#line 567 "src/cfgparser.yy"
+ {
+ currentMaterial->setTransAdditive( yyvsp[0].floatValue );
+ }
+ break;
+
+ case 119:
+#line 572 "src/cfgparser.yy"
+ {
+ currentMaterial->setTransAttCol( ntlColor(yyvsp[-2].floatValue,yyvsp[-1].floatValue,yyvsp[0].floatValue) );
+ }
+ break;
+
+ case 120:
+#line 577 "src/cfgparser.yy"
+ {
+ currentMaterial->setFresnel( yyvsp[0].intValue );
+ }
+ break;
+
+ case 121:
+#line 588 "src/cfgparser.yy"
+ {
+ currentAttrib = new AttributeList(yyvsp[-1].charValue);
+ currentAttrName = yyvsp[-1].charValue; }
+ break;
+
+ case 122:
+#line 591 "src/cfgparser.yy"
+ { // store attribute
+ //std::cerr << " NEW ATTR " << currentAttrName << std::endl;
+ //currentAttrib->print();
+ attrs[currentAttrName] = currentAttrib;
+ currentAttrib = NULL; }
+ break;
+
+ case 125:
+#line 601 "src/cfgparser.yy"
+ { currentAttrValue.clear(); currentAttribAddName = yyvsp[-1].charValue; }
+ break;
+
+ case 126:
+#line 602 "src/cfgparser.yy"
+ {
+ currentAttrib->addAttr( currentAttribAddName, currentAttrValue, lineCount);
+ //std::cerr << " ADD ATTR " << currentAttribAddName << std::endl;
+ //currentAttrib->find( currentAttribAddName )->print();
+ }
+ break;
+
+ case 128:
+#line 609 "src/cfgparser.yy"
+ {
+ //std::cerr << "LLL "<<$2<<endl;
+ currentAttrValue.push_back(yyvsp[0].charValue); }
+ break;
+
+ case 129:
+#line 612 "src/cfgparser.yy"
+ {
+ //std::cerr << "LRR "<<$1<<endl;
+ currentAttrValue.push_back(yyvsp[0].charValue); }
+ break;
+
+ case 131:
+#line 626 "src/cfgparser.yy"
+ {
+ if ( (yyvsp[0].floatValue < 0.0) || (yyvsp[0].floatValue > 1.0) ) {
+ yyerror("Value out of range (only 0 to 1 allowed)");
+ }
+
+ /* pass that value up the tree */
+ yyval.floatValue = yyvsp[0].floatValue;
+}
+ break;
+
+ case 132:
+#line 638 "src/cfgparser.yy"
+ { yyval.floatValue = yyvsp[0].floatValue; }
+ break;
+
+ case 133:
+#line 640 "src/cfgparser.yy"
+ { yyval.floatValue = (float) yyvsp[0].intValue; /* conversion from integers */ }
+ break;
+
+ case 134:
+#line 646 "src/cfgparser.yy"
+ {
+ if ( yyvsp[0].intValue <= 0 ) {
+ yy_error("Value out of range (has to be above zero)");
+ }
+
+ /* pass that value up the tree */
+ yyval.intValue = yyvsp[0].intValue;
+}
+ break;
+
+ case 135:
+#line 657 "src/cfgparser.yy"
+ {
+ //cout << " " << $1 << " ";
+ if ( yyvsp[0].intValue < 0 ) {
+ yy_error("Value out of range (has to be above or equal to zero)");
+ }
+
+ /* pass that value up the tree */
+ yyval.intValue = yyvsp[0].intValue;
+}
+ break;
+
+ case 136:
+#line 669 "src/cfgparser.yy"
+ {
+ if( ( yyvsp[0].intValue != 0 ) && ( yyvsp[0].intValue != 1 ) ) {
+ yy_error("Boolean value has to be 1|0, 'true'|'false' or 'on'|'off'!");
+ }
+ /* pass that value up the tree */
+ yyval.intValue = yyvsp[0].intValue;
+}
+ break;
+
+
+ }
+
+/* Line 1010 of yacc.c. */
+#line 2051 "bld-std-gcc/src/cfgparser.cpp"
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+
+
+ 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
+ yyn = yypact[yystate];
+
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
+ {
+ YYSIZE_T yysize = 0;
+ int yytype = YYTRANSLATE (yychar);
+ const char* yyprefix;
+ char *yymsg;
+ int yyx;
+
+ /* 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;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 0;
+
+ yyprefix = ", expecting ";
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]);
+ yycount += 1;
+ if (yycount == 5)
+ {
+ yysize = 0;
+ break;
+ }
+ }
+ yysize += (sizeof ("syntax error, unexpected ")
+ + yystrlen (yytname[yytype]));
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg != 0)
+ {
+ char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+ yyp = yystpcpy (yyp, yytname[yytype]);
+
+ if (yycount < 5)
+ {
+ yyprefix = ", expecting ";
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ yyp = yystpcpy (yyp, yyprefix);
+ yyp = yystpcpy (yyp, yytname[yyx]);
+ yyprefix = " or ";
+ }
+ }
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ yyerror ("syntax error; also virtual memory exhausted");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror ("syntax error");
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* If at end of input, pop the error token,
+ then the rest of the stack, then return failure. */
+ if (yychar == YYEOF)
+ for (;;)
+ {
+ YYPOPSTACK;
+ if (yyssp == yyss)
+ YYABORT;
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[*yyssp], yyvsp);
+ }
+ }
+ else
+ {
+ YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+ yydestruct (yytoken, &yylval);
+ yychar = YYEMPTY;
+
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+#ifdef __GNUC__
+ /* Pacify GCC when the user code never invokes YYERROR and the label
+ yyerrorlab therefore never appears in user code. */
+ if (0)
+ goto yyerrorlab;
+#endif
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+ 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;
+
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[yystate], yyvsp);
+ YYPOPSTACK;
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ YYDPRINTF ((stderr, "Shifting error token, "));
+
+ *++yyvsp = yylval;
+
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here. |
+`----------------------------------------------*/
+yyoverflowlab:
+ yyerror ("parser stack overflow");
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
+}
+
+
+#line 677 "src/cfgparser.yy"
+
+
+/*---------------------------------------------------------------------------*/
+/* parser functions */
+/*---------------------------------------------------------------------------*/
+
+
+/* parse warnings */
+void yy_warn(char *s)
+{
+ printf("Config Parse Warning at Line %d: %s \n", lineCount, s);
+}
+
+/* parse errors */
+void yy_error(const char *s)
+{
+ //errorOut("Current token: "<<yytname[ (int)yytranslate[yychar] ]);
+ errorOut("Config Parse Error at Line "<<lineCount<<": "<<s );
+ exit(1);
+}
+
+
+/* get the global pointers from calling program */
+char pointersInited = 0;
+void setPointers(ntlRenderGlobals *setglob)
+{
+ if(
+ (!setglob) ||
+ (!setglob)
+ ) {
+ errMsg("setPointers","Config Parse Error: Invalid Pointers!\n");
+ exit(1);
+ }
+
+ reglob = setglob;
+ pointersInited = 1;
+}
+
+
+/* parse given file as config file */
+void parseFile(string filename)
+{
+ if(!pointersInited) {
+ errMsg("parseFile","Config Parse Error: Pointers not set!\n");
+ exit(1);
+ }
+
+ /* open file */
+ yy_in = fopen( filename.c_str(), "r");
+ if(!yy_in) {
+ errMsg("parseFile","Config Parse Error: Unable to open '"<<filename.c_str() <<"'!\n" );
+ exit(1);
+ }
+
+ /* parse */
+ //yy_debug = 1; /* Enable debugging? */
+ yy_parse();
+
+ /* close file */
+ fclose( yy_in );
+ // cleanup static map<string,AttributeList*> attrs
+ for(map<string, AttributeList*>::iterator i=attrs.begin();
+ i != attrs.end(); i++) {
+ if((*i).second) {
+ delete (*i).second;
+ (*i).second = NULL;
+ }
+ }
+}
+
+
+
+
diff --git a/intern/elbeem/intern/cfgparser.hpp b/intern/elbeem/intern/cfgparser.hpp
new file mode 100644
index 00000000000..3262ddba03d
--- /dev/null
+++ b/intern/elbeem/intern/cfgparser.hpp
@@ -0,0 +1,259 @@
+/* A Bison parser, made by GNU Bison 1.875d. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 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., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 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 {
+ DT_INTEGER = 258,
+ DT_FLOAT = 259,
+ DT_STRING = 260,
+ DT_ATTRNAME = 261,
+ DT_ATTRVALUE = 262,
+ KW_LBMSIM = 263,
+ KW_COMPARELBM = 264,
+ KW_ANIFRAMETIME = 265,
+ KW_DEBUGMODE = 266,
+ KW_P_RELAXTIME = 267,
+ KW_P_REYNOLDS = 268,
+ KW_P_VISCOSITY = 269,
+ KW_P_SOUNDSPEED = 270,
+ KW_P_DOMAINSIZE = 271,
+ KW_P_FORCE = 272,
+ KW_P_TIMELENGTH = 273,
+ KW_P_STEPTIME = 274,
+ KW_P_TIMEFACTOR = 275,
+ KW_P_ANIFRAMETIME = 276,
+ KW_P_ANISTART = 277,
+ KW_P_SURFACETENSION = 278,
+ KW_P_ACTIVATE = 279,
+ KW_P_DEACTIVATE = 280,
+ KW_P_DENSITY = 281,
+ KW_P_CELLSIZE = 282,
+ KW_P_GSTAR = 283,
+ KW_PFSPATH = 284,
+ KW_PARTLINELENGTH = 285,
+ KW_PARTICLES = 286,
+ KW_FRAMESPERSEC = 287,
+ KW_RAYTRACING = 288,
+ KW_PAROPEN = 289,
+ KW_PARCLOSE = 290,
+ KW_FILENAME = 291,
+ KW_PMCAUSTICS = 292,
+ KW_MAXRAYDEPTH = 293,
+ KW_CAUSTICDIST = 294,
+ KW_CAUSTICPHOT = 295,
+ KW_SHADOWMAPBIAS = 296,
+ KW_TREEMAXDEPTH = 297,
+ KW_TREEMAXTRIANGLES = 298,
+ KW_RESOLUTION = 299,
+ KW_ANTIALIAS = 300,
+ KW_EYEPOINT = 301,
+ KW_ANISTART = 302,
+ KW_ANIFRAMES = 303,
+ KW_FRAMESKIP = 304,
+ KW_LOOKAT = 305,
+ KW_UPVEC = 306,
+ KW_FOVY = 307,
+ KW_ASPECT = 308,
+ KW_AMBIENCE = 309,
+ KW_BACKGROUND = 310,
+ KW_DEBUGPIXEL = 311,
+ KW_TESTMODE = 312,
+ KW_OPENGLATTR = 313,
+ KW_BLENDERATTR = 314,
+ KW_ATTRIBUTE = 315,
+ KW_OBJATTR = 316,
+ KW_EQUALS = 317,
+ KW_DEFINEATTR = 318,
+ KW_ATTREND = 319,
+ KW_GEOMETRY = 320,
+ KW_TYPE = 321,
+ KW_GEOTYPE_BOX = 322,
+ KW_GEOTYPE_FLUID = 323,
+ KW_GEOTYPE_OBJMODEL = 324,
+ KW_GEOTYPE_SPHERE = 325,
+ KW_CASTSHADOWS = 326,
+ KW_RECEIVESHADOWS = 327,
+ KW_VISIBLE = 328,
+ KW_BOX_END = 329,
+ KW_BOX_START = 330,
+ KW_POLY = 331,
+ KW_NUMVERTICES = 332,
+ KW_VERTEX = 333,
+ KW_NUMPOLYGONS = 334,
+ KW_ISOSURF = 335,
+ KW_FILEMODE = 336,
+ KW_INVERT = 337,
+ KW_MATERIAL = 338,
+ KW_MATTYPE_PHONG = 339,
+ KW_MATTYPE_BLINN = 340,
+ KW_NAME = 341,
+ KW_AMBIENT = 342,
+ KW_DIFFUSE = 343,
+ KW_SPECULAR = 344,
+ KW_MIRROR = 345,
+ KW_TRANSPARENCE = 346,
+ KW_REFRACINDEX = 347,
+ KW_TRANSADDITIVE = 348,
+ KW_TRANSATTCOL = 349,
+ KW_FRESNEL = 350,
+ KW_LIGHT = 351,
+ KW_ACTIVE = 352,
+ KW_COLOUR = 353,
+ KW_POSITION = 354,
+ KW_LIGHT_OMNI = 355,
+ KW_CAUSTICPHOTONS = 356,
+ KW_CAUSTICSTRENGTH = 357,
+ KW_SHADOWMAP = 358,
+ KW_CAUSTICSMAP = 359
+ };
+#endif
+#define DT_INTEGER 258
+#define DT_FLOAT 259
+#define DT_STRING 260
+#define DT_ATTRNAME 261
+#define DT_ATTRVALUE 262
+#define KW_LBMSIM 263
+#define KW_COMPARELBM 264
+#define KW_ANIFRAMETIME 265
+#define KW_DEBUGMODE 266
+#define KW_P_RELAXTIME 267
+#define KW_P_REYNOLDS 268
+#define KW_P_VISCOSITY 269
+#define KW_P_SOUNDSPEED 270
+#define KW_P_DOMAINSIZE 271
+#define KW_P_FORCE 272
+#define KW_P_TIMELENGTH 273
+#define KW_P_STEPTIME 274
+#define KW_P_TIMEFACTOR 275
+#define KW_P_ANIFRAMETIME 276
+#define KW_P_ANISTART 277
+#define KW_P_SURFACETENSION 278
+#define KW_P_ACTIVATE 279
+#define KW_P_DEACTIVATE 280
+#define KW_P_DENSITY 281
+#define KW_P_CELLSIZE 282
+#define KW_P_GSTAR 283
+#define KW_PFSPATH 284
+#define KW_PARTLINELENGTH 285
+#define KW_PARTICLES 286
+#define KW_FRAMESPERSEC 287
+#define KW_RAYTRACING 288
+#define KW_PAROPEN 289
+#define KW_PARCLOSE 290
+#define KW_FILENAME 291
+#define KW_PMCAUSTICS 292
+#define KW_MAXRAYDEPTH 293
+#define KW_CAUSTICDIST 294
+#define KW_CAUSTICPHOT 295
+#define KW_SHADOWMAPBIAS 296
+#define KW_TREEMAXDEPTH 297
+#define KW_TREEMAXTRIANGLES 298
+#define KW_RESOLUTION 299
+#define KW_ANTIALIAS 300
+#define KW_EYEPOINT 301
+#define KW_ANISTART 302
+#define KW_ANIFRAMES 303
+#define KW_FRAMESKIP 304
+#define KW_LOOKAT 305
+#define KW_UPVEC 306
+#define KW_FOVY 307
+#define KW_ASPECT 308
+#define KW_AMBIENCE 309
+#define KW_BACKGROUND 310
+#define KW_DEBUGPIXEL 311
+#define KW_TESTMODE 312
+#define KW_OPENGLATTR 313
+#define KW_BLENDERATTR 314
+#define KW_ATTRIBUTE 315
+#define KW_OBJATTR 316
+#define KW_EQUALS 317
+#define KW_DEFINEATTR 318
+#define KW_ATTREND 319
+#define KW_GEOMETRY 320
+#define KW_TYPE 321
+#define KW_GEOTYPE_BOX 322
+#define KW_GEOTYPE_FLUID 323
+#define KW_GEOTYPE_OBJMODEL 324
+#define KW_GEOTYPE_SPHERE 325
+#define KW_CASTSHADOWS 326
+#define KW_RECEIVESHADOWS 327
+#define KW_VISIBLE 328
+#define KW_BOX_END 329
+#define KW_BOX_START 330
+#define KW_POLY 331
+#define KW_NUMVERTICES 332
+#define KW_VERTEX 333
+#define KW_NUMPOLYGONS 334
+#define KW_ISOSURF 335
+#define KW_FILEMODE 336
+#define KW_INVERT 337
+#define KW_MATERIAL 338
+#define KW_MATTYPE_PHONG 339
+#define KW_MATTYPE_BLINN 340
+#define KW_NAME 341
+#define KW_AMBIENT 342
+#define KW_DIFFUSE 343
+#define KW_SPECULAR 344
+#define KW_MIRROR 345
+#define KW_TRANSPARENCE 346
+#define KW_REFRACINDEX 347
+#define KW_TRANSADDITIVE 348
+#define KW_TRANSATTCOL 349
+#define KW_FRESNEL 350
+#define KW_LIGHT 351
+#define KW_ACTIVE 352
+#define KW_COLOUR 353
+#define KW_POSITION 354
+#define KW_LIGHT_OMNI 355
+#define KW_CAUSTICPHOTONS 356
+#define KW_CAUSTICSTRENGTH 357
+#define KW_SHADOWMAP 358
+#define KW_CAUSTICSMAP 359
+
+
+
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 85 "src/cfgparser.yy"
+typedef union YYSTYPE {
+ int intValue;
+ float floatValue;
+ char *charValue;
+} YYSTYPE;
+/* Line 1285 of yacc.c. */
+#line 251 "bld-std-gcc/src/cfgparser.hpp"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+extern YYSTYPE yy_lval;
+
+
+
diff --git a/intern/elbeem/intern/elbeem.cpp b/intern/elbeem/intern/elbeem.cpp
new file mode 100644
index 00000000000..140c571fa8b
--- /dev/null
+++ b/intern/elbeem/intern/elbeem.cpp
@@ -0,0 +1,51 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * All code distributed as part of El'Beem is covered by the version 2 of the
+ * GNU General Public License. See the file COPYING for details.
+ * Copyright 2003-2005 Nils Thuerey
+ *
+ * Main program functions
+ *
+ */
+
+//#include "globals.h"
+
+
+/*****************************************************************************/
+// region of interest global vars
+// currently used by e.g. fsgr solver
+double guiRoiSX = 0.0;
+double guiRoiSY = 0.0;
+double guiRoiSZ = 0.0;
+double guiRoiEX = 1.0;
+double guiRoiEY = 1.0;
+double guiRoiEZ = 1.0;
+int guiRoiMaxLev=6, guiRoiMinLev=0;
+
+//! global raytracer pointer (=world)
+class ntlRaytracer;
+ntlRaytracer *gpWorld = (ntlRaytracer*)0;
+
+//! debug output switch
+bool myDebugOut = false;
+
+//! global leave program variable
+bool gQuit = false;
+
+//! start simulation?
+bool gThreadRunning = false;
+
+/* usage message */
+char* usageString =
+ "El'Beem - Lattice Boltzmann Free Surface Simulator\n\
+ Command-line Options: \n\
+ -b : .obj file dump mode for Blender\n\
+ -c : Force command line mode for rendering \n\
+ -d : Dump mode for ECR\n\
+ -f <filename> : Specify fluid description file to use as <filename>\n\
+ -h : Display this message \n\
+ -o : single frame output to given file\n\
+ \n ";
+
+
diff --git a/intern/elbeem/intern/factory_fsgr.cpp b/intern/elbeem/intern/factory_fsgr.cpp
new file mode 100644
index 00000000000..c64f54cc7ad
--- /dev/null
+++ b/intern/elbeem/intern/factory_fsgr.cpp
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004,2005 Nils Thuerey
+ *
+ * Standard LBM Factory implementation
+ *
+ *****************************************************************************/
+
+#include "factory_lbm.h"
+
+// compiler sanity check
+#ifndef LBMDIM
+#if LBMDIM!=2
+#if LBMDIM!=3
+print("Error - LBMDIM has to be defined (2/3)!");
+#endif
+#endif
+#endif
+
+// disable sometimes to speed up compiling/2d tests
+#define DISABLE 0
+
+#include "lbmdimensions.h"
+#include "lbmfsgrsolver.h"
+
+//! lbm factory functions
+LbmSolverInterface* createSolverLbmFsgr() {
+#if DISABLE!=1
+#if LBMDIM==2
+ return new LbmFsgrSolver< LbmBGK2D >();
+#endif // LBMDIM==2
+#if LBMDIM==3
+ return new LbmFsgrSolver< LbmBGK3D >();
+#endif // LBMDIM==3
+#endif // DISABLE
+ return NULL;
+}
+
+
diff --git a/intern/elbeem/intern/factory_lbm.h b/intern/elbeem/intern/factory_lbm.h
new file mode 100644
index 00000000000..0e7e4dcb9f8
--- /dev/null
+++ b/intern/elbeem/intern/factory_lbm.h
@@ -0,0 +1,18 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * 2D/3D LBM Factory header
+ *
+ *****************************************************************************/
+
+#include "lbminterface.h"
+
+//! lbm factory functions
+LbmSolverInterface* createSolverLbmFsgr();
+#ifdef LBM_INCLUDE_TESTSOLVERS
+LbmSolverInterface* createSolverOld();
+#endif // LBM_INCLUDE_OLD
+
+
diff --git a/intern/elbeem/intern/globals.h b/intern/elbeem/intern/globals.h
new file mode 100644
index 00000000000..864c3052ad3
--- /dev/null
+++ b/intern/elbeem/intern/globals.h
@@ -0,0 +1,32 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * All code distributed as part of El'Beem is covered by the version 2 of the
+ * GNU General Public License. See the file COPYING for details.
+ * Copyright 2003-2005 Nils Thuerey
+ *
+ * Global variables (unavoidable at times...)
+ * all defines in main.cpp
+ *
+ *****************************************************************************/
+
+
+/*****************************************************************************/
+//! user interface variables
+
+// global raytracer pointer (=world)
+class ntlRaytracer;
+extern ntlRaytracer *gpWorld;
+
+// debug output switch
+extern bool myDebugOut;
+
+// global leave program variable
+extern bool gQuit;
+
+//! start simulation?
+extern bool gThreadRunning;
+
+//! short manual
+extern char* usageString;
+
diff --git a/intern/elbeem/intern/isosurface.cpp b/intern/elbeem/intern/isosurface.cpp
new file mode 100644
index 00000000000..a69e2ccb998
--- /dev/null
+++ b/intern/elbeem/intern/isosurface.cpp
@@ -0,0 +1,1057 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2005 Nils Thuerey
+ *
+ * Marching Cubes surface mesh generation
+ *
+ *****************************************************************************/
+
+// IMPL ----------------------------------------------------------------------------------------
+#include "isosurface.h"
+#include "mcubes_tables.h"
+#include "ntl_scene.h"
+
+#include <algorithm>
+#include <stdio.h>
+#define MCUBES_MAXPOLNUM 10000
+#define MCUBES_MAXVERTNUM 30000
+
+
+
+/******************************************************************************
+ * Constructor
+ *****************************************************************************/
+IsoSurface::IsoSurface(double iso, double blend) :
+ ntlGeometryObject(),
+ mSizex(-1), mSizey(-1), mSizez(-1),
+ mIsoValue( iso ),
+ mBlendVal( blend ),
+ mPoints(),
+ mpEdgeVerticesX(NULL), mpEdgeVerticesY(NULL), mpEdgeVerticesZ(NULL),
+ mIndices(),
+
+ mStart(0.0), mEnd(0.0), mDomainExtent(0.0),
+ mInitDone(false),
+ mLoopSubdivs(0), mSmoothSurface(0.0), mSmoothNormals(0.0),
+ mAcrossEdge(), mAdjacentFaces()
+{
+}
+
+
+/******************************************************************************
+ * The real init...
+ *****************************************************************************/
+void IsoSurface::initializeIsosurface(int setx, int sety, int setz, ntlVec3Gfx extent)
+{
+ // init solver and size
+ mSizex = setx;
+ mSizey = sety;
+ if(setz == 1) {// 2D, create thin 2D surface
+ setz = 5;
+ }
+ mSizez = setz;
+ mDomainExtent = extent;
+
+ /* check triangulation size (for raytraing) */
+ if( ( mStart[0] >= mEnd[0] ) && ( mStart[1] >= mEnd[1] ) && ( mStart[2] >= mEnd[2] ) ){
+ // extent was not set, use normalized one from parametrizer
+ mStart = ntlVec3Gfx(0.0) - extent*0.5;
+ mEnd = ntlVec3Gfx(0.0) + extent*0.5;
+ }
+
+ // init
+ mIndices.clear();
+ mPoints.clear();
+
+ int nodes = mSizez*mSizey*mSizex;
+ mpData = new float[nodes];
+ for(int i=0;i<nodes;i++) { mpData[i] = 0.0; }
+
+ // allocate edge arrays (last slices are never used...)
+ mpEdgeVerticesX = new int[nodes];
+ mpEdgeVerticesY = new int[nodes];
+ mpEdgeVerticesZ = new int[nodes];
+ for(int i=0;i<nodes;i++) { mpEdgeVerticesX[i] = mpEdgeVerticesY[i] = mpEdgeVerticesZ[i] = -1; }
+
+ // marching cubes are ready
+ mInitDone = true;
+ unsigned long int memCnt = (3*sizeof(int)*nodes + sizeof(float)*nodes);
+ double memd = memCnt;
+ char *sizeStr = "";
+ const double sfac = 1000.0;
+ if(memd>sfac){ memd /= sfac; sizeStr="KB"; }
+ if(memd>sfac){ memd /= sfac; sizeStr="MB"; }
+ if(memd>sfac){ memd /= sfac; sizeStr="GB"; }
+ if(memd>sfac){ memd /= sfac; sizeStr="TB"; }
+
+ debMsgStd("IsoSurface::initializeIsosurface",DM_MSG,"Inited "<<PRINT_VEC(setx,sety,setz)<<" alloced:"<< memd<<" "<<sizeStr<<"." ,10);
+}
+
+
+
+
+/******************************************************************************
+ * Destructor
+ *****************************************************************************/
+IsoSurface::~IsoSurface( void )
+{
+
+ if(mpEdgeVerticesX) delete [] mpEdgeVerticesX;
+ if(mpEdgeVerticesY) delete [] mpEdgeVerticesY;
+ if(mpEdgeVerticesZ) delete [] mpEdgeVerticesZ;
+
+}
+
+
+
+
+/******************************************************************************
+ * triangulate the scalar field given by pointer
+ *****************************************************************************/
+void IsoSurface::triangulate( void )
+{
+ double gsx,gsy,gsz; // grid spacing in x,y,z direction
+ double px,py,pz; // current position in grid in x,y,z direction
+ IsoLevelCube cubie; // struct for a small subcube
+ myTime_t tritimestart = getTime();
+
+ if(!mpData) {
+ errorOut("IsoSurface::triangulate fatal error: no LBM object, and no scalar field...!");
+ exit( -1 );
+ }
+
+ // get grid spacing
+ gsx = (mEnd[0]-mStart[0])/(double)(mSizex-1.0);
+ gsy = (mEnd[1]-mStart[1])/(double)(mSizey-1.0);
+ gsz = (mEnd[2]-mStart[2])/(double)(mSizez-1.0);
+
+ // clean up previous frame
+ mIndices.clear();
+ mPoints.clear();
+
+ // reset edge vertices
+ for(int i=0;i<(mSizex*mSizey*mSizez);i++) {
+ mpEdgeVerticesX[i] = -1;
+ mpEdgeVerticesY[i] = -1;
+ mpEdgeVerticesZ[i] = -1;
+ }
+
+ ntlVec3Gfx pos[8];
+ float value[8];
+ int cubeIndex; // index entry of the cube
+ int triIndices[12]; // vertex indices
+ int *eVert[12];
+ IsoLevelVertex ilv;
+
+ // edges between which points?
+ const int mcEdges[24] = {
+ 0,1, 1,2, 2,3, 3,0,
+ 4,5, 5,6, 6,7, 7,4,
+ 0,4, 1,5, 2,6, 3,7 };
+
+ const int cubieOffsetX[8] = {
+ 0,1,1,0, 0,1,1,0 };
+ const int cubieOffsetY[8] = {
+ 0,0,1,1, 0,0,1,1 };
+ const int cubieOffsetZ[8] = {
+ 0,0,0,0, 1,1,1,1 };
+
+ // let the cubes march
+ pz = mStart[2]-gsz;
+ for(int k=0;k<(mSizez-2);k++) {
+ pz += gsz;
+ py = mStart[1]-gsy;
+ for(int j=0;j<(mSizey-2);j++) {
+ py += gsy;
+ px = mStart[0]-gsx;
+ for(int i=0;i<(mSizex-2);i++) {
+ px += gsx;
+ int baseIn = ISOLEVEL_INDEX( i+0, j+0, k+0);
+
+ value[0] = *getData(i ,j ,k );
+ value[1] = *getData(i+1,j ,k );
+ value[2] = *getData(i+1,j+1,k );
+ value[3] = *getData(i ,j+1,k );
+ value[4] = *getData(i ,j ,k+1);
+ value[5] = *getData(i+1,j ,k+1);
+ value[6] = *getData(i+1,j+1,k+1);
+ value[7] = *getData(i ,j+1,k+1);
+ //errMsg("ISOT2D"," at "<<PRINT_IJK<<" "
+ //<<" v0="<<value[0] <<" v1="<<value[1] <<" v2="<<value[2] <<" v3="<<value[3]
+ //<<" v4="<<value[4] <<" v5="<<value[5] <<" v6="<<value[6] <<" v7="<<value[7] );
+
+ // check intersections of isosurface with edges, and calculate cubie index
+ cubeIndex = 0;
+ if (value[0] < mIsoValue) cubeIndex |= 1;
+ if (value[1] < mIsoValue) cubeIndex |= 2;
+ if (value[2] < mIsoValue) cubeIndex |= 4;
+ if (value[3] < mIsoValue) cubeIndex |= 8;
+ if (value[4] < mIsoValue) cubeIndex |= 16;
+ if (value[5] < mIsoValue) cubeIndex |= 32;
+ if (value[6] < mIsoValue) cubeIndex |= 64;
+ if (value[7] < mIsoValue) cubeIndex |= 128;
+
+ // No triangles to generate?
+ if (mcEdgeTable[cubeIndex] == 0) {
+ continue;
+ }
+
+ // where to look up if this point already exists
+ eVert[ 0] = &mpEdgeVerticesX[ baseIn ];
+ eVert[ 1] = &mpEdgeVerticesY[ baseIn + 1 ];
+ eVert[ 2] = &mpEdgeVerticesX[ ISOLEVEL_INDEX( i+0, j+1, k+0) ];
+ eVert[ 3] = &mpEdgeVerticesY[ baseIn ];
+
+ eVert[ 4] = &mpEdgeVerticesX[ ISOLEVEL_INDEX( i+0, j+0, k+1) ];
+ eVert[ 5] = &mpEdgeVerticesY[ ISOLEVEL_INDEX( i+1, j+0, k+1) ];
+ eVert[ 6] = &mpEdgeVerticesX[ ISOLEVEL_INDEX( i+0, j+1, k+1) ];
+ eVert[ 7] = &mpEdgeVerticesY[ ISOLEVEL_INDEX( i+0, j+0, k+1) ];
+
+ eVert[ 8] = &mpEdgeVerticesZ[ baseIn ];
+ eVert[ 9] = &mpEdgeVerticesZ[ ISOLEVEL_INDEX( i+1, j+0, k+0) ];
+ eVert[10] = &mpEdgeVerticesZ[ ISOLEVEL_INDEX( i+1, j+1, k+0) ];
+ eVert[11] = &mpEdgeVerticesZ[ ISOLEVEL_INDEX( i+0, j+1, k+0) ];
+
+ // grid positions
+ pos[0] = ntlVec3Gfx(px ,py ,pz);
+ pos[1] = ntlVec3Gfx(px+gsx,py ,pz);
+ pos[2] = ntlVec3Gfx(px+gsx,py+gsy,pz);
+ pos[3] = ntlVec3Gfx(px ,py+gsy,pz);
+ pos[4] = ntlVec3Gfx(px ,py ,pz+gsz);
+ pos[5] = ntlVec3Gfx(px+gsx,py ,pz+gsz);
+ pos[6] = ntlVec3Gfx(px+gsx,py+gsy,pz+gsz);
+ pos[7] = ntlVec3Gfx(px ,py+gsy,pz+gsz);
+
+ // check all edges
+ for(int e=0;e<12;e++) {
+
+ if (mcEdgeTable[cubeIndex] & (1<<e)) {
+ // is the vertex already calculated?
+ if(*eVert[ e ] < 0) {
+ // interpolate edge
+ const int e1 = mcEdges[e*2 ];
+ const int e2 = mcEdges[e*2+1];
+ const ntlVec3Gfx p1 = pos[ e1 ]; // scalar field pos 1
+ const ntlVec3Gfx p2 = pos[ e2 ]; // scalar field pos 2
+ const float valp1 = value[ e1 ]; // scalar field val 1
+ const float valp2 = value[ e2 ]; // scalar field val 2
+ //double mu; // interpolation value
+ //ntlVec3Gfx p; // new point
+
+ // choose if point should be calculated by interpolation,
+ // or "Karolin" method
+
+ //double deltaVal = ABS(valp2-valp1);
+ //if(deltaVal >-10.0) {
+ // standard interpolation
+ //vertInfo[e].type = 0;
+ /*if (ABS(mIsoValue-valp1) < 0.000000001) {
+ mu = 0.0;
+ } else {
+ if (ABS(mIsoValue-valp2) < 0.000000001) {
+ mu = 1.0;
+ } else {
+ mu = (mIsoValue - valp1) / (valp2 - valp1);
+ }
+ } */
+ /*} else {
+ errorOut(" ? ");
+ // use fill grade (=karo)
+ vertInfo[e].type = 1;
+ if(valp1 < valp2) { mu = 1.0- (valp1 + valp2 - mIsoValue);
+ } else { mu = 0.0+ (valp1 + valp2 - mIsoValue); }
+ } */
+
+ //const float mu = (mIsoValue - valp1) / (valp2 - valp1);
+ float mu;
+ if(valp1 < valp2) {
+ mu = 1.0 - 1.0*(valp1 + valp2 - mIsoValue);
+ } else {
+ mu = 0.0 + 1.0*(valp1 + valp2 - mIsoValue);
+ }
+
+ float isov2 = mIsoValue;
+ isov2 = (valp1+valp2)*0.5;
+ mu = (isov2 - valp1) / (valp2 - valp1);
+ mu = (isov2) / (valp2 - valp1);
+
+ mu = (mIsoValue - valp1) / (valp2 - valp1);
+ //mu *= mu;
+
+
+
+ // init isolevel vertex
+ ilv.v = p1 + (p2-p1)*mu;
+ ilv.n = getNormal( i+cubieOffsetX[e1], j+cubieOffsetY[e1], k+cubieOffsetZ[e1]) * (1.0-mu) +
+ getNormal( i+cubieOffsetX[e2], j+cubieOffsetY[e2], k+cubieOffsetZ[e2]) * ( mu) ;
+ mPoints.push_back( ilv );
+
+ triIndices[e] = (mPoints.size()-1);
+ // store vertex
+ *eVert[ e ] = triIndices[e];
+ } else {
+ // retrieve from vert array
+ triIndices[e] = *eVert[ e ];
+ }
+ } // along all edges
+
+ }
+
+
+ // Create the triangles...
+ for(int e=0; mcTriTable[cubeIndex][e]!=-1; e+=3) {
+ //errMsg("MC","tri "<<mIndices.size() <<" "<< triIndices[ mcTriTable[cubeIndex][e+0] ]<<" "<< triIndices[ mcTriTable[cubeIndex][e+1] ]<<" "<< triIndices[ mcTriTable[cubeIndex][e+2] ] );
+ mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+0] ] );
+ mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+1] ] );
+ mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+2] ] );
+ }
+
+
+ }
+ }
+
+ } // k
+
+
+ // precalculate normals using an approximation of the scalar field gradient
+ for(int ni=0;ni<(int)mPoints.size();ni++) {
+ // use triangle normals?, this seems better for File-IsoSurf
+ normalize( mPoints[ni].n );
+ }
+
+ if(mSmoothSurface>0.0) {
+ // not needed for post normal smoothing?
+ // if(mSmoothNormals<=0.0) { smoothNormals(mSmoothSurface*0.5); }
+ smoothSurface(mSmoothSurface);
+ }
+ for(int i=0; i<mLoopSubdivs; i++) {
+ subdivide();
+ }
+ if(mSmoothNormals>0.0) {
+ smoothNormals(mSmoothNormals);
+ }
+ myTime_t tritimeend = getTime();
+#if ELBEEM_BLENDER!=1
+ debMsgStd("IsoSurface::triangulate",DM_MSG,"Took "<< ((tritimeend-tritimestart)/(double)1000.0)<<"s) " , 10 );
+#endif // ELBEEM_BLENDER!=1
+}
+
+
+
+
+
+/******************************************************************************
+ * Get triangles for rendering
+ *****************************************************************************/
+void IsoSurface::getTriangles( vector<ntlTriangle> *triangles,
+ vector<ntlVec3Gfx> *vertices,
+ vector<ntlVec3Gfx> *normals, int objectId )
+{
+ if(!mInitDone) {
+ debugOut("IsoSurface::getTriangles warning: Not initialized! ", 10);
+ return;
+ }
+
+ /* triangulate field */
+ triangulate();
+ //errMsg("TRIS"," "<<mIndices.size() );
+
+ // new output with vertice reuse
+ int iniVertIndex = (*vertices).size();
+ int iniNormIndex = (*normals).size();
+ if(iniVertIndex != iniNormIndex) {
+ errorOut("getTriangles Error for '"<<mName<<"': Vertices and normal array sizes to not match!!!");
+ exit(1); }
+ //errMsg("NM"," ivi"<<iniVertIndex<<" ini"<<iniNormIndex<<" vs"<<vertices->size()<<" ns"<<normals->size()<<" ts"<<triangles->size() );
+ //errMsg("NM"," ovs"<<mVertices.size()<<" ons"<<mVertNormals.size()<<" ots"<<mIndices.size() );
+
+ for(int i=0;i<(int)mPoints.size();i++) {
+ vertices->push_back( mPoints[i].v );
+ }
+ for(int i=0;i<(int)mPoints.size();i++) {
+ normals->push_back( mPoints[i].n );
+ }
+
+ //errMsg("N2"," ivi"<<iniVertIndex<<" ini"<<iniNormIndex<<" vs"<<vertices->size()<<" ns"<<normals->size()<<" ts"<<triangles->size() );
+ //errMsg("N2"," ovs"<<mVertices.size()<<" ons"<<mVertNormals.size()<<" ots"<<mIndices.size() );
+
+ for(int i=0;i<(int)mIndices.size();i+=3) {
+ const int smooth = 1;
+ int t1 = mIndices[i];
+ int t2 = mIndices[i+1];
+ int t3 = mIndices[i+2];
+ //errMsg("NM"," tri"<<t1<<" "<<t2<<" "<<t3 );
+
+ ntlTriangle tri;
+
+ tri.getPoints()[0] = t1+iniVertIndex;
+ tri.getPoints()[1] = t2+iniVertIndex;
+ tri.getPoints()[2] = t3+iniVertIndex;
+
+ /* init flags */
+ int flag = 0;
+ if(getVisible()){ flag |= TRI_GEOMETRY; }
+ if(getCastShadows() ) {
+ flag |= TRI_CASTSHADOWS; }
+ if( (getMaterial()->getMirror()>0.0) ||
+ (getMaterial()->getTransparence()>0.0) ||
+ (getMaterial()->getFresnel()>0.0) ) {
+ flag |= TRI_MAKECAUSTICS; }
+ else {
+ flag |= TRI_NOCAUSTICS; }
+
+ /* init geo init id */
+ int geoiId = getGeoInitId();
+ if(geoiId > 0) {
+ flag |= (1<< (geoiId+4));
+ flag |= mGeoInitType;
+ }
+
+ tri.setFlags( flag );
+
+ /* triangle normal missing */
+ tri.setNormal( ntlVec3Gfx(0.0) );
+ tri.setSmoothNormals( smooth );
+ tri.setObjectId( objectId );
+ triangles->push_back( tri );
+ }
+ //errMsg("N3"," ivi"<<iniVertIndex<<" ini"<<iniNormIndex<<" vs"<<vertices->size()<<" ns"<<normals->size()<<" ts"<<triangles->size() );
+ return;
+}
+
+
+
+inline ntlVec3Gfx IsoSurface::getNormal(int i, int j,int k) {
+ // WARNING - this assumes a security boundary layer...
+ /*
+ if(i<=0) i=1;
+ if(j<=0) j=1;
+ if(k<=0) k=1;
+ if(i>=(mSizex-1)) i=mSizex-2;
+ if(j>=(mSizex-1)) j=mSizex-2;
+ if(k>=(mSizex-1)) k=mSizex-2; // */
+
+ ntlVec3Gfx ret(0.0);
+ ret[0] = *getData(i-1,j ,k ) -
+ *getData(i+1,j ,k );
+ ret[1] = *getData(i ,j-1,k ) -
+ *getData(i ,j+1,k );
+ ret[2] = *getData(i ,j ,k-1 ) -
+ *getData(i ,j ,k+1 );
+ return ret;
+}
+
+#define RECALCNORMALS 0
+
+// Subdivide a mesh allways loop
+void IsoSurface::subdivide()
+{
+ int i;
+
+ mAdjacentFaces.clear();
+ mAcrossEdge.clear();
+
+ //void TriMesh::need_adjacentfaces()
+ {
+ vector<int> numadjacentfaces(mPoints.size());
+ //errMsg("SUBDIV ADJFA1", " "<<mPoints.size()<<" - "<<numadjacentfaces.size() );
+ int i;
+ for (i = 0; i < (int)mIndices.size()/3; i++) {
+ numadjacentfaces[mIndices[i*3 + 0]]++;
+ numadjacentfaces[mIndices[i*3 + 1]]++;
+ numadjacentfaces[mIndices[i*3 + 2]]++;
+ }
+
+ mAdjacentFaces.resize(mPoints.size());
+ for (i = 0; i < (int)mPoints.size(); i++)
+ mAdjacentFaces[i].reserve(numadjacentfaces[i]);
+
+ for (i = 0; i < (int)mIndices.size()/3; i++) {
+ for (int j = 0; j < 3; j++)
+ mAdjacentFaces[mIndices[i*3 + j]].push_back(i);
+ }
+
+ }
+
+ // Find the face across each edge from each other face (-1 on boundary)
+ // If topology is bad, not necessarily what one would expect...
+ //void TriMesh::need_across_edge()
+ {
+ mAcrossEdge.resize(mIndices.size(), -1);
+
+ for (int i = 0; i < (int)mIndices.size()/3; i++) {
+ for (int j = 0; j < 3; j++) {
+ if (mAcrossEdge[i*3 + j] != -1)
+ continue;
+ int v1 = mIndices[i*3 + ((j+1)%3)];
+ int v2 = mIndices[i*3 + ((j+2)%3)];
+ const vector<int> &a1 = mAdjacentFaces[v1];
+ const vector<int> &a2 = mAdjacentFaces[v2];
+ for (int k1 = 0; k1 < (int)a1.size(); k1++) {
+ int other = a1[k1];
+ if (other == i)
+ continue;
+ vector<int>::const_iterator it =
+ std::find(a2.begin(), a2.end(), other);
+ if (it == a2.end())
+ continue;
+
+ //int ind = (faces[other].indexof(v1)+1)%3;
+ int ind = -1;
+ if( mIndices[other*3+0] == (unsigned int)v1 ) ind = 0;
+ else if( mIndices[other*3+1] == (unsigned int)v1 ) ind = 1;
+ else if( mIndices[other*3+2] == (unsigned int)v1 ) ind = 2;
+ ind = (ind+1)%3;
+
+ if ( (int)mIndices[other*3 + ((ind+1)%3)] != v2)
+ continue;
+ mAcrossEdge[i*3 + j] = other;
+ mAcrossEdge[other*3 + ind] = i;
+ break;
+ }
+ }
+ }
+
+ //errMsg("SUBDIV ACREDG", "Done.\n");
+ }
+
+ //errMsg("SUBDIV","start");
+ // Introduce new vertices
+ int nf = (int)mIndices.size() / 3;
+
+ //vector<TriMesh::Face> newverts(nf, TriMesh::Face(-1,-1,-1));
+ vector<int> newverts(nf*3); //, TriMesh::Face(-1,-1,-1));
+ for(int j=0; j<(int)newverts.size(); j++) newverts[j] = -1;
+
+ int old_nv = (int)mPoints.size();
+ mPoints.reserve(4 * old_nv);
+ vector<int> newvert_count(old_nv + 3*nf); // wichtig...?
+ //errMsg("NC", newvert_count.size() );
+
+ for (i = 0; i < nf; i++) {
+ for (int j = 0; j < 3; j++) {
+ int ae = mAcrossEdge[i*3 + j];
+ if (newverts[i*3 + j] == -1 && ae != -1) {
+ if (mAcrossEdge[ae*3 + 0] == i)
+ newverts[i*3 + j] = newverts[ae*3 + 0];
+ else if (mAcrossEdge[ae*3 + 1] == i)
+ newverts[i*3 + j] = newverts[ae*3 + 1];
+ else if (mAcrossEdge[ae*3 + 2] == i)
+ newverts[i*3 + j] = newverts[ae*3 + 2];
+ }
+ if (newverts[i*3 + j] == -1) {
+ IsoLevelVertex ilv;
+ ilv.v = ntlVec3Gfx(0.0);
+ ilv.n = ntlVec3Gfx(0.0);
+ mPoints.push_back(ilv);
+ newverts[i*3 + j] = (int)mPoints.size() - 1;
+ if (ae != -1) {
+ if (mAcrossEdge[ae*3 + 0] == i)
+ newverts[ae*3 + 0] = newverts[i*3 + j];
+ else if (mAcrossEdge[ae*3 + 1] == i)
+ newverts[ae*3 + 1] = newverts[i*3 + j];
+ else if (mAcrossEdge[ae*3 + 2] == i)
+ newverts[ae*3 + 2] = newverts[i*3 + j];
+ }
+ }
+ if(ae != -1) {
+ mPoints[newverts[i*3 + j]].v +=
+ mPoints[ mIndices[i*3 + ( j )] ].v * 0.25f + // j = 0,1,2?
+ mPoints[ mIndices[i*3 + ((j+1)%3)] ].v * 0.375f +
+ mPoints[ mIndices[i*3 + ((j+2)%3)] ].v * 0.375f;
+#if RECALCNORMALS==0
+ mPoints[newverts[i*3 + j]].n +=
+ mPoints[ mIndices[i*3 + ( j )] ].n * 0.25f + // j = 0,1,2?
+ mPoints[ mIndices[i*3 + ((j+1)%3)] ].n * 0.375f +
+ mPoints[ mIndices[i*3 + ((j+2)%3)] ].n * 0.375f;
+#endif // RECALCNORMALS==0
+ } else {
+ mPoints[newverts[i*3 + j]].v +=
+ mPoints[ mIndices[i*3 + ((j+1)%3)] ].v * 0.5f +
+ mPoints[ mIndices[i*3 + ((j+2)%3)] ].v * 0.5f ;
+#if RECALCNORMALS==0
+ mPoints[newverts[i*3 + j]].n +=
+ mPoints[ mIndices[i*3 + ((j+1)%3)] ].n * 0.5f +
+ mPoints[ mIndices[i*3 + ((j+2)%3)] ].n * 0.5f ;
+#endif // RECALCNORMALS==0
+ }
+
+ newvert_count[newverts[i*3 + j]]++;
+ }
+ }
+ for (i = old_nv; i < (int)mPoints.size(); i++) {
+ if (!newvert_count[i])
+ continue;
+ float scale = 1.0f / newvert_count[i];
+ mPoints[i].v *= scale;
+
+#if RECALCNORMALS==0
+ //mPoints[i].n *= scale;
+ //normalize( mPoints[i].n );
+#endif // RECALCNORMALS==0
+ }
+
+ // Update old vertices
+ for (i = 0; i < old_nv; i++) {
+ ntlVec3Gfx bdyavg(0.0), nbdyavg(0.0);
+ ntlVec3Gfx norm_bdyavg(0.0), norm_nbdyavg(0.0); // N
+ int nbdy = 0, nnbdy = 0;
+ int naf = (int)mAdjacentFaces[i].size();
+ if (!naf)
+ continue;
+ for (int j = 0; j < naf; j++) {
+ int af = mAdjacentFaces[i][j];
+
+ int afi = -1;
+ if( mIndices[af*3+0] == (unsigned int)i ) afi = 0;
+ else if( mIndices[af*3+1] == (unsigned int)i ) afi = 1;
+ else if( mIndices[af*3+2] == (unsigned int)i ) afi = 2;
+
+ int n1 = (afi+1) % 3;
+ int n2 = (afi+2) % 3;
+ if (mAcrossEdge[af*3 + n1] == -1) {
+ bdyavg += mPoints[newverts[af*3 + n1]].v;
+#if RECALCNORMALS==0
+ //norm_bdyavg += mPoints[newverts[af*3 + n1]].n;
+#endif // RECALCNORMALS==0
+ nbdy++;
+ } else {
+ nbdyavg += mPoints[newverts[af*3 + n1]].v;
+#if RECALCNORMALS==0
+ //norm_nbdyavg += mPoints[newverts[af*3 + n1]].n;
+#endif // RECALCNORMALS==0
+ nnbdy++;
+ }
+ if (mAcrossEdge[af*3 + n2] == -1) {
+ bdyavg += mPoints[newverts[af*3 + n2]].v;
+#if RECALCNORMALS==0
+ //norm_bdyavg += mPoints[newverts[af*3 + n2]].n;
+#endif // RECALCNORMALS==0
+ nbdy++;
+ } else {
+ nbdyavg += mPoints[newverts[af*3 + n2]].v;
+#if RECALCNORMALS==0
+ //norm_nbdyavg += mPoints[newverts[af*3 + n2]].n;
+#endif // RECALCNORMALS==0
+ nnbdy++;
+ }
+ }
+
+ float alpha;
+ ntlVec3Gfx newpt;
+ if (nbdy) {
+ newpt = bdyavg / (float) nbdy;
+ alpha = 0.5f;
+ } else if (nnbdy) {
+ newpt = nbdyavg / (float) nnbdy;
+ if (nnbdy == 6)
+ alpha = 1.05;
+ else if (nnbdy == 8)
+ alpha = 0.86;
+ else if (nnbdy == 10)
+ alpha = 0.7;
+ else
+ alpha = 0.6;
+ } else {
+ continue;
+ }
+ mPoints[i].v *= 1.0f - alpha;
+ mPoints[i].v += newpt * alpha;
+
+#if RECALCNORMALS==0
+ //mPoints[i].n *= 1.0f - alpha;
+ //mPoints[i].n += newpt * alpha;
+#endif // RECALCNORMALS==0
+ }
+
+ // Insert new faces
+ mIndices.reserve(4*nf);
+ for (i = 0; i < nf; i++) {
+ mIndices.push_back( mIndices[i*3 + 0]);
+ mIndices.push_back( newverts[i*3 + 2]);
+ mIndices.push_back( newverts[i*3 + 1]);
+
+ mIndices.push_back( mIndices[i*3 + 1]);
+ mIndices.push_back( newverts[i*3 + 0]);
+ mIndices.push_back( newverts[i*3 + 2]);
+
+ mIndices.push_back( mIndices[i*3 + 2]);
+ mIndices.push_back( newverts[i*3 + 1]);
+ mIndices.push_back( newverts[i*3 + 0]);
+
+ mIndices[i*3+0] = newverts[i*3+0];
+ mIndices[i*3+1] = newverts[i*3+1];
+ mIndices[i*3+2] = newverts[i*3+2];
+ }
+
+ // recalc normals
+#if RECALCNORMALS==1
+ {
+ int nf = (int)mIndices.size()/3, nv = (int)mPoints.size(), i;
+ for (i = 0; i < nv; i++) {
+ mPoints[i].n = ntlVec3Gfx(0.0);
+ }
+ for (i = 0; i < nf; i++) {
+ const ntlVec3Gfx &p0 = mPoints[mIndices[i*3+0]].v;
+ const ntlVec3Gfx &p1 = mPoints[mIndices[i*3+1]].v;
+ const ntlVec3Gfx &p2 = mPoints[mIndices[i*3+2]].v;
+ ntlVec3Gfx a = p0-p1, b = p1-p2, c = p2-p0;
+ float l2a = normNoSqrt(a), l2b = normNoSqrt(b), l2c = normNoSqrt(c);
+
+ ntlVec3Gfx facenormal = cross(a, b);
+
+ mPoints[mIndices[i*3+0]].n += facenormal * (1.0f / (l2a * l2c));
+ mPoints[mIndices[i*3+1]].n += facenormal * (1.0f / (l2b * l2a));
+ mPoints[mIndices[i*3+2]].n += facenormal * (1.0f / (l2c * l2b));
+ }
+
+ for (i = 0; i < nv; i++) {
+ normalize(mPoints[i].n);
+ }
+ }
+#else // RECALCNORMALS==1
+ for (i = 0; i < (int)mPoints.size(); i++) {
+ normalize(mPoints[i].n);
+ }
+#endif // RECALCNORMALS==1
+
+ //errMsg("SUBDIV","done nv:"<<mPoints.size()<<" nf:"<<mIndices.size() );
+}
+
+
+
+
+
+
+
+/******************************************************************************
+ *
+ * Surface improvement
+ * makes use of trimesh2 library
+ * http://www.cs.princeton.edu/gfx/proj/trimesh2/
+ *
+ * Copyright (c) 2004 Szymon Rusinkiewicz.
+ * see COPYING_trimesh2
+ *
+ *****************************************************************************/
+
+
+
+// Diffuse a vector field at 1 vertex, weighted by
+// a gaussian of width 1/sqrt(invsigma2)
+void IsoSurface::diffuseVertexField(ntlVec3Gfx *field, const int pointerScale, int v, float invsigma2, ntlVec3Gfx &flt)
+{
+ flt = ntlVec3Gfx(0.0);
+ flt += *(field+pointerScale*v) *pointareas[v];
+ float sum_w = pointareas[v];
+ const ntlVec3Gfx &nv = mPoints[v].n;
+
+ unsigned &flag = flag_curr;
+ flag++;
+ flags[v] = flag;
+ vector<int> boundary = neighbors[v];
+ while (!boundary.empty()) {
+ const int bbn = boundary.back();
+ boundary.pop_back();
+ if (flags[bbn] == flag) continue;
+ flags[bbn] = flag;
+
+ // gaussian weight of width 1/sqrt(invsigma2)
+ const float d2 = invsigma2 * normNoSqrt(mPoints[bbn].v - mPoints[v].v);
+ if(d2 >= 9.0f) continue; // 25 also possible , slower
+ //float w = (d2 >= 9.0f) ? 0.0f : exp(-0.5f*d2);
+ float w = exp(-0.5f*d2);
+ if(dot(nv, mPoints[bbn].n) <= 0.0f) continue; // faster than before d2 calc?
+
+ // Downweight things pointing in different directions
+ w *= dot(nv , mPoints[bbn].n);
+ // Surface area "belonging" to each point
+ w *= pointareas[bbn];
+ // Accumulate weight times field at neighbor
+ flt += *(field+pointerScale*bbn)*w;
+
+ sum_w += w;
+ for (int i = 0; i < (int)neighbors[bbn].size(); i++) {
+ int nn = neighbors[bbn][i];
+ if (flags[nn] == flag) continue;
+ boundary.push_back(nn);
+ }
+ }
+ flt /= sum_w;
+}
+
+
+
+void IsoSurface::smoothSurface(float sigma)
+{
+ int nv = mPoints.size();
+ if ((int)flags.size() != nv) flags.resize(nv);
+ int nf = mIndices.size()/3;
+
+ { // need neighbors
+
+ vector<int> numneighbors(mPoints.size());
+ int i;
+ for (i = 0; i < (int)mIndices.size()/3; i++) {
+ numneighbors[mIndices[i*3+0]]++;
+ numneighbors[mIndices[i*3+1]]++;
+ numneighbors[mIndices[i*3+2]]++;
+ }
+
+ neighbors.clear();
+ neighbors.resize(mPoints.size());
+ for (i = 0; i < (int)mPoints.size(); i++) {
+ neighbors[i].clear();
+ neighbors[i].reserve(numneighbors[i]+2); // Slop for boundaries
+ }
+
+ for (i = 0; i < (int)mIndices.size()/3; i++) {
+ for (int j = 0; j < 3; j++) {
+ vector<int> &me = neighbors[ mIndices[i*3+j]];
+ int n1 = mIndices[i*3+((j+1)%3)];
+ int n2 = mIndices[i*3+((j+2)%3)];
+ if (std::find(me.begin(), me.end(), n1) == me.end())
+ me.push_back(n1);
+ if (std::find(me.begin(), me.end(), n2) == me.end())
+ me.push_back(n2);
+ }
+ }
+ } // need neighbor
+
+ { // need pointarea
+ pointareas.clear();
+ pointareas.resize(nv);
+ cornerareas.clear();
+ cornerareas.resize(nf);
+
+ for (int i = 0; i < nf; i++) {
+ // Edges
+ ntlVec3Gfx e[3] = {
+ mPoints[mIndices[i*3+2]].v - mPoints[mIndices[i*3+1]].v,
+ mPoints[mIndices[i*3+0]].v - mPoints[mIndices[i*3+2]].v,
+ mPoints[mIndices[i*3+1]].v - mPoints[mIndices[i*3+0]].v };
+
+ // Compute corner weights
+ float area = 0.5f * norm( cross(e[0], e[1]));
+ float l2[3] = { normNoSqrt(e[0]), normNoSqrt(e[1]), normNoSqrt(e[2]) };
+ float ew[3] = { l2[0] * (l2[1] + l2[2] - l2[0]),
+ l2[1] * (l2[2] + l2[0] - l2[1]),
+ l2[2] * (l2[0] + l2[1] - l2[2]) };
+ if (ew[0] <= 0.0f) {
+ cornerareas[i][1] = -0.25f * l2[2] * area /
+ dot(e[0] , e[2]);
+ cornerareas[i][2] = -0.25f * l2[1] * area /
+ dot(e[0] , e[1]);
+ cornerareas[i][0] = area - cornerareas[i][1] -
+ cornerareas[i][2];
+ } else if (ew[1] <= 0.0f) {
+ cornerareas[i][2] = -0.25f * l2[0] * area /
+ dot(e[1] , e[0]);
+ cornerareas[i][0] = -0.25f * l2[2] * area /
+ dot(e[1] , e[2]);
+ cornerareas[i][1] = area - cornerareas[i][2] -
+ cornerareas[i][0];
+ } else if (ew[2] <= 0.0f) {
+ cornerareas[i][0] = -0.25f * l2[1] * area /
+ dot(e[2] , e[1]);
+ cornerareas[i][1] = -0.25f * l2[0] * area /
+ dot(e[2] , e[0]);
+ cornerareas[i][2] = area - cornerareas[i][0] -
+ cornerareas[i][1];
+ } else {
+ float ewscale = 0.5f * area / (ew[0] + ew[1] + ew[2]);
+ for (int j = 0; j < 3; j++)
+ cornerareas[i][j] = ewscale * (ew[(j+1)%3] +
+ ew[(j+2)%3]);
+ }
+
+ // NT important, check this...
+#ifndef WIN32
+ if(! finite(cornerareas[i][0]) ) cornerareas[i][0]=1e-6;
+ if(! finite(cornerareas[i][1]) ) cornerareas[i][1]=1e-6;
+ if(! finite(cornerareas[i][2]) ) cornerareas[i][2]=1e-6;
+#else // WIN32
+ // FIXME check as well...
+ if(! (cornerareas[i][0]>=0.0) ) cornerareas[i][0]=1e-6;
+ if(! (cornerareas[i][1]>=0.0) ) cornerareas[i][1]=1e-6;
+ if(! (cornerareas[i][2]>=0.0) ) cornerareas[i][2]=1e-6;
+#endif // WIN32
+
+ pointareas[mIndices[i*3+0]] += cornerareas[i][0];
+ pointareas[mIndices[i*3+1]] += cornerareas[i][1];
+ pointareas[mIndices[i*3+2]] += cornerareas[i][2];
+ }
+
+ } // need pointarea
+ // */
+
+ float invsigma2 = 1.0f / (sigma*sigma);
+
+ vector<ntlVec3Gfx> dflt(nv);
+ for (int i = 0; i < nv; i++) {
+ diffuseVertexField( &mPoints[0].v, 2,
+ i, invsigma2, dflt[i]);
+ // Just keep the displacement
+ dflt[i] -= mPoints[i].v;
+ }
+
+ // Slightly better small-neighborhood approximation
+ for (int i = 0; i < nf; i++) {
+ ntlVec3Gfx c = mPoints[mIndices[i*3+0]].v +
+ mPoints[mIndices[i*3+1]].v +
+ mPoints[mIndices[i*3+2]].v;
+ c /= 3.0f;
+ for (int j = 0; j < 3; j++) {
+ int v = mIndices[i*3+j];
+ ntlVec3Gfx d =(c - mPoints[v].v) * 0.5f;
+ dflt[v] += d * (cornerareas[i][j] /
+ pointareas[mIndices[i*3+j]] *
+ exp(-0.5f * invsigma2 * normNoSqrt(d)) );
+ }
+ }
+
+ // Filter displacement field
+ vector<ntlVec3Gfx> dflt2(nv);
+ for (int i = 0; i < nv; i++) {
+ diffuseVertexField( &dflt[0], 1,
+ i, invsigma2, dflt2[i]);
+ }
+
+ // Update vertex positions
+ for (int i = 0; i < nv; i++) {
+ mPoints[i].v += dflt[i] - dflt2[i]; // second Laplacian
+ }
+
+ // when normals smoothing off, this cleans up quite well
+ // costs ca. 50% additional time though
+ float nsFac = 1.5f;
+ { float ninvsigma2 = 1.0f / (nsFac*nsFac*sigma*sigma);
+ for (int i = 0; i < nv; i++) {
+ diffuseVertexField( &mPoints[0].n, 2, i, ninvsigma2, dflt[i]);
+ normalize(dflt[i]);
+ }
+ for (int i = 0; i < nv; i++) {
+ mPoints[i].n = dflt[i];
+ }
+ } // smoothNormals copy */
+
+ //errMsg("SMSURF","done v:"<<sigma); // DEBUG
+}
+
+void IsoSurface::smoothNormals(float sigma)
+{
+ { // need neighbor
+ vector<int> numneighbors(mPoints.size());
+ int i;
+ for (i = 0; i < (int)mIndices.size()/3; i++) {
+ numneighbors[mIndices[i*3+0]]++;
+ numneighbors[mIndices[i*3+1]]++;
+ numneighbors[mIndices[i*3+2]]++;
+ }
+
+ neighbors.clear();
+ neighbors.resize(mPoints.size());
+ for (i = 0; i < (int)mPoints.size(); i++) {
+ neighbors[i].clear();
+ neighbors[i].reserve(numneighbors[i]+2); // Slop for boundaries
+ }
+
+ for (i = 0; i < (int)mIndices.size()/3; i++) {
+ for (int j = 0; j < 3; j++) {
+ vector<int> &me = neighbors[ mIndices[i*3+j]];
+ int n1 = mIndices[i*3+((j+1)%3)];
+ int n2 = mIndices[i*3+((j+2)%3)];
+ if (std::find(me.begin(), me.end(), n1) == me.end())
+ me.push_back(n1);
+ if (std::find(me.begin(), me.end(), n2) == me.end())
+ me.push_back(n2);
+ }
+ }
+ } // need neighbor
+
+ { // need pointarea
+ int nf = mIndices.size()/3, nv = mPoints.size();
+ pointareas.clear();
+ pointareas.resize(nv);
+ cornerareas.clear();
+ cornerareas.resize(nf);
+
+ for (int i = 0; i < nf; i++) {
+ // Edges
+ ntlVec3Gfx e[3] = {
+ mPoints[mIndices[i*3+2]].v - mPoints[mIndices[i*3+1]].v,
+ mPoints[mIndices[i*3+0]].v - mPoints[mIndices[i*3+2]].v,
+ mPoints[mIndices[i*3+1]].v - mPoints[mIndices[i*3+0]].v };
+
+ // Compute corner weights
+ float area = 0.5f * norm( cross(e[0], e[1]));
+ float l2[3] = { normNoSqrt(e[0]), normNoSqrt(e[1]), normNoSqrt(e[2]) };
+ float ew[3] = { l2[0] * (l2[1] + l2[2] - l2[0]),
+ l2[1] * (l2[2] + l2[0] - l2[1]),
+ l2[2] * (l2[0] + l2[1] - l2[2]) };
+ if (ew[0] <= 0.0f) {
+ cornerareas[i][1] = -0.25f * l2[2] * area /
+ dot(e[0] , e[2]);
+ cornerareas[i][2] = -0.25f * l2[1] * area /
+ dot(e[0] , e[1]);
+ cornerareas[i][0] = area - cornerareas[i][1] -
+ cornerareas[i][2];
+ } else if (ew[1] <= 0.0f) {
+ cornerareas[i][2] = -0.25f * l2[0] * area /
+ dot(e[1] , e[0]);
+ cornerareas[i][0] = -0.25f * l2[2] * area /
+ dot(e[1] , e[2]);
+ cornerareas[i][1] = area - cornerareas[i][2] -
+ cornerareas[i][0];
+ } else if (ew[2] <= 0.0f) {
+ cornerareas[i][0] = -0.25f * l2[1] * area /
+ dot(e[2] , e[1]);
+ cornerareas[i][1] = -0.25f * l2[0] * area /
+ dot(e[2] , e[0]);
+ cornerareas[i][2] = area - cornerareas[i][0] -
+ cornerareas[i][1];
+ } else {
+ float ewscale = 0.5f * area / (ew[0] + ew[1] + ew[2]);
+ for (int j = 0; j < 3; j++)
+ cornerareas[i][j] = ewscale * (ew[(j+1)%3] +
+ ew[(j+2)%3]);
+ }
+
+ // NT important, check this...
+#ifndef WIN32
+ if(! finite(cornerareas[i][0]) ) cornerareas[i][0]=1e-6;
+ if(! finite(cornerareas[i][1]) ) cornerareas[i][1]=1e-6;
+ if(! finite(cornerareas[i][2]) ) cornerareas[i][2]=1e-6;
+#else // WIN32
+ // FIXME check as well...
+ if(! (cornerareas[i][0]>=0.0) ) cornerareas[i][0]=1e-6;
+ if(! (cornerareas[i][1]>=0.0) ) cornerareas[i][1]=1e-6;
+ if(! (cornerareas[i][2]>=0.0) ) cornerareas[i][2]=1e-6;
+#endif // WIN32
+
+ pointareas[mIndices[i*3+0]] += cornerareas[i][0];
+ pointareas[mIndices[i*3+1]] += cornerareas[i][1];
+ pointareas[mIndices[i*3+2]] += cornerareas[i][2];
+ }
+
+ } // need pointarea
+
+ int nv = mPoints.size();
+ if ((int)flags.size() != nv) flags.resize(nv);
+ float invsigma2 = 1.0f / (sigma*sigma);
+
+ vector<ntlVec3Gfx> nflt(nv);
+ for (int i = 0; i < nv; i++) {
+ diffuseVertexField( &mPoints[0].n, 2, i, invsigma2, nflt[i]);
+ normalize(nflt[i]);
+ }
+
+ for (int i = 0; i < nv; i++) {
+ mPoints[i].n = nflt[i];
+ }
+
+ //errMsg("SMNRMLS","done v:"<<sigma); // DEBUG
+}
+
+
diff --git a/intern/elbeem/intern/isosurface.h b/intern/elbeem/intern/isosurface.h
new file mode 100644
index 00000000000..a574cccdba6
--- /dev/null
+++ b/intern/elbeem/intern/isosurface.h
@@ -0,0 +1,277 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Marching Cubes "displayer"
+ *
+ *****************************************************************************/
+
+#ifndef ISOSURFACE_H
+
+#include "ntl_geometryobject.h"
+#include "ntl_bsptree.h"
+//class LbmSolver3D;
+
+
+
+/* access some 3d array */
+//#define ISOLEVEL_INDEX(ii,ij,ik) ((S::mSizex*S::mSizey*(ik))+(S::mSizex*(ij))+((ii)))
+#define ISOLEVEL_INDEX(ii,ij,ik) ((mSizex*mSizey*(ik))+(mSizex*(ij))+((ii)))
+
+/* struct for a small cube in the scalar field */
+typedef struct {
+ ntlVec3Gfx pos[8];
+ double value[8];
+ int i,j,k;
+} IsoLevelCube;
+
+
+typedef struct {
+ ntlVec3Gfx v; // vertex
+ ntlVec3Gfx n; // vertex normal
+} IsoLevelVertex;
+
+//! class to triangulate a scalar field, e.g. for
+// the fluid surface, templated by scalar field access object
+//template<class S>
+class IsoSurface :
+ public ntlGeometryObject //, public S
+{
+
+ public:
+
+ /*! Constructor */
+ IsoSurface(double iso, double blend);
+ /*! Destructor */
+ ~IsoSurface();
+
+ /*! Init ararys etc. */
+ virtual void initializeIsosurface(int setx, int sety, int setz, ntlVec3Gfx extent);
+
+ /*! triangulate the scalar field given by pointer*/
+ void triangulate( void );
+
+ protected:
+
+ /* variables ... */
+
+ //! size
+ int mSizex, mSizey, mSizez;
+
+ //! data pointer
+ float *mpData;
+
+ //! Level of the iso surface
+ double mIsoValue;
+
+ //! blending distance for marching cubes
+ double mBlendVal;
+
+ //! Store all the triangles vertices
+ vector<IsoLevelVertex> mPoints;
+
+ //! Store indices of calculated points along the cubie edges
+ int *mpEdgeVerticesX;
+ int *mpEdgeVerticesY;
+ int *mpEdgeVerticesZ;
+
+
+ //! vector for all the triangles (stored as 3 indices)
+ vector<unsigned int> mIndices;
+
+ //! start and end vectors for the triangulation region to create triangles in
+ ntlVec3Gfx mStart, mEnd;
+
+ //! normalized domain extent from parametrizer/visualizer
+ ntlVec3Gfx mDomainExtent;
+
+ //! initialized?
+ bool mInitDone;
+
+ //! no. of refinement steps
+ int mLoopSubdivs;
+ //! amount of surface smoothing
+ float mSmoothSurface;
+ //! amount of normal smoothing
+ float mSmoothNormals;
+
+ //! grid data
+ vector<int> mAcrossEdge;
+ vector< vector<int> > mAdjacentFaces;
+
+ vector<unsigned> flags;
+ unsigned flag_curr;
+ vector<ntlVec3Gfx> cornerareas;
+ vector<float> pointareas;
+ vector< vector<int> > neighbors;
+
+ public:
+ // miscelleanous access functions
+
+ //! set geometry start (for renderer)
+ void setStart(ntlVec3Gfx set) { mStart = set; };
+ //! set geometry end (for renderer)
+ void setEnd(ntlVec3Gfx set) { mEnd = set; };
+ //! set iso level value for surface reconstruction
+ inline void setIsolevel(double set) { mIsoValue = set; };
+ //! set loop subdiv num
+ inline void setLoopSubdivs(int set) { mLoopSubdivs = set; };
+ inline void setSmoothSurface(float set) { mSmoothSurface = set; };
+ inline void setSmoothNormals(float set) { mSmoothNormals = set; };
+
+ // geometry object functions
+ virtual void getTriangles( vector<ntlTriangle> *triangles,
+ vector<ntlVec3Gfx> *vertices,
+ vector<ntlVec3Gfx> *normals, int objectId );
+
+ //! for easy GUI detection get start of axis aligned bounding box, return NULL of no BB
+ virtual inline ntlVec3Gfx *getBBStart() { return &mStart; }
+ virtual inline ntlVec3Gfx *getBBEnd() { return &mEnd; }
+
+ //! access data array
+ inline float* getData(){ return mpData; }
+ inline float* getData(int i, int j, int k){ return mpData + ISOLEVEL_INDEX(i,j,k); }
+ inline float* lbmGetData(int i, int j, int k){ return mpData + ISOLEVEL_INDEX(i+1,j+1,k+1); }
+
+ //! OpenGL viz "interface"
+ unsigned int getIsoVertexCount() {
+ return mPoints.size();
+ }
+ unsigned int getIsoIndexCount() {
+ return mIndices.size();
+ }
+ char* getIsoVertexArray() {
+ return (char *) &(mPoints[0]);
+ }
+ unsigned int *getIsoIndexArray() {
+ return &(mIndices[0]);
+ }
+
+ protected:
+
+ //! computer normal
+ inline ntlVec3Gfx getNormal(int i, int j,int k);
+
+ void subdivide();
+ void smoothSurface(float val);
+ void smoothNormals(float val);
+ void diffuseVertexField(ntlVec3Gfx *field, const int pointerScale, int v, float invsigma2, ntlVec3Gfx &flt);
+};
+
+
+
+class TriMesh {
+public:
+ // Types
+ struct Face {
+ int v[3];
+
+ Face() {}
+ Face(const int &v0, const int &v1, const int &v2)
+ { v[0] = v0; v[1] = v1; v[2] = v2; }
+ Face(const int *v_)
+ { v[0] = v_[0]; v[1] = v_[1]; v[2] = v_[2]; }
+ int &operator[] (int i) { return v[i]; }
+ const int &operator[] (int i) const { return v[i]; }
+ operator const int * () const { return &(v[0]); }
+ operator const int * () { return &(v[0]); }
+ operator int * () { return &(v[0]); }
+ int indexof(int v_) const
+ {
+ return (v[0] == v_) ? 0 :
+ (v[1] == v_) ? 1 :
+ (v[2] == v_) ? 2 : -1;
+ }
+ };
+
+ struct BBox {
+ ntlVec3Gfx min, max;
+ ntlVec3Gfx center() const { return (min+max)*0.5f; }
+ ntlVec3Gfx size() const { return max - min; }
+ };
+
+ struct BSphere {
+ ntlVec3Gfx center;
+ float r;
+ };
+
+ // Enums
+ enum tstrip_rep { TSTRIP_LENGTH, TSTRIP_TERM };
+
+ // The basics: vertices and faces
+ vector<ntlVec3Gfx> vertices;
+ vector<Face> faces;
+
+ // Triangle strips
+ vector<int> tstrips;
+
+ // Other per-vertex properties
+ //vector<Color> colors;
+ vector<float> confidences;
+ vector<unsigned> flags;
+ unsigned flag_curr;
+
+ // Computed per-vertex properties
+ vector<ntlVec3Gfx> normals;
+ vector<ntlVec3Gfx> pdir1, pdir2;
+ vector<float> curv1, curv2;
+ //vector< Vec<4,float> > dcurv;
+ vector<ntlVec3Gfx> cornerareas;
+ vector<float> pointareas;
+
+ // Bounding structures
+ BBox bbox;
+ BSphere bsphere;
+
+ // Connectivity structures:
+ // For each vertex, all neighboring vertices
+ vector< vector<int> > neighbors;
+ // For each vertex, all neighboring faces
+ vector< vector<int> > adjacentfaces;
+ // For each face, the three faces attached to its edges
+ // (for example, across_edge[3][2] is the number of the face
+ // that's touching the edge opposite vertex 2 of face 3)
+ vector<Face> across_edge;
+
+ // Compute all this stuff...
+ void need_tstrips();
+ void convert_strips(tstrip_rep rep);
+ void need_faces();
+ void need_normals();
+ void need_pointareas();
+ void need_curvatures();
+ void need_dcurv();
+ void need_bbox();
+ void need_bsphere();
+ void need_neighbors();
+ void need_adjacentfaces();
+ void need_across_edge();
+
+ // Input and output
+ static TriMesh *read(const char *filename);
+ void write(const char *filename);
+
+ // Statistics
+ // XXX - Add stuff here
+ float feature_size();
+
+ // Useful queries
+ // XXX - Add stuff here
+ bool is_bdy(int v)
+ {
+ if (neighbors.empty()) need_neighbors();
+ if (adjacentfaces.empty()) need_adjacentfaces();
+ return neighbors[v].size() != adjacentfaces[v].size();
+ }
+
+ // Debugging printout, controllable by a "verbose"ness parameter
+ static int verbose;
+ static void set_verbose(int);
+ static int dprintf(const char *format, ...);
+};
+
+#define ISOSURFACE_H
+#endif
+
+
diff --git a/intern/elbeem/intern/lbmdimensions.h b/intern/elbeem/intern/lbmdimensions.h
new file mode 100644
index 00000000000..5b084cbd3e8
--- /dev/null
+++ b/intern/elbeem/intern/lbmdimensions.h
@@ -0,0 +1,391 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * All code distributed as part of El'Beem is covered by the version 2 of the
+ * GNU General Public License. See the file COPYING for details.
+ * Copyright 2003-2005 Nils Thuerey
+ *
+ * Combined 2D/3D Lattice Boltzmann Solver auxiliary classes
+ *
+ *****************************************************************************/
+#ifndef LBMHEADER_H
+
+/* LBM Files */
+#include "lbminterface.h"
+#include <sstream>
+
+
+//! shorten static const definitions
+#define STCON static const
+
+
+/*****************************************************************************/
+/*! class for solver templating - 3D implementation */
+//class LbmD3Q19 : public LbmSolverInterface {
+class LbmD3Q19 {
+
+ public:
+
+ // constructor, init interface
+ LbmD3Q19() {};
+ // virtual destructor
+ virtual ~LbmD3Q19() {};
+ //! id string of solver
+ string getIdString() { return string("3D"); }
+
+ //! how many dimensions?
+ STCON int cDimension;
+
+ // Wi factors for collide step
+ STCON LbmFloat cCollenZero;
+ STCON LbmFloat cCollenOne;
+ STCON LbmFloat cCollenSqrtTwo;
+
+ //! threshold value for filled/emptied cells
+ STCON LbmFloat cMagicNr2;
+ STCON LbmFloat cMagicNr2Neg;
+ STCON LbmFloat cMagicNr;
+ STCON LbmFloat cMagicNrNeg;
+
+ //! size of a single set of distribution functions
+ STCON int cDfNum;
+ //! direction vector contain vecs for all spatial dirs, even if not used for LBM model
+ STCON int cDirNum;
+
+ //! distribution functions directions
+ typedef enum {
+ cDirInv= -1,
+ cDirC = 0,
+ cDirN = 1,
+ cDirS = 2,
+ cDirE = 3,
+ cDirW = 4,
+ cDirT = 5,
+ cDirB = 6,
+ cDirNE = 7,
+ cDirNW = 8,
+ cDirSE = 9,
+ cDirSW = 10,
+ cDirNT = 11,
+ cDirNB = 12,
+ cDirST = 13,
+ cDirSB = 14,
+ cDirET = 15,
+ cDirEB = 16,
+ cDirWT = 17,
+ cDirWB = 18
+ } dfDir;
+
+ /* Vector Order 3D:
+ * 0 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
+ * 0, 0, 0, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1,-1, 1,-1, 1,-1, 1,-1
+ * 0, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1
+ * 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 1,-1, 1,-1, 1,-1, 1,-1, 1, 1, 1, 1, -1,-1,-1,-1
+ */
+
+ /*! name of the dist. function
+ only for nicer output */
+ STCON char* dfString[ 19 ];
+
+ /*! index of normal dist func, not used so far?... */
+ STCON dfDir dfNorm[ 19 ];
+
+ /*! index of inverse dist func, not fast, but useful... */
+ STCON dfDir dfInv[ 19 ];
+
+ /*! index of x reflected dist func for free slip, not valid for all DFs... */
+ STCON int dfRefX[ 19 ];
+ /*! index of x reflected dist func for free slip, not valid for all DFs... */
+ STCON int dfRefY[ 19 ];
+ /*! index of x reflected dist func for free slip, not valid for all DFs... */
+ STCON int dfRefZ[ 19 ];
+
+ /*! dist func vectors */
+ STCON int dfVecX[ 27 ];
+ STCON int dfVecY[ 27 ];
+ STCON int dfVecZ[ 27 ];
+
+ /*! arrays as before with doubles */
+ STCON LbmFloat dfDvecX[ 27 ];
+ STCON LbmFloat dfDvecY[ 27 ];
+ STCON LbmFloat dfDvecZ[ 27 ];
+
+ /*! principal directions */
+ STCON int princDirX[ 2*3 ];
+ STCON int princDirY[ 2*3 ];
+ STCON int princDirZ[ 2*3 ];
+
+ /*! vector lengths */
+ STCON LbmFloat dfLength[ 19 ];
+
+ /*! equilibrium distribution functions, precalculated = getCollideEq(i, 0,0,0,0) */
+ static LbmFloat dfEquil[ 19 ];
+
+ /*! arrays for les model coefficients */
+ static LbmFloat lesCoeffDiag[ (3-1)*(3-1) ][ 27 ];
+ static LbmFloat lesCoeffOffdiag[ 3 ][ 27 ];
+
+}; // LbmData3D
+
+
+
+/*****************************************************************************/
+//! class for solver templating - 2D implementation
+//class LbmD2Q9 : public LbmSolverInterface {
+class LbmD2Q9 {
+
+ public:
+
+ // constructor, init interface
+ LbmD2Q9() {};
+ // virtual destructor
+ virtual ~LbmD2Q9() {};
+ //! id string of solver
+ string getIdString() { return string("2D"); }
+
+ //! how many dimensions?
+ STCON int cDimension;
+
+ //! Wi factors for collide step
+ STCON LbmFloat cCollenZero;
+ STCON LbmFloat cCollenOne;
+ STCON LbmFloat cCollenSqrtTwo;
+
+ //! threshold value for filled/emptied cells
+ STCON LbmFloat cMagicNr2;
+ STCON LbmFloat cMagicNr2Neg;
+ STCON LbmFloat cMagicNr;
+ STCON LbmFloat cMagicNrNeg;
+
+ //! size of a single set of distribution functions
+ STCON int cDfNum;
+ STCON int cDirNum;
+
+ //! distribution functions directions
+ typedef enum {
+ cDirInv= -1,
+ cDirC = 0,
+ cDirN = 1,
+ cDirS = 2,
+ cDirE = 3,
+ cDirW = 4,
+ cDirNE = 5,
+ cDirNW = 6,
+ cDirSE = 7,
+ cDirSW = 8
+ } dfDir;
+
+ /* Vector Order 2D:
+ * 0 1 2 3 4 5 6 7 8
+ * 0, 0,0, 1,-1, 1,-1,1,-1
+ * 0, 1,-1, 0,0, 1,1,-1,-1 */
+
+ /* name of the dist. function
+ only for nicer output */
+ STCON char* dfString[ 9 ];
+
+ /* index of normal dist func, not used so far?... */
+ STCON dfDir dfNorm[ 9 ];
+
+ /* index of inverse dist func, not fast, but useful... */
+ STCON dfDir dfInv[ 9 ];
+
+ /* index of x reflected dist func for free slip, not valid for all DFs... */
+ STCON int dfRefX[ 9 ];
+ /* index of x reflected dist func for free slip, not valid for all DFs... */
+ STCON int dfRefY[ 9 ];
+ /* index of x reflected dist func for free slip, not valid for all DFs... */
+ STCON int dfRefZ[ 9 ];
+
+ /* dist func vectors */
+ STCON int dfVecX[ 9 ];
+ STCON int dfVecY[ 9 ];
+ /* Z, 2D values are all 0! */
+ STCON int dfVecZ[ 9 ];
+
+ /* arrays as before with doubles */
+ STCON LbmFloat dfDvecX[ 9 ];
+ STCON LbmFloat dfDvecY[ 9 ];
+ /* Z, 2D values are all 0! */
+ STCON LbmFloat dfDvecZ[ 9 ];
+
+ /*! principal directions */
+ STCON int princDirX[ 2*2 ];
+ STCON int princDirY[ 2*2 ];
+ STCON int princDirZ[ 2*2 ];
+
+ /* vector lengths */
+ STCON LbmFloat dfLength[ 9 ];
+
+ /* equilibrium distribution functions, precalculated = getCollideEq(i, 0,0,0,0) */
+ static LbmFloat dfEquil[ 9 ];
+
+ /*! arrays for les model coefficients */
+ static LbmFloat lesCoeffDiag[ (2-1)*(2-1) ][ 9 ];
+ static LbmFloat lesCoeffOffdiag[ 2 ][ 9 ];
+
+}; // LbmData3D
+
+
+
+// not needed hereafter
+#undef STCON
+
+
+
+/*****************************************************************************/
+//! class for solver templating - lbgk (srt) model implementation
+template<class DQ>
+class LbmModelLBGK : public DQ , public LbmSolverInterface {
+ public:
+
+ /*! type for cells contents, needed for cell id interface */
+ typedef DQ LbmCellContents;
+ /*! type for cells */
+ typedef LbmCellTemplate< LbmCellContents > LbmCell;
+
+ // constructor
+ LbmModelLBGK() : DQ(), LbmSolverInterface() {};
+ // virtual destructor
+ virtual ~LbmModelLBGK() {};
+ //! id string of solver
+ std::string getIdString() { return DQ::getIdString() + std::string("lbgk]"); }
+
+ /*! calculate length of velocity vector */
+ static inline LbmFloat getVelVecLen(int l, LbmFloat ux,LbmFloat uy,LbmFloat uz) {
+ return ((ux)*DQ::dfDvecX[l]+(uy)*DQ::dfDvecY[l]+(uz)*DQ::dfDvecZ[l]);
+ };
+
+ /*! calculate equilibrium DF for given values */
+ static inline LbmFloat getCollideEq(int l, LbmFloat rho, LbmFloat ux, LbmFloat uy, LbmFloat uz) {
+ LbmFloat tmp = getVelVecLen(l,ux,uy,uz);
+ return( DQ::dfLength[l] *(
+ + rho - (3.0/2.0*(ux*ux + uy*uy + uz*uz))
+ + 3.0 *tmp
+ + 9.0/2.0 *(tmp*tmp) )
+ );
+ };
+
+
+ // input mux etc. as acceleration
+ // outputs rho,ux,uy,uz
+ /*inline void collideArrays_org(LbmFloat df[19],
+ LbmFloat &outrho, // out only!
+ // velocity modifiers (returns actual velocity!)
+ LbmFloat &mux, LbmFloat &muy, LbmFloat &muz,
+ LbmFloat omega
+ ) {
+ LbmFloat rho=df[0];
+ LbmFloat ux = mux;
+ LbmFloat uy = muy;
+ LbmFloat uz = muz;
+ for(int l=1; l<DQ::cDfNum; l++) {
+ rho += df[l];
+ ux += (DQ::dfDvecX[l]*df[l]);
+ uy += (DQ::dfDvecY[l]*df[l]);
+ uz += (DQ::dfDvecZ[l]*df[l]);
+ }
+ for(int l=0; l<DQ::cDfNum; l++) {
+ //LbmFloat tmp = (ux*DQ::dfDvecX[l]+uy*DQ::dfDvecY[l]+uz*DQ::dfDvecZ[l]);
+ df[l] = (1.0-omega ) * df[l] + omega * ( getCollideEq(l,rho,ux,uy,uz) );
+ }
+
+ mux = ux;
+ muy = uy;
+ muz = uz;
+ outrho = rho;
+ };*/
+
+ // LES functions
+ inline LbmFloat getLesNoneqTensorCoeff(
+ LbmFloat df[],
+ LbmFloat feq[] ) {
+ LbmFloat Qo = 0.0;
+ for(int m=0; m< ((DQ::cDimension*DQ::cDimension)-DQ::cDimension)/2 ; m++) {
+ LbmFloat qadd = 0.0;
+ for(int l=1; l<DQ::cDfNum; l++) {
+ if(DQ::lesCoeffOffdiag[m][l]==0.0) continue;
+ qadd += DQ::lesCoeffOffdiag[m][l]*(df[l]-feq[l]);
+ }
+ Qo += (qadd*qadd);
+ }
+ Qo *= 2.0; // off diag twice
+ for(int m=0; m<DQ::cDimension; m++) {
+ LbmFloat qadd = 0.0;
+ for(int l=1; l<DQ::cDfNum; l++) {
+ if(DQ::lesCoeffDiag[m][l]==0.0) continue;
+ qadd += DQ::lesCoeffDiag[m][l]*(df[l]-feq[l]);
+ }
+ Qo += (qadd*qadd);
+ }
+ Qo = sqrt(Qo);
+ return Qo;
+ }
+ inline LbmFloat getLesOmega(LbmFloat omega, LbmFloat csmago, LbmFloat Qo) {
+ const LbmFloat tau = 1.0/omega;
+ const LbmFloat nu = (2.0*tau-1.0) * (1.0/6.0);
+ const LbmFloat C = csmago;
+ const LbmFloat Csqr = C*C;
+ LbmFloat S = -nu + sqrt( nu*nu + 18.0*Csqr*Qo ) / (6.0*Csqr);
+ return( 1.0/( 3.0*( nu+Csqr*S ) +0.5 ) );
+ }
+
+ // "normal" collision
+ inline void collideArrays(LbmFloat df[],
+ LbmFloat &outrho, // out only!
+ // velocity modifiers (returns actual velocity!)
+ LbmFloat &mux, LbmFloat &muy, LbmFloat &muz,
+ LbmFloat omega, LbmFloat csmago, LbmFloat *newOmegaRet = NULL
+ ) {
+ LbmFloat rho=df[0];
+ LbmFloat ux = mux;
+ LbmFloat uy = muy;
+ LbmFloat uz = muz;
+ for(int l=1; l<DQ::cDfNum; l++) {
+ rho += df[l];
+ ux += (DQ::dfDvecX[l]*df[l]);
+ uy += (DQ::dfDvecY[l]*df[l]);
+ uz += (DQ::dfDvecZ[l]*df[l]);
+ }
+ LbmFloat feq[19];
+ for(int l=0; l<DQ::cDfNum; l++) {
+ feq[l] = getCollideEq(l,rho,ux,uy,uz);
+ }
+
+ LbmFloat omegaNew;
+ if(csmago>0.0) {
+ LbmFloat Qo = getLesNoneqTensorCoeff(df,feq);
+ omegaNew = getLesOmega(omega,csmago,Qo);
+ } else {
+ omegaNew = omega; // smago off...
+ }
+ if(newOmegaRet) *newOmegaRet=omegaNew; // return value for stats
+
+ for(int l=0; l<DQ::cDfNum; l++) {
+ df[l] = (1.0-omegaNew ) * df[l] + omegaNew * feq[l];
+ }
+
+ mux = ux;
+ muy = uy;
+ muz = uz;
+ outrho = rho;
+ };
+
+}; // LBGK
+
+#ifdef LBMMODEL_DEFINED
+// force compiler error!
+ERROR - Dont include several LBM models at once...
+#endif
+#define LBMMODEL_DEFINED 1
+
+
+typedef LbmModelLBGK< LbmD2Q9 > LbmBGK2D;
+typedef LbmModelLBGK< LbmD3Q19 > LbmBGK3D;
+
+
+#define LBMHEADER_H
+#endif
+
+
+
diff --git a/intern/elbeem/intern/lbmfsgrsolver.h b/intern/elbeem/intern/lbmfsgrsolver.h
new file mode 100644
index 00000000000..703d4d61989
--- /dev/null
+++ b/intern/elbeem/intern/lbmfsgrsolver.h
@@ -0,0 +1,6519 @@
+/******************************************************************************
+ *
+ * El'Beem - the visual lattice boltzmann freesurface simulator
+ * All code distributed as part of El'Beem is covered by the version 2 of the
+ * GNU General Public License. See the file COPYING for details.
+ * Copyright 2003-2005 Nils Thuerey
+ *
+ * Combined 2D/3D Lattice Boltzmann standard solver classes
+ *
+ *****************************************************************************/
+
+
+#ifndef LBMFSGRSOLVER_H
+#include "utilities.h"
+#include "arrays.h"
+#include "lbmdimensions.h"
+#include "lbmfunctions.h"
+#include "ntl_scene.h"
+#include <stdio.h>
+
+#if PARALLEL==1
+#include <omp.h>
+#endif // PARALLEL=1
+#ifndef PARALLEL
+#define PARALLEL 0
+#endif // PARALLEL
+
+#if ELBEEM_BLENDER==1
+#include "SDL.h"
+#include "SDL_thread.h"
+#include "SDL_mutex.h"
+extern "C" {
+ void simulateThreadIncreaseFrame(void);
+ extern SDL_mutex *globalBakeLock;
+ extern int globalBakeState;
+ extern int globalBakeFrame;
+}
+#endif // ELBEEM_BLENDER==1
+
+#ifndef LBMMODEL_DEFINED
+// force compiler error!
+ERROR - define model first!
+#endif // LBMMODEL_DEFINED
+
+
+//! debug coordinate accesses and the like? (much slower)
+#define FSGR_STRICT_DEBUG 0
+
+//! debug coordinate accesses and the like? (much slower)
+#define FSGR_OMEGA_DEBUG 0
+
+//! OPT3D quick LES on/off, only debug/benachmarking
+#define USE_LES 1
+
+//! order of interpolation (1/2)
+#define INTORDER 1
+
+//! order of interpolation (0=always current/1=interpolate/2=always other)
+#define TIMEINTORDER 0
+
+//! refinement border method (1 = small border / 2 = larger)
+#define REFINEMENTBORDER 1
+
+// interpolateCellFromCoarse test
+#define INTCFCOARSETEST 1
+
+// use optimized 3D code?
+#if LBMDIM==2
+#define OPT3D false
+#else
+// determine with debugging...
+# if FSGR_STRICT_DEBUG==1
+# define OPT3D false
+# else // FSGR_STRICT_DEBUG==1
+// usually switch optimizations for 3d on, when not debugging
+# define OPT3D true
+// COMPRT
+//# define OPT3D false
+# endif // FSGR_STRICT_DEBUG==1
+#endif
+
+// enable/disable fine grid compression for finest level
+#if LBMDIM==3
+#define COMPRESSGRIDS 1
+#else
+#define COMPRESSGRIDS 0
+#endif
+
+// cell mark debugging
+#if FSGR_STRICT_DEBUG==10
+#define debugMarkCell(lev,x,y,z) \
+ errMsg("debugMarkCell",D::mName<<" step: "<<D::mStepCnt<<" lev:"<<(lev)<<" marking "<<PRINT_VEC((x),(y),(z))<<" line "<< __LINE__ ); \
+ debugMarkCellCall((lev),(x),(y),(z));
+#else // FSGR_STRICT_DEBUG==1
+#define debugMarkCell(lev,x,y,z) \
+ debugMarkCellCall((lev),(x),(y),(z));
+#endif // FSGR_STRICT_DEBUG==1
+
+
+//! threshold for level set fluid generation/isosurface
+#define LS_FLUIDTHRESHOLD 0.5
+
+//! invalid mass value for unused mass data
+#define MASS_INVALID -1000.0
+
+// empty/fill cells without fluid/empty NB's by inserting them into the full/empty lists?
+#define FSGR_LISTTRICK true
+#define FSGR_LISTTTHRESHEMPTY 0.10
+#define FSGR_LISTTTHRESHFULL 0.90
+#define FSGR_MAGICNR 0.025
+//0.04
+
+// flag array defines -----------------------------------------------------------------------------------------------
+
+// lbm testsolver get index define
+#define _LBMGI(level, ii,ij,ik, is) ( (mLevel[level].lOffsy*(ik)) + (mLevel[level].lOffsx*(ij)) + (ii) )
+
+//! flag array acces macro
+#define _RFLAG(level,xx,yy,zz,set) mLevel[level].mprsFlags[set][ LBMGI((level),(xx),(yy),(zz),(set)) ]
+#define _RFLAG_NB(level,xx,yy,zz,set, dir) mLevel[level].mprsFlags[set][ LBMGI((level),(xx)+D::dfVecX[dir],(yy)+D::dfVecY[dir],(zz)+D::dfVecZ[dir],set) ]
+#define _RFLAG_NBINV(level,xx,yy,zz,set, dir) mLevel[level].mprsFlags[set][ LBMGI((level),(xx)+D::dfVecX[D::dfInv[dir]],(yy)+D::dfVecY[D::dfInv[dir]],(zz)+D::dfVecZ[D::dfInv[dir]],set) ]
+
+// array data layouts
+// standard array layout -----------------------------------------------------------------------------------------------
+#define ALSTRING "Standard Array Layout"
+//#define _LBMQI(level, ii,ij,ik, is, lunused) ( ((is)*mLevel[level].lOffsz) + (mLevel[level].lOffsy*(ik)) + (mLevel[level].lOffsx*(ij)) + (ii) )
+#define _LBMQI(level, ii,ij,ik, is, lunused) ( (mLevel[level].lOffsy*(ik)) + (mLevel[level].lOffsx*(ij)) + (ii) )
+#define _QCELL(level,xx,yy,zz,set,l) (mLevel[level].mprsCells[(set)][ LBMQI((level),(xx),(yy),(zz),(set), l)*dTotalNum +(l)])
+#define _QCELL_NB(level,xx,yy,zz,set, dir,l) (mLevel[level].mprsCells[(set)][ LBMQI((level),(xx)+D::dfVecX[dir],(yy)+D::dfVecY[dir],(zz)+D::dfVecZ[dir],set, l)*dTotalNum +(l)])
+#define _QCELL_NBINV(level,xx,yy,zz,set, dir,l) (mLevel[level].mprsCells[(set)][ LBMQI((level),(xx)+D::dfVecX[D::dfInv[dir]],(yy)+D::dfVecY[D::dfInv[dir]],(zz)+D::dfVecZ[D::dfInv[dir]],set, l)*dTotalNum +(l)])
+
+#define QCELLSTEP dTotalNum
+#define _RACPNT(level, ii,ij,ik, is ) &QCELL(level,ii,ij,ik,is,0)
+#define _RAC(s,l) (s)[(l)]
+
+// standard arrays
+#define CSRC_C RAC(ccel , dC )
+#define CSRC_E RAC(ccel + (-1) *(dTotalNum), dE )
+#define CSRC_W RAC(ccel + (+1) *(dTotalNum), dW )
+#define CSRC_N RAC(ccel + (-mLevel[lev].lOffsx) *(dTotalNum), dN )
+#define CSRC_S RAC(ccel + (+mLevel[lev].lOffsx) *(dTotalNum), dS )
+#define CSRC_NE RAC(ccel + (-mLevel[lev].lOffsx-1) *(dTotalNum), dNE)
+#define CSRC_NW RAC(ccel + (-mLevel[lev].lOffsx+1) *(dTotalNum), dNW)
+#define CSRC_SE RAC(ccel + (+mLevel[lev].lOffsx-1) *(dTotalNum), dSE)
+#define CSRC_SW RAC(ccel + (+mLevel[lev].lOffsx+1) *(dTotalNum), dSW)
+#define CSRC_T RAC(ccel + (-mLevel[lev].lOffsy) *(dTotalNum), dT )
+#define CSRC_B RAC(ccel + (+mLevel[lev].lOffsy) *(dTotalNum), dB )
+#define CSRC_ET RAC(ccel + (-mLevel[lev].lOffsy-1) *(dTotalNum), dET)
+#define CSRC_EB RAC(ccel + (+mLevel[lev].lOffsy-1) *(dTotalNum), dEB)
+#define CSRC_WT RAC(ccel + (-mLevel[lev].lOffsy+1) *(dTotalNum), dWT)
+#define CSRC_WB RAC(ccel + (+mLevel[lev].lOffsy+1) *(dTotalNum), dWB)
+#define CSRC_NT RAC(ccel + (-mLevel[lev].lOffsy-mLevel[lev].lOffsx) *(dTotalNum), dNT)
+#define CSRC_NB RAC(ccel + (+mLevel[lev].lOffsy-mLevel[lev].lOffsx) *(dTotalNum), dNB)
+#define CSRC_ST RAC(ccel + (-mLevel[lev].lOffsy+mLevel[lev].lOffsx) *(dTotalNum), dST)
+#define CSRC_SB RAC(ccel + (+mLevel[lev].lOffsy+mLevel[lev].lOffsx) *(dTotalNum), dSB)
+
+#define XSRC_C(x) RAC(ccel + (x) *dTotalNum, dC )
+#define XSRC_E(x) RAC(ccel + ((x)-1) *dTotalNum, dE )
+#define XSRC_W(x) RAC(ccel + ((x)+1) *dTotalNum, dW )
+#define XSRC_N(x) RAC(ccel + ((x)-mLevel[lev].lOffsx) *dTotalNum, dN )
+#define XSRC_S(x) RAC(ccel + ((x)+mLevel[lev].lOffsx) *dTotalNum, dS )
+#define XSRC_NE(x) RAC(ccel + ((x)-mLevel[lev].lOffsx-1) *dTotalNum, dNE)
+#define XSRC_NW(x) RAC(ccel + ((x)-mLevel[lev].lOffsx+1) *dTotalNum, dNW)
+#define XSRC_SE(x) RAC(ccel + ((x)+mLevel[lev].lOffsx-1) *dTotalNum, dSE)
+#define XSRC_SW(x) RAC(ccel + ((x)+mLevel[lev].lOffsx+1) *dTotalNum, dSW)
+#define XSRC_T(x) RAC(ccel + ((x)-mLevel[lev].lOffsy) *dTotalNum, dT )
+#define XSRC_B(x) RAC(ccel + ((x)+mLevel[lev].lOffsy) *dTotalNum, dB )
+#define XSRC_ET(x) RAC(ccel + ((x)-mLevel[lev].lOffsy-1) *dTotalNum, dET)
+#define XSRC_EB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy-1) *dTotalNum, dEB)
+#define XSRC_WT(x) RAC(ccel + ((x)-mLevel[lev].lOffsy+1) *dTotalNum, dWT)
+#define XSRC_WB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy+1) *dTotalNum, dWB)
+#define XSRC_NT(x) RAC(ccel + ((x)-mLevel[lev].lOffsy-mLevel[lev].lOffsx) *dTotalNum, dNT)
+#define XSRC_NB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy-mLevel[lev].lOffsx) *dTotalNum, dNB)
+#define XSRC_ST(x) RAC(ccel + ((x)-mLevel[lev].lOffsy+mLevel[lev].lOffsx) *dTotalNum, dST)
+#define XSRC_SB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy+mLevel[lev].lOffsx) *dTotalNum, dSB)
+
+
+
+#if FSGR_STRICT_DEBUG==1
+
+#define LBMGI(level,ii,ij,ik, is) debLBMGI(level,ii,ij,ik, is)
+#define RFLAG(level,xx,yy,zz,set) debRFLAG(level,xx,yy,zz,set)
+#define RFLAG_NB(level,xx,yy,zz,set, dir) debRFLAG_NB(level,xx,yy,zz,set, dir)
+#define RFLAG_NBINV(level,xx,yy,zz,set, dir) debRFLAG_NBINV(level,xx,yy,zz,set, dir)
+
+#define LBMQI(level,ii,ij,ik, is, l) debLBMQI(level,ii,ij,ik, is, l)
+#define QCELL(level,xx,yy,zz,set,l) debQCELL(level,xx,yy,zz,set,l)
+#define QCELL_NB(level,xx,yy,zz,set, dir,l) debQCELL_NB(level,xx,yy,zz,set, dir,l)
+#define QCELL_NBINV(level,xx,yy,zz,set, dir,l) debQCELL_NBINV(level,xx,yy,zz,set, dir,l)
+#define RACPNT(level, ii,ij,ik, is ) debRACPNT(level, ii,ij,ik, is )
+#define RAC(s,l) debRAC(s,l)
+
+#else // FSGR_STRICT_DEBUG==1
+
+#define LBMGI(level,ii,ij,ik, is) _LBMGI(level,ii,ij,ik, is)
+#define RFLAG(level,xx,yy,zz,set) _RFLAG(level,xx,yy,zz,set)
+#define RFLAG_NB(level,xx,yy,zz,set, dir) _RFLAG_NB(level,xx,yy,zz,set, dir)
+#define RFLAG_NBINV(level,xx,yy,zz,set, dir) _RFLAG_NBINV(level,xx,yy,zz,set, dir)
+
+#define LBMQI(level,ii,ij,ik, is, l) _LBMQI(level,ii,ij,ik, is, l)
+#define QCELL(level,xx,yy,zz,set,l) _QCELL(level,xx,yy,zz,set,l)
+#define QCELL_NB(level,xx,yy,zz,set, dir,l) _QCELL_NB(level,xx,yy,zz,set, dir, l)
+#define QCELL_NBINV(level,xx,yy,zz,set, dir,l) _QCELL_NBINV(level,xx,yy,zz,set, dir,l)
+#define RACPNT(level, ii,ij,ik, is ) _RACPNT(level, ii,ij,ik, is )
+#define RAC(s,l) _RAC(s,l)
+
+#endif // FSGR_STRICT_DEBUG==1
+
+// general defines -----------------------------------------------------------------------------------------------
+
+#define TESTFLAG(flag, compflag) ((flag & compflag)==compflag)
+
+#if LBMDIM==2
+#define dC 0
+#define dN 1
+#define dS 2
+#define dE 3
+#define dW 4
+#define dNE 5
+#define dNW 6
+#define dSE 7
+#define dSW 8
+#define LBM_DFNUM 9
+#else
+// direction indices
+#define dC 0
+#define dN 1
+#define dS 2
+#define dE 3
+#define dW 4
+#define dT 5
+#define dB 6
+#define dNE 7
+#define dNW 8
+#define dSE 9
+#define dSW 10
+#define dNT 11
+#define dNB 12
+#define dST 13
+#define dSB 14
+#define dET 15
+#define dEB 16
+#define dWT 17
+#define dWB 18
+#define LBM_DFNUM 19
+#endif
+#define dFfrac 19
+#define dMass 20
+#define dFlux 21
+#define dTotalNum 22
+#define dWB 18
+
+// default init for dFlux values
+#define FLUX_INIT 0.5f * (float)(D::cDfNum)
+
+// only for non DF dir handling!
+#define dNET 19
+#define dNWT 20
+#define dSET 21
+#define dSWT 22
+#define dNEB 23
+#define dNWB 24
+#define dSEB 25
+#define dSWB 26
+
+//! fill value for boundary cells
+#define BND_FILL 0.0
+
+#define DFL1 (1.0/ 3.0)
+#define DFL2 (1.0/18.0)
+#define DFL3 (1.0/36.0)
+
+#define OMEGA(l) mLevel[(l)].omega
+
+#define EQC ( DFL1*(rho - usqr))
+#define EQN ( DFL2*(rho + uy*(4.5*uy + 3.0) - usqr))
+#define EQS ( DFL2*(rho + uy*(4.5*uy - 3.0) - usqr))
+#define EQE ( DFL2*(rho + ux*(4.5*ux + 3.0) - usqr))
+#define EQW ( DFL2*(rho + ux*(4.5*ux - 3.0) - usqr))
+#define EQT ( DFL2*(rho + uz*(4.5*uz + 3.0) - usqr))
+#define EQB ( DFL2*(rho + uz*(4.5*uz - 3.0) - usqr))
+
+#define EQNE ( DFL3*(rho + (+ux+uy)*(4.5*(+ux+uy) + 3.0) - usqr))
+#define EQNW ( DFL3*(rho + (-ux+uy)*(4.5*(-ux+uy) + 3.0) - usqr))
+#define EQSE ( DFL3*(rho + (+ux-uy)*(4.5*(+ux-uy) + 3.0) - usqr))
+#define EQSW ( DFL3*(rho + (-ux-uy)*(4.5*(-ux-uy) + 3.0) - usqr))
+#define EQNT ( DFL3*(rho + (+uy+uz)*(4.5*(+uy+uz) + 3.0) - usqr))
+#define EQNB ( DFL3*(rho + (+uy-uz)*(4.5*(+uy-uz) + 3.0) - usqr))
+#define EQST ( DFL3*(rho + (-uy+uz)*(4.5*(-uy+uz) + 3.0) - usqr))
+#define EQSB ( DFL3*(rho + (-uy-uz)*(4.5*(-uy-uz) + 3.0) - usqr))
+#define EQET ( DFL3*(rho + (+ux+uz)*(4.5*(+ux+uz) + 3.0) - usqr))
+#define EQEB ( DFL3*(rho + (+ux-uz)*(4.5*(+ux-uz) + 3.0) - usqr))
+#define EQWT ( DFL3*(rho + (-ux+uz)*(4.5*(-ux+uz) + 3.0) - usqr))
+#define EQWB ( DFL3*(rho + (-ux-uz)*(4.5*(-ux-uz) + 3.0) - usqr))
+
+
+// this is a bit ugly, but necessary for the CSRC_ access...
+#define MSRC_C m[dC ]
+#define MSRC_N m[dN ]
+#define MSRC_S m[dS ]
+#define MSRC_E m[dE ]
+#define MSRC_W m[dW ]
+#define MSRC_T m[dT ]
+#define MSRC_B m[dB ]
+#define MSRC_NE m[dNE]
+#define MSRC_NW m[dNW]
+#define MSRC_SE m[dSE]
+#define MSRC_SW m[dSW]
+#define MSRC_NT m[dNT]
+#define MSRC_NB m[dNB]
+#define MSRC_ST m[dST]
+#define MSRC_SB m[dSB]
+#define MSRC_ET m[dET]
+#define MSRC_EB m[dEB]
+#define MSRC_WT m[dWT]
+#define MSRC_WB m[dWB]
+
+// this is a bit ugly, but necessary for the ccel local access...
+#define CCEL_C RAC(ccel, dC )
+#define CCEL_N RAC(ccel, dN )
+#define CCEL_S RAC(ccel, dS )
+#define CCEL_E RAC(ccel, dE )
+#define CCEL_W RAC(ccel, dW )
+#define CCEL_T RAC(ccel, dT )
+#define CCEL_B RAC(ccel, dB )
+#define CCEL_NE RAC(ccel, dNE)
+#define CCEL_NW RAC(ccel, dNW)
+#define CCEL_SE RAC(ccel, dSE)
+#define CCEL_SW RAC(ccel, dSW)
+#define CCEL_NT RAC(ccel, dNT)
+#define CCEL_NB RAC(ccel, dNB)
+#define CCEL_ST RAC(ccel, dST)
+#define CCEL_SB RAC(ccel, dSB)
+#define CCEL_ET RAC(ccel, dET)
+#define CCEL_EB RAC(ccel, dEB)
+#define CCEL_WT RAC(ccel, dWT)
+#define CCEL_WB RAC(ccel, dWB)
+
+
+#if PARALLEL==1
+#define CSMOMEGA_STATS(dlev, domega)
+#else // PARALLEL==1
+#if FSGR_OMEGA_DEBUG==1
+#define CSMOMEGA_STATS(dlev, domega) \
+ mLevel[dlev].avgOmega += domega; mLevel[dlev].avgOmegaCnt+=1.0;
+#else // FSGR_OMEGA_DEBUG==1
+#define CSMOMEGA_STATS(dlev, domega)
+#endif // FSGR_OMEGA_DEBUG==1
+#endif // PARALLEL==1
+
+
+// used for main loops and grav init
+// source set
+#define SRCS(l) mLevel[(l)].setCurr
+// target set
+#define TSET(l) mLevel[(l)].setOther
+
+
+// complete default stream&collide, 2d/3d
+/* read distribution funtions of adjacent cells = sweep step */
+#if OPT3D==false
+
+#if FSGR_STRICT_DEBUG==1
+#define MARKCELLCHECK \
+ debugMarkCell(lev,i,j,k); D::mPanic=1;
+#define STREAMCHECK(ni,nj,nk,nl) \
+ if((m[l] < -1.0) || (m[l]>1.0)) {\
+ errMsg("STREAMCHECK","Invalid streamed DF l"<<l<<" value:"<<m[l]<<" at "<<PRINT_IJK<<" from "<<PRINT_VEC(ni,nj,nk)<<" nl"<<(nl)<<\
+ " nfc"<< RFLAG(lev, ni,nj,nk, mLevel[lev].setCurr)<<" nfo"<< RFLAG(lev, ni,nj,nk, mLevel[lev].setOther) ); \
+ MARKCELLCHECK; \
+ }
+#define COLLCHECK \
+ if( (rho>2.0) || (rho<-1.0) || (ABS(ux)>1.0) || (ABS(uy)>1.0) |(ABS(uz)>1.0) ) {\
+ errMsg("COLLCHECK","Invalid collision values r:"<<rho<<" u:"PRINT_VEC(ux,uy,uz)<<" at? "<<PRINT_IJK ); \
+ MARKCELLCHECK; \
+ }
+#else
+#define STREAMCHECK(ni,nj,nk,nl)
+#define COLLCHECK
+#endif
+
+// careful ux,uy,uz need to be inited before!
+
+#define DEFAULT_STREAM \
+ m[dC] = RAC(ccel,dC); \
+ FORDF1 { \
+ if(NBFLAG( D::dfInv[l] )&CFBnd) { \
+ m[l] = RAC(ccel, D::dfInv[l] ); \
+ STREAMCHECK(i,j,k, D::dfInv[l]); \
+ } else { \
+ m[l] = QCELL_NBINV(lev, i, j, k, SRCS(lev), l,l); \
+ STREAMCHECK(i+D::dfVecX[D::dfInv[l]], j+D::dfVecY[D::dfInv[l]],k+D::dfVecZ[D::dfInv[l]], l); \
+ } \
+ }
+
+// careful ux,uy,uz need to be inited before!
+#define DEFAULT_COLLIDE \
+ D::collideArrays( m, rho,ux,uy,uz, OMEGA(lev), mLevel[lev].lcsmago, &mDebugOmegaRet ); \
+ CSMOMEGA_STATS(lev,mDebugOmegaRet); \
+ FORDF0 { RAC(tcel,l) = m[l]; } \
+ usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
+ COLLCHECK;
+#define OPTIMIZED_STREAMCOLLIDE \
+ m[0] = RAC(ccel,0); \
+ FORDF1 { /* df0 is set later on... */ \
+ /* FIXME CHECK INV ? */\
+ if(RFLAG_NBINV(lev, i,j,k,SRCS(lev),l)&CFBnd) { errMsg("???", "bnd-err-nobndfl"); D::mPanic=1; \
+ } else { m[l] = QCELL_NBINV(lev, i, j, k, SRCS(lev), l, l); } \
+ STREAMCHECK(i+D::dfVecX[D::dfInv[l]], j+D::dfVecY[D::dfInv[l]],k+D::dfVecZ[D::dfInv[l]], l); \
+ } \
+ rho=m[0]; ux = mLevel[lev].gravity[0]; uy = mLevel[lev].gravity[1]; uz = mLevel[lev].gravity[2]; \
+ ux = mLevel[lev].gravity[0]; uy = mLevel[lev].gravity[1]; uz = mLevel[lev].gravity[2]; \
+ D::collideArrays( m, rho,ux,uy,uz, OMEGA(lev), mLevel[lev].lcsmago , &mDebugOmegaRet ); \
+ CSMOMEGA_STATS(lev,mDebugOmegaRet); \
+ FORDF0 { RAC(tcel,l) = m[l]; } \
+ usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
+ COLLCHECK;
+
+#else // 3D, opt OPT3D==true
+
+#define DEFAULT_STREAM \
+ m[dC] = RAC(ccel,dC); \
+ /* explicit streaming */ \
+ if((!nbored & CFBnd)) { \
+ /* no boundary near?, no real speed diff.? */ \
+ m[dN ] = CSRC_N ; m[dS ] = CSRC_S ; \
+ m[dE ] = CSRC_E ; m[dW ] = CSRC_W ; \
+ m[dT ] = CSRC_T ; m[dB ] = CSRC_B ; \
+ m[dNE] = CSRC_NE; m[dNW] = CSRC_NW; m[dSE] = CSRC_SE; m[dSW] = CSRC_SW; \
+ m[dNT] = CSRC_NT; m[dNB] = CSRC_NB; m[dST] = CSRC_ST; m[dSB] = CSRC_SB; \
+ m[dET] = CSRC_ET; m[dEB] = CSRC_EB; m[dWT] = CSRC_WT; m[dWB] = CSRC_WB; \
+ } else { \
+ /* explicit streaming */ \
+ if(NBFLAG(dS )&CFBnd) { m[dN ] = RAC(ccel,dS ); } else { m[dN ] = CSRC_N ; } \
+ if(NBFLAG(dN )&CFBnd) { m[dS ] = RAC(ccel,dN ); } else { m[dS ] = CSRC_S ; } \
+ if(NBFLAG(dW )&CFBnd) { m[dE ] = RAC(ccel,dW ); } else { m[dE ] = CSRC_E ; } \
+ if(NBFLAG(dE )&CFBnd) { m[dW ] = RAC(ccel,dE ); } else { m[dW ] = CSRC_W ; } \
+ if(NBFLAG(dB )&CFBnd) { m[dT ] = RAC(ccel,dB ); } else { m[dT ] = CSRC_T ; } \
+ if(NBFLAG(dT )&CFBnd) { m[dB ] = RAC(ccel,dT ); } else { m[dB ] = CSRC_B ; } \
+ \
+ if(NBFLAG(dSW)&CFBnd) { m[dNE] = RAC(ccel,dSW); } else { m[dNE] = CSRC_NE; } \
+ if(NBFLAG(dSE)&CFBnd) { m[dNW] = RAC(ccel,dSE); } else { m[dNW] = CSRC_NW; } \
+ if(NBFLAG(dNW)&CFBnd) { m[dSE] = RAC(ccel,dNW); } else { m[dSE] = CSRC_SE; } \
+ if(NBFLAG(dNE)&CFBnd) { m[dSW] = RAC(ccel,dNE); } else { m[dSW] = CSRC_SW; } \
+ if(NBFLAG(dSB)&CFBnd) { m[dNT] = RAC(ccel,dSB); } else { m[dNT] = CSRC_NT; } \
+ if(NBFLAG(dST)&CFBnd) { m[dNB] = RAC(ccel,dST); } else { m[dNB] = CSRC_NB; } \
+ if(NBFLAG(dNB)&CFBnd) { m[dST] = RAC(ccel,dNB); } else { m[dST] = CSRC_ST; } \
+ if(NBFLAG(dNT)&CFBnd) { m[dSB] = RAC(ccel,dNT); } else { m[dSB] = CSRC_SB; } \
+ if(NBFLAG(dWB)&CFBnd) { m[dET] = RAC(ccel,dWB); } else { m[dET] = CSRC_ET; } \
+ if(NBFLAG(dWT)&CFBnd) { m[dEB] = RAC(ccel,dWT); } else { m[dEB] = CSRC_EB; } \
+ if(NBFLAG(dEB)&CFBnd) { m[dWT] = RAC(ccel,dEB); } else { m[dWT] = CSRC_WT; } \
+ if(NBFLAG(dET)&CFBnd) { m[dWB] = RAC(ccel,dET); } else { m[dWB] = CSRC_WB; } \
+ }
+
+
+
+#define COLL_CALCULATE_DFEQ(dstarray) \
+ dstarray[dN ] = EQN ; dstarray[dS ] = EQS ; \
+ dstarray[dE ] = EQE ; dstarray[dW ] = EQW ; \
+ dstarray[dT ] = EQT ; dstarray[dB ] = EQB ; \
+ dstarray[dNE] = EQNE; dstarray[dNW] = EQNW; dstarray[dSE] = EQSE; dstarray[dSW] = EQSW; \
+ dstarray[dNT] = EQNT; dstarray[dNB] = EQNB; dstarray[dST] = EQST; dstarray[dSB] = EQSB; \
+ dstarray[dET] = EQET; dstarray[dEB] = EQEB; dstarray[dWT] = EQWT; dstarray[dWB] = EQWB;
+#define COLL_CALCULATE_NONEQTENSOR(csolev, srcArray ) \
+ lcsmqadd = (srcArray##NE - lcsmeq[ dNE ]); \
+ lcsmqadd -= (srcArray##NW - lcsmeq[ dNW ]); \
+ lcsmqadd -= (srcArray##SE - lcsmeq[ dSE ]); \
+ lcsmqadd += (srcArray##SW - lcsmeq[ dSW ]); \
+ lcsmqo = (lcsmqadd* lcsmqadd); \
+ lcsmqadd = (srcArray##ET - lcsmeq[ dET ]); \
+ lcsmqadd -= (srcArray##EB - lcsmeq[ dEB ]); \
+ lcsmqadd -= (srcArray##WT - lcsmeq[ dWT ]); \
+ lcsmqadd += (srcArray##WB - lcsmeq[ dWB ]); \
+ lcsmqo += (lcsmqadd* lcsmqadd); \
+ lcsmqadd = (srcArray##NT - lcsmeq[ dNT ]); \
+ lcsmqadd -= (srcArray##NB - lcsmeq[ dNB ]); \
+ lcsmqadd -= (srcArray##ST - lcsmeq[ dST ]); \
+ lcsmqadd += (srcArray##SB - lcsmeq[ dSB ]); \
+ lcsmqo += (lcsmqadd* lcsmqadd); \
+ lcsmqo *= 2.0; \
+ lcsmqadd = (srcArray##E - lcsmeq[ dE ]); \
+ lcsmqadd += (srcArray##W - lcsmeq[ dW ]); \
+ lcsmqadd += (srcArray##NE - lcsmeq[ dNE ]); \
+ lcsmqadd += (srcArray##NW - lcsmeq[ dNW ]); \
+ lcsmqadd += (srcArray##SE - lcsmeq[ dSE ]); \
+ lcsmqadd += (srcArray##SW - lcsmeq[ dSW ]); \
+ lcsmqadd += (srcArray##ET - lcsmeq[ dET ]); \
+ lcsmqadd += (srcArray##EB - lcsmeq[ dEB ]); \
+ lcsmqadd += (srcArray##WT - lcsmeq[ dWT ]); \
+ lcsmqadd += (srcArray##WB - lcsmeq[ dWB ]); \
+ lcsmqo += (lcsmqadd* lcsmqadd); \
+ lcsmqadd = (srcArray##N - lcsmeq[ dN ]); \
+ lcsmqadd += (srcArray##S - lcsmeq[ dS ]); \
+ lcsmqadd += (srcArray##NE - lcsmeq[ dNE ]); \
+ lcsmqadd += (srcArray##NW - lcsmeq[ dNW ]); \
+ lcsmqadd += (srcArray##SE - lcsmeq[ dSE ]); \
+ lcsmqadd += (srcArray##SW - lcsmeq[ dSW ]); \
+ lcsmqadd += (srcArray##NT - lcsmeq[ dNT ]); \
+ lcsmqadd += (srcArray##NB - lcsmeq[ dNB ]); \
+ lcsmqadd += (srcArray##ST - lcsmeq[ dST ]); \
+ lcsmqadd += (srcArray##SB - lcsmeq[ dSB ]); \
+ lcsmqo += (lcsmqadd* lcsmqadd); \
+ lcsmqadd = (srcArray##T - lcsmeq[ dT ]); \
+ lcsmqadd += (srcArray##B - lcsmeq[ dB ]); \
+ lcsmqadd += (srcArray##NT - lcsmeq[ dNT ]); \
+ lcsmqadd += (srcArray##NB - lcsmeq[ dNB ]); \
+ lcsmqadd += (srcArray##ST - lcsmeq[ dST ]); \
+ lcsmqadd += (srcArray##SB - lcsmeq[ dSB ]); \
+ lcsmqadd += (srcArray##ET - lcsmeq[ dET ]); \
+ lcsmqadd += (srcArray##EB - lcsmeq[ dEB ]); \
+ lcsmqadd += (srcArray##WT - lcsmeq[ dWT ]); \
+ lcsmqadd += (srcArray##WB - lcsmeq[ dWB ]); \
+ lcsmqo += (lcsmqadd* lcsmqadd); \
+ lcsmqo = sqrt(lcsmqo); /* FIXME check effect of sqrt*/ \
+
+// COLL_CALCULATE_CSMOMEGAVAL(csolev, lcsmomega);
+
+// careful - need lcsmqo
+#define COLL_CALCULATE_CSMOMEGAVAL(csolev, dstomega ) \
+ dstomega = 1.0/\
+ ( 3.0*( mLevel[(csolev)].lcnu+mLevel[(csolev)].lcsmago_sqr*(\
+ -mLevel[(csolev)].lcnu + sqrt( mLevel[(csolev)].lcnu*mLevel[(csolev)].lcnu + 18.0*mLevel[(csolev)].lcsmago_sqr* lcsmqo ) \
+ / (6.0*mLevel[(csolev)].lcsmago_sqr)) \
+ ) +0.5 );
+
+#define DEFAULT_COLLIDE_LES \
+ rho = + MSRC_C + MSRC_N \
+ + MSRC_S + MSRC_E \
+ + MSRC_W + MSRC_T \
+ + MSRC_B + MSRC_NE \
+ + MSRC_NW + MSRC_SE \
+ + MSRC_SW + MSRC_NT \
+ + MSRC_NB + MSRC_ST \
+ + MSRC_SB + MSRC_ET \
+ + MSRC_EB + MSRC_WT \
+ + MSRC_WB; \
+ \
+ ux += MSRC_E - MSRC_W \
+ + MSRC_NE - MSRC_NW \
+ + MSRC_SE - MSRC_SW \
+ + MSRC_ET + MSRC_EB \
+ - MSRC_WT - MSRC_WB ; \
+ \
+ uy += MSRC_N - MSRC_S \
+ + MSRC_NE + MSRC_NW \
+ - MSRC_SE - MSRC_SW \
+ + MSRC_NT + MSRC_NB \
+ - MSRC_ST - MSRC_SB ; \
+ \
+ uz += MSRC_T - MSRC_B \
+ + MSRC_NT - MSRC_NB \
+ + MSRC_ST - MSRC_SB \
+ + MSRC_ET - MSRC_EB \
+ + MSRC_WT - MSRC_WB ; \
+ usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
+ COLL_CALCULATE_DFEQ(lcsmeq); \
+ COLL_CALCULATE_NONEQTENSOR(lev, MSRC_)\
+ COLL_CALCULATE_CSMOMEGAVAL(lev, lcsmomega); \
+ CSMOMEGA_STATS(lev,lcsmomega); \
+ \
+ RAC(tcel,dC ) = (1.0-lcsmomega)*MSRC_C + lcsmomega*EQC ; \
+ \
+ RAC(tcel,dN ) = (1.0-lcsmomega)*MSRC_N + lcsmomega*lcsmeq[ dN ]; \
+ RAC(tcel,dS ) = (1.0-lcsmomega)*MSRC_S + lcsmomega*lcsmeq[ dS ]; \
+ RAC(tcel,dE ) = (1.0-lcsmomega)*MSRC_E + lcsmomega*lcsmeq[ dE ]; \
+ RAC(tcel,dW ) = (1.0-lcsmomega)*MSRC_W + lcsmomega*lcsmeq[ dW ]; \
+ RAC(tcel,dT ) = (1.0-lcsmomega)*MSRC_T + lcsmomega*lcsmeq[ dT ]; \
+ RAC(tcel,dB ) = (1.0-lcsmomega)*MSRC_B + lcsmomega*lcsmeq[ dB ]; \
+ \
+ RAC(tcel,dNE) = (1.0-lcsmomega)*MSRC_NE + lcsmomega*lcsmeq[ dNE]; \
+ RAC(tcel,dNW) = (1.0-lcsmomega)*MSRC_NW + lcsmomega*lcsmeq[ dNW]; \
+ RAC(tcel,dSE) = (1.0-lcsmomega)*MSRC_SE + lcsmomega*lcsmeq[ dSE]; \
+ RAC(tcel,dSW) = (1.0-lcsmomega)*MSRC_SW + lcsmomega*lcsmeq[ dSW]; \
+ RAC(tcel,dNT) = (1.0-lcsmomega)*MSRC_NT + lcsmomega*lcsmeq[ dNT]; \
+ RAC(tcel,dNB) = (1.0-lcsmomega)*MSRC_NB + lcsmomega*lcsmeq[ dNB]; \
+ RAC(tcel,dST) = (1.0-lcsmomega)*MSRC_ST + lcsmomega*lcsmeq[ dST]; \
+ RAC(tcel,dSB) = (1.0-lcsmomega)*MSRC_SB + lcsmomega*lcsmeq[ dSB]; \
+ RAC(tcel,dET) = (1.0-lcsmomega)*MSRC_ET + lcsmomega*lcsmeq[ dET]; \
+ RAC(tcel,dEB) = (1.0-lcsmomega)*MSRC_EB + lcsmomega*lcsmeq[ dEB]; \
+ RAC(tcel,dWT) = (1.0-lcsmomega)*MSRC_WT + lcsmomega*lcsmeq[ dWT]; \
+ RAC(tcel,dWB) = (1.0-lcsmomega)*MSRC_WB + lcsmomega*lcsmeq[ dWB];
+
+#define DEFAULT_COLLIDE_NOLES \
+ rho = + MSRC_C + MSRC_N \
+ + MSRC_S + MSRC_E \
+ + MSRC_W + MSRC_T \
+ + MSRC_B + MSRC_NE \
+ + MSRC_NW + MSRC_SE \
+ + MSRC_SW + MSRC_NT \
+ + MSRC_NB + MSRC_ST \
+ + MSRC_SB + MSRC_ET \
+ + MSRC_EB + MSRC_WT \
+ + MSRC_WB; \
+ \
+ ux += MSRC_E - MSRC_W \
+ + MSRC_NE - MSRC_NW \
+ + MSRC_SE - MSRC_SW \
+ + MSRC_ET + MSRC_EB \
+ - MSRC_WT - MSRC_WB ; \
+ \
+ uy += MSRC_N - MSRC_S \
+ + MSRC_NE + MSRC_NW \
+ - MSRC_SE - MSRC_SW \
+ + MSRC_NT + MSRC_NB \
+ - MSRC_ST - MSRC_SB ; \
+ \
+ uz += MSRC_T - MSRC_B \
+ + MSRC_NT - MSRC_NB \
+ + MSRC_ST - MSRC_SB \
+ + MSRC_ET - MSRC_EB \
+ + MSRC_WT - MSRC_WB ; \
+ usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
+ \
+ RAC(tcel,dC ) = (1.0-OMEGA(lev))*MSRC_C + OMEGA(lev)*EQC ; \
+ \
+ RAC(tcel,dN ) = (1.0-OMEGA(lev))*MSRC_N + OMEGA(lev)*EQN ; \
+ RAC(tcel,dS ) = (1.0-OMEGA(lev))*MSRC_S + OMEGA(lev)*EQS ; \
+ RAC(tcel,dE ) = (1.0-OMEGA(lev))*MSRC_E + OMEGA(lev)*EQE ; \
+ RAC(tcel,dW ) = (1.0-OMEGA(lev))*MSRC_W + OMEGA(lev)*EQW ; \
+ RAC(tcel,dT ) = (1.0-OMEGA(lev))*MSRC_T + OMEGA(lev)*EQT ; \
+ RAC(tcel,dB ) = (1.0-OMEGA(lev))*MSRC_B + OMEGA(lev)*EQB ; \
+ \
+ RAC(tcel,dNE) = (1.0-OMEGA(lev))*MSRC_NE + OMEGA(lev)*EQNE; \
+ RAC(tcel,dNW) = (1.0-OMEGA(lev))*MSRC_NW + OMEGA(lev)*EQNW; \
+ RAC(tcel,dSE) = (1.0-OMEGA(lev))*MSRC_SE + OMEGA(lev)*EQSE; \
+ RAC(tcel,dSW) = (1.0-OMEGA(lev))*MSRC_SW + OMEGA(lev)*EQSW; \
+ RAC(tcel,dNT) = (1.0-OMEGA(lev))*MSRC_NT + OMEGA(lev)*EQNT; \
+ RAC(tcel,dNB) = (1.0-OMEGA(lev))*MSRC_NB + OMEGA(lev)*EQNB; \
+ RAC(tcel,dST) = (1.0-OMEGA(lev))*MSRC_ST + OMEGA(lev)*EQST; \
+ RAC(tcel,dSB) = (1.0-OMEGA(lev))*MSRC_SB + OMEGA(lev)*EQSB; \
+ RAC(tcel,dET) = (1.0-OMEGA(lev))*MSRC_ET + OMEGA(lev)*EQET; \
+ RAC(tcel,dEB) = (1.0-OMEGA(lev))*MSRC_EB + OMEGA(lev)*EQEB; \
+ RAC(tcel,dWT) = (1.0-OMEGA(lev))*MSRC_WT + OMEGA(lev)*EQWT; \
+ RAC(tcel,dWB) = (1.0-OMEGA(lev))*MSRC_WB + OMEGA(lev)*EQWB;
+
+
+
+#define OPTIMIZED_STREAMCOLLIDE_LES \
+ /* only surrounded by fluid cells...!, so safe streaming here... */ \
+ m[dC ] = CSRC_C ; \
+ m[dN ] = CSRC_N ; m[dS ] = CSRC_S ; \
+ m[dE ] = CSRC_E ; m[dW ] = CSRC_W ; \
+ m[dT ] = CSRC_T ; m[dB ] = CSRC_B ; \
+ m[dNE] = CSRC_NE; m[dNW] = CSRC_NW; m[dSE] = CSRC_SE; m[dSW] = CSRC_SW; \
+ m[dNT] = CSRC_NT; m[dNB] = CSRC_NB; m[dST] = CSRC_ST; m[dSB] = CSRC_SB; \
+ m[dET] = CSRC_ET; m[dEB] = CSRC_EB; m[dWT] = CSRC_WT; m[dWB] = CSRC_WB; \
+ \
+ rho = MSRC_C + MSRC_N + MSRC_S + MSRC_E + MSRC_W + MSRC_T \
+ + MSRC_B + MSRC_NE + MSRC_NW + MSRC_SE + MSRC_SW + MSRC_NT \
+ + MSRC_NB + MSRC_ST + MSRC_SB + MSRC_ET + MSRC_EB + MSRC_WT + MSRC_WB; \
+ ux = MSRC_E - MSRC_W + MSRC_NE - MSRC_NW + MSRC_SE - MSRC_SW \
+ + MSRC_ET + MSRC_EB - MSRC_WT - MSRC_WB + mLevel[lev].gravity[0]; \
+ uy = MSRC_N - MSRC_S + MSRC_NE + MSRC_NW - MSRC_SE - MSRC_SW \
+ + MSRC_NT + MSRC_NB - MSRC_ST - MSRC_SB + mLevel[lev].gravity[1]; \
+ uz = MSRC_T - MSRC_B + MSRC_NT - MSRC_NB + MSRC_ST - MSRC_SB \
+ + MSRC_ET - MSRC_EB + MSRC_WT - MSRC_WB + mLevel[lev].gravity[2]; \
+ usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
+ COLL_CALCULATE_DFEQ(lcsmeq); \
+ COLL_CALCULATE_NONEQTENSOR(lev, MSRC_) \
+ COLL_CALCULATE_CSMOMEGAVAL(lev, lcsmomega); \
+ CSMOMEGA_STATS(lev,lcsmomega); \
+ \
+ RAC(tcel,dC ) = (1.0-lcsmomega)*MSRC_C + lcsmomega*EQC ; \
+ RAC(tcel,dN ) = (1.0-lcsmomega)*MSRC_N + lcsmomega*lcsmeq[ dN ]; \
+ RAC(tcel,dS ) = (1.0-lcsmomega)*MSRC_S + lcsmomega*lcsmeq[ dS ]; \
+ RAC(tcel,dE ) = (1.0-lcsmomega)*MSRC_E + lcsmomega*lcsmeq[ dE ]; \
+ RAC(tcel,dW ) = (1.0-lcsmomega)*MSRC_W + lcsmomega*lcsmeq[ dW ]; \
+ RAC(tcel,dT ) = (1.0-lcsmomega)*MSRC_T + lcsmomega*lcsmeq[ dT ]; \
+ RAC(tcel,dB ) = (1.0-lcsmomega)*MSRC_B + lcsmomega*lcsmeq[ dB ]; \
+ \
+ RAC(tcel,dNE) = (1.0-lcsmomega)*MSRC_NE + lcsmomega*lcsmeq[ dNE]; \
+ RAC(tcel,dNW) = (1.0-lcsmomega)*MSRC_NW + lcsmomega*lcsmeq[ dNW]; \
+ RAC(tcel,dSE) = (1.0-lcsmomega)*MSRC_SE + lcsmomega*lcsmeq[ dSE]; \
+ RAC(tcel,dSW) = (1.0-lcsmomega)*MSRC_SW + lcsmomega*lcsmeq[ dSW]; \
+ \
+ RAC(tcel,dNT) = (1.0-lcsmomega)*MSRC_NT + lcsmomega*lcsmeq[ dNT]; \
+ RAC(tcel,dNB) = (1.0-lcsmomega)*MSRC_NB + lcsmomega*lcsmeq[ dNB]; \
+ RAC(tcel,dST) = (1.0-lcsmomega)*MSRC_ST + lcsmomega*lcsmeq[ dST]; \
+ RAC(tcel,dSB) = (1.0-lcsmomega)*MSRC_SB + lcsmomega*lcsmeq[ dSB]; \
+ \
+ RAC(tcel,dET) = (1.0-lcsmomega)*MSRC_ET + lcsmomega*lcsmeq[ dET]; \
+ RAC(tcel,dEB) = (1.0-lcsmomega)*MSRC_EB + lcsmomega*lcsmeq[ dEB]; \
+ RAC(tcel,dWT) = (1.0-lcsmomega)*MSRC_WT + lcsmomega*lcsmeq[ dWT]; \
+ RAC(tcel,dWB) = (1.0-lcsmomega)*MSRC_WB + lcsmomega*lcsmeq[ dWB]; \
+
+#define OPTIMIZED_STREAMCOLLIDE_UNUSED \
+ /* only surrounded by fluid cells...!, so safe streaming here... */ \
+ rho = CSRC_C + CSRC_N + CSRC_S + CSRC_E + CSRC_W + CSRC_T \
+ + CSRC_B + CSRC_NE + CSRC_NW + CSRC_SE + CSRC_SW + CSRC_NT \
+ + CSRC_NB + CSRC_ST + CSRC_SB + CSRC_ET + CSRC_EB + CSRC_WT + CSRC_WB; \
+ ux = CSRC_E - CSRC_W + CSRC_NE - CSRC_NW + CSRC_SE - CSRC_SW \
+ + CSRC_ET + CSRC_EB - CSRC_WT - CSRC_WB + mLevel[lev].gravity[0]; \
+ uy = CSRC_N - CSRC_S + CSRC_NE + CSRC_NW - CSRC_SE - CSRC_SW \
+ + CSRC_NT + CSRC_NB - CSRC_ST - CSRC_SB + mLevel[lev].gravity[1]; \
+ uz = CSRC_T - CSRC_B + CSRC_NT - CSRC_NB + CSRC_ST - CSRC_SB \
+ + CSRC_ET - CSRC_EB + CSRC_WT - CSRC_WB + mLevel[lev].gravity[2]; \
+ usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
+ COLL_CALCULATE_DFEQ(lcsmeq); \
+ COLL_CALCULATE_NONEQTENSOR(lev, CSRC_) \
+ COLL_CALCULATE_CSMOMEGAVAL(lev, lcsmomega); \
+ \
+ RAC(tcel,dC ) = (1.0-lcsmomega)*CSRC_C + lcsmomega*EQC ; \
+ RAC(tcel,dN ) = (1.0-lcsmomega)*CSRC_N + lcsmomega*lcsmeq[ dN ]; \
+ RAC(tcel,dS ) = (1.0-lcsmomega)*CSRC_S + lcsmomega*lcsmeq[ dS ]; \
+ RAC(tcel,dE ) = (1.0-lcsmomega)*CSRC_E + lcsmomega*lcsmeq[ dE ]; \
+ RAC(tcel,dW ) = (1.0-lcsmomega)*CSRC_W + lcsmomega*lcsmeq[ dW ]; \
+ RAC(tcel,dT ) = (1.0-lcsmomega)*CSRC_T + lcsmomega*lcsmeq[ dT ]; \
+ RAC(tcel,dB ) = (1.0-lcsmomega)*CSRC_B + lcsmomega*lcsmeq[ dB ]; \
+ \
+ RAC(tcel,dNE) = (1.0-lcsmomega)*CSRC_NE + lcsmomega*lcsmeq[ dNE]; \
+ RAC(tcel,dNW) = (1.0-lcsmomega)*CSRC_NW + lcsmomega*lcsmeq[ dNW]; \
+ RAC(tcel,dSE) = (1.0-lcsmomega)*CSRC_SE + lcsmomega*lcsmeq[ dSE]; \
+ RAC(tcel,dSW) = (1.0-lcsmomega)*CSRC_SW + lcsmomega*lcsmeq[ dSW]; \
+ \
+ RAC(tcel,dNT) = (1.0-lcsmomega)*CSRC_NT + lcsmomega*lcsmeq[ dNT]; \
+ RAC(tcel,dNB) = (1.0-lcsmomega)*CSRC_NB + lcsmomega*lcsmeq[ dNB]; \
+ RAC(tcel,dST) = (1.0-lcsmomega)*CSRC_ST + lcsmomega*lcsmeq[ dST]; \
+ RAC(tcel,dSB) = (1.0-lcsmomega)*CSRC_SB + lcsmomega*lcsmeq[ dSB]; \
+ \
+ RAC(tcel,dET) = (1.0-lcsmomega)*CSRC_ET + lcsmomega*lcsmeq[ dET]; \
+ RAC(tcel,dEB) = (1.0-lcsmomega)*CSRC_EB + lcsmomega*lcsmeq[ dEB]; \
+ RAC(tcel,dWT) = (1.0-lcsmomega)*CSRC_WT + lcsmomega*lcsmeq[ dWT]; \
+ RAC(tcel,dWB) = (1.0-lcsmomega)*CSRC_WB + lcsmomega*lcsmeq[ dWB]; \
+
+#define OPTIMIZED_STREAMCOLLIDE_NOLES \
+ /* only surrounded by fluid cells...!, so safe streaming here... */ \
+ rho = CSRC_C + CSRC_N + CSRC_S + CSRC_E + CSRC_W + CSRC_T \
+ + CSRC_B + CSRC_NE + CSRC_NW + CSRC_SE + CSRC_SW + CSRC_NT \
+ + CSRC_NB + CSRC_ST + CSRC_SB + CSRC_ET + CSRC_EB + CSRC_WT + CSRC_WB; \
+ ux = CSRC_E - CSRC_W + CSRC_NE - CSRC_NW + CSRC_SE - CSRC_SW \
+ + CSRC_ET + CSRC_EB - CSRC_WT - CSRC_WB + mLevel[lev].gravity[0]; \
+ uy = CSRC_N - CSRC_S + CSRC_NE + CSRC_NW - CSRC_SE - CSRC_SW \
+ + CSRC_NT + CSRC_NB - CSRC_ST - CSRC_SB + mLevel[lev].gravity[1]; \
+ uz = CSRC_T - CSRC_B + CSRC_NT - CSRC_NB + CSRC_ST - CSRC_SB \
+ + CSRC_ET - CSRC_EB + CSRC_WT - CSRC_WB + mLevel[lev].gravity[2]; \
+ usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
+ RAC(tcel,dC ) = (1.0-OMEGA(lev))*CSRC_C + OMEGA(lev)*EQC ; \
+ RAC(tcel,dN ) = (1.0-OMEGA(lev))*CSRC_N + OMEGA(lev)*EQN ; \
+ RAC(tcel,dS ) = (1.0-OMEGA(lev))*CSRC_S + OMEGA(lev)*EQS ; \
+ RAC(tcel,dE ) = (1.0-OMEGA(lev))*CSRC_E + OMEGA(lev)*EQE ; \
+ RAC(tcel,dW ) = (1.0-OMEGA(lev))*CSRC_W + OMEGA(lev)*EQW ; \
+ RAC(tcel,dT ) = (1.0-OMEGA(lev))*CSRC_T + OMEGA(lev)*EQT ; \
+ RAC(tcel,dB ) = (1.0-OMEGA(lev))*CSRC_B + OMEGA(lev)*EQB ; \
+ \
+ RAC(tcel,dNE) = (1.0-OMEGA(lev))*CSRC_NE + OMEGA(lev)*EQNE; \
+ RAC(tcel,dNW) = (1.0-OMEGA(lev))*CSRC_NW + OMEGA(lev)*EQNW; \
+ RAC(tcel,dSE) = (1.0-OMEGA(lev))*CSRC_SE + OMEGA(lev)*EQSE; \
+ RAC(tcel,dSW) = (1.0-OMEGA(lev))*CSRC_SW + OMEGA(lev)*EQSW; \
+ \
+ RAC(tcel,dNT) = (1.0-OMEGA(lev))*CSRC_NT + OMEGA(lev)*EQNT; \
+ RAC(tcel,dNB) = (1.0-OMEGA(lev))*CSRC_NB + OMEGA(lev)*EQNB; \
+ RAC(tcel,dST) = (1.0-OMEGA(lev))*CSRC_ST + OMEGA(lev)*EQST; \
+ RAC(tcel,dSB) = (1.0-OMEGA(lev))*CSRC_SB + OMEGA(lev)*EQSB; \
+ \
+ RAC(tcel,dET) = (1.0-OMEGA(lev))*CSRC_ET + OMEGA(lev)*EQET; \
+ RAC(tcel,dEB) = (1.0-OMEGA(lev))*CSRC_EB + OMEGA(lev)*EQEB; \
+ RAC(tcel,dWT) = (1.0-OMEGA(lev))*CSRC_WT + OMEGA(lev)*EQWT; \
+ RAC(tcel,dWB) = (1.0-OMEGA(lev))*CSRC_WB + OMEGA(lev)*EQWB; \
+
+
+// debug version1
+#define STREAMCHECK(ni,nj,nk,nl)
+#define COLLCHECK
+#define OPTIMIZED_STREAMCOLLIDE_DEBUG \
+ m[0] = RAC(ccel,0); \
+ FORDF1 { /* df0 is set later on... */ \
+ if(RFLAG_NB(lev, i,j,k,SRCS(lev),l)&CFBnd) { errMsg("???", "bnd-err-nobndfl"); D::mPanic=1; \
+ } else { m[l] = QCELL_NBINV(lev, i, j, k, SRCS(lev), l, l); } \
+ STREAMCHECK(i+D::dfVecX[D::dfInv[l]], j+D::dfVecY[D::dfInv[l]],k+D::dfVecZ[D::dfInv[l]], l); \
+ } \
+ rho=m[0]; ux = mLevel[lev].gravity[0]; uy = mLevel[lev].gravity[1]; uz = mLevel[lev].gravity[2]; \
+ ux = mLevel[lev].gravity[0]; uy = mLevel[lev].gravity[1]; uz = mLevel[lev].gravity[2]; \
+ D::collideArrays( m, rho,ux,uy,uz, OMEGA(lev), mLevel[lev].lcsmago , &mDebugOmegaRet ); \
+ CSMOMEGA_STATS(lev,mDebugOmegaRet); \
+ FORDF0 { RAC(tcel,l) = m[l]; } \
+ usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
+ COLLCHECK;
+
+
+
+// more debugging
+/*DEBUG \
+ m[0] = RAC(ccel,0); \
+ FORDF1 { \
+ if(RFLAG_NB(lev, i,j,k,SRCS(lev),l)&CFBnd) { errMsg("???", "bnd-err-nobndfl"); D::mPanic=1; \
+ } else { m[l] = QCELL_NBINV(lev, i, j, k, SRCS(lev), l, l); } \
+ } \
+f__printf(stderr,"QSDM at %d,%d,%d lcsmqo=%25.15f, lcsmomega=%f \n", i,j,k, lcsmqo,lcsmomega ); \
+ rho=m[0]; ux = mLevel[lev].gravity[0]; uy = mLevel[lev].gravity[1]; uz = mLevel[lev].gravity[2]; \
+ ux = mLevel[lev].gravity[0]; uy = mLevel[lev].gravity[1]; uz = mLevel[lev].gravity[2]; \
+ D::collideArrays( m, rho,ux,uy,uz, OMEGA(lev), mLevel[lev].lcsmago , &mDebugOmegaRet ); \
+ CSMOMEGA_STATS(lev,mDebugOmegaRet); \
+ */
+#if USE_LES==1
+#define DEFAULT_COLLIDE DEFAULT_COLLIDE_LES
+#define OPTIMIZED_STREAMCOLLIDE OPTIMIZED_STREAMCOLLIDE_LES
+#else
+#define DEFAULT_COLLIDE DEFAULT_COLLIDE_NOLES
+#define OPTIMIZED_STREAMCOLLIDE OPTIMIZED_STREAMCOLLIDE_NOLES
+#endif
+
+#endif
+
+#define USQRMAXCHECK(Cusqr,Cux,Cuy,Cuz, CmMaxVlen,CmMxvx,CmMxvy,CmMxvz) \
+ if(Cusqr>CmMaxVlen) { \
+ CmMxvx = Cux; CmMxvy = Cuy; CmMxvz = Cuz; CmMaxVlen = Cusqr; \
+ } /* stats */
+
+
+// iso value defines
+// border for marching cubes
+#define ISOCORR 3
+
+
+// helper for comparing floats with epsilon
+#define GFX_FLOATNEQ(x,y) ( ABS((x)-(y)) > (VECTOR_EPSILON) )
+#define LBM_FLOATNEQ(x,y) ( ABS((x)-(y)) > (10.0*LBM_EPSILON) )
+
+
+// macros for loops over all DFs
+#define FORDF0 for(int l= 0; l< LBM_DFNUM; ++l)
+#define FORDF1 for(int l= 1; l< LBM_DFNUM; ++l)
+
+/*****************************************************************************/
+/*! cell access classes */
+// WARNING - can be shadowed by class from lbmstdsolver.h 's
+template<typename D>
+class UniformFsgrCellIdentifier :
+ public CellIdentifierInterface
+{
+ public:
+ //! which grid level?
+ int level;
+ //! location in grid
+ int x,y,z;
+
+ //! reset constructor
+ UniformFsgrCellIdentifier() :
+ x(0), y(0), z(0) { };
+
+ // implement CellIdentifierInterface
+ virtual string getAsString() {
+ std::ostringstream ret;
+ ret <<"{ i"<<x<<",j"<<y;
+ if(D::cDimension>2) ret<<",k"<<z;
+ ret <<" }";
+ return ret.str();
+ }
+
+ virtual bool equal(CellIdentifierInterface* other) {
+ //UniformFsgrCellIdentifier<D> *cid = dynamic_cast<UniformFsgrCellIdentifier<D> *>( other );
+ UniformFsgrCellIdentifier<D> *cid = (UniformFsgrCellIdentifier<D> *)( other );
+ if(!cid) return false;
+ if( x==cid->x && y==cid->y && z==cid->z && level==cid->level ) return true;
+ return false;
+ }
+};
+
+//! information needed for each level in the simulation
+class FsgrLevelData {
+public:
+ int id; // level number
+
+ //! node size on this level (geometric, in world coordinates, not simulation units!)
+ LbmFloat nodeSize;
+ //! node size on this level in simulation units
+ LbmFloat simCellSize;
+ //! quadtree node relaxation parameter
+ LbmFloat omega;
+ //! size this level was advanced to
+ LbmFloat time;
+ //! size of a single lbm step in time units on this level
+ LbmFloat stepsize;
+ //! step count
+ int lsteps;
+ //! gravity force for this level
+ LbmVec gravity;
+ //! level array
+ LbmFloat *mprsCells[2];
+ CellFlagType *mprsFlags[2];
+
+ //! smago params and precalculated values
+ LbmFloat lcsmago;
+ LbmFloat lcsmago_sqr;
+ LbmFloat lcnu;
+
+ // LES statistics per level
+ double avgOmega;
+ double avgOmegaCnt;
+
+ //! current set of dist funcs
+ int setCurr;
+ //! target/other set of dist funcs
+ int setOther;
+
+ //! mass&volume for this level
+ LbmFloat lmass;
+ LbmFloat lvolume;
+ LbmFloat lcellfactor;
+
+ //! local storage of mSizes
+ int lSizex, lSizey, lSizez;
+ int lOffsx, lOffsy, lOffsz;
+
+};
+
+
+
+/*****************************************************************************/
+/*! class for solving a LBM problem */
+template<class D>
+class LbmFsgrSolver :
+ public /*? virtual */ D // this means, the solver is a lbmData object and implements the lbmInterface
+{
+
+ public:
+ //! Constructor
+ LbmFsgrSolver();
+ //! Destructor
+ virtual ~LbmFsgrSolver();
+ //! id string of solver
+ virtual string getIdString() { return string("FsgrSolver[") + D::getIdString(); }
+
+ //! initilize variables fom attribute list
+ virtual void parseAttrList();
+ //! Initialize omegas and forces on all levels (for init/timestep change)
+ void initLevelOmegas();
+ //! finish the init with config file values (allocate arrays...)
+ virtual bool initialize( ntlTree* /*tree*/, vector<ntlGeometryObject*>* /*objects*/ );
+
+#if LBM_USE_GUI==1
+ //! show simulation info (implement SimulationObject pure virtual func)
+ virtual void debugDisplay(fluidDispSettings *set);
+#endif
+
+
+ // implement CellIterator<UniformFsgrCellIdentifier> interface
+ typedef UniformFsgrCellIdentifier<typename D::LbmCellContents> stdCellId;
+ virtual CellIdentifierInterface* getFirstCell( );
+ virtual void advanceCell( CellIdentifierInterface* );
+ virtual bool noEndCell( CellIdentifierInterface* );
+ virtual void deleteCellIterator( CellIdentifierInterface** );
+ virtual CellIdentifierInterface* getCellAt( ntlVec3Gfx pos );
+ virtual int getCellSet ( CellIdentifierInterface* );
+ virtual ntlVec3Gfx getCellOrigin ( CellIdentifierInterface* );
+ virtual ntlVec3Gfx getCellSize ( CellIdentifierInterface* );
+ virtual int getCellLevel ( CellIdentifierInterface* );
+ virtual LbmFloat getCellDensity ( CellIdentifierInterface* ,int set);
+ virtual LbmVec getCellVelocity ( CellIdentifierInterface* ,int set);
+ virtual LbmFloat getCellDf ( CellIdentifierInterface* ,int set, int dir);
+ virtual LbmFloat getCellMass ( CellIdentifierInterface* ,int set);
+ virtual LbmFloat getCellFill ( CellIdentifierInterface* ,int set);
+ virtual CellFlagType getCellFlag ( CellIdentifierInterface* ,int set);
+ virtual LbmFloat getEquilDf ( int );
+ virtual int getDfNum ( );
+ // convert pointers
+ stdCellId* convertBaseCidToStdCid( CellIdentifierInterface* basecid);
+
+ //! perform geometry init (if switched on)
+ bool initGeometryFlags();
+ //! init part for all freesurface testcases
+ void initFreeSurfaces();
+ //! init density gradient if enabled
+ void initStandingFluidGradient();
+
+ /*! init a given cell with flag, density, mass and equilibrium dist. funcs */
+ inline void initEmptyCell(int level, int i,int j,int k, CellFlagType flag, LbmFloat rho, LbmFloat mass);
+ void initVelocityCell(int level, int i,int j,int k, CellFlagType flag, LbmFloat rho, LbmFloat mass, LbmVec vel);
+
+ /*! perform a single LBM step */
+ virtual void step() { stepMain(); }
+ void stepMain();
+ void fineAdvance();
+ void coarseAdvance(int lev);
+ void coarseCalculateFluxareas(int lev);
+ // coarsen a given level (returns true if sth. was changed)
+ bool performCoarsening(int lev);
+ bool performRefinement(int lev);
+ //void oarseInterpolateToFineSpaceTime(int lev,LbmFloat t);
+ void interpolateFineFromCoarse(int lev,LbmFloat t);
+ void coarseRestrictFromFine(int lev);
+
+ /*! init particle positions */
+ virtual int initParticles(ParticleTracer *partt);
+ /*! move all particles */
+ virtual void advanceParticles(ParticleTracer *partt );
+
+
+ /*! debug object display (used e.g. for preview surface) */
+ virtual vector<ntlGeometryObject*> getDebugObjects();
+
+ //! access the fillfrac field (for viz)
+ float getFillFrac(int i, int j, int k) {
+ return QCELL(mMaxRefine, i,j,k,mLevel[mMaxRefine].setOther, dFfrac);
+ }
+
+ //! retrieve the fillfrac field ready to display
+ void getIsofieldWeighted(float *iso);
+ void getIsofield(float *iso){ return getIsofieldWeighted(iso); }
+ //! for raytracing, preprocess
+ void prepareVisualization( void );
+
+ // rt interface
+ void addDrop(bool active, float mx, float my);
+ void initDrop(float mx, float my);
+ void printCellStats();
+ int checkGfxEndTime(); // {return 9;};
+ //! get gfx geo setup id
+ int getGfxGeoSetup() { return mGfxGeoSetup; }
+
+ /*! type for cells */
+ typedef typename D::LbmCell LbmCell;
+
+ protected:
+
+ //! internal quick print function (for debugging)
+ void printLbmCell(int level, int i, int j, int k,int set);
+ // debugging use CellIterator interface to mark cell
+ void debugMarkCellCall(int level, int vi,int vj,int vk);
+
+ void mainLoop(int lev);
+ void adaptTimestep();
+ //! flag reinit step - always works on finest grid!
+ void reinitFlags( int workSet );
+ //! mass dist weights
+ LbmFloat getMassdWeight(bool dirForw, int i,int j,int k,int workSet, int l);
+ //! add point to mListNewInter list
+ inline void addToNewInterList( int ni, int nj, int nk );
+ //! cell is interpolated from coarse level (inited into set, source sets are determined by t)
+ inline void interpolateCellFromCoarse(int lev, int i, int j,int k, int dstSet, LbmFloat t, CellFlagType flagSet,bool markNbs);
+
+ //! minimal and maximal z-coords (for 2D/3D loops)
+ int getForZMinBnd(int lev) {
+ return 0;
+ }
+ int getForZMaxBnd(int lev) {
+ if(D::cDimension==2) return 1;
+ //return D::getSizeZ()-0;
+ return mLevel[lev].lSizez -0;
+ }
+ int getForZMin1(int lev) {
+ if(D::cDimension==2) return 0;
+ return 1;
+ }
+ int getForZMax1(int lev) {
+ if(D::cDimension==2) return 1;
+ //return D::getSizeZ()-1;
+ return mLevel[lev].lSizez -1;
+ }
+
+
+ // member vars
+
+ //! mass calculated during streaming step
+ LbmFloat mCurrentMass;
+ LbmFloat mCurrentVolume;
+ LbmFloat mInitialMass;
+
+ //! count problematic cases, that occured so far...
+ int mNumProblems;
+
+ // average mlsups, count how many so far...
+ double mAvgMLSUPS;
+ double mAvgMLSUPSCnt;
+
+ //! Mcubes object for surface reconstruction
+ IsoSurface *mpPreviewSurface;
+ int mLoopSubdivs;
+ float mSmoothSurface;
+ float mSmoothNormals;
+
+ //! use time adaptivity?
+ bool mTimeAdap;
+
+ //! output surface preview? if >0 yes, and use as reduzed size
+ int mOutputSurfacePreview;
+ LbmFloat mPreviewFactor;
+ //! fluid vol height
+ LbmFloat mFVHeight;
+ LbmFloat mFVArea;
+ bool mUpdateFVHeight;
+
+ //! require some geo setup from the viz?
+ int mGfxGeoSetup;
+ //! force quit for gfx
+ LbmFloat mGfxEndTime;
+ //! smoother surface initialization?
+ int mInitSurfaceSmoothing;
+
+ int mTimestepReduceLock;
+ int mTimeSwitchCounts;
+ //! total simulation time so far
+ LbmFloat mSimulationTime;
+ //! smallest and largest step size so far
+ LbmFloat mMinStepTime, mMaxStepTime;
+ //! track max. velocity
+ LbmFloat mMxvx, mMxvy, mMxvz, mMaxVlen;
+
+ //! list of the cells to empty at the end of the step
+ vector<LbmPoint> mListEmpty;
+ //! list of the cells to make fluid at the end of the step
+ vector<LbmPoint> mListFull;
+ //! list of new interface cells to init
+ vector<LbmPoint> mListNewInter;
+ //! class for handling redist weights in reinit flag function
+ class lbmFloatSet {
+ public:
+ LbmFloat val[dTotalNum];
+ };
+ //! normalized vectors for all neighboring cell directions (for e.g. massdweight calc)
+ LbmVec mDvecNrm[27];
+
+
+ //! debugging
+ bool checkSymmetry(string idstring);
+ //! symmetric init?
+ //bool mStartSymm;
+ //! kepp track of max/min no. of filled cells
+ int mMaxNoCells, mMinNoCells;
+ long long int mAvgNumUsedCells;
+
+ //! for interactive - how to drop drops?
+ int mDropMode;
+ LbmFloat mDropSize;
+ LbmVec mDropSpeed;
+ //! dropping variables
+ bool mDropping;
+ LbmFloat mDropX, mDropY;
+ LbmFloat mDropHeight;
+
+ //! get isofield weights
+ int mIsoWeightMethod;
+ float mIsoWeight[27];
+
+ // grid coarsening vars
+
+ /*! vector for the data for each level */
+# define MAX_LEV 5
+ FsgrLevelData mLevel[MAX_LEV];
+
+ /*! minimal and maximal refinement levels */
+ int mMaxRefine;
+
+ /*! df scale factors for level up/down */
+ LbmFloat mDfScaleUp, mDfScaleDown;
+
+ /*! precomputed cell area values */
+ LbmFloat mFsgrCellArea[27];
+
+ /*! LES C_smago paramter for finest grid */
+ float mInitialCsmago;
+ float mCsmagoRefineMultiplier;
+ /*! LES stats for non OPT3D */
+ LbmFloat mDebugOmegaRet;
+
+ //! fluid stats
+ int mNumInterdCells;
+ int mNumInvIfCells;
+ int mNumInvIfTotal;
+
+ //! debug function to disable standing f init
+ int mDisableStandingFluidInit;
+ //! debug function to force tadap syncing
+ int mForceTadapRefine;
+
+
+# if FSGR_STRICT_DEBUG==1
+# define STRICT_EXIT *((int *)0)=0;
+ int debLBMGI(int level, int ii,int ij,int ik, int is) {
+ if(level < 0){ errMsg("LbmStrict::debLBMGI"," invLev- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+ if(level > mMaxRefine){ errMsg("LbmStrict::debLBMGI"," invLev+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+
+ if(ii<0){ errMsg("LbmStrict"," invX- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+ if(ij<0){ errMsg("LbmStrict"," invY- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+ if(ik<0){ errMsg("LbmStrict"," invZ- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+ if(ii>mLevel[level].lSizex-1){ errMsg("LbmStrict"," invX+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+ if(ij>mLevel[level].lSizey-1){ errMsg("LbmStrict"," invY+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+ if(ik>mLevel[level].lSizez-1){ errMsg("LbmStrict"," invZ+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+ if(is<0){ errMsg("LbmStrict"," invS- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+ if(is>1){ errMsg("LbmStrict"," invS+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+ return _LBMGI(level, ii,ij,ik, is);
+ };
+ CellFlagType& debRFLAG(int level, int xx,int yy,int zz,int set){
+ return _RFLAG(level, xx,yy,zz,set);
+ };
+ CellFlagType& debRFLAG_NB(int level, int xx,int yy,int zz,int set, int dir) {
+ if(dir<0) { errMsg("LbmStrict"," invD- l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
+ // warning might access all spatial nbs
+ if(dir>D::cDirNum){ errMsg("LbmStrict"," invD+ l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
+ return _RFLAG_NB(level, xx,yy,zz,set, dir);
+ };
+ CellFlagType& debRFLAG_NBINV(int level, int xx,int yy,int zz,int set, int dir) {
+ if(dir<0) { errMsg("LbmStrict"," invD- l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
+ if(dir>D::cDirNum){ errMsg("LbmStrict"," invD+ l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
+ return _RFLAG_NBINV(level, xx,yy,zz,set, dir);
+ };
+ int debLBMQI(int level, int ii,int ij,int ik, int is, int l) {
+ if(level < 0){ errMsg("LbmStrict::debLBMQI"," invLev- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+ if(level > mMaxRefine){ errMsg("LbmStrict::debLBMQI"," invLev+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+
+ if(ii<0){ errMsg("LbmStrict"," invX- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+ if(ij<0){ errMsg("LbmStrict"," invY- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+ if(ik<0){ errMsg("LbmStrict"," invZ- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+ if(ii>mLevel[level].lSizex-1){ errMsg("LbmStrict"," invX+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+ if(ij>mLevel[level].lSizey-1){ errMsg("LbmStrict"," invY+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+ if(ik>mLevel[level].lSizez-1){ errMsg("LbmStrict"," invZ+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+ if(is<0){ errMsg("LbmStrict"," invS- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+ if(is>1){ errMsg("LbmStrict"," invS+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
+ if(l<0) { errMsg("LbmStrict"," invD- "<<" l"<<l); STRICT_EXIT; }
+ if(l>D::cDfNum){ // dFfrac is an exception
+ if((l != dMass) && (l != dFfrac) && (l != dFlux)){ errMsg("LbmStrict"," invD+ "<<" l"<<l); STRICT_EXIT; } }
+#if COMPRESSGRIDS==1
+ //if((!D::mInitDone) && (is!=mLevel[level].setCurr)){ STRICT_EXIT; } // COMPRT debug
+#endif // COMPRESSGRIDS==1
+ return _LBMQI(level, ii,ij,ik, is, l);
+ };
+ LbmFloat& debQCELL(int level, int xx,int yy,int zz,int set,int l) {
+ //errMsg("LbmStrict","debQCELL debug: l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" l"<<l<<" index"<<LBMGI(level, xx,yy,zz,set));
+ return _QCELL(level, xx,yy,zz,set,l);
+ };
+ LbmFloat& debQCELL_NB(int level, int xx,int yy,int zz,int set, int dir,int l) {
+ if(dir<0) { errMsg("LbmStrict"," invD- l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
+ if(dir>D::cDfNum){ errMsg("LbmStrict"," invD+ l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
+ return _QCELL_NB(level, xx,yy,zz,set, dir,l);
+ };
+ LbmFloat& debQCELL_NBINV(int level, int xx,int yy,int zz,int set, int dir,int l) {
+ if(dir<0) { errMsg("LbmStrict"," invD- l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
+ if(dir>D::cDfNum){ errMsg("LbmStrict"," invD+ l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
+ return _QCELL_NBINV(level, xx,yy,zz,set, dir,l);
+ };
+ LbmFloat* debRACPNT(int level, int ii,int ij,int ik, int is ) {
+ return _RACPNT(level, ii,ij,ik, is );
+ };
+ LbmFloat& debRAC(LbmFloat* s,int l) {
+ if(l<0) { errMsg("LbmStrict"," invD- "<<" l"<<l); STRICT_EXIT; }
+ if(l>dTotalNum){ errMsg("LbmStrict"," invD+ "<<" l"<<l); STRICT_EXIT; }
+ //if(l>D::cDfNum){ // dFfrac is an exception
+ //if((l != dMass) && (l != dFfrac) && (l != dFlux)){ errMsg("LbmStrict"," invD+ "<<" l"<<l); STRICT_EXIT; } }
+ return _RAC(s,l);
+ };
+# endif // FSGR_STRICT_DEBUG==1
+};
+
+
+
+/*****************************************************************************/
+// compilation settings
+
+
+// loops over _all_ cells (including boundary layer)
+#define FSGR_FORIJK_BOUNDS(leveli) \
+ for(int k= getForZMinBnd(leveli); k< getForZMaxBnd(leveli); ++k) \
+ for(int j=0;j<mLevel[leveli].lSizey-0;++j) \
+ for(int i=0;i<mLevel[leveli].lSizex-0;++i) \
+
+// loops over _only inner_ cells
+#define FSGR_FORIJK1(leveli) \
+ for(int k= getForZMin1(leveli); k< getForZMax1(leveli); ++k) \
+ for(int j=1;j<mLevel[leveli].lSizey-1;++j) \
+ for(int i=1;i<mLevel[leveli].lSizex-1;++i) \
+
+
+/******************************************************************************
+ * Lbm Constructor
+ *****************************************************************************/
+template<class D>
+LbmFsgrSolver<D>::LbmFsgrSolver() :
+ D(),
+ mCurrentMass(0.0), mCurrentVolume(0.0),
+ mNumProblems(0),
+ mAvgMLSUPS(0.0), mAvgMLSUPSCnt(0.0),
+ mpPreviewSurface(NULL),
+ mLoopSubdivs(0), mSmoothSurface(0.0), mSmoothNormals(0.0),
+ mTimeAdap(false),
+ mOutputSurfacePreview(0), mPreviewFactor(0.25),
+ mFVHeight(0.0), mFVArea(1.0), mUpdateFVHeight(false),
+ mGfxGeoSetup(0), mGfxEndTime(-1.0), mInitSurfaceSmoothing(0),
+ mTimestepReduceLock(0),
+ mTimeSwitchCounts(0),
+ mSimulationTime(0.0),
+ mMinStepTime(0.0), mMaxStepTime(0.0),
+ mMaxNoCells(0), mMinNoCells(0), mAvgNumUsedCells(0),
+ mDropMode(1), mDropSize(0.15), mDropSpeed(0.0),
+ mDropping(false),
+ mDropX(0.0), mDropY(0.0), mDropHeight(0.8),
+ mIsoWeightMethod(2),
+ mMaxRefine(1),
+ mDfScaleUp(-1.0), mDfScaleDown(-1.0),
+ mInitialCsmago(0.04), mCsmagoRefineMultiplier(8.0), mDebugOmegaRet(0.0),
+ mNumInvIfTotal(0),
+ mDisableStandingFluidInit(0),
+ mForceTadapRefine(-1)
+{
+ /* not much to do here... */
+ D::mpIso = new IsoSurface( D::mIsoValue, false );
+
+ /* init equilibrium dist. func */
+ LbmFloat rho=1.0;
+ FORDF0 {
+ D::dfEquil[l] = D::getCollideEq( l,rho, 0.0, 0.0, 0.0);
+ }
+
+ int odm = 0;
+ for(int m=0; m<D::cDimension; m++) {
+ for(int l=0; l<D::cDfNum; l++) {
+ D::lesCoeffDiag[m][l] =
+ D::lesCoeffOffdiag[m][l] = 0.0;
+ }
+ }
+ for(int m=0; m<D::cDimension; m++) {
+ for(int n=0; n<D::cDimension; n++) {
+ //LbmFloat qadd = 0.0;
+ for(int l=1; l<D::cDfNum; l++) {
+ LbmFloat em;
+ switch(m) {
+ case 0: em = D::dfDvecX[l]; break;
+ case 1: em = D::dfDvecY[l]; break;
+ case 2: em = D::dfDvecZ[l]; break;
+ default: em = -1.0; errMsg("SMAGO","err m="<<m); exit(1);
+ }
+ LbmFloat en;
+ switch(n) {
+ case 0: en = D::dfDvecX[l]; break;
+ case 1: en = D::dfDvecY[l]; break;
+ case 2: en = D::dfDvecZ[l]; break;
+ default: en = -1.0; errMsg("SMAGO","err n="<<n); exit(1);
+ }
+ const LbmFloat coeff = em*en;
+ if(m==n) {
+ D::lesCoeffDiag[m][l] = coeff;
+ // f__printf(stderr,"QSMDEB: CF DIAG m:%d l:%d = %f \n", m,l, coeff);
+ } else {
+ if(m>n) {
+ D::lesCoeffOffdiag[odm][l] = coeff;
+ // f__printf(stderr,"QSMDEB: CF OFFDIAG odm:%d l:%d = %f \n", odm,l, coeff);
+ }
+ }
+ }
+
+
+ if(m==n) {
+ } else {
+ if(m>n) odm++;
+ }
+ }
+ }
+
+ mDvecNrm[0] = LbmVec(0.0);
+ FORDF1 {
+ mDvecNrm[l] = getNormalized(
+ LbmVec(D::dfDvecX[D::dfInv[l]], D::dfDvecY[D::dfInv[l]], D::dfDvecZ[D::dfInv[l]] )
+ ) * -1.0;
+ }
+
+ addDrop(false,0,0);
+}
+
+/*****************************************************************************/
+/* Destructor */
+/*****************************************************************************/
+template<class D>
+LbmFsgrSolver<D>::~LbmFsgrSolver()
+{
+ if(!D::mInitDone){ debugOut("LbmFsgrSolver::LbmFsgrSolver : not inited...",0); return; }
+
+#if COMPRESSGRIDS==1
+ delete mLevel[mMaxRefine].mprsCells[1];
+ mLevel[mMaxRefine].mprsCells[0] = mLevel[mMaxRefine].mprsCells[1] = NULL;
+#endif // COMPRESSGRIDS==1
+
+ for(int i=0; i<=mMaxRefine; i++) {
+ for(int s=0; s<2; s++) {
+ if(mLevel[i].mprsCells[s]) delete [] mLevel[i].mprsCells[s];
+ if(mLevel[i].mprsFlags[s]) delete [] mLevel[i].mprsFlags[s];
+ }
+ }
+ delete D::mpIso;
+ if(mpPreviewSurface) delete mpPreviewSurface;
+
+ // always output performance estimate
+ debMsgStd("LbmFsgrSolver::~LbmFsgrSolver",DM_MSG," Avg. MLSUPS:"<<(mAvgMLSUPS/mAvgMLSUPSCnt), 5);
+ if(!D::mSilent) debMsgStd("LbmFsgrSolver::~LbmFsgrSolver",DM_MSG,"Deleted...",10);
+}
+
+
+
+
+/******************************************************************************
+ * initilize variables fom attribute list
+ *****************************************************************************/
+template<class D>
+void
+LbmFsgrSolver<D>::parseAttrList()
+{
+ LbmSolverInterface::parseStdAttrList();
+
+ string matIso("default");
+ matIso = D::mpAttrs->readString("material_surf", matIso, "SimulationLbm","mpIso->material", false );
+ D::mpIso->setMaterialName( matIso );
+ mOutputSurfacePreview = D::mpAttrs->readInt("surfacepreview", mOutputSurfacePreview, "SimulationLbm","mOutputSurfacePreview", false );
+ mTimeAdap = D::mpAttrs->readBool("timeadap", mTimeAdap, "SimulationLbm","mTimeAdap", false );
+
+ mIsoWeightMethod= D::mpAttrs->readInt("isoweightmethod", mIsoWeightMethod, "SimulationLbm","mIsoWeightMethod", false );
+ mInitSurfaceSmoothing = D::mpAttrs->readInt("initsurfsmooth", mInitSurfaceSmoothing, "SimulationLbm","mInitSurfaceSmoothing", false );
+ mLoopSubdivs = D::mpAttrs->readInt("loopsubdivs", mLoopSubdivs, "SimulationLbm","mLoopSubdivs", false );
+ mSmoothSurface = D::mpAttrs->readFloat("smoothsurface", mSmoothSurface, "SimulationLbm","mSmoothSurface", false );
+ mSmoothNormals = D::mpAttrs->readFloat("smoothnormals", mSmoothNormals, "SimulationLbm","mSmoothNormals", false );
+
+ mInitialCsmago = D::mpAttrs->readFloat("csmago", mInitialCsmago, "SimulationLbm","mInitialCsmago", false );
+ mCsmagoRefineMultiplier = D::mpAttrs->readFloat("csmago_refinemultiplier", mCsmagoRefineMultiplier, "SimulationLbm","mCsmagoRefineMultiplier", false );
+
+ // refinement
+ mMaxRefine = D::mpAttrs->readInt("maxrefine", mMaxRefine ,"LbmFsgrSolver", "mMaxRefine", true);
+ mDisableStandingFluidInit = D::mpAttrs->readInt("disable_stfluidinit", mDisableStandingFluidInit,"LbmFsgrSolver", "mDisableStandingFluidInit", false);
+ mForceTadapRefine = D::mpAttrs->readInt("forcetadaprefine", mForceTadapRefine,"LbmFsgrSolver", "mForceTadapRefine", false);
+
+ // demo mode settings
+ mDropMode = D::mpAttrs->readInt("dropmode", mDropMode, "SimulationLbm","mDropMode", false );
+ mDropSize = D::mpAttrs->readFloat("dropsize", mDropSize, "SimulationLbm","mDropSize", false );
+ mDropHeight = D::mpAttrs->readFloat("dropheight", mDropHeight, "SimulationLbm","mDropHeight", false );
+ mDropSpeed = vec2L( D::mpAttrs->readVec3d("dropspeed", ntlVec3d(0.0), "SimulationLbm","mDropSpeed", false ) );
+ if( (mDropMode>2) || (mDropMode<-1) ) mDropMode=1;
+ mGfxGeoSetup = D::mpAttrs->readInt("gfxgeosetup", mGfxGeoSetup, "SimulationLbm","mGfxGeoSetup", false );
+ mGfxEndTime = D::mpAttrs->readFloat("gfxendtime", mGfxEndTime, "SimulationLbm","mGfxEndTime", false );
+ mFVHeight = D::mpAttrs->readFloat("fvolheight", mFVHeight, "SimulationLbm","mFVHeight", false );
+ mFVArea = D::mpAttrs->readFloat("fvolarea", mFVArea, "SimulationLbm","mFArea", false );
+
+}
+
+
+/******************************************************************************
+ * Initialize omegas and forces on all levels (for init/timestep change)
+ *****************************************************************************/
+template<class D>
+void
+LbmFsgrSolver<D>::initLevelOmegas()
+{
+ // no explicit settings
+ D::mOmega = D::mpParam->calculateOmega();
+ D::mGravity = vec2L( D::mpParam->calculateGravity() );
+ D::mSurfaceTension = D::mpParam->calculateSurfaceTension(); // unused
+
+ if(mInitialCsmago<=0.0) {
+ if(OPT3D==1) {
+ errMsg("LbmFsgrSolver::initLevelOmegas","Csmago-LES = 0 not supported for optimized 3D version...");
+ exit(1);
+ }
+ }
+
+ // use Tau instead of Omega for calculations
+ int i = mMaxRefine;
+ mLevel[i].omega = D::mOmega;
+ mLevel[i].stepsize = D::mpParam->getStepTime();
+ mLevel[i].lcsmago = mInitialCsmago; //CSMAGO_INITIAL;
+ mLevel[i].lcsmago_sqr = mLevel[i].lcsmago*mLevel[i].lcsmago;
+ mLevel[i].lcnu = (2.0* (1.0/mLevel[i].omega)-1.0) * (1.0/6.0);
+
+ // init all sub levels
+ for(int i=mMaxRefine-1; i>=0; i--) {
+ //mLevel[i].omega = 2.0 * (mLevel[i+1].omega-0.5) + 0.5;
+ double nomega = 0.5 * ( (1.0/(double)mLevel[i+1].omega) -0.5) + 0.5;
+ nomega = 1.0/nomega;
+ mLevel[i].omega = (LbmFloat)nomega;
+ mLevel[i].stepsize = 2.0 * mLevel[i+1].stepsize;
+ mLevel[i].lcsmago = mLevel[i+1].lcsmago*mCsmagoRefineMultiplier;
+ mLevel[i].lcsmago_sqr = mLevel[i].lcsmago*mLevel[i].lcsmago;
+ mLevel[i].lcnu = (2.0* (1.0/mLevel[i].omega)-1.0) * (1.0/6.0);
+ }
+
+ // for lbgk
+ mLevel[ mMaxRefine ].gravity = D::mGravity / mLevel[ mMaxRefine ].omega;
+ for(int i=mMaxRefine-1; i>=0; i--) {
+ // should be the same on all levels...
+ // for lbgk
+ mLevel[i].gravity = (mLevel[i+1].gravity * mLevel[i+1].omega) * 2.0 / mLevel[i].omega;
+ }
+
+ // debug? invalidate old values...
+ D::mGravity = -100.0;
+ D::mOmega = -100.0;
+
+ for(int i=0; i<=mMaxRefine; i++) {
+ if(!D::mSilent) {
+ errMsg("LbmFsgrSolver", "Level init "<<i<<" - sizes:"<<mLevel[i].lSizex<<","<<mLevel[i].lSizey<<","<<mLevel[i].lSizez<<" offs:"<<mLevel[i].lOffsx<<","<<mLevel[i].lOffsy<<","<<mLevel[i].lOffsz
+ <<" omega:"<<mLevel[i].omega<<" grav:"<<mLevel[i].gravity<< ", "
+ <<" cmsagp:"<<mLevel[i].lcsmago<<", "
+ << " ss"<<mLevel[i].stepsize<<" ns"<<mLevel[i].nodeSize<<" cs"<<mLevel[i].simCellSize );
+ } else {
+ if(!D::mInitDone) {
+ debMsgStd("LbmFsgrSolver", DM_MSG, "Level init "<<i<<" - sizes:"<<mLevel[i].lSizex<<","<<mLevel[i].lSizey<<","<<mLevel[i].lSizez<<" "
+ <<"omega:"<<mLevel[i].omega<<" grav:"<<mLevel[i].gravity , 5);
+ }
+ }
+ }
+ if(mMaxRefine>0) {
+ mDfScaleUp = (mLevel[0 ].stepsize/mLevel[0+1].stepsize)* (1.0/mLevel[0 ].omega-1.0)/ (1.0/mLevel[0+1].omega-1.0); // yu
+ mDfScaleDown = (mLevel[0+1].stepsize/mLevel[0 ].stepsize)* (1.0/mLevel[0+1].omega-1.0)/ (1.0/mLevel[0 ].omega-1.0); // yu
+ }
+}
+
+
+/******************************************************************************
+ * Init Solver (values should be read from config file)
+ *****************************************************************************/
+template<class D>
+bool
+LbmFsgrSolver<D>::initialize( ntlTree* /*tree*/, vector<ntlGeometryObject*>* /*objects*/ )
+{
+ debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Init start... (Layout:"<<ALSTRING<<") ",1);
+
+ // fix size inits to force cubic cells and mult4 level dimensions
+ const int debugGridsizeInit = 1;
+ mPreviewFactor = (LbmFloat)mOutputSurfacePreview / (LbmFloat)D::mSizex;
+ int maxGridSize = D::mSizex; // get max size
+ if(D::mSizey>maxGridSize) maxGridSize = D::mSizey;
+ if(D::mSizez>maxGridSize) maxGridSize = D::mSizez;
+ LbmFloat maxGeoSize = (D::mvGeoEnd[0]-D::mvGeoStart[0]); // get max size
+ if((D::mvGeoEnd[1]-D::mvGeoStart[1])>maxGridSize) maxGeoSize = (D::mvGeoEnd[1]-D::mvGeoStart[1]);
+ if((D::mvGeoEnd[2]-D::mvGeoStart[2])>maxGridSize) maxGeoSize = (D::mvGeoEnd[2]-D::mvGeoStart[2]);
+ // FIXME better divide max geo size by corresponding resolution rather than max? no prob for rx==ry==rz though
+ LbmFloat cellSize = (maxGeoSize / (LbmFloat)maxGridSize);
+ if(debugGridsizeInit) debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Start:"<<D::mvGeoStart<<" End:"<<D::mvGeoEnd<<" maxS:"<<maxGeoSize<<" maxG:"<<maxGridSize<<" cs:"<<cellSize, 10);
+ // force grid sizes according to geom. size, rounded
+ D::mSizex = (int) ((D::mvGeoEnd[0]-D::mvGeoStart[0]) / cellSize +0.5);
+ D::mSizey = (int) ((D::mvGeoEnd[1]-D::mvGeoStart[1]) / cellSize +0.5);
+ D::mSizez = (int) ((D::mvGeoEnd[2]-D::mvGeoStart[2]) / cellSize +0.5);
+ // match refinement sizes, round downwards to multiple of 4
+ int sizeMask = 0;
+ int maskBits = mMaxRefine;
+ if(PARALLEL==1) maskBits+=2;
+ for(int i=0; i<maskBits; i++) { sizeMask |= (1<<i); }
+ sizeMask = ~sizeMask;
+ if(debugGridsizeInit) debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Size X:"<<D::mSizex<<" Y:"<<D::mSizey<<" Z:"<<D::mSizez<<" m"<<convertFlags2String(sizeMask) ,10);
+ D::mSizex &= sizeMask;
+ D::mSizey &= sizeMask;
+ D::mSizez &= sizeMask;
+ if(PARALLEL==1) {
+ // make (size+2)%4 == 0 , assumes MAX_THREADS=4
+ D::mSizex += 2;
+ D::mSizey += 2;
+ D::mSizez += 2;
+ }
+ // force geom size to match rounded grid sizes
+ D::mvGeoEnd[0] = D::mvGeoStart[0] + cellSize*(LbmFloat)D::mSizex;
+ D::mvGeoEnd[1] = D::mvGeoStart[1] + cellSize*(LbmFloat)D::mSizey;
+ D::mvGeoEnd[2] = D::mvGeoStart[2] + cellSize*(LbmFloat)D::mSizez;
+
+ debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Final domain size X:"<<D::mSizex<<" Y:"<<D::mSizey<<" Z:"<<D::mSizez<<
+ ", Domain: "<<D::mvGeoStart<<":"<<D::mvGeoEnd<<", "<<(D::mvGeoEnd-D::mvGeoStart) ,2);
+ //debMsgStd("LbmFsgrSolver::initialize",DM_MSG, ,2);
+ D::mpParam->setSize(D::mSizex, D::mSizey, D::mSizez);
+
+ //debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Size X:"<<D::mSizex<<" Y:"<<D::mSizey<<" Z:"<<D::mSizez ,2);
+
+#if ELBEEM_BLENDER!=1
+ debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Definitions: "
+ <<"LBM_EPSILON="<<LBM_EPSILON <<" "
+ <<"FSGR_STRICT_DEBUG="<<FSGR_STRICT_DEBUG <<" "
+ <<"INTORDER="<<INTORDER <<" "
+ <<"TIMEINTORDER="<<TIMEINTORDER <<" "
+ <<"REFINEMENTBORDER="<<REFINEMENTBORDER <<" "
+ <<"INTCFCOARSETEST="<<INTCFCOARSETEST<<" "
+ <<"OPT3D="<<OPT3D <<" "
+ <<"COMPRESSGRIDS="<<COMPRESSGRIDS<<" "
+ <<"LS_FLUIDTHRESHOLD="<<LS_FLUIDTHRESHOLD <<" "
+ <<"MASS_INVALID="<<MASS_INVALID <<" "
+ <<"FSGR_LISTTRICK="<<FSGR_LISTTRICK <<" "
+ <<"FSGR_LISTTTHRESHEMPTY="<<FSGR_LISTTTHRESHEMPTY <<" "
+ <<"FSGR_LISTTTHRESHFULL="<<FSGR_LISTTTHRESHFULL <<" "
+ <<"FSGR_MAGICNR="<<FSGR_MAGICNR <<" "
+ <<"USE_LES="<<USE_LES <<" "
+ ,10);
+#endif // ELBEEM_BLENDER!=1
+
+ // perform 2D corrections...
+ if(D::cDimension == 2) D::mSizez = 1;
+
+ D::mpParam->setSimulationMaxSpeed(0.0);
+ if(mFVHeight>0.0) D::mpParam->setFluidVolumeHeight(mFVHeight);
+ D::mpParam->setTadapLevels( mMaxRefine+1 );
+
+ if(mForceTadapRefine>mMaxRefine) {
+ D::mpParam->setTadapLevels( mForceTadapRefine+1 );
+ debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Forcing a t-adap refine level of "<<mForceTadapRefine, 6);
+ }
+
+ if(!D::mpParam->calculateAllMissingValues()) {
+ errMsg("LbmFsgrSolver::initialize","Fatal: failed to init parameters! Aborting...");
+ exit(1);
+ }
+
+
+
+ // init vectors
+ if(mMaxRefine >= MAX_LEV) {
+ errMsg("LbmFsgrSolver::initializeLbmGridref"," error: Too many levels!");
+ exit(1);
+ }
+ for(int i=0; i<=mMaxRefine; i++) {
+ mLevel[i].id = i;
+ mLevel[i].nodeSize = 0.0;
+ mLevel[i].simCellSize = 0.0;
+ mLevel[i].omega = 0.0;
+ mLevel[i].time = 0.0;
+ mLevel[i].stepsize = 1.0;
+ mLevel[i].gravity = LbmVec(0.0);
+ mLevel[i].mprsCells[0] = NULL;
+ mLevel[i].mprsCells[1] = NULL;
+ mLevel[i].mprsFlags[0] = NULL;
+ mLevel[i].mprsFlags[1] = NULL;
+
+ mLevel[i].avgOmega = 0.0;
+ mLevel[i].avgOmegaCnt = 0.0;
+ }
+
+ // init sizes
+ mLevel[mMaxRefine].lSizex = D::mSizex;
+ mLevel[mMaxRefine].lSizey = D::mSizey;
+ mLevel[mMaxRefine].lSizez = D::mSizez;
+ for(int i=mMaxRefine-1; i>=0; i--) {
+ mLevel[i].lSizex = mLevel[i+1].lSizex/2;
+ mLevel[i].lSizey = mLevel[i+1].lSizey/2;
+ mLevel[i].lSizez = mLevel[i+1].lSizez/2;
+ if(
+ ((mLevel[i].lSizex % 4) != 0) ||
+ ((mLevel[i].lSizey % 4) != 0) ||
+ ((mLevel[i].lSizez % 4) != 0) ) {
+ errMsg("LbmFsgrSolver","Init: error invalid sizes on level "<<i<<" "<<PRINT_VEC(mLevel[i].lSizex,mLevel[i].lSizey,mLevel[i].lSizez) );
+ exit(1);
+ }
+ }
+
+ // estimate memory usage
+ {
+ unsigned long int memCnt = 0;
+ unsigned long int rcellSize = ((mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*mLevel[mMaxRefine].lSizez) *dTotalNum);
+ memCnt += sizeof(CellFlagType) * (rcellSize/dTotalNum +4) *2;
+#if COMPRESSGRIDS==0
+ memCnt += sizeof(LbmFloat) * (rcellSize +4) *2;
+#else // COMPRESSGRIDS==0
+ unsigned long int compressOffset = (mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*dTotalNum*2);
+ memCnt += sizeof(LbmFloat) * (rcellSize+compressOffset +4);
+#endif // COMPRESSGRIDS==0
+ for(int i=mMaxRefine-1; i>=0; i--) {
+ rcellSize = ((mLevel[i].lSizex*mLevel[i].lSizey*mLevel[i].lSizez) *dTotalNum);
+ memCnt += sizeof(CellFlagType) * (rcellSize/dTotalNum +4) *2;
+ memCnt += sizeof(LbmFloat) * (rcellSize +4) *2;
+ }
+ double memd = memCnt;
+ char *sizeStr = "";
+ const double sfac = 1000.0;
+ if(memd>sfac){ memd /= sfac; sizeStr="KB"; }
+ if(memd>sfac){ memd /= sfac; sizeStr="MB"; }
+ if(memd>sfac){ memd /= sfac; sizeStr="GB"; }
+ if(memd>sfac){ memd /= sfac; sizeStr="TB"; }
+ debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Required Grid memory: "<< memd <<" "<< sizeStr<<" ",4);
+ }
+
+ mLevel[ mMaxRefine ].nodeSize = ((D::mvGeoEnd[0]-D::mvGeoStart[0]) / (LbmFloat)(D::mSizex));
+ mLevel[ mMaxRefine ].simCellSize = D::mpParam->getCellSize();
+ mLevel[ mMaxRefine ].lcellfactor = 1.0;
+ unsigned long int rcellSize = ((mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*mLevel[mMaxRefine].lSizez) *dTotalNum);
+ // +4 for safety ?
+ mLevel[ mMaxRefine ].mprsFlags[0] = new CellFlagType[ rcellSize/dTotalNum +4 ];
+ mLevel[ mMaxRefine ].mprsFlags[1] = new CellFlagType[ rcellSize/dTotalNum +4 ];
+
+#if COMPRESSGRIDS==0
+ mLevel[ mMaxRefine ].mprsCells[0] = new LbmFloat[ rcellSize +4 ];
+ mLevel[ mMaxRefine ].mprsCells[1] = new LbmFloat[ rcellSize +4 ];
+#else // COMPRESSGRIDS==0
+ unsigned long int compressOffset = (mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*dTotalNum*2);
+ mLevel[ mMaxRefine ].mprsCells[1] = new LbmFloat[ rcellSize +compressOffset +4 ];
+ mLevel[ mMaxRefine ].mprsCells[0] = mLevel[ mMaxRefine ].mprsCells[1]+compressOffset;
+#endif // COMPRESSGRIDS==0
+
+ for(int i=mMaxRefine-1; i>=0; i--) {
+ mLevel[i].nodeSize = 2.0 * mLevel[i+1].nodeSize;
+ mLevel[i].simCellSize = 2.0 * mLevel[i+1].simCellSize;
+ LbmFloat dimFac = 8.0;
+ if(D::cDimension==2) dimFac = 4.0;
+ mLevel[i].lcellfactor = mLevel[i+1].lcellfactor * dimFac;
+
+ if(D::cDimension==2){ mLevel[i].lSizez = 1; } // 2D
+ rcellSize = ((mLevel[i].lSizex*mLevel[i].lSizey*mLevel[i].lSizez) *dTotalNum);
+ mLevel[i].mprsFlags[0] = new CellFlagType[ rcellSize/dTotalNum +4 ];
+ mLevel[i].mprsFlags[1] = new CellFlagType[ rcellSize/dTotalNum +4 ];
+ mLevel[i].mprsCells[0] = new LbmFloat[ rcellSize +4 ];
+ mLevel[i].mprsCells[1] = new LbmFloat[ rcellSize +4 ];
+ }
+
+ // init sizes for _all_ levels
+ for(int i=mMaxRefine; i>=0; i--) {
+ mLevel[i].lOffsx = mLevel[i].lSizex;
+ mLevel[i].lOffsy = mLevel[i].lOffsx*mLevel[i].lSizey;
+ mLevel[i].lOffsz = mLevel[i].lOffsy*mLevel[i].lSizez;
+ mLevel[i].setCurr = 0;
+ mLevel[i].setOther = 1;
+ mLevel[i].lsteps = 0;
+ mLevel[i].lmass = 0.0;
+ mLevel[i].lvolume = 0.0;
+ }
+
+ // calc omega, force for all levels
+ initLevelOmegas();
+ mMinStepTime = D::mpParam->getStepTime();
+ mMaxStepTime = D::mpParam->getStepTime();
+
+ // init isosurf
+ D::mpIso->setIsolevel( D::mIsoValue );
+ D::mpIso->setLoopSubdivs( mLoopSubdivs );
+ // approximate feature size with mesh resolution
+ float featureSize = mLevel[ mMaxRefine ].nodeSize*0.5;
+ D::mpIso->setSmoothSurface( mSmoothSurface * featureSize );
+ D::mpIso->setSmoothNormals( mSmoothNormals * featureSize );
+
+ // init iso weight values mIsoWeightMethod
+ int wcnt = 0;
+ float totw = 0.0;
+ for(int ak=-1;ak<=1;ak++)
+ for(int aj=-1;aj<=1;aj++)
+ for(int ai=-1;ai<=1;ai++) {
+ switch(mIsoWeightMethod) {
+ case 1: // light smoothing
+ mIsoWeight[wcnt] = sqrt(3.0) - sqrt( (LbmFloat)(ak*ak + aj*aj + ai*ai) );
+ break;
+ case 2: // very light smoothing
+ mIsoWeight[wcnt] = sqrt(3.0) - sqrt( (LbmFloat)(ak*ak + aj*aj + ai*ai) );
+ mIsoWeight[wcnt] *= mIsoWeight[wcnt];
+ break;
+ case 3: // no smoothing
+ if(ai==0 && aj==0 && ak==0) mIsoWeight[wcnt] = 1.0;
+ else mIsoWeight[wcnt] = 0.0;
+ break;
+ default: // strong smoothing (=0)
+ mIsoWeight[wcnt] = 1.0;
+ break;
+ }
+ totw += mIsoWeight[wcnt];
+ wcnt++;
+ }
+ for(int i=0; i<27; i++) mIsoWeight[i] /= totw;
+
+ LbmVec isostart = vec2L(D::mvGeoStart);
+ LbmVec isoend = vec2L(D::mvGeoEnd);
+ int twodOff = 0; // 2d slices
+ if(D::cDimension==2) {
+ LbmFloat sn,se;
+ sn = isostart[2]+(isoend[2]-isostart[2])*0.5 - ((isoend[0]-isostart[0]) / (LbmFloat)(D::mSizex+1.0))*0.5;
+ se = isostart[2]+(isoend[2]-isostart[2])*0.5 + ((isoend[0]-isostart[0]) / (LbmFloat)(D::mSizex+1.0))*0.5;
+ isostart[2] = sn;
+ isoend[2] = se;
+ twodOff = 2;
+ }
+ //errMsg(" SETISO ", " "<<isostart<<" - "<<isoend<<" "<<(((isoend[0]-isostart[0]) / (LbmFloat)(D::mSizex+1.0))*0.5)<<" "<<(LbmFloat)(D::mSizex+1.0)<<" " );
+ D::mpIso->setStart( vec2G(isostart) );
+ D::mpIso->setEnd( vec2G(isoend) );
+ LbmVec isodist = isoend-isostart;
+ D::mpIso->initializeIsosurface( D::mSizex+2, D::mSizey+2, D::mSizez+2+twodOff, vec2G(isodist) );
+ for(int ak=0;ak<D::mSizez+2+twodOff;ak++)
+ for(int aj=0;aj<D::mSizey+2;aj++)
+ for(int ai=0;ai<D::mSizex+2;ai++) { *D::mpIso->getData(ai,aj,ak) = 0.0; }
+
+ /* init array (set all invalid first) */
+ for(int lev=0; lev<=mMaxRefine; lev++) {
+ FSGR_FORIJK_BOUNDS(lev) {
+ initEmptyCell(lev, i,j,k, CFEmpty, -1.0, -1.0);
+ }
+ }
+
+ // init defaults
+ mAvgNumUsedCells = 0;
+ D::mFixMass= 0.0;
+
+ /* init boundaries */
+ debugOut("LbmFsgrSolver::initialize : Boundary init...",10);
+
+
+ // use the density init?
+ initGeometryFlags();
+ D::initGenericTestCases();
+
+ // new - init noslip 1 everywhere...
+ // half fill boundary cells?
+
+ for(int k=0;k<mLevel[mMaxRefine].lSizez;k++)
+ for(int i=0;i<mLevel[mMaxRefine].lSizex;i++) {
+ initEmptyCell(mMaxRefine, i,0,k, CFBnd, 0.0, BND_FILL);
+ initEmptyCell(mMaxRefine, i,mLevel[mMaxRefine].lSizey-1,k, CFBnd, 0.0, BND_FILL);
+ }
+
+ if(D::cDimension == 3) {
+ // only for 3D
+ for(int j=0;j<mLevel[mMaxRefine].lSizey;j++)
+ for(int i=0;i<mLevel[mMaxRefine].lSizex;i++) {
+ initEmptyCell(mMaxRefine, i,j,0, CFBnd, 0.0, BND_FILL);
+ initEmptyCell(mMaxRefine, i,j,mLevel[mMaxRefine].lSizez-1, CFBnd, 0.0, BND_FILL);
+ }
+ }
+
+ for(int k=0;k<mLevel[mMaxRefine].lSizez;k++)
+ for(int j=0;j<mLevel[mMaxRefine].lSizey;j++) {
+ initEmptyCell(mMaxRefine, 0,j,k, CFBnd, 0.0, BND_FILL);
+ // for quads! tag +x border... CF4_EMPTY, CF4_BND, CF4_UNUSED
+ // do this last to prevent any overwriting...
+ //initEmptyCell(mMaxRefine, mLevel[mMaxRefine].lSizex-1,j,k, CFBnd|CFBndMARK, 0.0, BND_FILL);
+ initEmptyCell(mMaxRefine, mLevel[mMaxRefine].lSizex-1,j,k, CFBnd, 0.0, BND_FILL);
+ }
+
+ /*for(int ii=0; ii<(int)pow(2.0,mMaxRefine)-1; ii++) {
+ errMsg("BNDTESTSYMM","set "<<mLevel[mMaxRefine].lSizex-2-ii );
+ for(int k=0;k<mLevel[mMaxRefine].lSizez;k++)
+ for(int j=0;j<mLevel[mMaxRefine].lSizey;j++) {
+ initEmptyCell(mMaxRefine, mLevel[mMaxRefine].lSizex-2-ii,j,k, CFBnd, 0.0, BND_FILL); // SYMM!? 2D?
+ }
+ for(int j=0;j<mLevel[mMaxRefine].lSizey;j++)
+ for(int i=0;i<mLevel[mMaxRefine].lSizex;i++) {
+ initEmptyCell(mMaxRefine, i,j,mLevel[mMaxRefine].lSizez-2-ii, CFBnd, 0.0, BND_FILL); // SYMM!? 3D?
+ }
+ }
+ // Symmetry tests */
+
+ // prepare interface cells
+ initFreeSurfaces();
+ D::mInitialMass = 0.0;
+ initStandingFluidGradient();
+
+ // perform first step to init initial mass
+ mInitialMass = 0.0;
+ int inmCellCnt = 0;
+ FSGR_FORIJK1(mMaxRefine) {
+ if( TESTFLAG( RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr), CFFluid) ) {
+ mInitialMass += 1.0;
+ inmCellCnt ++;
+ } else if( TESTFLAG( RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr), CFInter) ) {
+ mInitialMass += QCELL(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr, dMass);
+ inmCellCnt ++;
+ }
+ }
+ mCurrentVolume = mCurrentMass = mInitialMass;
+
+ ParamVec cspv = D::mpParam->calculateCellSize();
+ if(D::cDimension==2) cspv[2] = 1.0;
+ inmCellCnt = 1;
+ double nrmMass = (double)mInitialMass / (double)(inmCellCnt) *cspv[0]*cspv[1]*cspv[2] * 1000.0;
+ debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Initial Mass:"<<mInitialMass<<" normalized:"<<nrmMass, 3);
+
+ //mStartSymm = false;
+#if ELBEEM_BLENDER!=1
+ if((D::cDimension==2)&&(D::mSizex<200)) {
+ if(!checkSymmetry("init")) {
+ errMsg("LbmFsgrSolver::initialize","Unsymmetric init...");
+ } else {
+ errMsg("LbmFsgrSolver::initialize","Symmetric init!");
+ }
+ }
+#endif // ELBEEM_BLENDER!=1
+
+
+ // ----------------------------------------------------------------------
+ // coarsen region
+ myTime_t fsgrtstart = getTime();
+ for(int lev=mMaxRefine-1; lev>=0; lev--) {
+ while(performCoarsening(lev)){
+ coarseRestrictFromFine(lev);
+ debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Coarsening level "<<lev<<".",8);
+ }
+ }
+ D::markedClearList();
+ myTime_t fsgrtend = getTime();
+ if(!D::mSilent){ debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"FSGR init done ("<< ((fsgrtend-fsgrtstart)/(double)1000.0)<<"s) " , 10 ); }
+
+ for(int l=0; l<D::cDirNum; l++) {
+ LbmFloat area = 0.5 * 0.5 *0.5;
+ if(D::cDimension==2) area = 0.5 * 0.5;
+
+ if(D::dfVecX[l]!=0) area *= 0.5;
+ if(D::dfVecY[l]!=0) area *= 0.5;
+ if(D::dfVecZ[l]!=0) area *= 0.5;
+ mFsgrCellArea[l] = area;
+ } // l
+ /*for(int lev=0; lev<mMaxRefine; lev++) {
+ FSGR_FORIJK_BOUNDS(lev) {
+ if( RFLAG(lev, i,j,k,mLevel[lev].setCurr) & CFFluid) {
+ if( RFLAG(lev+1, i*2,j*2,k*2,mLevel[lev+1].setCurr) & CFGrFromCoarse) {
+ LbmFloat totArea = mFsgrCellArea[0]; // for l=0
+ for(int l=1; l<D::cDirNum; l++) {
+ int ni=(2*i)+D::dfVecX[l], nj=(2*j)+D::dfVecY[l], nk=(2*k)+D::dfVecZ[l];
+ if(RFLAG(lev+1, ni,nj,nk, mLevel[lev+1].setCurr)&
+ (CFGrFromCoarse|CFUnused|CFEmpty) //? (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused)
+ //(CFUnused|CFEmpty) //? (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused)
+ ) {
+ //LbmFloat area = 0.25; if(D::dfVecX[l]!=0) area *= 0.5; if(D::dfVecY[l]!=0) area *= 0.5; if(D::dfVecZ[l]!=0) area *= 0.5;
+ totArea += mFsgrCellArea[l];
+ }
+ } // l
+ QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = totArea;
+ } else if( RFLAG(lev+1, i*2,j*2,k*2,mLevel[lev+1].setCurr) & CFEmpty) {
+ QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = 1.0;
+ } else {
+ QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = 0.0;
+ }
+ errMsg("DFINI"," at l"<<lev<<" "<<PRINT_IJK<<" v:"<<QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) );
+ }
+ } } // */
+
+ // now really done...
+ debugOut("LbmFsgrSolver::initialize : Init done ...",10);
+ D::mInitDone = 1;
+
+ // make sure both sets are ok
+ // copy from other to curr
+ for(int lev=0; lev<=mMaxRefine; lev++) {
+ FSGR_FORIJK_BOUNDS(lev) {
+ RFLAG(lev, i,j,k,mLevel[lev].setOther) = RFLAG(lev, i,j,k,mLevel[lev].setCurr);
+ } } // first copy flags */
+#if COMPRESSGRIDS==0
+ /*for(int lev=0; lev<=mMaxRefine; lev++) {
+ FSGR_FORIJK_BOUNDS(lev) {
+ // copy from other to curr
+ for(int l=0; l<D::cDfNum; l++) {
+ QCELL(lev, i,j,k,mLevel[lev].setOther, l) = QCELL(lev, i,j,k,mLevel[lev].setCurr, l);
+ }
+ QCELL(lev, i,j,k,mLevel[lev].setOther, dMass) = QCELL(lev, i,j,k,mLevel[lev].setCurr, dMass);
+ QCELL(lev, i,j,k,mLevel[lev].setOther, dFfrac) = QCELL(lev, i,j,k,mLevel[lev].setCurr, dFfrac);
+ QCELL(lev, i,j,k,mLevel[lev].setOther, dFlux) = QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux);
+ } } // COMPRT OFF */
+#endif // COMPRESSGRIDS==0
+
+
+
+
+ if(mOutputSurfacePreview) {
+ if(D::cDimension==2) {
+ errMsg("LbmFsgrSolver::init","No preview in 2D allowed!"); exit (1);
+ }
+
+ //int previewSize = mOutputSurfacePreview;
+ // same as normal one, but use reduced size
+ mpPreviewSurface = new IsoSurface( D::mIsoValue, false );
+ mpPreviewSurface->setMaterialName( mpPreviewSurface->getMaterialName() );
+ mpPreviewSurface->setIsolevel( D::mIsoValue );
+ // usually dont display for rendering
+ mpPreviewSurface->setVisible( false );
+
+ mpPreviewSurface->setStart( vec2G(isostart) );
+ mpPreviewSurface->setEnd( vec2G(isoend) );
+ LbmVec isodist = isoend-isostart;
+ mpPreviewSurface->initializeIsosurface( (int)(mPreviewFactor*D::mSizex)+2, (int)(mPreviewFactor*D::mSizey)+2, (int)(mPreviewFactor*D::mSizez)+2, vec2G(isodist) );
+ //mpPreviewSurface->setName( D::getName() + "preview" );
+ mpPreviewSurface->setName( "preview" );
+
+ debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Preview with sizes "<<(mPreviewFactor*D::mSizex)<<","<<(mPreviewFactor*D::mSizey)<<","<<(mPreviewFactor*D::mSizez)<<" enabled",10);
+ }
+
+#if ELBEEM_BLENDER==1
+ // make sure fill fracs are right for first surface generation
+ stepMain();
+#endif // ELBEEM_BLENDER==1
+
+ // prepare once...
+ prepareVisualization();
+ // copy again for stats counting
+ for(int lev=0; lev<=mMaxRefine; lev++) {
+ FSGR_FORIJK_BOUNDS(lev) {
+ RFLAG(lev, i,j,k,mLevel[lev].setOther) = RFLAG(lev, i,j,k,mLevel[lev].setCurr);
+ } } // first copy flags */
+
+ /*{ int lev=mMaxRefine;
+ FSGR_FORIJK_BOUNDS(lev) { // COMPRT deb out
+ debMsgDirect("\n x="<<PRINT_IJK);
+ for(int l=0; l<D::cDfNum; l++) {
+ debMsgDirect(" df="<< QCELL(lev, i,j,k,mLevel[lev].setCurr, l) );
+ }
+ debMsgDirect(" m="<< QCELL(lev, i,j,k,mLevel[lev].setCurr, dMass) );
+ debMsgDirect(" f="<< QCELL(lev, i,j,k,mLevel[lev].setCurr, dFfrac) );
+ debMsgDirect(" x="<< QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) );
+ } } // COMPRT ON */
+ return true;
+}
+
+
+
+/*****************************************************************************/
+/*! perform geometry init (if switched on) */
+/*****************************************************************************/
+template<class D>
+bool
+LbmFsgrSolver<D>::initGeometryFlags() {
+ if(!D::mPerformGeoInit) return false;
+ int level = mMaxRefine;
+ myTime_t geotimestart = getTime();
+ ntlGeometryObject *pObj;
+ // getCellSize (due to forced cubes, use x values)
+ ntlVec3Gfx dvec( (D::mvGeoEnd[0]-D::mvGeoStart[0])/ ((LbmFloat)D::mSizex*2.0));
+ // real cell size from now on...
+ dvec *= 2.0;
+ ntlVec3Gfx nodesize = ntlVec3Gfx(mLevel[level].nodeSize); //dvec*1.0;
+ dvec = nodesize;
+ debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Performing geometry init ("<< D::mGeoInitId <<") v"<<dvec,3);
+
+ /* set interface cells */
+ D::initGeoTree(D::mGeoInitId);
+ ntlVec3Gfx maxIniVel = vec2G( D::mpParam->calculateLattVelocityFromRw( vec2P(D::getGeoMaxInitialVelocity()) ));
+ D::mpParam->setSimulationMaxSpeed( norm(maxIniVel) + norm(mLevel[level].gravity) );
+ LbmFloat allowMax = D::mpParam->getTadapMaxSpeed(); // maximum allowed velocity
+ debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Maximum Velocity from geo init="<< maxIniVel <<", allowed Max="<<allowMax ,5);
+ if(D::mpParam->getSimulationMaxSpeed() > allowMax) {
+ // similar to adaptTimestep();
+ LbmFloat nextmax = D::mpParam->getSimulationMaxSpeed();
+ LbmFloat newdt = D::mpParam->getStepTime() * (allowMax / nextmax); // newtr
+ debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Performing reparametrization, newdt="<< newdt<<" prevdt="<< D::mpParam->getStepTime() <<" ",5);
+ D::mpParam->setDesiredStepTime( newdt );
+ D::mpParam->calculateAllMissingValues( D::mSilent );
+ maxIniVel = vec2G( D::mpParam->calculateLattVelocityFromRw( vec2P(D::getGeoMaxInitialVelocity()) ));
+ debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"New maximum Velocity from geo init="<< maxIniVel,5);
+ }
+
+
+ ntlVec3Gfx pos,iniPos; // position of current cell
+ LbmFloat rhomass = 0.0;
+ int savedNodes = 0;
+ int OId = -1;
+ gfxReal distance;
+ LbmVec nodevel(0.0);
+
+ // 2d display as rectangles
+ if(D::cDimension==2) {
+ dvec[2] = 0.0;
+ iniPos =(D::mvGeoStart + ntlVec3Gfx( 0.0, 0.0, (D::mvGeoEnd[2]-D::mvGeoStart[2])*0.5 ))-(dvec*0.0);
+ //iniPos =(D::mvGeoStart + ntlVec3Gfx( 0.0 ))+dvec;
+ } else {
+ iniPos =(D::mvGeoStart + ntlVec3Gfx( 0.0 ))-(dvec*0.0);
+ iniPos[2] = D::mvGeoStart[2] + dvec[2]*getForZMin1(level);
+ }
+
+
+ // first init boundary conditions
+#define GETPOS(i,j,k) \
+ ntlVec3Gfx( iniPos[0]+ dvec[0]*(gfxReal)(i), \
+ iniPos[1]+ dvec[1]*(gfxReal)(j), \
+ iniPos[2]+ dvec[2]*(gfxReal)(k) )
+ //pos = iniPos;
+ for(int k= getForZMin1(level); k< getForZMax1(level); ++k) {
+ //pos[1] = D::mvGeoStart[1] + dvec[1]*1.0;
+ for(int j=1;j<mLevel[level].lSizey-1;j++) {
+ //pos[0] = D::mvGeoStart[0] + dvec[0]*1.0;
+ for(int i=1;i<mLevel[level].lSizex-1;i++) {
+
+ //CellFlagType ntype = D::geoInitGetPointType( pos, nodesize, &pObj, distance );
+ CellFlagType ntype = CFInvalid;
+ if(D::geoInitCheckPointInside( GETPOS(i,j,k) , FGI_ALLBOUNDS, OId, distance)) {
+ ntype = CFBnd;
+ pObj = (*D::mpGiObjects)[OId];
+ }
+ //CellFlagType convntype = ntype;
+ if(ntype != CFInvalid) {
+ // initDefaultCell
+ nodevel = LbmVec(0.0);
+ rhomass = BND_FILL;
+ initVelocityCell(level, i,j,k, ntype, rhomass, rhomass, nodevel );
+ }
+
+ // walk along x until hit for following inits
+ if(distance<=-1.0) { distance = 100.0; }
+ if(distance>0.0) {
+ //distance += pos[0];
+ //while(((pos[0]+dvec[0])<distance)&&(i+1<mLevel[level].lSizex-1)) {
+ gfxReal dcnt=dvec[0];
+ while((dcnt<distance)&&(i+1<mLevel[level].lSizex-1)) {
+ dcnt += dvec[0]; i++;
+ savedNodes++;
+ if(ntype != CFInvalid) {
+ // nodevel&rhomass are still inited from above
+ initVelocityCell(level, i,j,k, ntype, rhomass, rhomass, nodevel );
+ }
+ }
+ } //pos[0] += dvec[0];
+ } //pos[1] += dvec[1];
+ } //pos[2] += dvec[2];
+ } // zmax
+
+
+ // now init fluid layer
+ //pos = iniPos;
+ for(int k= getForZMin1(level); k< getForZMax1(level); ++k) {
+ //pos[1] = D::mvGeoStart[1] + dvec[1]*1.0;
+ for(int j=1;j<mLevel[level].lSizey-1;j++) {
+ //pos[0] = D::mvGeoStart[0] + dvec[0]*1.0;
+ for(int i=1;i<mLevel[level].lSizex-1;i++) {
+ if(!(RFLAG(level, i,j,k, mLevel[level].setCurr)&CFEmpty)) continue;
+
+ //CellFlagType ntype = D::geoInitGetPointType( pos, nodesize, &pObj, distance );
+ CellFlagType ntype = CFInvalid;
+ if(D::geoInitCheckPointInside( GETPOS(i,j,k) , FGI_FLUID, OId, distance)) {
+ ntype = CFFluid;
+ pObj = (*D::mpGiObjects)[OId];
+ }
+ //CellFlagType convntype = ntype;
+ if(ntype != CFInvalid) {
+ // initDefaultCell
+ nodevel = vec2L(D::mpParam->calculateLattVelocityFromRw( vec2P(pObj->getInitialVelocity() )));
+ rhomass = 1.0;
+ initVelocityCell(level, i,j,k, ntype, rhomass, rhomass, nodevel );
+ }
+
+ // walk along x until hit for following inits
+ if(distance<=-1.0) { distance = 100.0; }
+ if(distance>0.0) {
+ //distance += pos[0];
+ //while(((pos[0]+dvec[0])<distance)&&(i+1<mLevel[level].lSizex-1)) {
+ //pos[0] += dvec[0]; i++;
+ gfxReal dcnt=dvec[0];
+ while((dcnt<distance)&&(i+1<mLevel[level].lSizex-1)) {
+ dcnt += dvec[0]; i++;
+ savedNodes++;
+ if(!(RFLAG(level, i,j,k, mLevel[level].setCurr)&CFEmpty)) continue;
+ if(ntype != CFInvalid) {
+ // nodevel&rhomass are still inited from above
+ initVelocityCell(level, i,j,k, ntype, rhomass, rhomass, nodevel );
+ }
+ }
+ } //pos[0] += dvec[0];
+ } //pos[1] += dvec[1];
+ } //pos[2] += dvec[2];
+ } // zmax
+
+ /*
+ // now init fluid layer
+ if(D::cDimension==2) {
+ dvec[2] = 0.0;
+ pos =(D::mvGeoStart + ntlVec3Gfx( 0.0, 0.0, (D::mvGeoEnd[2]-D::mvGeoStart[2])*0.5 ))+dvec;
+ pos[2] = D::mvGeoStart[2] + dvec[2]*getForZMin1(mMaxRefine);
+ } else {
+ pos =(D::mvGeoStart + ntlVec3Gfx( 0.0, 0.0, 0.0 ))+dvec;
+ }
+ for(int k= getForZMin1(mMaxRefine); k< getForZMax1(mMaxRefine); ++k) {
+ pos[1] = D::mvGeoStart[1] + dvec[1]*1.0;
+ for(int j=1;j<mLevel[mMaxRefine].lSizey-1;j++) {
+ pos[0] = D::mvGeoStart[0] + dvec[0]*1.0;
+ for(int i=1;i<mLevel[mMaxRefine].lSizex-1;i++) {
+ //debMsgInter("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Checking"<<PRINT_IJK,2,2000 );
+ if(RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr)&CFEmpty) {
+ // overwrite these...
+ } else {
+ continue;
+ }
+
+ CellFlagType ntype = D::geoInitGetPointType( pos, nodesize, &pObj, distance );
+ CellFlagType convntype = ntype;
+ if(ntype != CFInvalid) {
+ // initDefaultCell
+ if(convntype & CFFluid) { nodevel = vec2L(D::mpParam->calculateLattVelocityFromRw( vec2P(pObj->getInitialVelocity() ))); }
+ else { nodevel = LbmVec(0.0); }
+
+ if(convntype & CFFluid) { rhomass = 1.0; }
+ else if(convntype & CFBnd) { rhomass = BND_FILL; }
+ else { rhomass = 0.0; } // empty, inter
+ //initEmptyCell(mMaxRefine, i,j,k, convntype, rhomass, rhomass );
+ initVelocityCell(mMaxRefine, i,j,k, convntype, rhomass, rhomass, nodevel );
+ //errMsg(" DT ",PRINT_IJK<<" "<<distance<<" "<<pos<<" i"<<i<<" "<<ntype );
+ }
+
+ // walk along x until hit for following inits
+ //if(distance==-1.0) { distance = 100.0; }
+ if(distance<=-1.0) { distance = 100.0; }
+ if(distance>0.0) {
+ distance += pos[0];
+ //errMsg(" DS "," "<<distance<<" "<<pos<<" i"<<i<<" type:"<<ntype<<" "<<convertFlags2String(ntype) );
+ while(((pos[0]+dvec[0])<distance)&&(i+1<mLevel[mMaxRefine].lSizex-1)) {
+ if(RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr)&CFEmpty) {
+ // overwrite these...
+ } else {
+ continue;
+ }
+ pos[0] += dvec[0]; i++;
+ savedNodes++;
+ //errMsg(" DT "," "<<distance<<" "<<pos<<" i"<<i<<" "<<ntype );
+ if(ntype != CFInvalid) {
+ // initDefaultCell
+ // nodevel is still inited from above
+ if(convntype & CFFluid) { rhomass = 1.0; }
+ else if(convntype & CFBnd) { rhomass = BND_FILL; }
+ else { rhomass = 0.0; } // empty, inter
+ //initEmptyCell(mMaxRefine, i,j,k, convntype, rhomass, rhomass );
+ initVelocityCell(mMaxRefine, i,j,k, convntype, rhomass, rhomass, nodevel );
+ }
+ }
+ }
+ pos[0] += dvec[0];
+ }
+ pos[1] += dvec[1];
+ }
+ pos[2] += dvec[2];
+ } // */
+
+ D::freeGeoTree();
+ myTime_t geotimeend = getTime();
+ debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Geometry init done ("<< ((geotimeend-geotimestart)/(double)1000.0)<<"s) " , 10 );
+ //errMsg(" SAVED "," "<<savedNodes<<" of "<<(mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*mLevel[mMaxRefine].lSizez));
+ return true;
+}
+
+/*****************************************************************************/
+/* init part for all freesurface testcases */
+template<class D>
+void
+LbmFsgrSolver<D>::initFreeSurfaces() {
+ double interfaceFill = 0.45; // filling level of interface cells
+
+ // set interface cells
+ FSGR_FORIJK1(mMaxRefine) {
+
+ /*if( TESTFLAG( RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr), CFEmpty )) {
+ int initInter = 0;
+ // check for neighboring fluid cells
+ FORDF1 {
+ if( TESTFLAG( RFLAG_NBINV(mMaxRefine, i, j, k, mLevel[mMaxRefine].setCurr,l), CFFluid ) ) {
+ initInter = 1;
+ }
+ }
+
+ if(initInter) {
+ initEmptyCell(mMaxRefine, i,j,k, CFInter, 1.0, interfaceFill);
+ }
+
+ } // empty cells OLD */
+
+ if( TESTFLAG( RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr), CFFluid )) {
+ int initInter = 0; // check for neighboring empty cells
+ FORDF1 {
+ if( TESTFLAG( RFLAG_NBINV(mMaxRefine, i, j, k, mLevel[mMaxRefine].setCurr,l), CFEmpty ) ) {
+ initInter = 1;
+ }
+ }
+ if(initInter) {
+ QCELL(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr, dMass) =
+ //QCELL(mMaxRefine,i,j,k,mLevel[mMaxRefine].setOther, dMass) = // COMPRT OFF
+ interfaceFill;
+ RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) = RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setOther) = CFInter;
+ }
+ }
+ }
+
+ // remove invalid interface cells
+ FSGR_FORIJK1(mMaxRefine) {
+ // remove invalid interface cells
+ if( TESTFLAG( RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr), CFInter) ) {
+ int delit = 0;
+ int NBs = 0; // neighbor flags or'ed
+ int noEmptyNB = 1;
+
+ FORDF1 {
+ if( TESTFLAG( RFLAG_NBINV(mMaxRefine, i, j, k, mLevel[mMaxRefine].setCurr,l ), CFEmpty ) ) {
+ noEmptyNB = 0;
+ }
+ NBs |= RFLAG_NBINV(mMaxRefine, i, j, k, mLevel[mMaxRefine].setCurr, l);
+ }
+
+ // remove cells with no fluid or interface neighbors
+ if((NBs & CFFluid)==0) { delit = 1; }
+ if((NBs & CFInter)==0) { delit = 1; }
+
+ // remove cells with no empty neighbors
+ if(noEmptyNB) { delit = 2; }
+
+ // now we can remove the cell
+ if(delit==1) {
+ initEmptyCell(mMaxRefine, i,j,k, CFEmpty, 1.0, 0.0);
+ }
+ if(delit==2) {
+ initEmptyCell(mMaxRefine, i,j,k, CFFluid, 1.0, 1.0);
+ }
+ } // interface
+ }
+
+ // another brute force init, make sure the fill values are right...
+ // and make sure both sets are equal
+ for(int lev=0; lev<=mMaxRefine; lev++) {
+ FSGR_FORIJK_BOUNDS(lev) {
+ if( (RFLAG(lev, i,j,k,0) & (CFBnd)) ) {
+ QCELL(lev, i,j,k,mLevel[mMaxRefine].setCurr, dFfrac) =
+ //QCELL(lev, i,j,k,mLevel[mMaxRefine].setOther, dFfrac) = // COMPRT OFF
+ BND_FILL;
+ continue;
+ }
+ if( (RFLAG(lev, i,j,k,0) & (CFEmpty)) ) {
+ QCELL(lev, i,j,k,mLevel[mMaxRefine].setCurr, dFfrac) =
+ //QCELL(lev, i,j,k,mLevel[mMaxRefine].setOther, dFfrac) = // COMPRT OFF
+ 0.0;
+ continue;
+ }
+
+ // copy from other to curr
+ //?? RFLAG(lev, i,j,k,mLevel[lev].setOther) = RFLAG(lev, i,j,k,mLevel[lev].setCurr);
+ //?? for(int l=0; l<D::cDfNum; l++) {
+ //?? QCELL(lev, i,j,k,mLevel[lev].setOther, l) = QCELL(lev, i,j,k,mLevel[lev].setCurr, l);
+ //?? }
+ //?? QCELL(lev, i,j,k,mLevel[lev].setOther, dMass) = QCELL(lev, i,j,k,mLevel[lev].setCurr, dMass);
+ //?? QCELL(lev, i,j,k,mLevel[lev].setOther, dFfrac) = QCELL(lev, i,j,k,mLevel[lev].setCurr, dFfrac);
+ } }
+
+ // ----------------------------------------------------------------------
+ // smoother surface...
+ if(mInitSurfaceSmoothing>0) {
+ debMsgStd("Surface Smoothing init", DM_MSG, "Performing "<<(mInitSurfaceSmoothing)<<" smoothing steps ",10);
+#if COMPRESSGRIDS==1
+ errMsg("NYI","COMPRESSGRIDS mInitSurfaceSmoothing"); exit(1);
+#endif // COMPRESSGRIDS==0
+ }
+ for(int s=0; s<mInitSurfaceSmoothing; s++) {
+ FSGR_FORIJK1(mMaxRefine) {
+ if( TESTFLAG( RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr), CFInter) ) {
+ LbmFloat mass = 0.0;
+ //LbmFloat nbdiv;
+ FORDF0 {
+ int ni=i+D::dfVecX[l], nj=j+D::dfVecY[l], nk=k+D::dfVecZ[l];
+ if( RFLAG(mMaxRefine, ni,nj,nk, mLevel[mMaxRefine].setCurr) & CFFluid ){
+ mass += 1.0;
+ }
+ if( RFLAG(mMaxRefine, ni,nj,nk, mLevel[mMaxRefine].setCurr) & CFInter ){
+ mass += QCELL(mMaxRefine, ni,nj,nk, mLevel[mMaxRefine].setCurr, dMass);
+ }
+ //nbdiv+=1.0;
+ }
+
+ //errMsg(" I ", PRINT_IJK<<" m"<<mass );
+ QCELL(mMaxRefine, i,j,k, mLevel[mMaxRefine].setOther, dMass) = (mass/19.0);
+ QCELL(mMaxRefine, i,j,k, mLevel[mMaxRefine].setOther, dFfrac) = QCELL(mMaxRefine, i,j,k, mLevel[mMaxRefine].setOther, dMass);
+ }
+ }
+
+ mLevel[mMaxRefine].setOther = mLevel[mMaxRefine].setCurr;
+ mLevel[mMaxRefine].setCurr ^= 1;
+ }
+
+ // copy back...
+ /*for(int lev=0; lev<=mMaxRefine; lev++) {
+ FSGR_FORIJK1(lev) {
+ if( TESTFLAG( RFLAG(lev, i,j,k, mLevel[lev].setCurr), CFInter) ) {
+ QCELL(lev, i,j,k, mLevel[lev].setOther, dMass ) = QCELL(lev, i,j,k, mLevel[lev].setCurr, dMass);
+ QCELL(lev, i,j,k, mLevel[lev].setOther, dFfrac) = QCELL(lev, i,j,k, mLevel[lev].setCurr, dFfrac);
+ QCELL(lev, i,j,k, mLevel[lev].setOther, dFlux) = QCELL(lev, i,j,k, mLevel[lev].setCurr, dFlux);
+ }
+ }
+ } // COMPRT OFF */
+
+}
+
+/*****************************************************************************/
+/* init part for all freesurface testcases */
+template<class D>
+void
+LbmFsgrSolver<D>::initStandingFluidGradient() {
+ // ----------------------------------------------------------------------
+ // standing fluid preinit
+ const int debugStandingPreinit = 0;
+ int haveStandingFluid = 0;
+
+#define STANDFLAGCHECK(iindex) \
+ if( ( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFInter)) ) || \
+ ( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFEmpty)) ) ){ \
+ if((iindex)>1) { haveStandingFluid=(iindex); } \
+ j = mLevel[mMaxRefine].lSizey; i=mLevel[mMaxRefine].lSizex; k=D::getForZMaxBnd(); \
+ continue; \
+ }
+ int gravIndex[3] = {0,0,0};
+ int gravDir[3] = {1,1,1};
+ int maxGravComp = 1; // by default y
+ int gravComp1 = 0; // by default y
+ int gravComp2 = 2; // by default y
+ if( ABS(mLevel[mMaxRefine].gravity[0]) > ABS(mLevel[mMaxRefine].gravity[1]) ){ maxGravComp = 0; gravComp1=1; gravComp2=2; }
+ if( ABS(mLevel[mMaxRefine].gravity[2]) > ABS(mLevel[mMaxRefine].gravity[0]) ){ maxGravComp = 2; gravComp1=0; gravComp2=1; }
+
+ int gravIMin[3] = { 0 , 0 , 0 };
+ int gravIMax[3] = {
+ mLevel[mMaxRefine].lSizex + 0,
+ mLevel[mMaxRefine].lSizey + 0,
+ mLevel[mMaxRefine].lSizez + 0 };
+ if(LBMDIM==2) gravIMax[2] = 1;
+
+ //int gravDir = 1;
+ if( mLevel[mMaxRefine].gravity[maxGravComp] > 0.0 ) {
+ // swap directions
+ int i=maxGravComp;
+ int tmp = gravIMin[i];
+ gravIMin[i] = gravIMax[i] - 1;
+ gravIMax[i] = tmp - 1;
+ gravDir[i] = -1;
+ }
+#define PRINTGDIRS \
+ errMsg("Standing fp","X start="<<gravIMin[0]<<" end="<<gravIMax[0]<<" dir="<<gravDir[0] ); \
+ errMsg("Standing fp","Y start="<<gravIMin[1]<<" end="<<gravIMax[1]<<" dir="<<gravDir[1] ); \
+ errMsg("Standing fp","Z start="<<gravIMin[2]<<" end="<<gravIMax[2]<<" dir="<<gravDir[2] );
+ // _PRINTGDIRS;
+
+ bool gravAbort = false;
+#define GRAVLOOP \
+ gravAbort=false; \
+ for(gravIndex[2]= gravIMin[2]; (gravIndex[2]!=gravIMax[2])&&(!gravAbort); gravIndex[2] += gravDir[2]) \
+ for(gravIndex[1]= gravIMin[1]; (gravIndex[1]!=gravIMax[1])&&(!gravAbort); gravIndex[1] += gravDir[1]) \
+ for(gravIndex[0]= gravIMin[0]; (gravIndex[0]!=gravIMax[0])&&(!gravAbort); gravIndex[0] += gravDir[0])
+
+ GRAVLOOP {
+ int i = gravIndex[0], j = gravIndex[1], k = gravIndex[2];
+ //if((gravIndex[gravComp1]==gravIMin[gravComp1]) && (gravIndex[gravComp2]==gravIMin[gravComp2])) {debMsgStd("Standing fluid preinit", DM_MSG, "fluidheightinit check "<<PRINT_IJK<<" "<< haveStandingFluid, 1 ); }
+ //STANDFLAGCHECK(gravIndex[maxGravComp]);
+ if( ( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFInter)) ) ||
+ ( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFEmpty)) ) ){
+ int fluidHeight = (ABS(gravIndex[maxGravComp] - gravIMin[maxGravComp]));
+ if(debugStandingPreinit) errMsg("Standing fp","fh="<<fluidHeight<<" gmax="<<gravIMax[maxGravComp]<<" gi="<<gravIndex[maxGravComp] );
+ //if(gravIndex[maxGravComp]>1)
+ if(fluidHeight>1)
+ {
+ haveStandingFluid = fluidHeight; //gravIndex[maxGravComp];
+ gravIMax[maxGravComp] = gravIndex[maxGravComp] + gravDir[maxGravComp];
+ }
+ gravAbort = true; continue;
+ }
+ } // GRAVLOOP
+ // _PRINTGDIRS;
+
+ LbmFloat fluidHeight;
+ //if(gravDir>0) { fluidHeight = (LbmFloat)haveStandingFluid;
+ //} else { fluidHeight = (LbmFloat)haveStandingFluid; }
+ fluidHeight = (LbmFloat)(ABS(gravIMax[maxGravComp]-gravIMin[maxGravComp]));
+ if(debugStandingPreinit) debMsgStd("Standing fluid preinit", DM_MSG, "fheight="<<fluidHeight<<" min="<<PRINT_VEC(gravIMin[0],gravIMin[1], gravIMin[2])<<" max="<<PRINT_VEC(gravIMax[0], gravIMax[1],gravIMax[2])<<
+ " mgc="<<maxGravComp<<" mc1="<<gravComp1<<" mc2="<<gravComp2<<" dir="<<gravDir[maxGravComp]<<" have="<<haveStandingFluid ,10);
+
+ if(mDisableStandingFluidInit) {
+ debMsgStd("Standing fluid preinit", DM_MSG, "Should be performed - but skipped due to mDisableStandingFluidInit flag set!", 2);
+ haveStandingFluid=0;
+ }
+
+ if(haveStandingFluid) {
+ int lev = mMaxRefine;
+ int rhoworkSet = mLevel[lev].setCurr;
+ myTime_t timestart = getTime(); // FIXME use user time here?
+#if OPT3D==true
+ LbmFloat lcsmqadd, lcsmqo, lcsmeq[LBM_DFNUM], lcsmomega;
+#endif // OPT3D==true
+
+ GRAVLOOP {
+ int i = gravIndex[0], j = gravIndex[1], k = gravIndex[2];
+ //debMsgStd("Standing fluid preinit", DM_MSG, " init check "<<PRINT_IJK<<" "<< haveStandingFluid, 1 );
+ if( ( (RFLAG(lev, i,j,k,rhoworkSet) & (CFInter)) ) ||
+ ( (RFLAG(lev, i,j,k,rhoworkSet) & (CFEmpty)) ) ){
+ //gravAbort = true;
+ continue;
+ }
+
+ LbmFloat rho = 1.0;
+ // 1/6 velocity from denisty gradient, 1/2 for delta of two cells
+ rho += 1.0* (fluidHeight-gravIndex[maxGravComp]) *
+ (mLevel[lev].gravity[maxGravComp])* (-3.0/1.0)*(mLevel[lev].omega);
+ if(debugStandingPreinit)
+ if((gravIndex[gravComp1]==gravIMin[gravComp1]) && (gravIndex[gravComp2]==gravIMin[gravComp2])) {
+ errMsg("Standing fp","gi="<<gravIndex[maxGravComp]<<" rho="<<rho<<" at "<<PRINT_IJK);
+ }
+
+ if( (RFLAG(lev, i,j,k, rhoworkSet) & CFFluid) ||
+ (RFLAG(lev, i,j,k, rhoworkSet) & CFInter) ) {
+ FORDF0 { QCELL(lev, i,j,k, rhoworkSet, l) *= rho; }
+ QCELL(lev, i,j,k, rhoworkSet, dMass) *= rho;
+ }
+
+ } // GRAVLOOP
+ debMsgStd("Standing fluid preinit", DM_MSG, "Density gradient inited", 8);
+
+ // copy flags and init , as no flags will be changed during grav init
+ CellFlagType nbflag[LBM_DFNUM], nbored;
+ for(int k=D::getForZMinBnd();k<D::getForZMaxBnd();++k) {
+ for(int j=0;j<mLevel[lev].lSizey-0;++j) {
+ for(int i=0;i<mLevel[lev].lSizex-0;++i) {
+ if( (RFLAG(lev, i,j,k,SRCS(lev)) & (CFFluid)) ) {
+ nbored = 0;
+ FORDF1 {
+ nbflag[l] = RFLAG_NB(lev, i,j,k, SRCS(lev),l);
+ nbored |= nbflag[l];
+ }
+ if(nbored&CFBnd) {
+ RFLAG(lev, i,j,k,SRCS(lev)) &= (~CFNoBndFluid);
+ } else {
+ RFLAG(lev, i,j,k,SRCS(lev)) |= CFNoBndFluid;
+ }
+ }
+ RFLAG(lev, i,j,k,TSET(lev)) = RFLAG(lev, i,j,k,SRCS(lev));
+ } } }
+
+ int preinitSteps = (haveStandingFluid* ((mLevel[lev].lSizey+mLevel[lev].lSizez+mLevel[lev].lSizex)/3) );
+ preinitSteps = (haveStandingFluid>>2); // not much use...?
+ //preinitSteps = 4; // DEBUG!!!!
+ //D::mInitDone = 1; // GRAVTEST
+ //preinitSteps = 0;
+ debMsgNnl("Standing fluid preinit", DM_MSG, "Performing "<<preinitSteps<<" prerelaxations ",10);
+ for(int s=0; s<preinitSteps; s++) {
+ int workSet = SRCS(lev); //mLevel[lev].setCurr;
+ int otherSet = TSET(lev); //mLevel[lev].setOther;
+ //debMsgDirect(".");
+ if(debugStandingPreinit) debMsgStd("Standing fluid preinit", DM_MSG, "s="<<s<<" curset="<<workSet<<" srcs"<<SRCS(lev), 10);
+ LbmFloat *ccel;
+ LbmFloat *tcel;
+ LbmFloat m[LBM_DFNUM];
+
+ // grav loop not necessary here
+#define NBFLAG(l) (nbflag[(l)])
+ LbmFloat rho, ux,uy,uz, usqr;
+ int kstart=D::getForZMinBnd(), kend=D::getForZMaxBnd();
+#if COMPRESSGRIDS==0
+ for(int k=kstart;k<kend;++k) {
+#else // COMPRESSGRIDS==0
+ int kdir = 1; // COMPRT ON
+ if(mLevel[lev].setCurr==1) {
+ kdir = -1;
+ int temp = kend;
+ kend = kstart-1;
+ kstart = temp-1;
+ } // COMPRT
+ for(int k=kstart;k!=kend;k+=kdir) {
+
+ //errMsg("LbmFsgrSolver::mainLoop","k="<<k<<" ks="<<kstart<<" ke="<<kend<<" kdir="<<kdir ); // debug
+#endif // COMPRESSGRIDS==0
+
+ for(int j=0;j<mLevel[lev].lSizey-0;++j) {
+ for(int i=0;i<mLevel[lev].lSizex-0;++i) {
+ const CellFlagType currFlag = RFLAG(lev, i,j,k,workSet);
+ if( (currFlag & (CFEmpty|CFBnd)) ) continue;
+ ccel = RACPNT(lev, i,j,k,workSet);
+ tcel = RACPNT(lev, i,j,k,otherSet);
+
+ if( (currFlag & (CFInter)) ) {
+ // copy all values
+ for(int l=0; l<dTotalNum;l++) { RAC(tcel,l) = RAC(ccel,l); }
+ continue;
+ }
+
+ if( (currFlag & CFNoBndFluid)) {
+ OPTIMIZED_STREAMCOLLIDE;
+ } else {
+ FORDF1 {
+ nbflag[l] = RFLAG_NB(lev, i,j,k, SRCS(lev),l);
+ }
+ DEFAULT_STREAM;
+ ux = mLevel[lev].gravity[0]; uy = mLevel[lev].gravity[1]; uz = mLevel[lev].gravity[2];
+ DEFAULT_COLLIDE;
+ }
+ for(int l=LBM_DFNUM; l<dTotalNum;l++) { RAC(tcel,l) = RAC(ccel,l); }
+ } } } // GRAVLOOP
+
+ mLevel[lev].setOther = mLevel[lev].setCurr;
+ mLevel[lev].setCurr ^= 1;
+ }
+ //D::mInitDone = 0; // GRAVTEST
+ // */
+
+ myTime_t timeend = getTime();
+ //debMsgDirect(" done, "<<((timeend-timestart)/(double)1000.0)<<"s \n");
+#undef NBFLAG
+ }
+}
+
+
+
+/*****************************************************************************/
+/* init a given cell with flag, density, mass and equilibrium dist. funcs */
+template<class D>
+void
+LbmFsgrSolver<D>::initEmptyCell(int level, int i,int j,int k, CellFlagType flag, LbmFloat rho, LbmFloat mass) {
+ /* init eq. dist funcs */
+ LbmFloat *ecel;
+ int workSet = mLevel[level].setCurr;
+
+ ecel = RACPNT(level, i,j,k, workSet);
+ FORDF0 { RAC(ecel, l) = D::dfEquil[l] * rho; }
+ RAC(ecel, dMass) = mass;
+ RAC(ecel, dFfrac) = mass/rho;
+ RAC(ecel, dFlux) = FLUX_INIT;
+ RFLAG(level, i,j,k, workSet)= flag;
+
+ workSet ^= 1;
+#if COMPRESSGRIDS==0
+ /*ecel = RACPNT(level, i,j,k, workSet); FIXME why doesnt this work with COMPRESSGRIDS off?
+ FORDF0 { RAC(ecel, l) = D::dfEquil[l] * rho; }
+ RAC(ecel, dMass) = mass;
+ RAC(ecel, dFfrac) = mass/rho;
+ RAC(ecel, dFlux) = FLUX_INIT; // COMPRT OFF */
+#endif // COMPRESSGRIDS==0
+ RFLAG(level, i,j,k, workSet)= flag;
+ return;
+}
+
+template<class D>
+void
+LbmFsgrSolver<D>::initVelocityCell(int level, int i,int j,int k, CellFlagType flag, LbmFloat rho, LbmFloat mass, LbmVec vel) {
+ LbmFloat *ecel;
+ int workSet = mLevel[level].setCurr;
+
+ ecel = RACPNT(level, i,j,k, workSet);
+ FORDF0 { RAC(ecel, l) = D::getCollideEq(l, rho,vel[0],vel[1],vel[2]); }
+ RAC(ecel, dMass) = mass;
+ RAC(ecel, dFfrac) = mass/rho;
+ RAC(ecel, dFlux) = FLUX_INIT;
+ RFLAG(level, i,j,k, workSet) = flag;
+
+ workSet ^= 1;
+#if COMPRESSGRIDS==0
+ /*ecel = RACPNT(level, i,j,k, workSet); FIXME why doesnt this work with COMPRESSGRIDS off?
+ FORDF0 { RAC(ecel, l) = D::getCollideEq(l, rho,vel[0],vel[1],vel[2]); }
+ RAC(ecel, dMass) = mass;
+ RAC(ecel, dFfrac) = mass/rho;
+ RAC(ecel, dFlux) = FLUX_INIT; // COMPRT OFF */
+#endif // COMPRESSGRIDS==0
+ RFLAG(level, i,j,k, workSet) = flag;
+ return;
+}
+
+template<class D>
+bool
+LbmFsgrSolver<D>::checkSymmetry(string idstring)
+{
+ bool erro = false;
+ bool symm = true;
+ int msgs = 0;
+ const int maxMsgs = 10;
+ const bool markCells = false;
+
+ //for(int lev=0; lev<=mMaxRefine; lev++) {
+ { int lev = mMaxRefine;
+
+ // no point if not symm.
+ if( (mLevel[lev].lSizex==mLevel[lev].lSizey) && (mLevel[lev].lSizex==mLevel[lev].lSizez)) {
+ // ok
+ } else {
+ return false;
+ }
+
+ for(int s=0; s<2; s++) {
+ FSGR_FORIJK1(lev) {
+ if(i<(mLevel[lev].lSizex/2)) {
+ int inb = (mLevel[lev].lSizey-1-i);
+
+ if(lev==mMaxRefine) inb -= 1; // FSGR_SYMM_T
+
+ if( RFLAG(lev, i,j,k,s) != RFLAG(lev, inb,j,k,s) ) { erro = true;
+ if(D::cDimension==2) {
+ if(msgs<maxMsgs) { msgs++;
+ errMsg("EFLAG", PRINT_IJK<<"s"<<s<<" flag "<<RFLAG(lev, i,j,k,s)<<" , at "<<PRINT_VEC(inb,j,k)<<"s"<<s<<" flag "<<RFLAG(lev, inb,j,k,s) );
+ }
+ }
+ if(markCells){ debugMarkCell(lev, i,j,k); debugMarkCell(lev, inb,j,k); }
+ symm = false;
+ }
+ if( LBM_FLOATNEQ(QCELL(lev, i,j,k,s, dMass), QCELL(lev, inb,j,k,s, dMass)) ) { erro = true;
+ if(D::cDimension==2) {
+ if(msgs<maxMsgs) { msgs++;
+ /*
+ debMsgDirect(" mass1 "<<QCELL(lev, i,j,k,s, dMass)<<" mass2 "<<QCELL(lev, inb,j,k,s, dMass) <<std::endl);
+ errMsg("EMASS", PRINT_IJK<<"s"<<s<<" mass "<<QCELL(lev, i,j,k,s, dMass)<<" , at "<<PRINT_VEC(inb,j,k)<<"s"<<s<<" mass "<<QCELL(lev, inb,j,k,s, dMass) );
+ */
+ }
+ }
+ if(markCells){ debugMarkCell(lev, i,j,k); debugMarkCell(lev, inb,j,k); }
+ symm = false;
+ }
+
+ LbmFloat nbrho = QCELL(lev, i,j,k, s, dC);
+ FORDF1 { nbrho += QCELL(lev, i,j,k, s, l); }
+ LbmFloat otrho = QCELL(lev, inb,j,k, s, dC);
+ FORDF1 { otrho += QCELL(lev, inb,j,k, s, l); }
+ if( LBM_FLOATNEQ(nbrho, otrho) ) { erro = true;
+ if(D::cDimension==2) {
+ if(msgs<maxMsgs) { msgs++;
+ //debMsgDirect(" rho 1 "<<nbrho <<" rho 2 "<<otrho <<std::endl);
+ errMsg("ERHO ", PRINT_IJK<<"s"<<s<<" rho "<<nbrho <<" , at "<<PRINT_VEC(inb,j,k)<<"s"<<s<<" rho "<<otrho );
+ }
+ }
+ if(markCells){ debugMarkCell(lev, i,j,k); debugMarkCell(lev, inb,j,k); }
+ symm = false;
+ }
+ }
+ } }
+ } // lev
+ LbmFloat maxdiv =0.0;
+ if(erro) {
+ errMsg("SymCheck Failed!", idstring<<" rho maxdiv:"<< maxdiv );
+ //if(D::cDimension==2) D::mPanic = true;
+ //return false;
+ } else {
+ errMsg("SymCheck OK!", idstring<<" rho maxdiv:"<< maxdiv );
+ }
+ // all ok...
+ return symm;
+}// */
+
+
+/*****************************************************************************/
+/*! debug object display */
+/*****************************************************************************/
+template<class D>
+vector<ntlGeometryObject*> LbmFsgrSolver<D>::getDebugObjects() {
+ vector<ntlGeometryObject*> debo;
+ if(mOutputSurfacePreview) {
+ debo.push_back( mpPreviewSurface );
+ }
+ return debo;
+}
+
+/*****************************************************************************/
+/*! perform a single LBM step */
+/*****************************************************************************/
+
+template<class D>
+void
+LbmFsgrSolver<D>::stepMain()
+{
+#if ELBEEM_BLENDER==1
+ // update gui display
+ SDL_mutexP(globalBakeLock);
+ if(globalBakeState<0) {
+ // this means abort... cause panic
+ D::mPanic = 1;
+ errMsg("LbmFsgrSolver::step","Got abort signal from GUI, causing panic, aborting...");
+ }
+ SDL_mutexV(globalBakeLock);
+#endif // ELBEEM_BLENDER==1
+ D::markedClearList(); // DMC clearMarkedCellsList
+ if(mDropping) {
+ initDrop(mDropX, mDropY);
+ }
+ if(mGfxGeoSetup==6) {
+ // xobs init hack
+ if(mSimulationTime<0.400) {
+ if((mSimulationTime>0.25) && (mSimulationTime<0.325)) {
+ // stop shortly...
+ mDropping = false;
+ } else {
+ initDrop(0.0, 1.0);
+ }
+ } else {
+ mDropping=false;
+ }
+ }
+
+ // safety check, counter reset
+ D::mNumUsedCells = 0;
+ mNumInterdCells = 0;
+ mNumInvIfCells = 0;
+
+ //debugOutNnl("LbmFsgrSolver::step : "<<D::mStepCnt, 10);
+ if(!D::mSilent){ debMsgNnl("LbmFsgrSolver::step", DM_MSG, D::mName<<" cnt:"<<D::mStepCnt<<" ", 10); }
+ //debMsgDirect( "LbmFsgrSolver::step : "<<D::mStepCnt<<" ");
+ myTime_t timestart = getTime();
+ //myTime_t timestart = 0;
+ //if(mStartSymm) { checkSymmetry("step1"); } // DEBUG
+
+ // important - keep for tadap
+ mCurrentMass = D::mFixMass; // reset here for next step
+ mCurrentVolume = 0.0;
+
+ //stats
+ mMaxVlen = mMxvz = mMxvy = mMxvx = 0.0;
+
+ //change to single step advance!
+ int dsbits = D::mStepCnt ^ (D::mStepCnt-1);
+ //errMsg("S"," step:"<<D::mStepCnt<<" s-1:"<<(D::mStepCnt-1)<<" xf:"<<convertFlags2String(dsbits));
+ for(int lev=0; lev<=mMaxRefine; lev++) {
+ //if(! (D::mStepCnt&(1<<lev)) ) {
+ if( dsbits & (1<<(mMaxRefine-lev)) ) {
+ //errMsg("S"," l"<<lev);
+
+ if(lev==mMaxRefine) {
+ // always advance fine level...
+ fineAdvance();
+ //performRefinement(lev-1); // TEST here?
+ } else {
+ performRefinement(lev); // TEST here?
+ performCoarsening(lev); // TEST here?
+ coarseRestrictFromFine(lev);
+ coarseAdvance(lev);
+ //performRefinement(lev-1); // TEST here?
+ }
+#if FSGR_OMEGA_DEBUG==1
+ errMsg("LbmFsgrSolver::step","LES stats l="<<lev<<" omega="<<mLevel[lev].omega<<" avgOmega="<< (mLevel[lev].avgOmega/mLevel[lev].avgOmegaCnt) );
+ mLevel[lev].avgOmega = 0.0; mLevel[lev].avgOmegaCnt = 0.0;
+#endif // FSGR_OMEGA_DEBUG==1
+
+ LbmFloat interTime = -10.0;
+#if TIMEINTORDER==1
+ interTime = 0.5;
+ if( D::mStepCnt & (1<<(mMaxRefine-lev)) ) interTime = 0.0;
+ // TEST influence... interTime = 0.0;
+#elif TIMEINTORDER==2
+ interTime = 1.0;
+#else // TIMEINTORDER==0
+ interTime = 0.0;
+#endif // TIMEINTORDER==1
+
+ // test mix! , double 0.5 stablest?
+#if INTCFCOARSETEST==1
+ //if(lev!=mMaxRefine) { interpolateFineFromCoarse(lev,interTime); } // test!
+#else // INTCFCOARSETEST==1
+ interpolateFineFromCoarse(lev,interTime);
+ ooo
+#endif // INTCFCOARSETEST==1
+ // */
+
+ }
+ mCurrentMass += mLevel[lev].lmass;
+ mCurrentVolume += mLevel[lev].lvolume;
+ }
+
+ // prepare next step
+ D::mStepCnt++;
+
+
+ // some dbugging output follows
+ // calculate MLSUPS
+ myTime_t timeend = getTime();
+
+ D::mNumUsedCells += mNumInterdCells; // count both types for MLSUPS
+ mAvgNumUsedCells += D::mNumUsedCells;
+ D::mMLSUPS = (D::mNumUsedCells / ((timeend-timestart)/(double)1000.0) ) / (1000000);
+ if(D::mMLSUPS>10000){ D::mMLSUPS = -1; }
+ else { mAvgMLSUPS += D::mMLSUPS; mAvgMLSUPSCnt += 1.0; } // track average mlsups
+
+ LbmFloat totMLSUPS = ( ((mLevel[mMaxRefine].lSizex-2)*(mLevel[mMaxRefine].lSizey-2)*(getForZMax1(mMaxRefine)-getForZMin1(mMaxRefine))) / ((timeend-timestart)/(double)1000.0) ) / (1000000);
+ if(totMLSUPS>10000) totMLSUPS = -1;
+ mNumInvIfTotal += mNumInvIfCells; // debug
+
+ // do some formatting
+ if(!D::mSilent){
+ string sepStr(""); // DEBUG
+ debMsgDirect(
+ "mlsups(curr:"<<D::mMLSUPS<<
+ " avg:"<<(mAvgMLSUPS/mAvgMLSUPSCnt)<<"), "<< sepStr<<
+ " totcls:"<<(D::mNumUsedCells)<< sepStr<<
+ " avgcls:"<< (int)(mAvgNumUsedCells/(long long int)D::mStepCnt)<< sepStr<<
+ " intd:"<<mNumInterdCells<< sepStr<<
+ " invif:"<<mNumInvIfCells<< sepStr<<
+ " invift:"<<mNumInvIfTotal<< sepStr<<
+ " filled:"<<D::mNumFilledCells<<", emptied:"<<D::mNumEmptiedCells<< sepStr<<
+ " mMxv:"<<mMxvx<<","<<mMxvy<<","<<mMxvz<<", tscnts:"<<mTimeSwitchCounts<< sepStr<<
+ /*" rhoMax:"<<mRhoMax<<", rhoMin:"<<mRhoMin<<", vlenMax:"<<mMaxVlen<<", "*/
+ " probs:"<<mNumProblems<< sepStr<<
+ " simt:"<<mSimulationTime<< sepStr<<
+ " for '"<<D::mName<<"' " );
+
+ //wrong?
+ debMsgDirect(", dccd:"<< mCurrentMass<<"/"<<mCurrentVolume<<"("<<D::mFixMass<<")" );
+ debMsgDirect(std::endl);
+
+ // nicer output
+ debMsgDirect(std::endl); //
+ //debMsgStd(" ",DM_MSG," ",10);
+ }
+ // else {
+ //debMsgDirect(".");
+ //if((mStepCnt%10)==9) debMsgDirect("\n");
+ //}
+
+ if(D::mStepCnt==1) {
+ mMinNoCells = mMaxNoCells = D::mNumUsedCells;
+ } else {
+ if(D::mNumUsedCells>mMaxNoCells) mMaxNoCells = D::mNumUsedCells;
+ if(D::mNumUsedCells<mMinNoCells) mMinNoCells = D::mNumUsedCells;
+ }
+
+ // mass scale test
+ if(mMaxRefine>0) {
+ LbmFloat mscale = mInitialMass/mCurrentMass;
+
+ mscale = 1.0;
+ const LbmFloat dchh = 0.001;
+ if(mCurrentMass<mInitialMass) mscale = 1.0+dchh;
+ if(mCurrentMass>mInitialMass) mscale = 1.0-dchh;
+
+ const int MSInter = 2;
+ static int mscount = 0;
+ if( (1) && ((mLevel[0].lsteps%MSInter)== (MSInter-1)) && ( ABS( (mInitialMass/mCurrentMass)-1.0 ) > 0.01) && ( dsbits & (1<<(mMaxRefine-0)) ) ){
+ // example: FORCE RESCALE MASS! ini:1843.5, cur:1817.6, f=1.01425 step:22153 levstep:5539 msc:37
+ errMsg("MDTDD","\n\n");
+ errMsg("MDTDD","FORCE RESCALE MASS! "
+ <<"ini:"<<mInitialMass<<", cur:"<<mCurrentMass<<", f="<<ABS(mInitialMass/mCurrentMass)
+ <<" step:"<<D::mStepCnt<<" levstep:"<<mLevel[0].lsteps<<" msc:"<<mscount<<" "
+ );
+ errMsg("MDTDD","\n\n");
+
+ mscount++;
+ for(int lev=mMaxRefine; lev>=0 ; lev--) {
+ //for(int workSet = 0; workSet<=1; workSet++) {
+ int wss = 0;
+ int wse = 1;
+#if COMPRESSGRIDS==1
+ if(lev== mMaxRefine) wss = wse = mLevel[lev].setCurr;
+#endif // COMPRESSGRIDS==1
+ for(int workSet = wss; workSet<=wse; workSet++) { // COMPRT
+
+ FSGR_FORIJK1(lev) {
+ if( (RFLAG(lev,i,j,k, workSet) & (CFFluid| CFInter| CFGrFromCoarse| CFGrFromFine| CFGrNorm))
+ ) {
+
+ FORDF0 { QCELL(lev, i,j,k,workSet, l) *= mscale; }
+ QCELL(lev, i,j,k,workSet, dMass) *= mscale;
+ QCELL(lev, i,j,k,workSet, dFfrac) *= mscale;
+
+ } else {
+ continue;
+ }
+ }
+ }
+ mLevel[lev].lmass *= mscale;
+ }
+ }
+
+ mCurrentMass *= mscale;
+ }// if mass scale test */
+
+ // one of the last things to do - adapt timestep
+ // was in fineAdvance before...
+ if(mTimeAdap) {
+ adaptTimestep();
+ } // time adaptivity
+
+ // debug - raw dump of ffrac values
+ /*if((mStepCnt%200)==1){
+ std::ostringstream name;
+ name <<"fill_" << mStepCnt <<".dump";
+ FILE *file = fopen(name.str().c_str(),"w");
+ for(int k= getForZMinBnd(mMaxRefine); k< getForZMaxBnd(mMaxRefine); ++k)
+ for(int j=0;j<mLevel[mMaxRefine].lSizey-0;j++)
+ for(int i=0;i<mLevel[mMaxRefine].lSizex-0;i++) {
+ float val = QCELL(mMaxRefine,i,j,k, mLevel[mMaxRefine].setCurr,dFfrac);
+ fwrite( &val, sizeof(val), 1, file);
+ //errMsg("W", PRINT_IJK<<" val:"<<val);
+ }
+ fclose(file);
+ } // */
+
+ /*
+ if(1) { // DEBUG
+ const int lev = mMaxRefine;
+ int workSet = mLevel[lev].setCurr;
+ FSGR_FORIJK1(lev) {
+ if(
+ (RFLAG(lev,i,j,k, workSet) & CFFluid) ||
+ (RFLAG(lev,i,j,k, workSet) & CFInter) ||
+ (RFLAG(lev,i,j,k, workSet) & CFGrFromCoarse) ||
+ (RFLAG(lev,i,j,k, workSet) & CFGrFromFine) ||
+ (RFLAG(lev,i,j,k, workSet) & CFGrNorm)
+ ) {
+ // these cells have to be scaled...
+ } else {
+ continue;
+ }
+
+ // collide on current set
+ LbmFloat rho, ux,uy,uz;
+ rho=0.0; ux = uy = uz = 0.0;
+ for(int l=0; l<D::cDfNum; l++) {
+ LbmFloat m = QCELL(lev, i, j, k, workSet, l);
+ rho += m;
+ ux += (D::dfDvecX[l]*m);
+ uy += (D::dfDvecY[l]*m);
+ uz += (D::dfDvecZ[l]*m);
+ }
+ //errMsg("DEBUG"," "<<PRINT_IJK <<" rho="<<rho<<" vel="<<PRINT_VEC(ux,uy,uz) );
+ f__printf(stdout,"D %d,%d rho=%+'.5f vel=[%+'.5f,%+'.5f] \n", i,j, rho, ux,uy );
+ }
+ } // DEBUG */
+
+}
+
+template<class D>
+void
+LbmFsgrSolver<D>::fineAdvance()
+{
+ // do the real thing...
+ mainLoop( mMaxRefine );
+ if(mUpdateFVHeight) {
+ // warning assume -Y gravity...
+ mFVHeight = mCurrentMass*mFVArea/((LbmFloat)(mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizez));
+ if(mFVHeight<1.0) mFVHeight = 1.0;
+ D::mpParam->setFluidVolumeHeight(mFVHeight);
+ }
+
+ // advance time before timestep change
+ mSimulationTime += D::mpParam->getStepTime();
+
+ // time adaptivity
+ D::mpParam->setSimulationMaxSpeed( sqrt(mMaxVlen / 1.5) );
+ if(mTimeAdap) {
+ // ORG adaptTimestep();
+ } // time adaptivity
+
+ //if(mStartSymm) { checkSymmetry("step2"); } // DEBUG
+
+ if(!D::mSilent){ errMsg("fineAdvance"," stepped from "<<mLevel[mMaxRefine].setCurr<<" to "<<mLevel[mMaxRefine].setOther<<" step"<< (mLevel[mMaxRefine].lsteps) ); }
+
+ // update other set
+ mLevel[mMaxRefine].setOther = mLevel[mMaxRefine].setCurr;
+ mLevel[mMaxRefine].setCurr ^= 1;
+ mLevel[mMaxRefine].lsteps++;
+
+ // flag init... (work on current set, to simplify flag checks)
+ reinitFlags( mLevel[mMaxRefine].setCurr );
+ //if((D::cDimension==2)&&(mStartSymm)) { checkSymmetry("step3"); } // DEBUG
+ if(!D::mSilent){ errMsg("fineAdvance"," flags reinit on set "<< mLevel[mMaxRefine].setCurr ); }
+}
+
+
+/*****************************************************************************/
+//! coarse/fine step functions
+/*****************************************************************************/
+
+// access to own dfs during step (may be changed to local array)
+#define MYDF(l) RAC(ccel, l)
+
+template<class D>
+void
+LbmFsgrSolver<D>::mainLoop(int lev)
+{
+ // loops over _only inner_ cells -----------------------------------------------------------------------------------
+ LbmFloat calcCurrentMass = 0.0; //mCurrentMass;
+ LbmFloat calcCurrentVolume = 0.0; //mCurrentVolume;
+ int calcCellsFilled = D::mNumFilledCells;
+ int calcCellsEmptied = D::mNumEmptiedCells;
+ int calcNumUsedCells = D::mNumUsedCells;
+
+#if PARALLEL==1
+#include "paraloop.h"
+#else // PARALLEL==1
+ { // main loop region
+ const int id = 0, Nthrds = 1;
+ int kstart=D::getForZMin1(), kend=D::getForZMax1();
+#define PERFORM_USQRMAXCHECK USQRMAXCHECK(usqr,ux,uy,uz, mMaxVlen, mMxvx,mMxvy,mMxvz);
+#endif // PARALLEL==1
+
+
+ // local to loop
+ CellFlagType nbflag[LBM_DFNUM];
+#define NBFLAG(l) nbflag[(l)]
+ // */
+
+ LbmFloat *ccel = NULL;
+ LbmFloat *tcel = NULL;
+ int oldFlag;
+ int newFlag;
+ int nbored;
+ LbmFloat m[LBM_DFNUM];
+ LbmFloat rho, ux, uy, uz, tmp, usqr;
+ LbmFloat mass, change;
+ usqr = tmp = 0.0;
+#if OPT3D==true
+ LbmFloat lcsmqadd, lcsmqo, lcsmeq[LBM_DFNUM], lcsmomega;
+#endif // OPT3D==true
+
+
+ // ifempty cell conversion flags
+ bool iffilled, ifemptied;
+ int recons[LBM_DFNUM]; // reconstruct this DF?
+ int numRecons; // how many are reconstructed?
+
+
+ CellFlagType *pFlagSrc;
+ CellFlagType *pFlagDst;
+ pFlagSrc = &RFLAG(lev, 0,1, kstart,SRCS(lev)); // omp
+ pFlagDst = &RFLAG(lev, 0,1, kstart,TSET(lev)); // omp
+ ccel = RACPNT(lev, 0,1, kstart ,SRCS(lev)); // omp
+ tcel = RACPNT(lev, 0,1, kstart ,TSET(lev)); // omp
+ //CellFlagType *pFlagTar = NULL;
+ int pFlagTarOff;
+ if(mLevel[lev].setOther==1) pFlagTarOff = mLevel[lev].lOffsz;
+ else pFlagTarOff = -mLevel[lev].lOffsz;
+#define ADVANCE_POINTERS(p) \
+ ccel += (QCELLSTEP*(p)); \
+ tcel += (QCELLSTEP*(p)); \
+ pFlagSrc+= (p); \
+ pFlagDst+= (p); \
+ i+= (p);
+
+ // nutshell outflow HACK
+ if(mGfxGeoSetup==2) {
+ for(int k= getForZMin1(lev); k< getForZMax1(lev); ++k) {
+ {const int j=1;
+ for(int i=1;i<mLevel[mMaxRefine].lSizex-1;++i) {
+ if(RFLAG(lev, i,j,k,SRCS(lev)) & CFFluid) {
+ RFLAG(lev, i,j,k,SRCS(lev)) = CFInter;
+ QCELL(lev, i,j,k,SRCS(lev), dMass) = 0.1;
+ QCELL(lev, i,j,k,SRCS(lev), dFfrac) = 0.1;
+ }
+ else if(RFLAG(lev, i,j,k,SRCS(lev)) & CFInter) {
+ QCELL(lev, i,j,k,SRCS(lev), dMass) = 0.1;
+ QCELL(lev, i,j,k,SRCS(lev), dFfrac) = 0.1;
+ }
+ } } } }
+
+
+
+ // ---
+ // now stream etc.
+
+ // use template functions for 2D/3D
+ //#pragma omp for schedule(static,1) nowait
+ //for(int k= getForZMin1(lev); k< getForZMax1(lev); ++k) {
+#if COMPRESSGRIDS==0
+ for(int k=kstart;k<kend;++k) {
+ for(int j=1;j<mLevel[lev].lSizey-1;++j) {
+ for(int i=0;i<mLevel[lev].lSizex-2; ) {
+#else // COMPRESSGRIDS==0
+ int kdir = 1; // COMPRT ON
+ if(mLevel[mMaxRefine].setCurr==1) {
+ kdir = -1;
+ int temp = kend;
+ kend = kstart-1;
+ kstart = temp-1;
+ } // COMPRT
+
+ const int Nj = D::mSizey-2;
+ const int jstart = 1+( id * (Nj / Nthrds) );
+ const int jend = 1+( (id+1) * (Nj / Nthrds) );
+ if( ((Nj/Nthrds) *Nthrds) != Nj) {
+ errMsg("LbmFsgrSolver","Invalid domain size Nj="<<Nj<<" Nthrds="<<Nthrds);
+ }
+
+#if PARALLEL==1
+ errMsg("LbmFsgrSolver::mainLoop","id="<<id<<" js="<<jstart<<" je="<<jend<<" jdir="<<(1) ); // debug
+#endif // PARALLEL==1
+ for(int k=kstart;k!=kend;k+=kdir) {
+
+ //errMsg("LbmFsgrSolver::mainLoop","k="<<k<<" ks="<<kstart<<" ke="<<kend<<" kdir="<<kdir<<" x*y="<<mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*dTotalNum ); // debug
+ pFlagSrc = &RFLAG(lev, 0, jstart, k, SRCS(lev)); // omp test // COMPRT ON
+ pFlagDst = &RFLAG(lev, 0, jstart, k, TSET(lev)); // omp test
+ ccel = RACPNT(lev, 0, jstart, k, SRCS(lev)); // omp test
+ tcel = RACPNT(lev, 0, jstart, k, TSET(lev)); // omp test // COMPRT ON
+
+ //for(int j=1;j<mLevel[lev].lSizey-1;++j) {
+ for(int j=jstart;j!=jend;++j) {
+ for(int i=0;i<mLevel[lev].lSizex-2; ) {
+#endif // COMPRESSGRIDS==0
+
+ ADVANCE_POINTERS(1);
+#if FSGR_STRICT_DEBUG==1
+ rho = ux = uy = uz = tmp = usqr = -100.0; // DEBUG
+ if( (&RFLAG(lev, i,j,k,mLevel[lev].setCurr) != pFlagSrc) ||
+ (&RFLAG(lev, i,j,k,mLevel[lev].setOther) != pFlagDst) ) {
+ errMsg("LbmFsgrSolver::mainLoop","Err flagp "<<PRINT_IJK<<"="<<
+ RFLAG(lev, i,j,k,mLevel[lev].setCurr)<<","<<RFLAG(lev, i,j,k,mLevel[lev].setOther)<<" but is "<<
+ (*pFlagSrc)<<","<<(*pFlagDst) <<", pointers "<<
+ (int)(&RFLAG(lev, i,j,k,mLevel[lev].setCurr))<<","<<(int)(&RFLAG(lev, i,j,k,mLevel[lev].setOther))<<" but is "<<
+ (int)(pFlagSrc)<<","<<(int)(pFlagDst)<<" "
+ );
+ D::mPanic=1;
+ }
+ if( (&QCELL(lev, i,j,k,mLevel[lev].setCurr,0) != ccel) ||
+ (&QCELL(lev, i,j,k,mLevel[lev].setOther,0) != tcel) ) {
+ errMsg("LbmFsgrSolver::mainLoop","Err cellp "<<PRINT_IJK<<"="<<
+ (int)(&QCELL(lev, i,j,k,mLevel[lev].setCurr,0))<<","<<(int)(&QCELL(lev, i,j,k,mLevel[lev].setOther,0))<<" but is "<<
+ (int)(ccel)<<","<<(int)(tcel)<<" "
+ );
+ D::mPanic=1;
+ }
+#endif
+ // stream from current set to other, then collide and store
+
+#if INTCFCOARSETEST==1
+ //if(RFLAG(lev, i,j,k,mLevel[lev].setCurr)&CFGrFromCoarse) {
+ if( ((*pFlagSrc) & (CFGrFromCoarse)) ) { // interpolateFineFromCoarse test!
+ if(( D::mStepCnt & (1<<(mMaxRefine-lev)) ) ==1) {
+ FORDF0 { RAC(tcel,l) = RAC(ccel,l); }
+ } else {
+ interpolateCellFromCoarse( lev, i,j,k, TSET(lev), 0.0, CFFluid|CFGrFromCoarse, false);
+ calcNumUsedCells++;
+ }
+ continue; // interpolateFineFromCoarse test!
+ } // interpolateFineFromCoarse test!
+#else // INTCFCOARSETEST==1
+ done in main loop afterwards..
+#endif // INTCFCOARSETEST==1
+
+ if( ((*pFlagSrc) & (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused)) ) {
+ *pFlagDst = *pFlagSrc;
+ //RAC(tcel,dFfrac) = 0.0;
+ //RAC(tcel,dFlux) = FLUX_INIT; // necessary?
+ continue;
+ }
+
+ // only neighbor flags! not own flag
+ oldFlag = * pFlagSrc;
+ nbored = 0;
+
+#if OPT3D==false
+ FORDF1 {
+ nbflag[l] = RFLAG_NB(lev, i,j,k,SRCS(lev),l);
+ nbored |= nbflag[l];
+ }
+#else
+ nbflag[dSB] = *(pFlagSrc + (-mLevel[lev].lOffsy+-mLevel[lev].lOffsx)); nbored |= nbflag[dSB];
+ nbflag[dWB] = *(pFlagSrc + (-mLevel[lev].lOffsy+-1)); nbored |= nbflag[dWB];
+ nbflag[ dB] = *(pFlagSrc + (-mLevel[lev].lOffsy)); nbored |= nbflag[dB];
+ nbflag[dEB] = *(pFlagSrc + (-mLevel[lev].lOffsy+ 1)); nbored |= nbflag[dEB];
+ nbflag[dNB] = *(pFlagSrc + (-mLevel[lev].lOffsy+ mLevel[lev].lOffsx)); nbored |= nbflag[dNB];
+
+ nbflag[dSW] = *(pFlagSrc + (-mLevel[lev].lOffsx+-1)); nbored |= nbflag[dSW];
+ nbflag[ dS] = *(pFlagSrc + (-mLevel[lev].lOffsx)); nbored |= nbflag[dS];
+ nbflag[dSE] = *(pFlagSrc + (-mLevel[lev].lOffsx+ 1)); nbored |= nbflag[dSE];
+
+ nbflag[ dW] = *(pFlagSrc + (-1)); nbored |= nbflag[dW];
+ nbflag[ dE] = *(pFlagSrc + ( 1)); nbored |= nbflag[dE];
+
+ nbflag[dNW] = *(pFlagSrc + ( mLevel[lev].lOffsx+-1)); nbored |= nbflag[dNW];
+ nbflag[ dN] = *(pFlagSrc + ( mLevel[lev].lOffsx)); nbored |= nbflag[dN];
+ nbflag[dNE] = *(pFlagSrc + ( mLevel[lev].lOffsx+ 1)); nbored |= nbflag[dNE];
+
+ nbflag[dST] = *(pFlagSrc + ( mLevel[lev].lOffsy+-mLevel[lev].lOffsx)); nbored |= nbflag[dST];
+ nbflag[dWT] = *(pFlagSrc + ( mLevel[lev].lOffsy+-1)); nbored |= nbflag[dWT];
+ nbflag[ dT] = *(pFlagSrc + ( mLevel[lev].lOffsy)); nbored |= nbflag[dT];
+ nbflag[dET] = *(pFlagSrc + ( mLevel[lev].lOffsy+ 1)); nbored |= nbflag[dET];
+ nbflag[dNT] = *(pFlagSrc + ( mLevel[lev].lOffsy+ mLevel[lev].lOffsx)); nbored |= nbflag[dNT];
+ // */
+#endif
+
+ // pointer to destination cell
+ calcNumUsedCells++;
+
+ // FLUID cells
+ if( oldFlag & CFFluid ) {
+
+ // only standard fluid cells (with nothing except fluid as nbs
+ if(!( (nbored) & (~(CFFluid)) )) {
+ // do standard stream/collide
+ OPTIMIZED_STREAMCOLLIDE;
+ // FIXME check for which cells this is executed!
+ } else {
+ DEFAULT_STREAM;
+ ux = mLevel[lev].gravity[0]; uy = mLevel[lev].gravity[1]; uz = mLevel[lev].gravity[2];
+ DEFAULT_COLLIDE;
+ }
+ if(nbored&CFBnd) {
+ oldFlag &= (~CFNoBndFluid);
+ } else {
+ oldFlag |= CFNoBndFluid;
+ }
+
+ PERFORM_USQRMAXCHECK;
+ // "normal" fluid cells
+ RAC(tcel,dFfrac) = 1.0;
+ *pFlagDst = (CellFlagType)oldFlag; // newFlag;
+ calcCurrentMass += rho;
+ calcCurrentVolume += 1.0;
+ continue;
+ }
+
+ newFlag = oldFlag; //cell(i,j,k, SRCS(lev)).flag;
+ // make sure: check which flags to really unset...!
+ newFlag = newFlag & (~(
+ CFNoNbFluid|CFNoNbEmpty| CFNoDelete
+ |CFNoInterpolSrc
+ |CFNoBndFluid
+ ));
+
+ // unnecessary for interface cells... !?
+ if(nbored&CFBnd) { } else { newFlag |= CFNoBndFluid; }
+
+ // store own dfs and mass
+ mass = RAC(ccel,dMass);
+
+ // WARNING - only interface cells arrive here!
+ // read distribution funtions of adjacent cells = sweep step // FIXME after empty?
+ DEFAULT_STREAM;
+
+ if((nbored & CFFluid)==0) { newFlag |= CFNoNbFluid; mNumInvIfCells++; }
+ if((nbored & CFEmpty)==0) { newFlag |= CFNoNbEmpty; mNumInvIfCells++; }
+
+ // calculate mass exchange for interface cells
+ LbmFloat myfrac = RAC(ccel,dFfrac);
+# define nbdf(l) m[ D::dfInv[(l)] ]
+
+ // update mass
+ // only do boundaries for fluid cells, and interface cells without
+ // any fluid neighbors (assume that interface cells _with_ fluid
+ // neighbors are affected enough by these)
+ // which Df's have to be reconstructed?
+ // for fluid cells - just the f_i difference from streaming to empty cells ----
+ numRecons = 0;
+
+ FORDF1 { // dfl loop
+ recons[l] = 0;
+ // finally, "normal" interface cells ----
+ if( NBFLAG(l)&CFFluid ) {
+ change = nbdf(l) - MYDF(l);
+ }
+ // interface cells - distuingish cells that shouldn't fill/empty
+ else if( NBFLAG(l) & CFInter ) {
+
+ LbmFloat mynbfac = //numNbs[l] / numNbs[0];
+ QCELL_NB(lev, i,j,k,SRCS(lev),l, dFlux) / QCELL(lev, i,j,k,SRCS(lev), dFlux);
+ LbmFloat nbnbfac = 1.0/mynbfac;
+ //mynbfac = nbnbfac = 1.0; // switch calc flux off
+ // OLD
+ if ((oldFlag|NBFLAG(l))&(CFNoNbFluid|CFNoNbEmpty)) {
+ switch (oldFlag&(CFNoNbFluid|CFNoNbEmpty)) {
+ case 0:
+ // we are a normal cell so...
+ switch (NBFLAG(l)&(CFNoNbFluid|CFNoNbEmpty)) {
+ case CFNoNbFluid:
+ // just fill current cell = empty neighbor
+ change = nbnbfac*nbdf(l) ; goto changeDone;
+ case CFNoNbEmpty:
+ // just empty current cell = fill neighbor
+ change = - mynbfac*MYDF(l) ; goto changeDone;
+ }
+ break;
+
+ case CFNoNbFluid:
+ // we dont have fluid nb's so...
+ switch (NBFLAG(l)&(CFNoNbFluid|CFNoNbEmpty)) {
+ case 0:
+ case CFNoNbEmpty:
+ // we have no fluid nb's -> just empty
+ change = - mynbfac*MYDF(l) ; goto changeDone;
+ }
+ break;
+
+ case CFNoNbEmpty:
+ // we dont have empty nb's so...
+ switch (NBFLAG(l)&(CFNoNbFluid|CFNoNbEmpty)) {
+ case 0:
+ case CFNoNbFluid:
+ // we have no empty nb's -> just fill
+ change = nbnbfac*nbdf(l); goto changeDone;
+ }
+ break;
+ }} // inter-inter exchange
+
+ // just do normal mass exchange...
+ change = ( nbnbfac*nbdf(l) - mynbfac*MYDF(l) ) ;
+ changeDone: ;
+ change *= ( myfrac + QCELL_NB(lev, i,j,k, SRCS(lev),l, dFfrac) ) * 0.5;
+ } // the other cell is interface
+
+ // last alternative - reconstruction in this direction
+ else {
+ //if(NBFLAG(l) & CFEmpty) { recons[l] = true; }
+ recons[l] = 1;
+ numRecons++;
+ change = 0.0;
+ // which case is this...? empty + bnd
+ }
+
+ // modify mass at SRCS
+ mass += change;
+ } // l
+ // normal interface, no if empty/fluid
+
+ LbmFloat nv1,nv2;
+ LbmFloat nx,ny,nz;
+
+ if(NBFLAG(dE) &(CFFluid|CFInter)){ nv1 = RAC((ccel+QCELLSTEP ),dFfrac); } else nv1 = 0.0;
+ if(NBFLAG(dW) &(CFFluid|CFInter)){ nv2 = RAC((ccel-QCELLSTEP ),dFfrac); } else nv2 = 0.0;
+ nx = 0.5* (nv2-nv1);
+ if(NBFLAG(dN) &(CFFluid|CFInter)){ nv1 = RAC((ccel+(mLevel[lev].lOffsx*QCELLSTEP)),dFfrac); } else nv1 = 0.0;
+ if(NBFLAG(dS) &(CFFluid|CFInter)){ nv2 = RAC((ccel-(mLevel[lev].lOffsx*QCELLSTEP)),dFfrac); } else nv2 = 0.0;
+ ny = 0.5* (nv2-nv1);
+#if LBMDIM==3
+ if(NBFLAG(dT) &(CFFluid|CFInter)){ nv1 = RAC((ccel+(mLevel[lev].lOffsy*QCELLSTEP)),dFfrac); } else nv1 = 0.0;
+ if(NBFLAG(dB) &(CFFluid|CFInter)){ nv2 = RAC((ccel-(mLevel[lev].lOffsy*QCELLSTEP)),dFfrac); } else nv2 = 0.0;
+ nz = 0.5* (nv2-nv1);
+#else // LBMDIM==3
+ nz = 0.0;
+#endif // LBMDIM==3
+
+ if( (ABS(nx)+ABS(ny)+ABS(nz)) > LBM_EPSILON) {
+ // normal ok and usable...
+ FORDF1 {
+ if( (D::dfDvecX[l]*nx + D::dfDvecY[l]*ny + D::dfDvecZ[l]*nz) // dot Dvec,norml
+ > LBM_EPSILON) {
+ recons[l] = 2;
+ numRecons++;
+ }
+ }
+ }
+
+ // calculate macroscopic cell values
+ LbmFloat oldUx, oldUy, oldUz;
+ LbmFloat oldRho; // OLD rho = ccel->rho;
+#if OPT3D==false
+ oldRho=RAC(ccel,0);
+ oldUx = oldUy = oldUz = 0.0;
+ for(int l=1; l<D::cDfNum; l++) {
+ oldRho += RAC(ccel,l);
+ oldUx += (D::dfDvecX[l]*RAC(ccel,l));
+ oldUy += (D::dfDvecY[l]*RAC(ccel,l));
+ oldUz += (D::dfDvecZ[l]*RAC(ccel,l));
+ }
+#else // OPT3D==false
+ oldRho = + RAC(ccel,dC) + RAC(ccel,dN )
+ + RAC(ccel,dS ) + RAC(ccel,dE )
+ + RAC(ccel,dW ) + RAC(ccel,dT )
+ + RAC(ccel,dB ) + RAC(ccel,dNE)
+ + RAC(ccel,dNW) + RAC(ccel,dSE)
+ + RAC(ccel,dSW) + RAC(ccel,dNT)
+ + RAC(ccel,dNB) + RAC(ccel,dST)
+ + RAC(ccel,dSB) + RAC(ccel,dET)
+ + RAC(ccel,dEB) + RAC(ccel,dWT)
+ + RAC(ccel,dWB);
+
+ oldUx = + RAC(ccel,dE) - RAC(ccel,dW)
+ + RAC(ccel,dNE) - RAC(ccel,dNW)
+ + RAC(ccel,dSE) - RAC(ccel,dSW)
+ + RAC(ccel,dET) + RAC(ccel,dEB)
+ - RAC(ccel,dWT) - RAC(ccel,dWB);
+
+ oldUy = + RAC(ccel,dN) - RAC(ccel,dS)
+ + RAC(ccel,dNE) + RAC(ccel,dNW)
+ - RAC(ccel,dSE) - RAC(ccel,dSW)
+ + RAC(ccel,dNT) + RAC(ccel,dNB)
+ - RAC(ccel,dST) - RAC(ccel,dSB);
+
+ oldUz = + RAC(ccel,dT) - RAC(ccel,dB)
+ + RAC(ccel,dNT) - RAC(ccel,dNB)
+ + RAC(ccel,dST) - RAC(ccel,dSB)
+ + RAC(ccel,dET) - RAC(ccel,dEB)
+ + RAC(ccel,dWT) - RAC(ccel,dWB);
+#endif
+
+ // now reconstruction
+#define REFERENCE_PRESSURE 1.0 // always atmosphere...
+#if OPT3D==false
+ // NOW - construct dist funcs from empty cells
+ FORDF1 {
+ if(recons[ l ]) {
+ m[ D::dfInv[l] ] =
+ D::getCollideEq(l, REFERENCE_PRESSURE, oldUx,oldUy,oldUz) +
+ D::getCollideEq(D::dfInv[l], REFERENCE_PRESSURE, oldUx,oldUy,oldUz)
+ - MYDF( l );
+ /*errMsg("D", " "<<PRINT_IJK<<" l"<<l<<" eql"<<D::getCollideEq(l, REFERENCE_PRESSURE, oldUx,oldUy,oldUz)<<
+ " eqInvl"<<D::getCollideEq(D::dfInv[l], REFERENCE_PRESSURE, oldUx,oldUy,oldUz)<<
+ " mydfl"<< MYDF( l ) <<
+ " newdf"<< m[ D::dfInv[l] ]<<" m"<<mass ); // MRT_FS_TEST */
+ } // */
+ }
+#else
+ ux=oldUx, uy=oldUy, uz=oldUz; // no local vars, only for usqr
+ rho = REFERENCE_PRESSURE;
+ usqr = 1.5 * (ux*ux + uy*uy + uz*uz);
+ if(recons[dN ]) { m[dS ] = EQN + EQS - MYDF(dN ); }
+ if(recons[dS ]) { m[dN ] = EQS + EQN - MYDF(dS ); }
+ if(recons[dE ]) { m[dW ] = EQE + EQW - MYDF(dE ); }
+ if(recons[dW ]) { m[dE ] = EQW + EQE - MYDF(dW ); }
+ if(recons[dT ]) { m[dB ] = EQT + EQB - MYDF(dT ); }
+ if(recons[dB ]) { m[dT ] = EQB + EQT - MYDF(dB ); }
+ if(recons[dNE]) { m[dSW] = EQNE + EQSW - MYDF(dNE); }
+ if(recons[dNW]) { m[dSE] = EQNW + EQSE - MYDF(dNW); }
+ if(recons[dSE]) { m[dNW] = EQSE + EQNW - MYDF(dSE); }
+ if(recons[dSW]) { m[dNE] = EQSW + EQNE - MYDF(dSW); }
+ if(recons[dNT]) { m[dSB] = EQNT + EQSB - MYDF(dNT); }
+ if(recons[dNB]) { m[dST] = EQNB + EQST - MYDF(dNB); }
+ if(recons[dST]) { m[dNB] = EQST + EQNB - MYDF(dST); }
+ if(recons[dSB]) { m[dNT] = EQSB + EQNT - MYDF(dSB); }
+ if(recons[dET]) { m[dWB] = EQET + EQWB - MYDF(dET); }
+ if(recons[dEB]) { m[dWT] = EQEB + EQWT - MYDF(dEB); }
+ if(recons[dWT]) { m[dEB] = EQWT + EQEB - MYDF(dWT); }
+ if(recons[dWB]) { m[dET] = EQWB + EQET - MYDF(dWB); }
+#endif
+
+ // mass streaming done...
+ // now collide new fluid or "old" if cells
+ ux = mLevel[lev].gravity[0]; uy = mLevel[lev].gravity[1]; uz = mLevel[lev].gravity[2];
+ DEFAULT_COLLIDE;
+ rho = m[dC];
+ FORDF1 { rho+=m[l]; };
+ // only with interface neighbors...?
+ PERFORM_USQRMAXCHECK;
+
+ // interface cell filled or emptied?
+ iffilled = ifemptied = 0;
+ // interface cells empty/full?, WARNING: to mark these cells, better do it at the end of reinitCellFlags
+ // interface cell if full?
+ if( (mass) >= (rho * (1.0+FSGR_MAGICNR)) ) { iffilled = 1; }
+ // interface cell if empty?
+ if( (mass) <= (rho * ( -FSGR_MAGICNR)) ) { ifemptied = 1; }
+
+ // looks much nicer... LISTTRICK
+#if FSGR_LISTTRICK==true
+ if(!iffilled) {
+ // remove cells independent from amount of change...
+ if( (oldFlag & CFNoNbEmpty)&&(newFlag & CFNoNbEmpty)&&
+ ( (mass>(rho*FSGR_LISTTTHRESHFULL)) || ((nbored&CFInter)==0) )
+ ) {
+ //if((nbored&CFInter)==0){ errMsg("NBORED!CFINTER","filled "<<PRINT_IJK); };
+ iffilled = 1;
+ }
+ }
+ if(!ifemptied) {
+ if( (oldFlag & CFNoNbFluid)&&(newFlag & CFNoNbFluid)&&
+ ( (mass<(rho*FSGR_LISTTTHRESHEMPTY)) || ((nbored&CFInter)==0) )
+ )
+ {
+ //if((nbored&CFInter)==0){ errMsg("NBORED!CFINTER","emptied "<<PRINT_IJK); };
+ ifemptied = 1;
+ }
+ } // */
+#endif
+
+ //iffilled = ifemptied = 0; // DEBUG!!!!!!!!!!!!!!!
+
+
+ // now that all dfs are known, handle last changes
+ if(iffilled) {
+ LbmPoint filledp;
+ filledp.x = i; filledp.y = j; filledp.z = k;
+#if PARALLEL==1
+ calcListFull[id].push_back( filledp );
+#else // PARALLEL==1
+ mListFull.push_back( filledp );
+#endif // PARALLEL==1
+ //D::mNumFilledCells++; // DEBUG
+ calcCellsFilled++;
+ }
+ else if(ifemptied) {
+ LbmPoint emptyp;
+ emptyp.x = i; emptyp.y = j; emptyp.z = k;
+#if PARALLEL==1
+ calcListEmpty[id].push_back( emptyp );
+#else // PARALLEL==1
+ mListEmpty.push_back( emptyp );
+#endif // PARALLEL==1
+ //D::mNumEmptiedCells++; // DEBUG
+ calcCellsEmptied++;
+ } else {
+ // ...
+ }
+
+ // dont cutoff values -> better cell conversions
+ RAC(tcel,dFfrac) = (mass/rho);
+
+ // init new flux value
+ float flux = 0.5*(float)(D::cDfNum); // dxqn on
+ //flux = 50.0; // extreme on
+ for(int nn=1; nn<D::cDfNum; nn++) {
+ if(RFLAG_NB(lev, i,j,k,SRCS(lev),nn) & (CFFluid|CFInter|CFBnd)) {
+ flux += D::dfLength[nn];
+ }
+ }
+ //flux = FLUX_INIT; // calc flux off
+ QCELL(lev, i,j,k,TSET(lev), dFlux) = flux; // */
+
+ // perform mass exchange with streamed values
+ QCELL(lev, i,j,k,TSET(lev), dMass) = mass; // MASST
+ // set new flag
+ *pFlagDst = (CellFlagType)newFlag;
+ calcCurrentMass += mass;
+ calcCurrentVolume += RAC(tcel,dFfrac);
+
+ // interface cell handling done...
+ } // i
+ int i=0; //dummy
+ ADVANCE_POINTERS(2);
+ } // j
+
+#if COMPRESSGRIDS==1
+#if PARALLEL==1
+ //fprintf(stderr," (id=%d k=%d) ",id,k);
+# pragma omp barrier
+#endif // PARALLEL==1
+#else // COMPRESSGRIDS==1
+ int i=0; //dummy
+ ADVANCE_POINTERS(mLevel[lev].lSizex*2);
+#endif // COMPRESSGRIDS==1
+ } // all cell loop k,j,i
+
+ } // main loop region
+
+ // write vars from parallel computations to class
+ //errMsg("DFINI"," maxr l"<<mMaxRefine<<" cm="<<calcCurrentMass<<" cv="<<calcCurrentVolume );
+ mLevel[lev].lmass = calcCurrentMass;
+ mLevel[lev].lvolume = calcCurrentVolume;
+ //mCurrentMass += calcCurrentMass;
+ //mCurrentVolume += calcCurrentVolume;
+ D::mNumFilledCells = calcCellsFilled;
+ D::mNumEmptiedCells = calcCellsEmptied;
+ D::mNumUsedCells = calcNumUsedCells;
+#if PARALLEL==1
+ errMsg("PARALLELusqrcheck"," curr: "<<mMaxVlen<<"|"<<mMxvx<<","<<mMxvy<<","<<mMxvz);
+ for(int i=0; i<MAX_THREADS; i++) {
+ for(int j=0; j<calcListFull[i].size() ; j++) mListFull.push_back( calcListFull[i][j] );
+ for(int j=0; j<calcListEmpty[i].size(); j++) mListEmpty.push_back( calcListEmpty[i][j] );
+ if(calcMaxVlen[i]>mMaxVlen) {
+ mMxvx = calcMxvx[i];
+ mMxvy = calcMxvy[i];
+ mMxvz = calcMxvz[i];
+ mMaxVlen = calcMaxVlen[i];
+ }
+ errMsg("PARALLELusqrcheck"," curr: "<<mMaxVlen<<"|"<<mMxvx<<","<<mMxvy<<","<<mMxvz<<
+ " calc["<<i<<": "<<calcMaxVlen[i]<<"|"<<calcMxvx[i]<<","<<calcMxvy[i]<<","<<calcMxvz[i] );
+ }
+#endif // PARALLEL==1
+
+ // check other vars...?
+}
+
+template<class D>
+void
+LbmFsgrSolver<D>::coarseCalculateFluxareas(int lev)
+{
+ //LbmFloat calcCurrentMass = 0.0;
+ //LbmFloat calcCurrentVolume = 0.0;
+ //LbmFloat *ccel = NULL;
+ //LbmFloat *tcel = NULL;
+ //LbmFloat m[LBM_DFNUM];
+ //LbmFloat rho, ux, uy, uz, tmp, usqr;
+#if OPT3D==true
+ //LbmFloat lcsmqadd, lcsmqo, lcsmeq[LBM_DFNUM], lcsmomega;
+#endif // OPT3D==true
+ //m[0] = tmp = usqr = 0.0;
+
+ //for(int lev=0; lev<mMaxRefine; lev++) { TEST DEBUG
+ FSGR_FORIJK_BOUNDS(lev) {
+ if( RFLAG(lev, i,j,k,mLevel[lev].setCurr) & CFFluid) {
+ if( RFLAG(lev+1, i*2,j*2,k*2,mLevel[lev+1].setCurr) & CFGrFromCoarse) {
+ LbmFloat totArea = mFsgrCellArea[0]; // for l=0
+ for(int l=1; l<D::cDirNum; l++) {
+ int ni=(2*i)+D::dfVecX[l], nj=(2*j)+D::dfVecY[l], nk=(2*k)+D::dfVecZ[l];
+ if(RFLAG(lev+1, ni,nj,nk, mLevel[lev+1].setCurr)&
+ (CFGrFromCoarse|CFUnused|CFEmpty) //? (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused)
+ ) {
+ totArea += mFsgrCellArea[l];
+ }
+ } // l
+ QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = totArea;
+ //continue;
+ } else
+ if( RFLAG(lev+1, i*2,j*2,k*2,mLevel[lev+1].setCurr) & (CFEmpty|CFUnused)) {
+ QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = 1.0;
+ //continue;
+ } else {
+ QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = 0.0;
+ }
+ //errMsg("DFINI"," at l"<<lev<<" "<<PRINT_IJK<<" v:"<<QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) );
+ }
+ } // } TEST DEBUG
+ if(!D::mSilent){ debMsgStd("coarseCalculateFluxareas",DM_MSG,"level "<<lev<<" calculated", 7); }
+}
+
+template<class D>
+void
+LbmFsgrSolver<D>::coarseAdvance(int lev)
+{
+ LbmFloat calcCurrentMass = 0.0;
+ LbmFloat calcCurrentVolume = 0.0;
+
+ LbmFloat *ccel = NULL;
+ LbmFloat *tcel = NULL;
+ LbmFloat m[LBM_DFNUM];
+ LbmFloat rho, ux, uy, uz, tmp, usqr;
+#if OPT3D==true
+ LbmFloat lcsmqadd, lcsmqo, lcsmeq[LBM_DFNUM], lcsmomega;
+#endif // OPT3D==true
+ m[0] = tmp = usqr = 0.0;
+
+ coarseCalculateFluxareas(lev);
+ /*
+ //for(int lev=0; lev<mMaxRefine; lev++) { TEST DEBUG
+ FSGR_FORIJK_BOUNDS(lev) {
+ if( RFLAG(lev, i,j,k,mLevel[lev].setCurr) & CFFluid) {
+ if( RFLAG(lev+1, i*2,j*2,k*2,mLevel[lev+1].setCurr) & CFGrFromCoarse) {
+ LbmFloat totArea = mFsgrCellArea[0]; // for l=0
+ for(int l=1; l<D::cDirNum; l++) {
+ int ni=(2*i)+D::dfVecX[l], nj=(2*j)+D::dfVecY[l], nk=(2*k)+D::dfVecZ[l];
+ if(RFLAG(lev+1, ni,nj,nk, mLevel[lev+1].setCurr)&
+ (CFGrFromCoarse|CFUnused|CFEmpty) //? (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused)
+ ) {
+ totArea += mFsgrCellArea[l];
+ }
+ } // l
+ QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = totArea;
+ //continue;
+ } else
+ if( RFLAG(lev+1, i*2,j*2,k*2,mLevel[lev+1].setCurr) & (CFEmpty|CFUnused)) {
+ QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = 1.0;
+ //continue;
+ } else {
+ QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = 0.0;
+ }
+ //errMsg("DFINI"," at l"<<lev<<" "<<PRINT_IJK<<" v:"<<QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) );
+ }
+ } // } TEST DEBUG */
+
+ // copied from fineAdv.
+ CellFlagType *pFlagSrc = &RFLAG(lev, 1,1,getForZMin1(lev),SRCS(lev));
+ CellFlagType *pFlagDst = &RFLAG(lev, 1,1,getForZMin1(lev),TSET(lev));
+ pFlagSrc -= 1;
+ pFlagDst -= 1;
+ ccel = RACPNT(lev, 1,1,getForZMin1(lev) ,SRCS(lev)); // QTEST
+ ccel -= QCELLSTEP;
+ tcel = RACPNT(lev, 1,1,getForZMin1(lev) ,TSET(lev)); // QTEST
+ tcel -= QCELLSTEP;
+
+ // use template functions for 2D/3D
+ //for(int k= getForZMin1(lev); k< getForZMax1(lev); ++k) {
+ //for(int j=1;j<mLevel[lev].lSizey-1;++j) {
+ //for(int i=1;i<mLevel[lev].lSizex-1;++i) {
+ //CellFlagType *pFlagSrc = &RFLAG(lev, i,j,k,SRCS(lev));
+ for(int k= getForZMin1(lev); k< getForZMax1(lev); ++k) {
+ for(int j=1;j<mLevel[lev].lSizey-1;++j) {
+ for(int i=1;i<mLevel[lev].lSizex-1;++i) {
+#if FSGR_STRICT_DEBUG==1
+ rho = ux = uy = uz = tmp = usqr = -100.0; // DEBUG
+#endif
+ pFlagSrc++;
+ pFlagDst++;
+ ccel += QCELLSTEP;
+ tcel += QCELLSTEP;
+ /*if(
+ //((*((ULLI*) pFlagSrc))==CF4_EMPTY ) ||
+ ((*((ULLI*) pFlagSrc))==CF4_UNUSED )
+ ) {
+ //ebugMarkCell(mMaxRefine, i,j,k);
+ ADVANCE_POINTERS(3); continue;
+ } //else */
+
+ // from coarse cells without unused nbs are not necessary...! -> remove
+ if( ((*pFlagSrc) & (CFGrFromCoarse)) ) {
+ bool invNb = false;
+ FORDF1 {
+ if(RFLAG_NB(lev, i, j, k, SRCS(lev), l) & CFUnused) { invNb = true; }
+ }
+ if(!invNb) {
+ *pFlagSrc = CFFluid|CFGrNorm;
+#if ELBEEM_BLENDER!=1
+ errMsg("coarseAdvance","FC2NRM_CHECK Converted CFGrFromCoarse to Norm at "<<lev<<" "<<PRINT_IJK);
+#endif // ELBEEM_BLENDER!=1
+ // FIXME add debug check for these types of cells?
+ }
+ } // */
+
+ //*(pFlagSrc+pFlagTarOff) = *pFlagSrc; // always set other set...
+ *pFlagDst = *pFlagSrc; // always set other set...
+#if INTCFCOARSETEST==1
+ if((*pFlagSrc) & CFGrFromCoarse) { // interpolateFineFromCoarse test!
+ if(( D::mStepCnt & (1<<(mMaxRefine-lev)) ) ==1) {
+ FORDF0 { RAC(tcel,l) = RAC(ccel,l); }
+ } else {
+ interpolateCellFromCoarse( lev, i,j,k, TSET(lev), 0.0, CFFluid|CFGrFromCoarse, false);
+ D::mNumUsedCells++;
+ }
+ continue; // interpolateFineFromCoarse test!
+ } // interpolateFineFromCoarse test!
+#else // INTCFCOARSETEST==1
+ //done in main loop afterwards..
+#endif // INTCFCOARSETEST==1
+
+ /*if( ( (*((ULLI*) pFlagSrc))==CF4_NOBND_NORMFLUID ) ) {
+ //ebugMarkCell(lev,i,j,k);
+ // WARNING removed iis stuff
+ // -------------------------------------------------------------------------------------------------------------
+ //tcel = (ccel+(pFlagTarOff*dTotalNum));
+ OPTIMIZED_STREAMCOLLIDE;
+ //USQRMAXCHECK(usqr,ux,uy,uz, mMaxVlen, mMxvx,mMxvy,mMxvz);
+ calcCurrentVolume += RAC(ccel,dFlux); calcCurrentMass += RAC(ccel,dFlux)*rho;
+ RAC(tcel,dFfrac) = 1.0;
+ *pFlagDst = *pFlagSrc;
+ ADVANCE_POINTERS(1); //tcel += (QCELLSTEP);
+ // -------------------------------------------------------------------------------------------------------------
+ OPTIMIZED_STREAMCOLLIDE;
+ //USQRMAXCHECK(usqr,ux,uy,uz, mMaxVlen, mMxvx,mMxvy,mMxvz);
+ //calcCurrentVolume += 1.0; calcCurrentMass += rho;
+ calcCurrentVolume += RAC(ccel,dFlux); calcCurrentMass += RAC(ccel,dFlux)*rho;
+ tcel[dFfrac] = 1.0;
+ *pFlagDst = *pFlagSrc;
+ ADVANCE_POINTERS(1); //tcel += (QCELLSTEP);
+ // -------------------------------------------------------------------------------------------------------------
+ OPTIMIZED_STREAMCOLLIDE;
+ //USQRMAXCHECK(usqr,ux,uy,uz, mMaxVlen, mMxvx,mMxvy,mMxvz);
+ //calcCurrentVolume += 1.0; calcCurrentMass += rho;
+ calcCurrentVolume += RAC(ccel,dFlux); calcCurrentMass += RAC(ccel,dFlux)*rho;
+ tcel[dFfrac] = 1.0;
+ *pFlagDst = *pFlagSrc;
+ ADVANCE_POINTERS(1); //tcel += (QCELLSTEP);
+ // -------------------------------------------------------------------------------------------------------------
+ OPTIMIZED_STREAMCOLLIDE;
+ //USQRMAXCHECK(usqr,ux,uy,uz, mMaxVlen, mMxvx,mMxvy,mMxvz);
+ //calcCurrentVolume += 1.0; calcCurrentMass += rho;
+ calcCurrentVolume += RAC(ccel,dFlux); calcCurrentMass += RAC(ccel,dFlux)*rho;
+ tcel[dFfrac] = 1.0;
+ *pFlagDst = *pFlagSrc;
+
+ D::mNumUsedCells+=4;
+ continue; // nobnd fluid case
+ } // */
+
+ if( ((*pFlagSrc) & (CFFluid)) ) {
+ ccel = RACPNT(lev, i,j,k ,SRCS(lev));
+ tcel = RACPNT(lev, i,j,k ,TSET(lev));
+
+ if( ((*pFlagSrc) & (CFGrFromFine)) ) {
+ FORDF0 { RAC(tcel,l) = RAC(ccel,l); } // always copy...?
+ continue; // comes from fine grid
+ }
+ // also ignore CFGrFromCoarse
+ else if( ((*pFlagSrc) & (CFGrFromCoarse)) ) {
+ FORDF0 { RAC(tcel,l) = RAC(ccel,l); } // always copy...?
+ continue;
+ }
+
+ OPTIMIZED_STREAMCOLLIDE;
+ //USQRMAXCHECK(usqr,ux,uy,uz, mMaxVlen, mMxvx,mMxvy,mMxvz);
+
+ //if(nbored&CFBnd) { oldFlag &= (~CFNoBndFluid); } else { }
+ *pFlagDst |= CFNoBndFluid; // test?
+ //calcCurrentVolume += 1.0; calcCurrentMass += rho;
+ calcCurrentVolume += RAC(ccel,dFlux); calcCurrentMass += RAC(ccel,dFlux)*rho;
+
+ //ebugMarkCell(lev+1, 2*i+1,2*j+1,2*k );
+#if FSGR_STRICT_DEBUG==1
+ if(rho<-1.0){ debugMarkCell(lev, i,j,k );
+ errMsg("INVRHOCELL_CHECK"," l"<<lev<<" "<< PRINT_IJK<<" rho:"<<rho );
+ D::mPanic = 1;
+ }
+#endif // FSGR_STRICT_DEBUG==1
+ D::mNumUsedCells++;
+
+ }
+ }
+ pFlagSrc+=2; // after x
+ pFlagDst+=2; // after x
+ ccel += (QCELLSTEP*2);
+ tcel += (QCELLSTEP*2);
+ }
+ pFlagSrc+= mLevel[lev].lSizex*2; // after y
+ pFlagDst+= mLevel[lev].lSizex*2; // after y
+ ccel += (QCELLSTEP*mLevel[lev].lSizex*2);
+ tcel += (QCELLSTEP*mLevel[lev].lSizex*2);
+ } // all cell loop k,j,i
+
+
+ //errMsg("coarseAdvance","level "<<lev<<" stepped from "<<mLevel[lev].setCurr<<" to "<<mLevel[lev].setOther);
+ if(!D::mSilent){ errMsg("coarseAdvance","level "<<lev<<" stepped from "<<SRCS(lev)<<" to "<<TSET(lev)); }
+ // */
+
+ // update other set
+ mLevel[lev].setOther = mLevel[lev].setCurr;
+ mLevel[lev].setCurr ^= 1;
+ mLevel[lev].lsteps++;
+ mLevel[lev].lmass = calcCurrentMass * mLevel[lev].lcellfactor;
+ mLevel[lev].lvolume = calcCurrentVolume * mLevel[lev].lcellfactor;
+ //errMsg("DFINI", " m l"<<lev<<" m="<<mLevel[lev].lmass<<" c="<<calcCurrentMass<<" lcf="<< mLevel[lev].lcellfactor );
+ //errMsg("DFINI", " v l"<<lev<<" v="<<mLevel[lev].lvolume<<" c="<<calcCurrentVolume<<" lcf="<< mLevel[lev].lcellfactor );
+}
+
+/*****************************************************************************/
+//! multi level functions
+/*****************************************************************************/
+
+#define MARK_INT_CELLS false
+#define SHOWALL_INT_CELLS true
+// interpolate from level lev-1 to lev at borders CFGrFromCoarse
+template<class D>
+void
+LbmFsgrSolver<D>::interpolateFineFromCoarse(int lev, LbmFloat t)
+{
+ if((lev-1<0) || ((lev)>mMaxRefine)) return;
+
+# if FSGR_STRICT_DEBUG==1
+ // reset all unused cell values to invalid
+ { int dlev = lev; //mMaxRefine;
+ int unuCnt = 0;
+ for(int k= getForZMin1(dlev); k< getForZMax1(dlev); ++k) {
+ for(int j=1;j<mLevel[dlev].lSizey-1;++j) {
+ for(int i=1;i<mLevel[dlev].lSizex-1;++i) {
+ if( (RFLAG(dlev, i,j,k,mLevel[dlev].setCurr) & CFGrFromCoarse ) ||
+ (RFLAG(dlev, i,j,k,mLevel[dlev].setCurr) & CFUnused ) ||
+ (RFLAG(dlev, i,j,k,mLevel[dlev].setCurr) & CFEmpty ) ) {
+ if(RFLAG(dlev, i,j,k,mLevel[dlev].setCurr) & CFGrFromCoarse ) { RFLAG(dlev, i,j,k,mLevel[dlev].setCurr) = CFFluid|CFGrFromCoarse; }
+ FORDF0 { QCELL(dlev,i,j,k,mLevel[dlev].setCurr,l) = -100.0; }
+ unuCnt++;
+ }
+ } } }
+ errMsg("interpolateFineFromCoarse"," reset l"<<dlev<<" "<<unuCnt<<" cells unused ");
+ } // dlev
+# endif // FSGR_STRICT_DEBUG==1
+
+
+// INTCFCOARSETEST
+ // now set fine bc
+ for(int k= getForZMin1(lev); k< getForZMax1(lev); ++k) {
+ for(int j=1;j<mLevel[lev].lSizey-1;++j) {
+ for(int i=1;i<mLevel[lev].lSizex-1;++i) {
+ if(RFLAG(lev, i,j,k,mLevel[lev].setCurr)&CFGrFromCoarse) {
+ /*if((i&1) && (j&1) && ( (D::cDimension==2) || (k&1) ) ){
+ errMsg("IFFC_CHECK", " betXYZ cell? on lev "<<lev<<" "<<PRINT_IJK);
+ debugMarkCell(lev,i,j,k);
+ D::mPanic=1;
+ } // */
+ interpolateCellFromCoarse( lev,i,j,k, mLevel[lev].setCurr, t, CFFluid|CFGrFromCoarse, false);
+ D::mNumUsedCells++;
+ //int lev, int i, int j,int k, int set, LbmFloat t, CellFlagType flagSet) {
+ }
+ } } }
+
+
+# if FSGR_STRICT_DEBUG==1
+ // check that all values are now correctly inited
+ { int dlev = lev; //mMaxRefine;
+ for(int k= getForZMin1(dlev); k< getForZMax1(dlev); ++k) {
+ for(int j=1;j<mLevel[dlev].lSizey-1;++j) {
+ for(int i=1;i<mLevel[dlev].lSizex-1;++i) {
+ if(RFLAG(dlev, i,j,k,mLevel[dlev].setCurr) & CFGrFromCoarse ) {
+ FORDF0 { if(QCELL(dlev,i,j,k,mLevel[dlev].setCurr,l)<-1.0){
+ errMsg("CHECKFCINITS"," l"<<(dlev)<<" "<< PRINT_IJK <<" was not inited! ");
+ debugMarkCell(dlev,i,j,k);
+ D::mPanic = 1;
+ } }
+ }
+ } } }
+ } // dlev
+# endif // FSGR_STRICT_DEBUG==1
+
+ if(!D::mSilent){ errMsg("interpolateFineFromCoarse"," to l"<<lev<<" s"<<mLevel[lev].setCurr<<", from "<<(lev-1)<<" (s"<< mLevel[lev-1].setCurr<<"*"<<(1.0-(t))<<"+ s"<<mLevel[lev-1].setOther<<"*"<<((t))<<")" <<" "); }
+}
+
+// get dfs from level (lev+1) to (lev) coarse border nodes
+template<class D>
+void
+LbmFsgrSolver<D>::coarseRestrictFromFine(int lev)
+{
+ if((lev<0) || ((lev+1)>mMaxRefine)) return;
+#if FSGR_STRICT_DEBUG==1
+ // reset all unused cell values to invalid
+ int unuCnt = 0;
+ for(int k= getForZMin1(lev); k< getForZMax1(lev); ++k) {
+ for(int j=1;j<mLevel[lev].lSizey-1;++j) {
+ for(int i=1;i<mLevel[lev].lSizex-1;++i) {
+ CellFlagType *pFlagSrc = &RFLAG(lev, i,j,k,mLevel[lev].setCurr);
+ if( ((*pFlagSrc) & (CFFluid|CFGrFromFine)) == (CFFluid|CFGrFromFine) ) {
+ FORDF0{ QCELL(lev, i,j,k,mLevel[lev].setCurr, l) = -10000.0; }
+ unuCnt++;
+ // set here
+ } else if( ((*pFlagSrc) & (CFFluid|CFGrNorm)) == (CFFluid|CFGrNorm) ) {
+ // simulated...
+ } else {
+ // reset in interpolation
+ //errMsg("coarseRestrictFromFine"," reset l"<<lev<<" "<<PRINT_IJK);
+ }
+ if( ((*pFlagSrc) & (CFEmpty|CFUnused)) ) { // test, also reset?
+ FORDF0{ QCELL(lev, i,j,k,mLevel[lev].setCurr, l) = -10000.0; }
+ } // test
+ } } }
+ errMsg("coarseRestrictFromFine"," reset l"<<lev<<" fluid|coarseBorder cells: "<<unuCnt);
+#endif // FSGR_STRICT_DEBUG==1
+ const int srcSet = mLevel[lev+1].setCurr;
+ const int dstSet = mLevel[lev].setCurr;
+
+ LbmFloat rho=0.0, ux=0.0, uy=0.0, uz=0.0;
+ LbmFloat omegaDst, omegaSrc;
+ LbmFloat df[LBM_DFNUM];
+ LbmFloat feq[LBM_DFNUM];
+ LbmFloat dfScale = mDfScaleUp;
+ LbmFloat *ccel = NULL;
+ LbmFloat *tcel = NULL;
+#if OPT3D==true
+ // for macro add
+ LbmFloat usqr;
+ //LbmFloat *addfcel, *dstcell;
+ LbmFloat lcsmqadd, lcsmqo, lcsmeq[LBM_DFNUM];
+ LbmFloat lcsmDstOmega, lcsmSrcOmega, lcsmdfscale;
+#endif // OPT3D==true
+
+
+ //restrict
+ for(int k= getForZMin1(lev); k< getForZMax1(lev); ++k) {
+ for(int j=1;j<mLevel[lev].lSizey-1;++j) {
+ for(int i=1;i<mLevel[lev].lSizex-1;++i) {
+ CellFlagType *pFlagSrc = &RFLAG(lev, i,j,k,dstSet);
+ if((*pFlagSrc) & (CFFluid)) {
+ if( ((*pFlagSrc) & (CFFluid|CFGrFromFine)) == (CFFluid|CFGrFromFine) ) {
+ // TODO? optimize?
+ // do resctriction
+ mNumInterdCells++;
+ ccel = RACPNT(lev+1, 2*i,2*j,2*k,srcSet);
+ tcel = RACPNT(lev , i,j,k ,dstSet);
+
+#if OPT3D==false
+ rho= ux= uy= uz=0.0;
+ FORDF0{
+ df[l] = RAC(ccel,l); //QCELL(lev+1, 2*i,2*j,2*k,srcSet, l);
+ //df[l] = QCELL(lev+1, 2*i,2*j,2*k,srcSet, l); // OLD
+#if FSGR_STRICT_DEBUG==1
+ if( df[l]<-1.0 ){ errMsg("INVDFCREST_DFCHECK", PRINT_IJK<<" s"<<dstSet<<" from "<<PRINT_VEC(2*i,2*j,2*k)<<" s"<<srcSet<<" df"<<l<<":"<< df[l]); }
+#endif
+ rho += df[l];
+ ux += (D::dfDvecX[l]*df[l]);
+ uy += (D::dfDvecY[l]*df[l]);
+ uz += (D::dfDvecZ[l]*df[l]);
+ }
+
+ FORDF0{
+ feq[l] = D::getCollideEq(l, rho,ux,uy,uz);
+ //df[l] = QCELL(lev+1, 2*i,2*j,2*k,srcSet, l); // OLD
+ }
+ if(mLevel[lev ].lcsmago>0.0) {
+ const LbmFloat Qo = D::getLesNoneqTensorCoeff(df,feq);
+ omegaDst = D::getLesOmega(mLevel[lev ].omega,mLevel[lev ].lcsmago,Qo);
+ omegaSrc = D::getLesOmega(mLevel[lev+1].omega,mLevel[lev+1].lcsmago,Qo);
+ } else {
+ omegaDst = mLevel[lev+0].omega; /* NEWSMAGOT*/
+ omegaSrc = mLevel[lev+1].omega;
+ }
+ //LbmFloat dfScaleFac = (newSteptime/1.0)/(levOldStepsize[lev]/levOldOmega[lev]);
+ dfScale = (mLevel[lev ].stepsize/mLevel[lev+1].stepsize)* (1.0/omegaDst-1.0)/ (1.0/omegaSrc-1.0); // yu
+ //dfScale = 1.0;
+ FORDF0{
+ //QCELL(lev, i,j,k,dstSet, l) = feq[l]+ (df[l]-feq[l])*dfScale; // OLD
+ RAC(tcel, l) = feq[l]+ (df[l]-feq[l])*dfScale;
+ }
+#else // OPT3D
+ /*test this*/
+ // similar to OPTIMIZED_STREAMCOLLIDE_UNUSED
+ rho = CCEL_C + CCEL_N + CCEL_S + CCEL_E + CCEL_W + CCEL_T \
+ + CCEL_B + CCEL_NE + CCEL_NW + CCEL_SE + CCEL_SW + CCEL_NT \
+ + CCEL_NB + CCEL_ST + CCEL_SB + CCEL_ET + CCEL_EB + CCEL_WT + CCEL_WB; \
+ ux = CCEL_E - CCEL_W + CCEL_NE - CCEL_NW + CCEL_SE - CCEL_SW \
+ + CCEL_ET + CCEL_EB - CCEL_WT - CCEL_WB; \
+ uy = CCEL_N - CCEL_S + CCEL_NE + CCEL_NW - CCEL_SE - CCEL_SW \
+ + CCEL_NT + CCEL_NB - CCEL_ST - CCEL_SB; \
+ uz = CCEL_T - CCEL_B + CCEL_NT - CCEL_NB + CCEL_ST - CCEL_SB \
+ + CCEL_ET - CCEL_EB + CCEL_WT - CCEL_WB; \
+ usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
+ \
+ lcsmeq[dC] = EQC ; \
+ COLL_CALCULATE_DFEQ(lcsmeq); \
+ COLL_CALCULATE_NONEQTENSOR(lev+0, CCEL_ )\
+ COLL_CALCULATE_CSMOMEGAVAL(lev+0, lcsmDstOmega); \
+ COLL_CALCULATE_CSMOMEGAVAL(lev+1, lcsmSrcOmega); \
+ \
+ lcsmdfscale = (mLevel[lev+0].stepsize/mLevel[lev+1].stepsize)* (1.0/lcsmDstOmega-1.0)/ (1.0/lcsmSrcOmega-1.0); \
+ RAC(tcel, dC ) = (lcsmeq[dC ] + (CCEL_C -lcsmeq[dC ] )*lcsmdfscale);\
+ RAC(tcel, dN ) = (lcsmeq[dN ] + (CCEL_N -lcsmeq[dN ] )*lcsmdfscale);\
+ RAC(tcel, dS ) = (lcsmeq[dS ] + (CCEL_S -lcsmeq[dS ] )*lcsmdfscale);\
+ RAC(tcel, dE ) = (lcsmeq[dE ] + (CCEL_E -lcsmeq[dE ] )*lcsmdfscale);\
+ RAC(tcel, dW ) = (lcsmeq[dW ] + (CCEL_W -lcsmeq[dW ] )*lcsmdfscale);\
+ RAC(tcel, dT ) = (lcsmeq[dT ] + (CCEL_T -lcsmeq[dT ] )*lcsmdfscale);\
+ RAC(tcel, dB ) = (lcsmeq[dB ] + (CCEL_B -lcsmeq[dB ] )*lcsmdfscale);\
+ RAC(tcel, dNE) = (lcsmeq[dNE] + (CCEL_NE-lcsmeq[dNE] )*lcsmdfscale);\
+ RAC(tcel, dNW) = (lcsmeq[dNW] + (CCEL_NW-lcsmeq[dNW] )*lcsmdfscale);\
+ RAC(tcel, dSE) = (lcsmeq[dSE] + (CCEL_SE-lcsmeq[dSE] )*lcsmdfscale);\
+ RAC(tcel, dSW) = (lcsmeq[dSW] + (CCEL_SW-lcsmeq[dSW] )*lcsmdfscale);\
+ RAC(tcel, dNT) = (lcsmeq[dNT] + (CCEL_NT-lcsmeq[dNT] )*lcsmdfscale);\
+ RAC(tcel, dNB) = (lcsmeq[dNB] + (CCEL_NB-lcsmeq[dNB] )*lcsmdfscale);\
+ RAC(tcel, dST) = (lcsmeq[dST] + (CCEL_ST-lcsmeq[dST] )*lcsmdfscale);\
+ RAC(tcel, dSB) = (lcsmeq[dSB] + (CCEL_SB-lcsmeq[dSB] )*lcsmdfscale);\
+ RAC(tcel, dET) = (lcsmeq[dET] + (CCEL_ET-lcsmeq[dET] )*lcsmdfscale);\
+ RAC(tcel, dEB) = (lcsmeq[dEB] + (CCEL_EB-lcsmeq[dEB] )*lcsmdfscale);\
+ RAC(tcel, dWT) = (lcsmeq[dWT] + (CCEL_WT-lcsmeq[dWT] )*lcsmdfscale);\
+ RAC(tcel, dWB) = (lcsmeq[dWB] + (CCEL_WB-lcsmeq[dWB] )*lcsmdfscale);\
+ // */
+ /* IDF_WRITEBACK optimized */
+ //errMsg("coarseRestrictFromFine", "CRFF_DFDEBUG cell "<<PRINT_IJK<<" rho:"<<rho<<" u:"<<PRINT_VEC(ux,uy,uz)<<" "<<lcsmdfscale<<","<<lcsmDstOmega<<","<<lcsmSrcOmega );
+#endif // OPT3D==false
+
+ if( ((lev)<mMaxRefine) || (SHOWALL_INT_CELLS))
+ if((MARK_INT_CELLS)&&(D::cDimension==2)) { debugMarkCell(lev,i,j,k); }
+# if FSGR_STRICT_DEBUG==1
+ errMsg("coarseRestrictFromFine", "CRFF_DFDEBUG cell "<<PRINT_IJK<<" rho:"<<rho<<" u:"<<PRINT_VEC(ux,uy,uz)<<" " );
+# endif // FSGR_STRICT_DEBUG==1
+ D::mNumUsedCells++;
+ } // from fine & fluid
+ else {
+ if(RFLAG(lev+1, 2*i,2*j,2*k,srcSet) & CFGrFromCoarse) {
+ RFLAG(lev, i,j,k,dstSet) |= CFGrToFine;
+ } else {
+ RFLAG(lev, i,j,k,dstSet) &= (~CFGrToFine);
+ }
+ }
+ } // & fluid
+ }}}
+ if(!D::mSilent){ errMsg("coarseRestrictFromFine"," from l"<<(lev+1)<<",s"<<mLevel[lev+1].setCurr<<" to l"<<lev<<",s"<<mLevel[lev].setCurr); }
+}
+
+template<class D>
+bool
+LbmFsgrSolver<D>::performCoarsening(int lev) {
+ if((lev<0) || ((lev+1)>mMaxRefine)) return false;
+ bool change = false;
+ bool nbsok;
+
+ // use template functions for 2D/3D
+ for(int k= getForZMin1(lev); k< getForZMax1(lev); ++k) {
+ for(int j=1;j<mLevel[lev].lSizey-1;++j) {
+ for(int i=1;i<mLevel[lev].lSizex-1;++i) {
+
+ // from coarse cells without unused nbs are not necessary...! -> remove
+ // perform check from coarseAdvance here?
+ if(RFLAG(lev, i,j,k, mLevel[lev].setCurr) & CFGrFromFine) {
+ nbsok = true;
+ if((lev+1 == mMaxRefine) && (RFLAG(lev+1, 2*i,2*j,2*k, mLevel[lev+1].setCurr)&(CFInter))) {
+ // dont turn CFGrFromFine above interface cells into CFGrNorm
+ nbsok=false;
+ }
+ if(lev+1 == mMaxRefine) {
+ for(int l=1; l<D::cDirNum && nbsok; l++) {
+ int ni=(2*i)+D::dfVecX[l], nj=(2*j)+D::dfVecY[l], nk=(2*k)+D::dfVecZ[l];
+ if(RFLAG(lev+1, ni,nj,nk, mLevel[lev+1].setCurr)&(CFInter)) { // dont coarsen when near interface
+ nbsok = false;
+ }
+ } // l
+ } else {
+ for(int l=1; l<D::cDirNum && nbsok; l++) {
+ int ni=(2*i)+D::dfVecX[l], nj=(2*j)+D::dfVecY[l], nk=(2*k)+D::dfVecZ[l];
+ if(RFLAG(lev+1, ni,nj,nk, mLevel[lev+1].setCurr)&(CFGrFromFine)) { // dont coarsen when near interface
+ nbsok = false;
+ }
+ } // l
+ }
+ // dont turn CFGrFromFine above interface cells into CFGrNorm
+ // now check nbs on same level
+ for(int l=1; l<D::cDirNum && nbsok; l++) {
+ int ni=i+D::dfVecX[l], nj=j+D::dfVecY[l], nk=k+D::dfVecZ[l];
+ if(RFLAG(lev, ni,nj,nk, mLevel[lev].setCurr)&(CFFluid)) { //ok
+ } else {
+ nbsok = false;
+ }
+ } // l
+ if(nbsok) {
+ // conversion to coarse fluid cell
+ change = true;
+ RFLAG(lev, i,j,k, mLevel[lev].setCurr) = CFFluid|CFGrNorm;
+ // dfs are already ok...
+ //if(D::mInitDone) errMsg("performCoarsening","CFGrFromFine changed to CFGrNorm at lev"<<lev<<" " <<PRINT_IJK );
+ if(D::cDimension==2) debugMarkCell(lev,i,j,k);
+
+ // only check complete cubes
+ for(int dx=-1;dx<=1;dx+=2) {
+ for(int dy=-1;dy<=1;dy+=2) {
+ for(int dz=-1*(LBMDIM&1);dz<=1*(LBMDIM&1);dz+=2) { // 2d/3d
+ // check for norm and from coarse, as the coarse level might just have been refined...
+ /*if(D::mInitDone) errMsg("performCoarsening","CFGrFromFine subc check "<<
+ "x"<<convertFlags2String( RFLAG(lev, i+dx, j , k , mLevel[lev].setCurr))<<" "
+ "y"<<convertFlags2String( RFLAG(lev, i , j+dy, k , mLevel[lev].setCurr))<<" "
+ "z"<<convertFlags2String( RFLAG(lev, i , j , k+dz, mLevel[lev].setCurr))<<" "
+ "xy"<<convertFlags2String( RFLAG(lev, i+dx, j+dy, k , mLevel[lev].setCurr))<<" "
+ "xz"<<convertFlags2String( RFLAG(lev, i+dx, j , k+dz, mLevel[lev].setCurr))<<" "
+ "yz"<<convertFlags2String( RFLAG(lev, i , j+dy, k+dz, mLevel[lev].setCurr))<<" "
+ "xyz"<<convertFlags2String( RFLAG(lev, i+dx, j+dy, k+dz, mLevel[lev].setCurr))<<" " ); // */
+ if(
+ // we now the flag of the current cell! ( RFLAG(lev, i , j , k , mLevel[lev].setCurr)&(CFGrNorm)) &&
+ ( RFLAG(lev, i+dx, j , k , mLevel[lev].setCurr)&(CFGrNorm|CFGrFromCoarse)) &&
+ ( RFLAG(lev, i , j+dy, k , mLevel[lev].setCurr)&(CFGrNorm|CFGrFromCoarse)) &&
+ ( RFLAG(lev, i , j , k+dz, mLevel[lev].setCurr)&(CFGrNorm|CFGrFromCoarse)) &&
+
+ ( RFLAG(lev, i+dx, j+dy, k , mLevel[lev].setCurr)&(CFGrNorm|CFGrFromCoarse)) &&
+ ( RFLAG(lev, i+dx, j , k+dz, mLevel[lev].setCurr)&(CFGrNorm|CFGrFromCoarse)) &&
+ ( RFLAG(lev, i , j+dy, k+dz, mLevel[lev].setCurr)&(CFGrNorm|CFGrFromCoarse)) &&
+ ( RFLAG(lev, i+dx, j+dy, k+dz, mLevel[lev].setCurr)&(CFGrNorm|CFGrFromCoarse))
+ ) {
+ // middle source node on higher level
+ int dstlev = lev+1;
+ int dstx = (2*i)+dx;
+ int dsty = (2*j)+dy;
+ int dstz = (2*k)+dz;
+
+ RFLAG(dstlev, dstx,dsty,dstz, mLevel[dstlev].setCurr) = CFUnused;
+ RFLAG(dstlev, dstx,dsty,dstz, mLevel[dstlev].setOther) = CFUnused; // FLAGTEST
+ //if(D::mInitDone) errMsg("performCoarsening","CFGrFromFine subcube init center unused set l"<<dstlev<<" at "<<PRINT_VEC(dstx,dsty,dstz) );
+
+ for(int l=1; l<D::cDirNum; l++) {
+ int dstni=dstx+D::dfVecX[l], dstnj=dsty+D::dfVecY[l], dstnk=dstz+D::dfVecZ[l];
+ if(RFLAG(dstlev, dstni,dstnj,dstnk, mLevel[dstlev].setCurr)&(CFFluid)) {
+ RFLAG(dstlev, dstni,dstnj,dstnk, mLevel[dstlev].setCurr) = CFFluid|CFGrFromCoarse;
+ }
+ if(RFLAG(dstlev, dstni,dstnj,dstnk, mLevel[dstlev].setCurr)&(CFInter)) {
+ //if(D::mInitDone) errMsg("performCoarsening","CFGrFromFine subcube init CHECK Warning - deleting interface cell...");
+ D::mFixMass += QCELL( dstlev, dstni,dstnj,dstnk, mLevel[dstlev].setCurr, dMass);
+ RFLAG(dstlev, dstni,dstnj,dstnk, mLevel[dstlev].setCurr) = CFFluid|CFGrFromCoarse;
+ }
+ } // l
+
+ // again check nb flags of all surrounding cells to see if any from coarse
+ // can be convted to unused
+ for(int l=1; l<D::cDirNum; l++) {
+ int dstni=dstx+D::dfVecX[l], dstnj=dsty+D::dfVecY[l], dstnk=dstz+D::dfVecZ[l];
+ // have to be at least from coarse here...
+ //errMsg("performCoarsening","CFGrFromFine subcube init unused check l"<<dstlev<<" at "<<PRINT_VEC(dstni,dstnj,dstnk)<<" "<< convertFlags2String(RFLAG(dstlev, dstni,dstnj,dstnk, mLevel[dstlev].setCurr)) );
+ if(!(RFLAG(dstlev, dstni,dstnj,dstnk, mLevel[dstlev].setCurr)&(CFUnused) )) {
+ bool delok = true;
+ // careful long range here... check domain bounds?
+ for(int m=1; m<D::cDirNum; m++) {
+ int chkni=dstni+D::dfVecX[m], chknj=dstnj+D::dfVecY[m], chknk=dstnk+D::dfVecZ[m];
+ if(RFLAG(dstlev, chkni,chknj,chknk, mLevel[dstlev].setCurr)&(CFUnused|CFGrFromCoarse)) {
+ // this nb cell is ok for deletion
+ } else {
+ delok=false; // keep it!
+ }
+ //errMsg("performCoarsening"," CHECK "<<PRINT_VEC(dstni,dstnj,dstnk)<<" to "<<PRINT_VEC( chkni,chknj,chknk )<<" f:"<< convertFlags2String( RFLAG(dstlev, chkni,chknj,chknk, mLevel[dstlev].setCurr))<<" nbsok"<<delok );
+ }
+ //errMsg("performCoarsening","CFGrFromFine subcube init unused check l"<<dstlev<<" at "<<PRINT_VEC(dstni,dstnj,dstnk)<<" ok"<<delok );
+ if(delok) {
+ RFLAG(dstlev, dstni,dstnj,dstnk, mLevel[dstlev].setCurr) = CFUnused;
+ RFLAG(dstlev, dstni,dstnj,dstnk, mLevel[dstlev].setOther) = CFUnused; // FLAGTEST
+ if(D::cDimension==2) debugMarkCell(dstlev,dstni,dstnj,dstnk);
+ }
+ }
+ } // l
+ // treat subcube
+ //ebugMarkCell(lev,i+dx,j+dy,k+dz);
+ //if(D::mInitDone) errMsg("performCoarsening","CFGrFromFine subcube init, dir:"<<PRINT_VEC(dx,dy,dz) );
+ }
+ } } }
+
+ } // ?
+ } // convert regions of from fine
+
+ // reinit cell area value
+ /*if( RFLAG(lev, i,j,k,mLevel[lev].setCurr) & CFFluid) {
+ if( RFLAG(lev+1, i*2,j*2,k*2,mLevel[lev+1].setCurr) & CFGrFromCoarse) {
+ LbmFloat totArea = mFsgrCellArea[0]; // for l=0
+ for(int l=1; l<D::cDirNum; l++) {
+ int ni=(2*i)+D::dfVecX[l], nj=(2*j)+D::dfVecY[l], nk=(2*k)+D::dfVecZ[l];
+ if(RFLAG(lev+1, ni,nj,nk, mLevel[lev+1].setCurr)&
+ (CFGrFromCoarse|CFUnused|CFEmpty) //? (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused)
+ //(CFUnused|CFEmpty) //? (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused)
+ ) {
+ //LbmFloat area = 0.25; if(D::dfVecX[l]!=0) area *= 0.5; if(D::dfVecY[l]!=0) area *= 0.5; if(D::dfVecZ[l]!=0) area *= 0.5;
+ totArea += mFsgrCellArea[l];
+ }
+ } // l
+ QCELL(lev, i,j,k,mLevel[lev].setOther, dFlux) =
+ QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = totArea;
+ } else {
+ QCELL(lev, i,j,k,mLevel[lev].setOther, dFlux) =
+ QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = 1.0;
+ }
+ //errMsg("DFINI"," at l"<<lev<<" "<<PRINT_IJK<<" v:"<<QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) );
+ }
+ // */
+
+ if(RFLAG(lev, i,j,k, mLevel[lev].setCurr) & CFEmpty) {
+ bool changeToFromFine = false;
+ const CellFlagType notAllowed = (CFInter|CFGrFromCoarse|CFGrFromFine|CFGrToFine);
+ const CellFlagType notNbAllowed = (CFEmpty|CFGrFromFine|CFInter|CFBnd);
+#if REFINEMENTBORDER==1
+ if( (RFLAG(lev+1, (2*i),(2*j),(2*k), mLevel[lev+1].setCurr) & (CFFluid)) &&
+ (!(RFLAG(lev+1, (2*i),(2*j),(2*k), mLevel[lev+1].setCurr) & (notAllowed)) ) ){
+ changeToFromFine=true;
+ }
+#elif REFINEMENTBORDER==2 // REFINEMENTBORDER==1
+ if( (RFLAG(lev+1, (2*i),(2*j),(2*k), mLevel[lev+1].setCurr) & (CFFluid)) &&
+ (!(RFLAG(lev+1, (2*i),(2*j),(2*k), mLevel[lev+1].setCurr) & (notAllowed)) ) ){
+ changeToFromFine=true;
+ for(int l=0; ((l<D::cDirNum)&&(changeToFromFine)); l++) {
+ int ni=2*i+D::dfVecX[l], nj=2*j+D::dfVecY[l], nk=2*k+D::dfVecZ[l];
+ if(RFLAG(lev+1, ni,nj,nk, mLevel[lev+1].setCurr)&(notNbAllowed)) { // NEWREFT
+ changeToFromFine=false;
+ }
+ }
+ /*for(int l=0; ((l<D::cDirNum)&&(changeToFromFine)); l++) { // FARBORD
+ int ni=2*i+2*D::dfVecX[l], nj=2*j+2*D::dfVecY[l], nk=2*k+2*D::dfVecZ[l];
+ if(RFLAG(lev+1, ni,nj,nk, mLevel[lev+1].setCurr)&(notNbAllowed)) { // NEWREFT
+ changeToFromFine=false;
+ }
+ } // FARBORD*/
+ }
+#elif REFINEMENTBORDER==3 // REFINEMENTBORDER==3
+ if(lev+1==mMaxRefine) { // mixborder
+ if( (RFLAG(lev+1, (2*i),(2*j),(2*k), mLevel[lev+1].setCurr) & (CFFluid|CFInter)) &&
+ (!(RFLAG(lev+1, (2*i),(2*j),(2*k), mLevel[lev+1].setCurr) & (notAllowed)) ) ){
+ changeToFromFine=true;
+ }
+ } else {
+ if( (RFLAG(lev+1, (2*i),(2*j),(2*k), mLevel[lev+1].setCurr) & (CFFluid)) &&
+ (!(RFLAG(lev+1, (2*i),(2*j),(2*k), mLevel[lev+1].setCurr) & (notAllowed)) ) ){
+ changeToFromFine=true;
+ for(int l=0; l<D::cDirNum; l++) {
+ int ni=2*i+D::dfVecX[l], nj=2*j+D::dfVecY[l], nk=2*k+D::dfVecZ[l];
+ if(RFLAG(lev+1, ni,nj,nk, mLevel[lev+1].setCurr)&(notNbAllowed)) { // NEWREFT
+ changeToFromFine=false;
+ }
+ }
+ } } // mixborder
+#else // REFINEMENTBORDER==3
+ ERROR
+#endif // REFINEMENTBORDER==1
+ if(changeToFromFine) {
+ change = true;
+ RFLAG(lev, i,j,k, mLevel[lev].setCurr) = CFFluid|CFGrFromFine;
+ if(D::cDimension==2) debugMarkCell(lev,i,j,k);
+ // same as restr from fine func! not necessary ?!
+ // coarseRestrictFromFine part */
+ }
+ } // only check empty cells
+
+ } } }
+
+ if(!D::mSilent){ errMsg("performCoarsening"," for l"<<lev<<" done " ); }
+ return change;
+}
+
+template<class D>
+bool
+LbmFsgrSolver<D>::performRefinement(int lev) {
+ if((lev<0) || ((lev+1)>mMaxRefine)) return false;
+ bool change = false;
+ //bool nbsok;
+ // TIMEINTORDER ?
+ LbmFloat interTime = 0.0;
+
+ // use template functions for 2D/3D
+ for(int k= getForZMin1(lev); k< getForZMax1(lev); ++k) {
+ for(int j=1;j<mLevel[lev].lSizey-1;++j) {
+ for(int i=1;i<mLevel[lev].lSizex-1;++i) {
+
+ // ????
+ /*if(RFLAG(lev, i,j,k, mLevel[lev].setCurr) & CFGrFromFine) {
+ // from fine cells without fluid nbs are not necessary...! -> remove
+ bool fluidNb = false;
+ for(int l=1; l<D::cDirNum; l++) {
+ if(RFLAG_NB(lev, i, j, k, mLevel[lev].setCurr, l) & CFFluid) { fluidNb = true; }
+ }
+ if(!fluidNb) {
+ RFLAG(lev, i,j,k, mLevel[lev].setCurr) = CFFluid|CFGrNorm;
+ }
+ } // */
+
+ // check for "inactive" norm cells (without finer border near)?
+ if(RFLAG(lev, i,j,k, mLevel[lev].setCurr) & CFGrNorm) {
+ if(lev+1 == mMaxRefine) {
+ for(int l=0; l<D::cDirNum; l++) {
+ int ni=(2*i)+D::dfVecX[l], nj=(2*j)+D::dfVecY[l], nk=(2*k)+D::dfVecZ[l];
+ if(RFLAG(lev+1, ni,nj,nk, mLevel[lev+1].setCurr)&(CFInter)) { // dont compute
+ //nbsok = false;
+ RFLAG(lev, i,j,k, mLevel[lev].setCurr) = CFFluid|CFGrFromFine;
+ if(D::cDimension==2) debugMarkCell(lev,i,j,k);
+ l = D::cDirNum;
+ }
+ } // l
+ }
+
+ }
+
+ if(RFLAG(lev, i,j,k, mLevel[lev].setCurr) & CFGrFromFine) {
+
+ // remove from coarse cells in neighborhood !?
+ //for(int l=0; l<D::cDirNum; l++) {
+ //}
+ bool removeFromFine = false;
+ const CellFlagType notSrcAllowed = (CFEmpty|CFGrFromFine|CFInter|CFBnd|CFGrToFine);
+
+#if REFINEMENTBORDER==1
+ if(RFLAG(lev+1, 2*i,2*j,2*k, mLevel[lev+1].setCurr)&notSrcAllowed) {
+ removeFromFine=true;
+ }
+#elif REFINEMENTBORDER==2 // REFINEMENTBORDER==1
+ for(int l=0;((l<D::cDirNum) && (!removeFromFine)); l++) {
+ int ni=2*i+D::dfVecX[l], nj=2*j+D::dfVecY[l], nk=2*k+D::dfVecZ[l];
+ if(RFLAG(lev+1, ni,nj,nk, mLevel[lev+1].setCurr)&notSrcAllowed) { // NEWREFT
+ removeFromFine=true;
+ }
+ }
+ /*for(int l=0;((l<D::cDirNum) && (!removeFromFine)); l++) { // FARBORD
+ int ni=2*i+2*D::dfVecX[l], nj=2*j+2*D::dfVecY[l], nk=2*k+2*D::dfVecZ[l];
+ if(RFLAG(lev+1, ni,nj,nk, mLevel[lev+1].setCurr)&notSrcAllowed) { // NEWREFT
+ removeFromFine=true;
+ }
+ } // FARBORD */
+#elif REFINEMENTBORDER==3 // REFINEMENTBORDER==1
+ if(lev+1==mMaxRefine) { // mixborder
+ if(RFLAG(lev+1, 2*i,2*j,2*k, mLevel[lev+1].setCurr)&notSrcAllowed) {
+ removeFromFine=true;
+ }
+ } else { // mixborder
+ for(int l=0; l<D::cDirNum; l++) {
+ int ni=2*i+D::dfVecX[l], nj=2*j+D::dfVecY[l], nk=2*k+D::dfVecZ[l];
+ if(RFLAG(lev+1, ni,nj,nk, mLevel[lev+1].setCurr)&notSrcAllowed) { // NEWREFT
+ removeFromFine=true;
+ }
+ }
+ } // mixborder
+ // also remove from fine cells that are above from fine
+#else // REFINEMENTBORDER==1
+ ERROR
+#endif // REFINEMENTBORDER==1
+
+ if(removeFromFine) {
+ // dont turn CFGrFromFine above interface cells into CFGrNorm
+ //errMsg("performRefinement","Removing CFGrFromFine on lev"<<lev<<" " <<PRINT_IJK );
+ RFLAG(lev, i,j,k, mLevel[lev].setCurr) = CFEmpty;
+ RFLAG(lev, i,j,k, mLevel[lev].setOther) = CFEmpty; // FLAGTEST
+ if(D::cDimension==2) debugMarkCell(lev,i,j,k);
+ change=true;
+ for(int l=1; l<D::cDirNum; l++) {
+ int ni=i+D::dfVecX[l], nj=j+D::dfVecY[l], nk=k+D::dfVecZ[l];
+ if(RFLAG(lev, ni,nj,nk, mLevel[lev].setCurr)&(CFFluid)) { //ok
+ RFLAG(lev, ni,nj,nk, mLevel[lev].setCurr) = CFFluid|CFGrFromFine;
+ if(D::cDimension==2) debugMarkCell(lev,ni,nj,nk);
+ }
+ } // l
+ }
+
+ // recheck from fine flag
+ }
+
+ if(RFLAG(lev, i,j,k, mLevel[lev].setCurr) & CFGrFromFine) {
+ if((RFLAG(lev+1, 2*i,2*j,2*k, mLevel[lev+1].setCurr)&(CFGrFromCoarse))) {
+ //errMsg("performRefinement","Removing CFGrFromCoarse on lev"<<(lev+1)<<" from l"<<lev<<" " <<PRINT_IJK );
+ CellFlagType setf = CFFluid;
+ if(lev+1 < mMaxRefine) setf = CFFluid|CFGrNorm;
+ RFLAG(lev+1, 2*i,2*j,2*k, mLevel[lev+1].setCurr)=setf;
+ change=true;
+ for(int l=1; l<D::cDirNum; l++) {
+ int bi=(2*i)+D::dfVecX[l], bj=(2*j)+D::dfVecY[l], bk=(2*k)+D::dfVecZ[l];
+ if(RFLAG(lev+1, bi, bj, bk, mLevel[lev+1].setCurr)&(CFGrFromCoarse)) {
+ //errMsg("performRefinement","Removing CFGrFromCoarse on lev"<<(lev+1)<<" "<<PRINT_VEC(bi,bj,bk) );
+ RFLAG(lev+1, bi, bj, bk, mLevel[lev+1].setCurr) = setf;
+ if(D::cDimension==2) debugMarkCell(lev+1,bi,bj,bk);
+ }
+ else if(RFLAG(lev+1, bi, bj, bk, mLevel[lev+1].setCurr)&(CFUnused )) {
+ //errMsg("performRefinement","Removing CFUnused on lev"<<(lev+1)<<" "<<PRINT_VEC(bi,bj,bk) );
+ interpolateCellFromCoarse(lev+1, bi, bj, bk, mLevel[lev+1].setCurr, interTime, setf, false);
+ if(D::cDimension==2) debugMarkCell(lev+1,bi,bj,bk);
+ }
+ }
+ for(int l=1; l<D::cDirNum; l++) {
+ int bi=(2*i)+D::dfVecX[l], bj=(2*j)+D::dfVecY[l], bk=(2*k)+D::dfVecZ[l];
+ if( (RFLAG(lev+1, bi, bj, bk, mLevel[lev+1].setCurr)&CFFluid ) &&
+ (!(RFLAG(lev+1, bi, bj, bk, mLevel[lev+1].setCurr)&CFGrFromCoarse)) ) {
+ // all unused nbs now of coarse have to be from coarse
+ for(int m=1; m<D::cDirNum; m++) {
+ int mi= bi +D::dfVecX[m], mj= bj +D::dfVecY[m], mk= bk +D::dfVecZ[m];
+ if(RFLAG(lev+1, mi, mj, mk, mLevel[lev+1].setCurr)&CFUnused) {
+ //errMsg("performRefinement","Changing CFUnused on lev"<<(lev+1)<<" "<<PRINT_VEC(mi,mj,mk) );
+ interpolateCellFromCoarse(lev+1, mi, mj, mk, mLevel[lev+1].setCurr, interTime, CFFluid|CFGrFromCoarse, false);
+ if(D::cDimension==2) debugMarkCell(lev+1,mi,mj,mk);
+ }
+ }
+ // nbs prepared...
+ }
+ }
+ }
+
+ } // convert regions of from fine
+
+ if(RFLAG(lev, i,j,k, mLevel[lev].setCurr) & CFGrFromCoarse) {
+
+ // from coarse cells without unused nbs are not necessary...! -> remove
+ bool invNb = false;
+ bool fluidNb = false;
+ for(int l=1; l<D::cDirNum; l++) {
+ if(RFLAG_NB(lev, i, j, k, mLevel[lev].setCurr, l) & CFUnused) { invNb = true; }
+ if(RFLAG_NB(lev, i, j, k, mLevel[lev].setCurr, l) & (CFGrNorm)) { fluidNb = true; }
+ }
+ if(!invNb) {
+ RFLAG(lev, i,j,k, mLevel[lev].setCurr) = CFFluid|CFGrNorm;
+ if(D::cDimension==2) debugMarkCell(lev, i, j, k);
+ change=true;
+ } // from advance */
+ if(!fluidNb) {
+ RFLAG(lev, i,j,k, mLevel[lev].setCurr) = CFUnused;
+ RFLAG(lev, i,j,k, mLevel[lev].setOther) = CFUnused; // FLAGTEST
+ if(D::cDimension==2) debugMarkCell(lev, i, j, k);
+ change=true;
+ } // from advance */
+
+
+ // dont allow double transfer
+ if(RFLAG(lev+1, 2*i,2*j,2*k, mLevel[lev+1].setCurr)&(CFGrFromCoarse)) {
+ // dont turn CFGrFromFine above interface cells into CFGrNorm
+ //errMsg("performRefinement","Removing CFGrFromCoarse on lev"<<lev<<" " <<PRINT_IJK<<" due to finer from coarse cell " );
+ RFLAG(lev, i,j,k, mLevel[lev].setCurr) = CFFluid|CFGrNorm;
+ if(D::cDimension==2) debugMarkCell(lev, i, j, k);
+ change=true;
+ for(int l=1; l<D::cDirNum; l++) {
+ int ni=i+D::dfVecX[l], nj=j+D::dfVecY[l], nk=k+D::dfVecZ[l];
+ if(RFLAG(lev, ni,nj,nk, mLevel[lev].setCurr)&(CFGrNorm)) { //ok
+ for(int m=1; m<D::cDirNum; m++) {
+ int mi= ni +D::dfVecX[m], mj= nj +D::dfVecY[m], mk= nk +D::dfVecZ[m];
+ if(RFLAG(lev, mi, mj, mk, mLevel[lev].setCurr)&CFUnused) {
+ // norm cells in neighborhood with unused nbs have to be new border...
+ RFLAG(lev, ni,nj,nk, mLevel[lev].setCurr) = CFFluid|CFGrFromCoarse;
+ if(D::cDimension==2) debugMarkCell(lev,ni,nj,nk);
+ }
+ }
+ // these alreay have valid values...
+ }
+ else if(RFLAG(lev, ni,nj,nk, mLevel[lev].setCurr)&(CFUnused)) { //ok
+ //RFLAG(lev, ni,nj,nk, mLevel[lev].setCurr) = CFFluid|CFGrFromFine;
+ // is this guaranteed to always work?
+ interpolateCellFromCoarse(lev, ni, nj, nk, mLevel[lev].setCurr, interTime, CFFluid|CFGrFromCoarse, false);
+ if(D::cDimension==2) debugMarkCell(lev,ni,nj,nk);
+ }
+ } // l
+ }
+ } // from coarse
+
+ } } }
+
+ if(!D::mSilent){ errMsg("performRefinement"," for l"<<lev<<" done ("<<change<<") " ); }
+ return change;
+}
+
+
+
+/*****************************************************************************/
+/*! perform a single LBM step */
+/*****************************************************************************/
+template<class D>
+void
+LbmFsgrSolver<D>::adaptTimestep()
+{
+ LbmFloat massTOld=0.0, massTNew=0.0;
+ LbmFloat volTOld=0.0, volTNew=0.0;
+
+ bool rescale = false; // do any rescale at all?
+ LbmFloat scaleFac = -1.0; // timestep scaling
+
+ LbmFloat levOldOmega[MAX_LEV];
+ LbmFloat levOldStepsize[MAX_LEV];
+ for(int lev=mMaxRefine; lev>=0 ; lev--) {
+ levOldOmega[lev] = mLevel[lev].omega;
+ levOldStepsize[lev] = mLevel[lev].stepsize;
+ }
+ //if(mTimeSwitchCounts>0){ errMsg("DEB CSKIP",""); return; } // DEBUG
+
+ LbmFloat fac = 0.8; // modify time step by 20%, TODO? do multiple times for large changes?
+ LbmFloat diffPercent = 0.05; // dont scale if less than 5%
+ LbmFloat allowMax = D::mpParam->getTadapMaxSpeed(); // maximum allowed velocity
+ LbmFloat nextmax = D::mpParam->getSimulationMaxSpeed() + norm(mLevel[mMaxRefine].gravity);
+
+ //newdt = D::mpParam->getStepTime() * (allowMax/nextmax);
+ LbmFloat newdt = D::mpParam->getStepTime(); // newtr
+ if(nextmax>allowMax/fac) {
+ newdt = D::mpParam->getStepTime() * fac;
+ } else {
+ if(nextmax<allowMax*fac) {
+ newdt = D::mpParam->getStepTime() / fac;
+ }
+ } // newtr
+ //errMsg("LbmFsgrSolver::adaptTimestep","nextmax="<<nextmax<<" allowMax="<<allowMax<<" fac="<<fac<<" simmaxv="<< D::mpParam->getSimulationMaxSpeed() );
+
+ bool minCutoff = false;
+ LbmFloat desireddt = newdt;
+ if(newdt>D::mpParam->getMaxStepTime()){ newdt = D::mpParam->getMaxStepTime(); }
+ if(newdt<D::mpParam->getMinStepTime()){
+ newdt = D::mpParam->getMinStepTime();
+ if(nextmax>allowMax/fac){ minCutoff=true; } // only if really large vels...
+ }
+
+ LbmFloat dtdiff = fabs(newdt - D::mpParam->getStepTime());
+ if(!D::mSilent) {
+ debMsgStd("LbmFsgrSolver::TAdp",DM_MSG, "new"<<newdt<<" max"<<D::mpParam->getMaxStepTime()<<" min"<<D::mpParam->getMinStepTime()<<" diff"<<dtdiff<<
+ " simt:"<<mSimulationTime<<" minsteps:"<<(mSimulationTime/mMaxStepTime)<<" maxsteps:"<<(mSimulationTime/mMinStepTime) , 10); }
+
+ // in range, and more than X% change?
+ //if( newdt < D::mpParam->getStepTime() ) // DEBUG
+ LbmFloat rhoAvg = mCurrentMass/mCurrentVolume;
+ if( (newdt<=D::mpParam->getMaxStepTime()) && (newdt>=D::mpParam->getMinStepTime())
+ && (dtdiff>(D::mpParam->getStepTime()*diffPercent)) ) {
+ if((newdt>levOldStepsize[mMaxRefine])&&(mTimestepReduceLock)) {
+ // wait some more...
+ //debMsgNnl("LbmFsgrSolver::TAdp",DM_NOTIFY," Delayed... "<<mTimestepReduceLock<<" ",10);
+ //debMsgDirect("D");
+ } else {
+ D::mpParam->setDesiredStepTime( newdt );
+ rescale = true;
+ if(!D::mSilent) {
+ debMsgStd("LbmFsgrSolver::TAdp",DM_NOTIFY,"\n\n\n\n",10);
+ debMsgStd("LbmFsgrSolver::TAdp",DM_NOTIFY,"Timestep change: new="<<newdt<<" old="<<D::mpParam->getStepTime()<<" maxSpeed:"<<D::mpParam->getSimulationMaxSpeed()<<" next:"<<nextmax<<" step:"<<D::mStepCnt, 10 );
+ debMsgStd("LbmFsgrSolver::TAdp",DM_NOTIFY,"Timestep change: "<<
+ "rhoAvg="<<rhoAvg<<" cMass="<<mCurrentMass<<" cVol="<<mCurrentVolume,10);
+ }
+ } // really change dt
+ }
+
+ if(mTimestepReduceLock>0) mTimestepReduceLock--;
+
+ /*
+ // forced back and forth switchting (for testing)
+ const int tadtogInter = 40;
+ const double tadtogSwitch = 0.66;
+ errMsg("TIMESWITCHTOGGLETEST","warning enabled "<< tadtogSwitch<<","<<tadtogSwitch<<" !!!!!!!!!!!!!!!!!!!");
+ if((D::mStepCnt% tadtogInter)== tadtogInter/2-1) {
+ rescale = true; minCutoff = false;
+ newdt = tadtogSwitch * D::mpParam->getStepTime();
+ D::mpParam->setDesiredStepTime( newdt );
+ } else
+ if((D::mStepCnt% tadtogInter)== tadtogInter-1) {
+ rescale = true; minCutoff = false;
+ newdt = D::mpParam->getStepTime()/tadtogSwitch ;
+ D::mpParam->setDesiredStepTime( newdt );
+ } else {
+ rescale = false; minCutoff = false;
+ }
+ // */
+
+ // test mass rescale
+
+ scaleFac = newdt/D::mpParam->getStepTime();
+ if(rescale) {
+ // fixme - warum y, wird jetzt gemittelt...
+ mTimestepReduceLock = 4*(mLevel[mMaxRefine].lSizey+mLevel[mMaxRefine].lSizez+mLevel[mMaxRefine].lSizex)/3;
+
+ mTimeSwitchCounts++;
+ D::mpParam->calculateAllMissingValues( D::mSilent );
+ // calc omega, force for all levels
+ initLevelOmegas();
+ if(D::mpParam->getStepTime()<mMinStepTime) mMinStepTime = D::mpParam->getStepTime();
+ if(D::mpParam->getStepTime()>mMaxStepTime) mMaxStepTime = D::mpParam->getStepTime();
+
+ for(int lev=mMaxRefine; lev>=0 ; lev--) {
+ LbmFloat newSteptime = mLevel[lev].stepsize;
+ LbmFloat newOmega = mLevel[lev].omega;
+ LbmFloat dfScaleFac = (newSteptime/1.0)/(levOldStepsize[lev]/levOldOmega[lev]);
+
+ if(!D::mSilent) {
+ debMsgStd("LbmFsgrSolver::TAdp",DM_NOTIFY,"Level: "<<lev<<" Timestep change: "<<
+ " scaleFac="<<dfScaleFac<<" newDt="<<newSteptime<<" newOmega="<<newOmega,10);
+ }
+ if(lev!=mMaxRefine) coarseCalculateFluxareas(lev);
+
+ int wss = 0, wse = 1;
+ // FIXME always currset!?
+ wss = wse = mLevel[lev].setCurr;
+ for(int workSet = wss; workSet<=wse; workSet++) { // COMPRT
+ // warning - check sets for higher levels...?
+ FSGR_FORIJK1(lev) {
+ if(
+ (RFLAG(lev,i,j,k, workSet) & CFFluid) ||
+ (RFLAG(lev,i,j,k, workSet) & CFInter) ||
+ (RFLAG(lev,i,j,k, workSet) & CFGrFromCoarse) ||
+ (RFLAG(lev,i,j,k, workSet) & CFGrFromFine) ||
+ (RFLAG(lev,i,j,k, workSet) & CFGrNorm)
+ ) {
+ // these cells have to be scaled...
+ } else {
+ continue;
+ }
+
+ // collide on current set
+ LbmFloat rhoOld;
+ LbmVec velOld;
+ LbmFloat rho, ux,uy,uz;
+ rho=0.0; ux = uy = uz = 0.0;
+ for(int l=0; l<D::cDfNum; l++) {
+ LbmFloat m = QCELL(lev, i, j, k, workSet, l);
+ rho += m;
+ ux += (D::dfDvecX[l]*m);
+ uy += (D::dfDvecY[l]*m);
+ uz += (D::dfDvecZ[l]*m);
+ }
+ rhoOld = rho;
+ velOld = LbmVec(ux,uy,uz);
+
+ LbmFloat rhoNew = (rhoOld-rhoAvg)*scaleFac +rhoAvg;
+ LbmVec velNew = velOld * scaleFac;
+
+ LbmFloat df[LBM_DFNUM];
+ LbmFloat feqOld[LBM_DFNUM];
+ LbmFloat feqNew[LBM_DFNUM];
+ for(int l=0; l<D::cDfNum; l++) {
+ feqOld[l] = D::getCollideEq(l,rhoOld, velOld[0],velOld[1],velOld[2] );
+ feqNew[l] = D::getCollideEq(l,rhoNew, velNew[0],velNew[1],velNew[2] );
+ df[l] = QCELL(lev, i,j,k,workSet, l);
+ }
+ const LbmFloat Qo = D::getLesNoneqTensorCoeff(df,feqOld);
+ const LbmFloat oldOmega = D::getLesOmega(levOldOmega[lev], mLevel[lev].lcsmago,Qo);
+ const LbmFloat newOmega = D::getLesOmega(mLevel[lev].omega,mLevel[lev].lcsmago,Qo);
+ //newOmega = mLevel[lev].omega; // FIXME debug test
+
+ //LbmFloat dfScaleFac = (newSteptime/1.0)/(levOldStepsize[lev]/levOldOmega[lev]);
+ const LbmFloat dfScale = (newSteptime/newOmega)/(levOldStepsize[lev]/oldOmega);
+ //dfScale = dfScaleFac/newOmega;
+
+ for(int l=0; l<D::cDfNum; l++) {
+ // org scaling
+ //df = eqOld + (df-eqOld)*dfScale; df *= (eqNew/eqOld); // non-eq. scaling, important
+ // new scaling
+ LbmFloat dfn = feqNew[l] + (df[l]-feqOld[l])*dfScale*feqNew[l]/feqOld[l]; // non-eq. scaling, important
+ //df = eqNew + (df-eqOld)*dfScale; // modified ig scaling, no real difference?
+ QCELL(lev, i,j,k,workSet, l) = dfn;
+ }
+
+ if(RFLAG(lev,i,j,k, workSet) & CFInter) {
+ //if(workSet==mLevel[lev].setCurr)
+ LbmFloat area = 1.0;
+ if(lev!=mMaxRefine) area = QCELL(lev, i,j,k,workSet, dFlux);
+ massTOld += QCELL(lev, i,j,k,workSet, dMass) * area;
+ volTOld += QCELL(lev, i,j,k,workSet, dFfrac);
+
+ // wrong... QCELL(i,j,k,workSet, dMass] = (QCELL(i,j,k,workSet, dFfrac]*rhoNew);
+ QCELL(lev, i,j,k,workSet, dMass) = (QCELL(lev, i,j,k,workSet, dMass)/rhoOld*rhoNew);
+ QCELL(lev, i,j,k,workSet, dFfrac) = (QCELL(lev, i,j,k,workSet, dMass)/rhoNew);
+
+ //if(workSet==mLevel[lev].setCurr)
+ massTNew += QCELL(lev, i,j,k,workSet, dMass);
+ volTNew += QCELL(lev, i,j,k,workSet, dFfrac);
+ }
+ if(RFLAG(lev,i,j,k, workSet) & CFFluid) { // DEBUG
+ if(RFLAG(lev,i,j,k, workSet) & (CFGrFromFine|CFGrFromCoarse)) { // DEBUG
+ // dont include
+ } else {
+ LbmFloat area = 1.0;
+ if(lev!=mMaxRefine) area = QCELL(lev, i,j,k,workSet, dFlux) * mLevel[lev].lcellfactor;
+ //if(workSet==mLevel[lev].setCurr)
+ massTOld += rhoOld*area;
+ //if(workSet==mLevel[lev].setCurr)
+ massTNew += rhoNew*area;
+ volTOld += area;
+ volTNew += area;
+ }
+ }
+
+ } // IJK
+ } // workSet
+
+ } // lev
+
+ if(!D::mSilent) {
+ debMsgStd("LbmFsgrSolver::step",DM_MSG,"REINIT DONE "<<D::mStepCnt<<
+ " no"<<mTimeSwitchCounts<<" maxdt"<<mMaxStepTime<<
+ " mindt"<<mMinStepTime<<" currdt"<<mLevel[mMaxRefine].stepsize, 10);
+ debMsgStd("LbmFsgrSolver::step",DM_MSG,"REINIT DONE masst:"<<massTNew<<","<<massTOld<<" org:"<<mCurrentMass<<"; "<<
+ " volt:"<<volTNew<<","<<volTOld<<" org:"<<mCurrentVolume, 10);
+ } else {
+ debMsgStd("\nLbmOptSolver::step",DM_MSG,"Timestep change by "<< (newdt/levOldStepsize[mMaxRefine]) <<" newDt:"<<newdt
+ <<", oldDt:"<<levOldStepsize[mMaxRefine]<<" newOmega:"<<D::mOmega<<" gStar:"<<D::mpParam->getCurrentGStar() , 10);
+ }
+ } // rescale?
+
+ //errMsg("adaptTimestep","Warning - brute force rescale off!"); minCutoff = false; // DEBUG
+ if(minCutoff) {
+ errMsg("adaptTimestep","Warning - performing Brute-Force rescale... (sim:"<<D::mName<<" step:"<<D::mStepCnt<<" newdt="<<desireddt<<" mindt="<<D::mpParam->getMinStepTime()<<") " );
+ //brute force resacle all the time?
+
+ for(int lev=mMaxRefine; lev>=0 ; lev--) {
+ int rescs=0;
+ int wss = 0, wse = 1;
+#if COMPRESSGRIDS==1
+ if(lev== mMaxRefine) wss = wse = mLevel[lev].setCurr;
+#endif // COMPRESSGRIDS==1
+ for(int workSet = wss; workSet<=wse; workSet++) { // COMPRT
+ //for(int workSet = 0; workSet<=1; workSet++) {
+ FSGR_FORIJK1(lev) {
+
+ //if( (RFLAG(lev, i,j,k, workSet) & CFFluid) || (RFLAG(lev, i,j,k, workSet) & CFInter) ) {
+ if(
+ (RFLAG(lev,i,j,k, workSet) & CFFluid) ||
+ (RFLAG(lev,i,j,k, workSet) & CFInter) ||
+ (RFLAG(lev,i,j,k, workSet) & CFGrFromCoarse) ||
+ (RFLAG(lev,i,j,k, workSet) & CFGrFromFine) ||
+ (RFLAG(lev,i,j,k, workSet) & CFGrNorm)
+ ) {
+ // these cells have to be scaled...
+ } else {
+ continue;
+ }
+
+ // collide on current set
+ LbmFloat rho, ux,uy,uz;
+ rho=0.0; ux = uy = uz = 0.0;
+ for(int l=0; l<D::cDfNum; l++) {
+ LbmFloat m = QCELL(lev, i, j, k, workSet, l);
+ rho += m;
+ ux += (D::dfDvecX[l]*m);
+ uy += (D::dfDvecY[l]*m);
+ uz += (D::dfDvecZ[l]*m);
+ }
+#ifndef WIN32
+ if (!finite(rho)) {
+ //errMsg("adaptTimestep","Brute force non-finite rho at"<<PRINT_IJK); // DEBUG!
+ rho = 1.0;
+ ux = uy = uz = 0.0;
+ QCELL(lev, i, j, k, workSet, dMass) = 1.0;
+ QCELL(lev, i, j, k, workSet, dFfrac) = 1.0;
+ }
+#endif // WIN32
+
+ if( (ux*ux+uy*uy+uz*uz)> (allowMax*allowMax) ) {
+ LbmFloat cfac = allowMax/sqrt(ux*ux+uy*uy+uz*uz);
+ ux *= cfac;
+ uy *= cfac;
+ uz *= cfac;
+ for(int l=0; l<D::cDfNum; l++) {
+ QCELL(lev, i, j, k, workSet, l) = D::getCollideEq(l, rho, ux,uy,uz); }
+ rescs++;
+ //debMsgDirect("B");
+ }
+
+ } }
+ //if(rescs>0) { errMsg("adaptTimestep","!!!!! Brute force rescaling was necessary !!!!!!!"); }
+ debMsgStd("adaptTimestep",DM_MSG,"Brute force rescale done. level:"<<lev<<" rescs:"<<rescs, 1);
+ //TTT mNumProblems += rescs; // add to problem display...
+ } // lev,set,ijk
+
+ } // try brute force rescale?
+
+ // time adap done...
+}
+
+
+
+
+/******************************************************************************
+ * work on lists from updateCellMass to reinit cell flags
+ *****************************************************************************/
+
+template<class D>
+LbmFloat
+LbmFsgrSolver<D>::getMassdWeight(bool dirForw, int i,int j,int k,int workSet, int l) {
+ //return 0.0; // test
+ int level = mMaxRefine;
+ LbmFloat *ccel = RACPNT(level, i,j,k, workSet);
+
+ LbmFloat nx,ny,nz, nv1,nv2;
+ if(RFLAG_NB(level,i,j,k,workSet, dE) &(CFFluid|CFInter)){ nv1 = RAC((ccel+QCELLSTEP ),dFfrac); } else nv1 = 0.0;
+ if(RFLAG_NB(level,i,j,k,workSet, dW) &(CFFluid|CFInter)){ nv2 = RAC((ccel-QCELLSTEP ),dFfrac); } else nv2 = 0.0;
+ nx = 0.5* (nv2-nv1);
+ if(RFLAG_NB(level,i,j,k,workSet, dN) &(CFFluid|CFInter)){ nv1 = RAC((ccel+(mLevel[level].lOffsx*QCELLSTEP)),dFfrac); } else nv1 = 0.0;
+ if(RFLAG_NB(level,i,j,k,workSet, dS) &(CFFluid|CFInter)){ nv2 = RAC((ccel-(mLevel[level].lOffsx*QCELLSTEP)),dFfrac); } else nv2 = 0.0;
+ ny = 0.5* (nv2-nv1);
+#if LBMDIM==3
+ if(RFLAG_NB(level,i,j,k,workSet, dT) &(CFFluid|CFInter)){ nv1 = RAC((ccel+(mLevel[level].lOffsy*QCELLSTEP)),dFfrac); } else nv1 = 0.0;
+ if(RFLAG_NB(level,i,j,k,workSet, dB) &(CFFluid|CFInter)){ nv2 = RAC((ccel-(mLevel[level].lOffsy*QCELLSTEP)),dFfrac); } else nv2 = 0.0;
+ nz = 0.5* (nv2-nv1);
+#else //LBMDIM==3
+ nz = 0.0;
+#endif //LBMDIM==3
+ LbmFloat scal = mDvecNrm[l][0]*nx + mDvecNrm[l][1]*ny + mDvecNrm[l][2]*nz;
+
+ LbmFloat ret = 1.0;
+ // forward direction, add mass (for filling cells):
+ if(dirForw) {
+ if(scal<LBM_EPSILON) ret = 0.0;
+ else ret = scal;
+ } else {
+ // backward for emptying
+ if(scal>-LBM_EPSILON) ret = 0.0;
+ else ret = scal * -1.0;
+ }
+ //errMsg("massd", PRINT_IJK<<" nv"<<nvel<<" : ret="<<ret ); //exit(1); //VECDEB
+ return ret;
+}
+
+template<class D>
+void LbmFsgrSolver<D>::addToNewInterList( int ni, int nj, int nk ) {
+#if FSGR_STRICT_DEBUG==10
+ // dangerous, this can change the simulation...
+ /*for( vector<LbmPoint>::iterator iter=mListNewInter.begin();
+ iter != mListNewInter.end(); iter++ ) {
+ if(ni!=iter->x) continue;
+ if(nj!=iter->y) continue;
+ if(nk!=iter->z) continue;
+ // all 3 values match... skip point
+ return;
+ } */
+#endif // FSGR_STRICT_DEBUG==1
+ // store point
+ LbmPoint newinter;
+ newinter.x = ni; newinter.y = nj; newinter.z = nk;
+ mListNewInter.push_back(newinter);
+}
+
+
+// WOXDY_N = Weight Order X Dimension Y _ number N
+#define WO1D1 ( 1.0/ 2.0)
+#define WO1D2 ( 1.0/ 4.0)
+#define WO1D3 ( 1.0/ 8.0)
+
+#define WO2D1_1 (-1.0/16.0)
+#define WO2D1_9 ( 9.0/16.0)
+
+#define WO2D2_11 (WO2D1_1 * WO2D1_1)
+#define WO2D2_19 (WO2D1_9 * WO2D1_1)
+#define WO2D2_91 (WO2D1_9 * WO2D1_1)
+#define WO2D2_99 (WO2D1_9 * WO2D1_9)
+
+#define WO2D3_111 (WO2D1_1 * WO2D1_1 * WO2D1_1)
+#define WO2D3_191 (WO2D1_9 * WO2D1_1 * WO2D1_1)
+#define WO2D3_911 (WO2D1_9 * WO2D1_1 * WO2D1_1)
+#define WO2D3_991 (WO2D1_9 * WO2D1_9 * WO2D1_1)
+#define WO2D3_119 (WO2D1_1 * WO2D1_1 * WO2D1_9)
+#define WO2D3_199 (WO2D1_9 * WO2D1_1 * WO2D1_9)
+#define WO2D3_919 (WO2D1_9 * WO2D1_1 * WO2D1_9)
+#define WO2D3_999 (WO2D1_9 * WO2D1_9 * WO2D1_9)
+
+#if FSGR_STRICT_DEBUG==1
+#define ADD_INT_DFSCHECK(alev, ai,aj,ak, at, afac, l) \
+ if( (((1.0-(at))>0.0) && (!(QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr , l) > -1.0 ))) || \
+ ((( (at))>0.0) && (!(QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setOther, l) > -1.0 ))) ){ \
+ errMsg("INVDFSCHECK", " l"<<(alev)<<" "<<PRINT_VEC((ai),(aj),(ak))<<" fc:"<<RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr )<<" fo:"<<RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setOther )<<" dfl"<<l ); \
+ debugMarkCell((alev), (ai),(aj),(ak));\
+ D::mPanic = 1; \
+ }
+ // end ADD_INT_DFSCHECK
+#define ADD_INT_FLAGCHECK(alev, ai,aj,ak, at, afac) \
+ if( (((1.0-(at))>0.0) && (!(RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr )&(CFInter|CFFluid|CFGrCoarseInited) ))) || \
+ ((( (at))>0.0) && (!(RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setOther)&(CFInter|CFFluid|CFGrCoarseInited) ))) ){ \
+ errMsg("INVFLAGCINTCHECK", " l"<<(alev)<<" "<<PRINT_VEC((ai),(aj),(ak))<<" fc:"<<RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr ) <<"="<<convertFlags2String(RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr ))<<" fold:"<<RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setOther ) ); \
+ debugMarkCell((alev), (ai),(aj),(ak));\
+ D::mPanic = 1; \
+ }
+ // end ADD_INT_DFSCHECK
+
+ //if( !(RFLAG(lev+1, (ix),(iy),(iz), mLevel[lev+1].setCurr) & CFUnused) ){
+ //errMsg("INTFLAGUNU", PRINT_VEC(i,j,k)<<" child at "<<PRINT_VEC((ix),(iy),(iz)) );
+ //if(iy==15) errMsg("IFFC", PRINT_VEC(i,j,k)<<" child interpolated at "<<PRINT_VEC((ix),(iy),(iz)) );
+ //if(((ix)>10)&&(iy>5)&&(iz>5)) { debugMarkCell(lev+1, (ix),(iy),(iz) ); }
+#define INTUNUTCHECK(ix,iy,iz) \
+ if( (RFLAG(lev+1, (ix),(iy),(iz), mLevel[lev+1].setCurr) != (CFFluid|CFGrFromCoarse)) ){\
+ errMsg("INTFLAGUNU_CHECK", PRINT_VEC(i,j,k)<<" child not unused at l"<<(lev+1)<<" "<<PRINT_VEC((ix),(iy),(iz))<<" flag: "<< RFLAG(lev+1, (ix),(iy),(iz), mLevel[lev+1].setCurr) ); \
+ debugMarkCell((lev+1), (ix),(iy),(iz));\
+ D::mPanic = 1; \
+ }\
+ RFLAG(lev+1, (ix),(iy),(iz), mLevel[lev+1].setCurr) |= CFGrCoarseInited; \
+ // INTUNUTCHECK
+#define INTSTRICTCHECK(ix,iy,iz,caseId) \
+ if( QCELL(lev+1, (ix),(iy),(iz), mLevel[lev+1].setCurr, l) <= 0.0 ){\
+ errMsg("INVDFCCELLCHECK", "caseId:"<<caseId<<" "<<PRINT_VEC(i,j,k)<<" child inter at "<<PRINT_VEC((ix),(iy),(iz))<<" invalid df "<<l<<" = "<< QCELL(lev+1, (ix),(iy),(iz), mLevel[lev+1].setCurr, l) ); \
+ debugMarkCell((lev+1), (ix),(iy),(iz));\
+ D::mPanic = 1; \
+ }\
+ // INTSTRICTCHECK
+
+#else// FSGR_STRICT_DEBUG==1
+#define ADD_INT_FLAGCHECK(alev, ai,aj,ak, at, afac)
+#define ADD_INT_DFSCHECK(alev, ai,aj,ak, at, afac, l)
+#define INTSTRICTCHECK(x,y,z,caseId)
+#define INTUNUTCHECK(ix,iy,iz)
+#endif// FSGR_STRICT_DEBUG==1
+
+
+#if FSGR_STRICT_DEBUG==1
+#define INTDEBOUT \
+ { LbmFloat rho,ux,uy,uz; \
+ rho = ux=uy=uz=0.0; \
+ FORDF0{ LbmFloat m = QCELL(lev,i,j,k, dstSet, l); \
+ rho += m; ux += (D::dfDvecX[l]*m); uy += (D::dfDvecY[l]*m); uz += (D::dfDvecZ[l]*m); \
+ if(ABS(m)>1.0) { errMsg("interpolateCellFromCoarse", "ICFC_DFCHECK cell "<<PRINT_IJK<<" m"<<l<<":"<< m ); D::mPanic=1; }\
+ /*errMsg("interpolateCellFromCoarse", " cell "<<PRINT_IJK<<" df"<<l<<":"<<m );*/ \
+ } \
+ /*if(D::mPanic) { errMsg("interpolateCellFromCoarse", "ICFC_DFOUT cell "<<PRINT_IJK<<" rho:"<<rho<<" u:"<<PRINT_VEC(ux,uy,uz)<<" b"<<PRINT_VEC(betx,bety,betz) ); }*/ \
+ if(markNbs) errMsg("interpolateCellFromCoarse", " cell "<<PRINT_IJK<<" rho:"<<rho<<" u:"<<PRINT_VEC(ux,uy,uz)<<" b"<<PRINT_VEC(betx,bety,betz) ); \
+ errMsg("interpolateCellFromCoarse", "ICFC_DFDEBUG cell "<<PRINT_IJK<<" rho:"<<rho<<" u:"<<PRINT_VEC(ux,uy,uz)<<" b"<<PRINT_VEC(betx,bety,betz) ); \
+ } \
+ /* both cases are ok to interpolate */ \
+ if( (!(RFLAG(lev,i,j,k, dstSet) & CFGrFromCoarse)) && \
+ (!(RFLAG(lev,i,j,k, dstSet) & CFUnused)) ) { \
+ /* might also have CFGrCoarseInited (shouldnt be a problem here)*/ \
+ errMsg("interpolateCellFromCoarse", "CHECK cell not CFGrFromCoarse? "<<PRINT_IJK<<" flag:"<< RFLAG(lev,i,j,k, dstSet)<<" fstr:"<<convertFlags2String( RFLAG(lev,i,j,k, dstSet) )); \
+ /* FIXME check this warning...? return; this can happen !? */ \
+ /*D::mPanic = 1;*/ \
+ } \
+ // end INTDEBOUT
+#else // FSGR_STRICT_DEBUG==1
+#define INTDEBOUT
+#endif // FSGR_STRICT_DEBUG==1
+
+
+// t=0.0 -> only current
+// t=0.5 -> mix
+// t=1.0 -> only other
+#if OPT3D==false
+#define ADD_INT_DFS(alev, ai,aj,ak, at, afac) \
+ ADD_INT_FLAGCHECK(alev, ai,aj,ak, at, afac); \
+ FORDF0{ \
+ LbmFloat df = ( \
+ QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr , l)*(1.0-(at)) + \
+ QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setOther, l)*( (at)) \
+ ) ; \
+ ADD_INT_DFSCHECK(alev, ai,aj,ak, at, afac, l); \
+ df *= (afac); \
+ rho += df; \
+ ux += (D::dfDvecX[l]*df); \
+ uy += (D::dfDvecY[l]*df); \
+ uz += (D::dfDvecZ[l]*df); \
+ intDf[l] += df; \
+ }
+// write interpolated dfs back to cell (correct non-eq. parts)
+#define IDF_WRITEBACK_ \
+ FORDF0{ \
+ LbmFloat eq = D::getCollideEq(l, rho,ux,uy,uz);\
+ QCELL(lev,i,j,k, dstSet, l) = (eq+ (intDf[l]-eq)*mDfScaleDown);\
+ } \
+ /* check that all values are ok */ \
+ INTDEBOUT
+#define IDF_WRITEBACK \
+ LbmFloat omegaDst, omegaSrc;\
+ /* smago new */ \
+ LbmFloat feq[LBM_DFNUM]; \
+ LbmFloat dfScale = mDfScaleDown; \
+ FORDF0{ \
+ feq[l] = D::getCollideEq(l, rho,ux,uy,uz); \
+ } \
+ if(mLevel[lev ].lcsmago>0.0) {\
+ LbmFloat Qo = D::getLesNoneqTensorCoeff(intDf,feq); \
+ omegaDst = D::getLesOmega(mLevel[lev+0].omega,mLevel[lev+0].lcsmago,Qo); \
+ omegaSrc = D::getLesOmega(mLevel[lev-1].omega,mLevel[lev-1].lcsmago,Qo); \
+ } else {\
+ omegaDst = mLevel[lev+0].omega; \
+ omegaSrc = mLevel[lev-1].omega;\
+ } \
+ \
+ dfScale = (mLevel[lev+0].stepsize/mLevel[lev-1].stepsize)* (1.0/omegaDst-1.0)/ (1.0/omegaSrc-1.0); \
+ FORDF0{ \
+ /*errMsg("SMAGO"," org"<<mDfScaleDown<<" n"<<dfScale<<" qc"<< QCELL(lev,i,j,k, dstSet, l)<<" idf"<<intDf[l]<<" eq"<<feq[l] ); */ \
+ QCELL(lev,i,j,k, dstSet, l) = (feq[l]+ (intDf[l]-feq[l])*dfScale);\
+ } \
+ /* check that all values are ok */ \
+ INTDEBOUT
+
+#else //OPT3D==false
+
+#define ADDALLVALS \
+ addVal = addDfFacT * RAC(addfcel , dC ); \
+ intDf[dC ] += addVal; rho += addVal; \
+ addVal = addDfFacT * RAC(addfcel , dN ); \
+ uy+=addVal; intDf[dN ] += addVal; rho += addVal; \
+ addVal = addDfFacT * RAC(addfcel , dS ); \
+ uy-=addVal; intDf[dS ] += addVal; rho += addVal; \
+ addVal = addDfFacT * RAC(addfcel , dE ); \
+ ux+=addVal; intDf[dE ] += addVal; rho += addVal; \
+ addVal = addDfFacT * RAC(addfcel , dW ); \
+ ux-=addVal; intDf[dW ] += addVal; rho += addVal; \
+ addVal = addDfFacT * RAC(addfcel , dT ); \
+ uz+=addVal; intDf[dT ] += addVal; rho += addVal; \
+ addVal = addDfFacT * RAC(addfcel , dB ); \
+ uz-=addVal; intDf[dB ] += addVal; rho += addVal; \
+ addVal = addDfFacT * RAC(addfcel , dNE); \
+ ux+=addVal; uy+=addVal; intDf[dNE] += addVal; rho += addVal; \
+ addVal = addDfFacT * RAC(addfcel , dNW); \
+ ux-=addVal; uy+=addVal; intDf[dNW] += addVal; rho += addVal; \
+ addVal = addDfFacT * RAC(addfcel , dSE); \
+ ux+=addVal; uy-=addVal; intDf[dSE] += addVal; rho += addVal; \
+ addVal = addDfFacT * RAC(addfcel , dSW); \
+ ux-=addVal; uy-=addVal; intDf[dSW] += addVal; rho += addVal; \
+ addVal = addDfFacT * RAC(addfcel , dNT); \
+ uy+=addVal; uz+=addVal; intDf[dNT] += addVal; rho += addVal; \
+ addVal = addDfFacT * RAC(addfcel , dNB); \
+ uy+=addVal; uz-=addVal; intDf[dNB] += addVal; rho += addVal; \
+ addVal = addDfFacT * RAC(addfcel , dST); \
+ uy-=addVal; uz+=addVal; intDf[dST] += addVal; rho += addVal; \
+ addVal = addDfFacT * RAC(addfcel , dSB); \
+ uy-=addVal; uz-=addVal; intDf[dSB] += addVal; rho += addVal; \
+ addVal = addDfFacT * RAC(addfcel , dET); \
+ ux+=addVal; uz+=addVal; intDf[dET] += addVal; rho += addVal; \
+ addVal = addDfFacT * RAC(addfcel , dEB); \
+ ux+=addVal; uz-=addVal; intDf[dEB] += addVal; rho += addVal; \
+ addVal = addDfFacT * RAC(addfcel , dWT); \
+ ux-=addVal; uz+=addVal; intDf[dWT] += addVal; rho += addVal; \
+ addVal = addDfFacT * RAC(addfcel , dWB); \
+ ux-=addVal; uz-=addVal; intDf[dWB] += addVal; rho += addVal;
+
+#define ADD_INT_DFS(alev, ai,aj,ak, at, afac) \
+ addDfFacT = at*afac; \
+ addfcel = RACPNT((alev), (ai),(aj),(ak),mLevel[(alev)].setOther); \
+ ADDALLVALS\
+ addDfFacT = (1.0-at)*afac; \
+ addfcel = RACPNT((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr); \
+ ADDALLVALS
+
+// also ugly...
+#define INTDF_C intDf[dC ]
+#define INTDF_N intDf[dN ]
+#define INTDF_S intDf[dS ]
+#define INTDF_E intDf[dE ]
+#define INTDF_W intDf[dW ]
+#define INTDF_T intDf[dT ]
+#define INTDF_B intDf[dB ]
+#define INTDF_NE intDf[dNE]
+#define INTDF_NW intDf[dNW]
+#define INTDF_SE intDf[dSE]
+#define INTDF_SW intDf[dSW]
+#define INTDF_NT intDf[dNT]
+#define INTDF_NB intDf[dNB]
+#define INTDF_ST intDf[dST]
+#define INTDF_SB intDf[dSB]
+#define INTDF_ET intDf[dET]
+#define INTDF_EB intDf[dEB]
+#define INTDF_WT intDf[dWT]
+#define INTDF_WB intDf[dWB]
+
+
+// write interpolated dfs back to cell (correct non-eq. parts)
+#define IDF_WRITEBACK_LES \
+ dstcell = RACPNT(lev, i,j,k,dstSet); \
+ usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
+ \
+ lcsmeq[dC] = EQC ; \
+ COLL_CALCULATE_DFEQ(lcsmeq); \
+ COLL_CALCULATE_NONEQTENSOR(lev, INTDF_ )\
+ COLL_CALCULATE_CSMOMEGAVAL(lev+0, lcsmDstOmega); \
+ COLL_CALCULATE_CSMOMEGAVAL(lev-1, lcsmSrcOmega); \
+ \
+ lcsmdfscale = (mLevel[lev+0].stepsize/mLevel[lev-1].stepsize)* (1.0/lcsmDstOmega-1.0)/ (1.0/lcsmSrcOmega-1.0); \
+ RAC(dstcell, dC ) = (lcsmeq[dC ] + (intDf[dC ]-lcsmeq[dC ] )*lcsmdfscale);\
+ RAC(dstcell, dN ) = (lcsmeq[dN ] + (intDf[dN ]-lcsmeq[dN ] )*lcsmdfscale);\
+ RAC(dstcell, dS ) = (lcsmeq[dS ] + (intDf[dS ]-lcsmeq[dS ] )*lcsmdfscale);\
+ RAC(dstcell, dE ) = (lcsmeq[dE ] + (intDf[dE ]-lcsmeq[dE ] )*lcsmdfscale);\
+ RAC(dstcell, dW ) = (lcsmeq[dW ] + (intDf[dW ]-lcsmeq[dW ] )*lcsmdfscale);\
+ RAC(dstcell, dT ) = (lcsmeq[dT ] + (intDf[dT ]-lcsmeq[dT ] )*lcsmdfscale);\
+ RAC(dstcell, dB ) = (lcsmeq[dB ] + (intDf[dB ]-lcsmeq[dB ] )*lcsmdfscale);\
+ RAC(dstcell, dNE) = (lcsmeq[dNE] + (intDf[dNE]-lcsmeq[dNE] )*lcsmdfscale);\
+ RAC(dstcell, dNW) = (lcsmeq[dNW] + (intDf[dNW]-lcsmeq[dNW] )*lcsmdfscale);\
+ RAC(dstcell, dSE) = (lcsmeq[dSE] + (intDf[dSE]-lcsmeq[dSE] )*lcsmdfscale);\
+ RAC(dstcell, dSW) = (lcsmeq[dSW] + (intDf[dSW]-lcsmeq[dSW] )*lcsmdfscale);\
+ RAC(dstcell, dNT) = (lcsmeq[dNT] + (intDf[dNT]-lcsmeq[dNT] )*lcsmdfscale);\
+ RAC(dstcell, dNB) = (lcsmeq[dNB] + (intDf[dNB]-lcsmeq[dNB] )*lcsmdfscale);\
+ RAC(dstcell, dST) = (lcsmeq[dST] + (intDf[dST]-lcsmeq[dST] )*lcsmdfscale);\
+ RAC(dstcell, dSB) = (lcsmeq[dSB] + (intDf[dSB]-lcsmeq[dSB] )*lcsmdfscale);\
+ RAC(dstcell, dET) = (lcsmeq[dET] + (intDf[dET]-lcsmeq[dET] )*lcsmdfscale);\
+ RAC(dstcell, dEB) = (lcsmeq[dEB] + (intDf[dEB]-lcsmeq[dEB] )*lcsmdfscale);\
+ RAC(dstcell, dWT) = (lcsmeq[dWT] + (intDf[dWT]-lcsmeq[dWT] )*lcsmdfscale);\
+ RAC(dstcell, dWB) = (lcsmeq[dWB] + (intDf[dWB]-lcsmeq[dWB] )*lcsmdfscale);\
+ /* IDF_WRITEBACK optimized */
+
+#define IDF_WRITEBACK_NOLES \
+ dstcell = RACPNT(lev, i,j,k,dstSet); \
+ usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
+ \
+ RAC(dstcell, dC ) = (EQC + (intDf[dC ]-EQC )*mDfScaleDown);\
+ RAC(dstcell, dN ) = (EQN + (intDf[dN ]-EQN )*mDfScaleDown);\
+ RAC(dstcell, dS ) = (EQS + (intDf[dS ]-EQS )*mDfScaleDown);\
+ /*old*/ RAC(dstcell, dE ) = (EQE + (intDf[dE ]-EQE )*mDfScaleDown);\
+ RAC(dstcell, dW ) = (EQW + (intDf[dW ]-EQW )*mDfScaleDown);\
+ RAC(dstcell, dT ) = (EQT + (intDf[dT ]-EQT )*mDfScaleDown);\
+ RAC(dstcell, dB ) = (EQB + (intDf[dB ]-EQB )*mDfScaleDown);\
+ /*old*/ RAC(dstcell, dNE) = (EQNE + (intDf[dNE]-EQNE )*mDfScaleDown);\
+ RAC(dstcell, dNW) = (EQNW + (intDf[dNW]-EQNW )*mDfScaleDown);\
+ RAC(dstcell, dSE) = (EQSE + (intDf[dSE]-EQSE )*mDfScaleDown);\
+ RAC(dstcell, dSW) = (EQSW + (intDf[dSW]-EQSW )*mDfScaleDown);\
+ RAC(dstcell, dNT) = (EQNT + (intDf[dNT]-EQNT )*mDfScaleDown);\
+ RAC(dstcell, dNB) = (EQNB + (intDf[dNB]-EQNB )*mDfScaleDown);\
+ RAC(dstcell, dST) = (EQST + (intDf[dST]-EQST )*mDfScaleDown);\
+ RAC(dstcell, dSB) = (EQSB + (intDf[dSB]-EQSB )*mDfScaleDown);\
+ RAC(dstcell, dET) = (EQET + (intDf[dET]-EQET )*mDfScaleDown);\
+ /*old*/ RAC(dstcell, dEB) = (EQEB + (intDf[dEB]-EQEB )*mDfScaleDown);\
+ RAC(dstcell, dWT) = (EQWT + (intDf[dWT]-EQWT )*mDfScaleDown);\
+ RAC(dstcell, dWB) = (EQWB + (intDf[dWB]-EQWB )*mDfScaleDown);\
+ /* IDF_WRITEBACK optimized */
+
+#if USE_LES==1
+#define IDF_WRITEBACK IDF_WRITEBACK_LES
+#else
+#define IDF_WRITEBACK IDF_WRITEBACK_NOLES
+#endif
+
+#endif// OPT3D==false
+
+template<class D>
+void LbmFsgrSolver<D>::interpolateCellFromCoarse(int lev, int i, int j,int k, int dstSet, LbmFloat t, CellFlagType flagSet, bool markNbs) {
+ //errMsg("INV DEBUG REINIT! off!",""); exit(1); // DEBUG exit
+ //if(markNbs) errMsg("interpolateCellFromCoarse"," l"<<lev<<" "<<PRINT_VEC(i,j,k)<<" s"<<dstSet<<" t"<<t); //exit(1); // DEBUG exit
+
+ LbmFloat rho=0.0, ux=0.0, uy=0.0, uz=0.0;
+ //LbmFloat intDf[LBM_DFNUM];
+ // warning only q19 and below!
+ LbmFloat intDf[19] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
+
+#if OPT3D==true
+ // for macro add
+ LbmFloat addDfFacT, addVal, usqr;
+ LbmFloat *addfcel, *dstcell;
+ LbmFloat lcsmqadd, lcsmqo, lcsmeq[LBM_DFNUM];
+ LbmFloat lcsmDstOmega, lcsmSrcOmega, lcsmdfscale;
+#endif // OPT3D==true
+
+ // SET required nbs to from coarse (this might overwrite flag several times)
+ // this is not necessary for interpolateFineFromCoarse
+ if(markNbs) {
+ FORDF1{
+ int ni=i+D::dfVecX[l], nj=j+D::dfVecY[l], nk=k+D::dfVecZ[l];
+ if(RFLAG(lev,ni,nj,nk,dstSet)&CFUnused) {
+ // parents have to be inited!
+ interpolateCellFromCoarse(lev, ni, nj, nk, dstSet, t, CFFluid|CFGrFromCoarse, false);
+ }
+ } }
+
+ // change flag of cell to be interpolated
+ RFLAG(lev,i,j,k, dstSet) = flagSet;
+ mNumInterdCells++;
+
+ // interpolation lines...
+ int betx = i&1;
+ int bety = j&1;
+ int betz = k&1;
+
+ if((!betx) && (!bety) && (!betz)) {
+ ADD_INT_DFS(lev-1, i/2 ,j/2 ,k/2 , 0.0, 1.0);
+
+ IDF_WRITEBACK;
+ return;
+ }
+
+ if(( betx) && (!bety) && (!betz)) {
+ //if((i==19)&&(j==14)&&(D::cDimension==2)) { debugMarkCell(lev,i,j,k); debugMarkCell(lev-1, (i/2)-1, (j/2) , (k/2) ); debugMarkCell(lev-1, (i/2) , (j/2) , (k/2) ); debugMarkCell(lev-1, (i/2)+1, (j/2) , (k/2) ); debugMarkCell(lev-1, (i/2)+2, (j/2) , (k/2) ); }
+#if INTORDER==1
+ ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D1);
+ ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D1);
+#else // INTORDER==1
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2) , (k/2) , t, WO2D1_1);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2) , (k/2) , t, WO2D1_9);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2) , (k/2) , t, WO2D1_9);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2) , (k/2) , t, WO2D1_1);
+#endif // INTORDER==1
+ IDF_WRITEBACK;
+ return;
+ }
+
+ if((!betx) && ( bety) && (!betz)) {
+ //if((i==4)&&(j==9)&&(D::cDimension==2)) { debugMarkCell(lev,i,j,k); debugMarkCell(lev-1, (i/2), (j/2)-1 , (k/2) ); debugMarkCell(lev-1, (i/2), (j/2) , (k/2) ); debugMarkCell(lev-1, (i/2), (j/2)+1 , (k/2) ); debugMarkCell(lev-1, (i/2), (j/2)+2 , (k/2) ); }
+#if INTORDER==1
+ ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D1);
+ ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D1);
+#else // INTORDER==1
+ ADD_INT_DFS(lev-1, (i/2), (j/2)-1 , (k/2) , t, WO2D1_1);
+ ADD_INT_DFS(lev-1, (i/2), (j/2) , (k/2) , t, WO2D1_9);
+ ADD_INT_DFS(lev-1, (i/2), (j/2)+1 , (k/2) , t, WO2D1_9);
+ ADD_INT_DFS(lev-1, (i/2), (j/2)+2 , (k/2) , t, WO2D1_1);
+#endif // INTORDER==1
+ IDF_WRITEBACK;
+ return;
+ }
+
+ if((!betx) && (!bety) && ( betz)) {
+#if INTORDER==1
+ ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D1);
+ ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D1);
+#else // INTORDER==1
+ ADD_INT_DFS(lev-1, i/2 ,j/2 ,k/2-1, t, WO2D1_1);
+ ADD_INT_DFS(lev-1, i/2 ,j/2 ,k/2 , t, WO2D1_9);
+ ADD_INT_DFS(lev-1, i/2 ,j/2 ,k/2+1, t, WO2D1_9);
+ ADD_INT_DFS(lev-1, i/2 ,j/2 ,k/2+2, t, WO2D1_1);
+#endif // INTORDER==1
+ IDF_WRITEBACK;
+ return;
+ }
+
+ if(( betx) && ( bety) && (!betz)) {
+#if INTORDER==1
+ ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D2);
+ ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D2);
+ ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D2);
+ ADD_INT_DFS(lev-1, (i/2)+1,(j/2)+1,(k/2) , t, WO1D2);
+#else // INTORDER==1
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2)-1 , (k/2) , t, WO2D2_11);
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2) , (k/2) , t, WO2D2_91);
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2)+1 , (k/2) , t, WO2D2_91);
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2)+2 , (k/2) , t, WO2D2_11);
+
+ ADD_INT_DFS(lev-1, (i/2) , (j/2)-1 , (k/2) , t, WO2D2_19);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2) , (k/2) , t, WO2D2_99);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2)+1 , (k/2) , t, WO2D2_99);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2)+2 , (k/2) , t, WO2D2_19);
+
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2)-1 , (k/2) , t, WO2D2_19);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2) , (k/2) , t, WO2D2_99);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2)+1 , (k/2) , t, WO2D2_99);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2)+2 , (k/2) , t, WO2D2_19);
+
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2)-1 , (k/2) , t, WO2D2_11);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2) , (k/2) , t, WO2D2_91);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2)+1 , (k/2) , t, WO2D2_91);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2)+2 , (k/2) , t, WO2D2_11);
+#endif // INTORDER==1
+ IDF_WRITEBACK;
+ return;
+ }
+
+ if((!betx) && ( bety) && ( betz)) {
+#if INTORDER==1
+ ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D2);
+ ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D2);
+ ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D2);
+ ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2)+1, t, WO1D2);
+#else // INTORDER==1
+ ADD_INT_DFS(lev-1, (i/2), (j/2)-1, (k/2)-1, t, WO2D2_11);
+ ADD_INT_DFS(lev-1, (i/2), (j/2)-1, (k/2) , t, WO2D2_91);
+ ADD_INT_DFS(lev-1, (i/2), (j/2)-1, (k/2)+1, t, WO2D2_91);
+ ADD_INT_DFS(lev-1, (i/2), (j/2)-1, (k/2)+2, t, WO2D2_11);
+
+ ADD_INT_DFS(lev-1, (i/2), (j/2) , (k/2)-1, t, WO2D2_19);
+ ADD_INT_DFS(lev-1, (i/2), (j/2) , (k/2) , t, WO2D2_99);
+ ADD_INT_DFS(lev-1, (i/2), (j/2) , (k/2)+1, t, WO2D2_99);
+ ADD_INT_DFS(lev-1, (i/2), (j/2) , (k/2)+2, t, WO2D2_19);
+
+ ADD_INT_DFS(lev-1, (i/2), (j/2)+1, (k/2)-1, t, WO2D2_19);
+ ADD_INT_DFS(lev-1, (i/2), (j/2)+1, (k/2) , t, WO2D2_99);
+ ADD_INT_DFS(lev-1, (i/2), (j/2)+1, (k/2)+1, t, WO2D2_99);
+ ADD_INT_DFS(lev-1, (i/2), (j/2)+1, (k/2)+2, t, WO2D2_19);
+
+ ADD_INT_DFS(lev-1, (i/2), (j/2)+2, (k/2)-1, t, WO2D2_11);
+ ADD_INT_DFS(lev-1, (i/2), (j/2)+2, (k/2) , t, WO2D2_91);
+ ADD_INT_DFS(lev-1, (i/2), (j/2)+2, (k/2)+1, t, WO2D2_91);
+ ADD_INT_DFS(lev-1, (i/2), (j/2)+2, (k/2)+2, t, WO2D2_11);
+#endif // INTORDER==1
+ IDF_WRITEBACK;
+ return;
+ }
+
+ if(( betx) && (!bety) && ( betz)) {
+#if INTORDER==1
+ ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D2);
+ ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D2);
+ ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D2);
+ ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2)+1, t, WO1D2);
+#else // INTORDER==1
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2), (k/2)-1, t, WO2D2_11);
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2), (k/2) , t, WO2D2_91);
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2), (k/2)+1, t, WO2D2_91);
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2), (k/2)+2, t, WO2D2_11);
+
+ ADD_INT_DFS(lev-1, (i/2) , (j/2), (k/2)-1, t, WO2D2_19);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2), (k/2) , t, WO2D2_99);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2), (k/2)+1, t, WO2D2_99);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2), (k/2)+2, t, WO2D2_19);
+
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2), (k/2)-1, t, WO2D2_19);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2), (k/2) , t, WO2D2_99);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2), (k/2)+1, t, WO2D2_99);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2), (k/2)+2, t, WO2D2_19);
+
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2), (k/2)-1, t, WO2D2_11);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2), (k/2) , t, WO2D2_91);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2), (k/2)+1, t, WO2D2_91);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2), (k/2)+2, t, WO2D2_11);
+#endif // INTORDER==1
+ IDF_WRITEBACK;
+ return;
+ }
+
+ if(( betx) && ( bety) && ( betz)) {
+#if INTORDER==1
+ ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D3);
+ ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D3);
+ ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D3);
+ ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2)+1, t, WO1D3);
+ ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D3);
+ ADD_INT_DFS(lev-1, (i/2)+1,(j/2)+1,(k/2) , t, WO1D3);
+ ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2)+1, t, WO1D3);
+ ADD_INT_DFS(lev-1, (i/2)+1,(j/2)+1,(k/2)+1, t, WO1D3);
+#else // INTORDER==1
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2)-1 , (k/2)-1, t, WO2D3_111);
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2) , (k/2)-1, t, WO2D3_911);
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2)+1 , (k/2)-1, t, WO2D3_911);
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2)+2 , (k/2)-1, t, WO2D3_111);
+
+ ADD_INT_DFS(lev-1, (i/2) , (j/2)-1 , (k/2)-1, t, WO2D3_191);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2) , (k/2)-1, t, WO2D3_991);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2)+1 , (k/2)-1, t, WO2D3_991);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2)+2 , (k/2)-1, t, WO2D3_191);
+
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2)-1 , (k/2)-1, t, WO2D3_191);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2) , (k/2)-1, t, WO2D3_991);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2)+1 , (k/2)-1, t, WO2D3_991);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2)+2 , (k/2)-1, t, WO2D3_191);
+
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2)-1 , (k/2)-1, t, WO2D3_111);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2) , (k/2)-1, t, WO2D3_911);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2)+1 , (k/2)-1, t, WO2D3_911);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2)+2 , (k/2)-1, t, WO2D3_111);
+
+
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2)-1 , (k/2) , t, WO2D3_119);
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2) , (k/2) , t, WO2D3_919);
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2)+1 , (k/2) , t, WO2D3_919);
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2)+2 , (k/2) , t, WO2D3_119);
+
+ ADD_INT_DFS(lev-1, (i/2) , (j/2)-1 , (k/2) , t, WO2D3_199);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2) , (k/2) , t, WO2D3_999);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2)+1 , (k/2) , t, WO2D3_999);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2)+2 , (k/2) , t, WO2D3_199);
+
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2)-1 , (k/2) , t, WO2D3_199);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2) , (k/2) , t, WO2D3_999);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2)+1 , (k/2) , t, WO2D3_999);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2)+2 , (k/2) , t, WO2D3_199);
+
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2)-1 , (k/2) , t, WO2D3_119);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2) , (k/2) , t, WO2D3_919);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2)+1 , (k/2) , t, WO2D3_919);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2)+2 , (k/2) , t, WO2D3_119);
+
+
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2)-1 , (k/2)+1, t, WO2D3_119);
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2) , (k/2)+1, t, WO2D3_919);
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2)+1 , (k/2)+1, t, WO2D3_919);
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2)+2 , (k/2)+1, t, WO2D3_119);
+
+ ADD_INT_DFS(lev-1, (i/2) , (j/2)-1 , (k/2)+1, t, WO2D3_199);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2) , (k/2)+1, t, WO2D3_999);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2)+1 , (k/2)+1, t, WO2D3_999);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2)+2 , (k/2)+1, t, WO2D3_199);
+
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2)-1 , (k/2)+1, t, WO2D3_199);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2) , (k/2)+1, t, WO2D3_999);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2)+1 , (k/2)+1, t, WO2D3_999);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2)+2 , (k/2)+1, t, WO2D3_199);
+
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2)-1 , (k/2)+1, t, WO2D3_119);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2) , (k/2)+1, t, WO2D3_919);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2)+1 , (k/2)+1, t, WO2D3_919);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2)+2 , (k/2)+1, t, WO2D3_119);
+
+
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2)-1 , (k/2)+2, t, WO2D3_111);
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2) , (k/2)+2, t, WO2D3_911);
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2)+1 , (k/2)+2, t, WO2D3_911);
+ ADD_INT_DFS(lev-1, (i/2)-1, (j/2)+2 , (k/2)+2, t, WO2D3_111);
+
+ ADD_INT_DFS(lev-1, (i/2) , (j/2)-1 , (k/2)+2, t, WO2D3_191);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2) , (k/2)+2, t, WO2D3_991);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2)+1 , (k/2)+2, t, WO2D3_991);
+ ADD_INT_DFS(lev-1, (i/2) , (j/2)+2 , (k/2)+2, t, WO2D3_191);
+
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2)-1 , (k/2)+2, t, WO2D3_191);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2) , (k/2)+2, t, WO2D3_991);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2)+1 , (k/2)+2, t, WO2D3_991);
+ ADD_INT_DFS(lev-1, (i/2)+1, (j/2)+2 , (k/2)+2, t, WO2D3_191);
+
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2)-1 , (k/2)+2, t, WO2D3_111);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2) , (k/2)+2, t, WO2D3_911);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2)+1 , (k/2)+2, t, WO2D3_911);
+ ADD_INT_DFS(lev-1, (i/2)+2, (j/2)+2 , (k/2)+2, t, WO2D3_111);
+#endif // INTORDER==1
+ IDF_WRITEBACK;
+ return;
+ }
+
+ errMsg("interpolateCellFromCoarse","Invalid!?");
+ exit(1);
+}
+
+template<class D>
+void LbmFsgrSolver<D>::reinitFlags( int workSet )
+{
+ // OLD mods:
+ // add all to intel list?
+ // check ffrac for new cells
+ // new if cell inits (last loop)
+ // vweights handling
+
+#if ELBEEM_BLENDER==1
+ const int debugFlagreinit = 0;
+#else // ELBEEM_BLENDER==1
+ const int debugFlagreinit = 0;
+#endif // ELBEEM_BLENDER==1
+
+ // some things need to be read/modified on the other set
+ int otherSet = (workSet^1);
+ // fixed level on which to perform
+ int workLev = mMaxRefine;
+
+ /* modify interface cells from lists */
+ /* mark filled interface cells as fluid, or emptied as empty */
+ /* count neighbors and distribute excess mass to interface neighbor cells
+ * problems arise when there are no interface neighbors anymore
+ * then just distribute to any fluid neighbors...
+ */
+
+ // for symmetry, first init all neighbor cells */
+ for( vector<LbmPoint>::iterator iter=mListFull.begin();
+ iter != mListFull.end(); iter++ ) {
+ int i=iter->x, j=iter->y, k=iter->z;
+ if(debugFlagreinit) errMsg("FULL", PRINT_IJK<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" rho"<< QCELL(workLev, i,j,k, workSet, 0) ); // DEBUG SYMM
+ FORDF1 {
+ int ni=i+D::dfVecX[l], nj=j+D::dfVecY[l], nk=k+D::dfVecZ[l];
+ if( RFLAG(workLev, ni,nj,nk, workSet) & CFEmpty ){
+ // new and empty interface cell, dont change old flag here!
+ addToNewInterList(ni,nj,nk);
+
+ // preinit speed, get from average surrounding cells
+ // interpolate from non-workset to workset, sets are handled in function
+ {
+ // WARNING - other i,j,k than filling cell!
+ int ei=ni; int ej=nj; int ek=nk;
+ LbmFloat avgrho = 0.0;
+ LbmFloat avgux = 0.0, avguy = 0.0, avguz = 0.0;
+ LbmFloat cellcnt = 0.0;
+ LbmFloat avgnbdf[LBM_DFNUM];
+ FORDF0 { avgnbdf[l]= 0.0; }
+
+ for(int nbl=1; nbl< D::cDfNum ; ++nbl) {
+ if( (RFLAG_NB(workLev,ei,ej,ek,workSet,nbl) & CFFluid) ||
+ ((!(RFLAG_NB(workLev,ei,ej,ek,workSet,nbl) & CFNoInterpolSrc) ) &&
+ (RFLAG_NB(workLev,ei,ej,ek,workSet,nbl) & CFInter) )) {
+ cellcnt += 1.0;
+ for(int rl=0; rl< D::cDfNum ; ++rl) {
+ LbmFloat nbdf = QCELL_NB(workLev,ei,ej,ek, workSet,nbl, rl);
+ avgnbdf[rl] += nbdf;
+ avgux += (D::dfDvecX[rl]*nbdf);
+ avguy += (D::dfDvecY[rl]*nbdf);
+ avguz += (D::dfDvecZ[rl]*nbdf);
+ avgrho += nbdf;
+ }
+ }
+ }
+
+ if(cellcnt<=0.0) {
+ // no nbs? just use eq.
+ //FORDF0 { QCELL(workLev,ei,ej,ek, workSet, l) = D::dfEquil[l]; }
+ avgrho = 1.0;
+ avgux = avguy = avguz = 0.0;
+ //TTT mNumProblems++;
+#if ELBEEM_BLENDER!=1
+ errMsg("NYI2",""); exit(1);
+#endif // ELBEEM_BLENDER
+ } else {
+ // init speed
+ avgux /= cellcnt; avguy /= cellcnt; avguz /= cellcnt;
+ avgrho /= cellcnt;
+ FORDF0 { avgnbdf[l] /= cellcnt; } // CHECK FIXME test?
+ }
+
+ // careful with l's...
+ FORDF0 {
+ QCELL(workLev,ei,ej,ek, workSet, l) = D::getCollideEq( l,avgrho, avgux, avguy, avguz );
+ //QCELL(workLev,ei,ej,ek, workSet, l) = avgnbdf[l]; // CHECK FIXME test?
+ }
+ //errMsg("FNEW", PRINT_VEC(ei,ej,ek)<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" rho"<<avgrho<<" vel"<<PRINT_VEC(avgux,avguy,avguz) ); // DEBUG SYMM
+ QCELL(workLev,ei,ej,ek, workSet, dMass) = 0.0; //?? new
+ QCELL(workLev,ei,ej,ek, workSet, dFfrac) = 0.0; //?? new
+ RFLAG(workLev,ei,ej,ek,workSet) = (CellFlagType)(CFInter|CFNoInterpolSrc);
+ if(debugFlagreinit) errMsg("NEWE", PRINT_IJK<<" newif "<<PRINT_VEC(ei,ej,ek)<<" rho"<<avgrho<<" vel("<<avgux<<","<<avguy<<","<<avguz<<") " );
+ }
+ }
+ /* prevent surrounding interface cells from getting removed as empty cells
+ * (also cells that are not newly inited) */
+ if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) {
+ RFLAG(workLev,ni,nj,nk, workSet) = (CellFlagType)(RFLAG(workLev,ni,nj,nk, workSet) | CFNoDelete);
+ // also add to list...
+ addToNewInterList(ni,nj,nk);
+ } // NEW?
+ }
+
+ // NEW? no extra loop...
+ RFLAG(workLev,i,j,k, workSet) = CFFluid;
+ }
+
+ /* remove empty interface cells that are not allowed to be removed anyway
+ * this is important, otherwise the dreaded cell-type-flickering can occur! */
+ for( vector<LbmPoint>::iterator iter=mListEmpty.begin();
+ iter != mListEmpty.end(); iter++ ) {
+ int i=iter->x, j=iter->y, k=iter->z;
+ if((RFLAG(workLev,i,j,k, workSet)&(CFInter|CFNoDelete)) == (CFInter|CFNoDelete)) {
+ // remove entry
+ if(debugFlagreinit) errMsg("EMPT REMOVED!!!", PRINT_IJK<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" rho"<< QCELL(workLev, i,j,k, workSet, 0) ); // DEBUG SYMM
+ iter = mListEmpty.erase(iter);
+ iter--; // and continue with next...
+
+ // treat as "new inter"
+ addToNewInterList(i,j,k);
+ }
+ }
+
+
+ /* problems arise when adjacent cells empty&fill ->
+ let fill cells+surrounding interface cells have the higher importance */
+ for( vector<LbmPoint>::iterator iter=mListEmpty.begin();
+ iter != mListEmpty.end(); iter++ ) {
+ int i=iter->x, j=iter->y, k=iter->z;
+ if((RFLAG(workLev,i,j,k, workSet)&(CFInter|CFNoDelete)) == (CFInter|CFNoDelete)){ errMsg("A"," ARGHARGRAG "); } // DEBUG
+ if(debugFlagreinit) errMsg("EMPT", PRINT_IJK<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" rho"<< QCELL(workLev, i,j,k, workSet, 0) );
+
+ /* set surrounding fluid cells to interface cells */
+ FORDF1 {
+ int ni=i+D::dfVecX[l], nj=j+D::dfVecY[l], nk=k+D::dfVecZ[l];
+ if( RFLAG(workLev,ni,nj,nk, workSet) & CFFluid){
+ // init fluid->interface
+ RFLAG(workLev,ni,nj,nk, workSet) = (CellFlagType)(CFInter);
+ /* new mass = current density */
+ LbmFloat nbrho = QCELL(workLev,ni,nj,nk, workSet, dC);
+ for(int rl=1; rl< D::cDfNum ; ++rl) { nbrho += QCELL(workLev,ni,nj,nk, workSet, rl); }
+ QCELL(workLev,ni,nj,nk, workSet, dMass) = nbrho;
+ QCELL(workLev,ni,nj,nk, workSet, dFfrac) = 1.0;
+
+ // store point
+ addToNewInterList(ni,nj,nk);
+ }
+ if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter){
+ // test, also add to list...
+ addToNewInterList(ni,nj,nk);
+ } // NEW?
+ }
+
+ /* for symmetry, set our flag right now */
+ RFLAG(workLev,i,j,k, workSet) = CFEmpty;
+ // mark cell not be changed mass... - not necessary, not in list anymore anyway!
+ } // emptylist
+
+
+
+ /* precompute weights! */
+ //vector<LbmFloat[dTotalNum]> vWeights;
+ vector<lbmFloatSet> vWeights;
+ vWeights.reserve( mListFull.size() + mListEmpty.size() );
+ int weightIndex = 0;
+ int nbCount = 0;
+ LbmFloat nbWeights[LBM_DFNUM];
+ LbmFloat nbTotWeights = 0.0;
+ for( vector<LbmPoint>::iterator iter=mListFull.begin();
+ iter != mListFull.end(); iter++ ) {
+ int i=iter->x, j=iter->y, k=iter->z;
+ //int nbCount = 0;
+ //LbmFloat nbWeights[LBM_DFNUM];
+ //LbmFloat nbTotWeights = 0.0;
+ nbCount = 0; nbTotWeights = 0.0;
+ FORDF1 {
+ int ni=i+D::dfVecX[l], nj=j+D::dfVecY[l], nk=k+D::dfVecZ[l];
+ if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) {
+ nbCount++;
+ nbWeights[l] = getMassdWeight(1,i,j,k,workSet,l);
+ nbTotWeights += nbWeights[l];
+ } else {
+ nbWeights[l] = -100.0; // DEBUG;
+ }
+ }
+ if(nbCount>0) {
+ //errMsg("FF I", PRINT_IJK<<" "<<weightIndex<<" "<<nbTotWeights);
+ vWeights[weightIndex].val[0] = nbTotWeights;
+ FORDF1 { vWeights[weightIndex].val[l] = nbWeights[l]; }
+ weightIndex++;
+ } else { }
+ }
+ for( vector<LbmPoint>::iterator iter=mListEmpty.begin();
+ iter != mListEmpty.end(); iter++ ) {
+ int i=iter->x, j=iter->y, k=iter->z;
+ nbCount = 0; nbTotWeights = 0.0;
+ FORDF1 {
+ int ni=i+D::dfVecX[l], nj=j+D::dfVecY[l], nk=k+D::dfVecZ[l];
+ if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) {
+ nbCount++;
+ nbWeights[l] = getMassdWeight(0,i,j,k,workSet,l);
+ nbTotWeights += nbWeights[l];
+ } else {
+ nbWeights[l] = -100.0; // DEBUG;
+ }
+ }
+ if(nbCount>0) {
+ //errMsg("EE I", PRINT_IJK<<" "<<weightIndex<<" "<<nbTotWeights);
+ vWeights[weightIndex].val[0] = nbTotWeights;
+ FORDF1 { vWeights[weightIndex].val[l] = nbWeights[l]; }
+ weightIndex++;
+ } else { }
+ }
+ weightIndex = 0;
+
+
+ /* process full list entries, filled cells are done after this loop */
+ for( vector<LbmPoint>::iterator iter=mListFull.begin();
+ iter != mListFull.end(); iter++ ) {
+ int i=iter->x, j=iter->y, k=iter->z;
+
+ LbmFloat myrho = QCELL(workLev,i,j,k, workSet, dC);
+ FORDF1 { myrho += QCELL(workLev,i,j,k, workSet, l); } // QCELL.rho
+
+ LbmFloat massChange = QCELL(workLev,i,j,k, workSet, dMass) - myrho;
+ int nbCount = 0;
+ LbmFloat nbWeights[LBM_DFNUM];
+ LbmFloat nbTotWeights = 0.0;
+ FORDF1 {
+ int ni=i+D::dfVecX[l], nj=j+D::dfVecY[l], nk=k+D::dfVecZ[l];
+ if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) {
+ nbCount++;
+ nbWeights[l] = vWeights[weightIndex].val[l];
+ //nbWeights[l] = getMassdWeight(1,i,j,k,workSet,l);
+ //nbTotWeights += nbWeights[l];
+ } else {
+ //nbWeights[l] = -100.0; // DEBUG;
+ }
+ }
+
+ //errMsg("FDIST", PRINT_IJK<<" mss"<<massChange <<" nb"<< nbCount ); // DEBUG SYMM
+ if(nbCount>0) {
+ nbTotWeights = vWeights[weightIndex].val[0];
+ //errMsg("FF I", PRINT_IJK<<" "<<weightIndex<<" "<<nbTotWeights);
+ //if(vWeights[weightIndex].val[0] != nbTotWeights) { errMsg("WD","WD"<<vWeights[weightIndex].val[0]<<" "<<nbTotWeights); }
+ FORDF1 {
+ int ni=i+D::dfVecX[l], nj=j+D::dfVecY[l], nk=k+D::dfVecZ[l];
+ if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) {
+ LbmFloat change = -1.0;
+ if(nbTotWeights>0.0) {
+ //if(nbWeights[l] != vWeights[weightIndex].val[l]) { errMsg("WD","WD"<<nbWeights[l]<<" "<<vWeights[weightIndex].val[l]); } // DEBUG
+ change = massChange * ( nbWeights[l]/nbTotWeights );
+ } else {
+ change = (LbmFloat)(massChange/(LbmFloat)nbCount);
+ }
+ QCELL(workLev,ni,nj,nk, workSet, dMass) += change;
+ }
+ }
+ massChange = 0.0;
+ weightIndex++;
+ } else {
+ // Problem! no interface neighbors
+ D::mFixMass += massChange;
+ //TTT mNumProblems++;
+ //errMsg(" FULL PROBLEM ", PRINT_IJK<<" "<<D::mFixMass);
+ }
+
+ // already done? RFLAG(workLev,i,j,k, workSet) = CFFluid;
+ QCELL(workLev,i,j,k, workSet, dMass) = myrho; // should be rho... but unused?
+ QCELL(workLev,i,j,k, workSet, dFfrac) = 1.0; // should be rho... but unused?
+ /*QCELL(workLev,i,j,k, otherSet, dMass) = myrho; // NEW?
+ QCELL(workLev,i,j,k, otherSet, dFfrac) = 1.0; // NEW? COMPRT */
+ } // fulllist
+
+
+ /* now, finally handle the empty cells - order is important, has to be after
+ * full cell handling */
+ for( vector<LbmPoint>::iterator iter=mListEmpty.begin();
+ iter != mListEmpty.end(); iter++ ) {
+ int i=iter->x, j=iter->y, k=iter->z;
+
+ LbmFloat massChange = QCELL(workLev, i,j,k, workSet, dMass);
+ int nbCount = 0;
+ LbmFloat nbWeights[LBM_DFNUM];
+ LbmFloat nbTotWeights = 0.0;
+ FORDF1 {
+ int ni=i+D::dfVecX[l], nj=j+D::dfVecY[l], nk=k+D::dfVecZ[l];
+ if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) {
+ nbCount++;
+ nbWeights[l] = vWeights[weightIndex].val[l];
+ //nbWeights[l] = getMassdWeight(0,i,j,k,workSet,l);
+ //nbTotWeights += nbWeights[l];
+ } else {
+ nbWeights[l] = -100.0; // DEBUG;
+ }
+ }
+
+ //errMsg("EDIST", PRINT_IJK<<" mss"<<massChange <<" nb"<< nbCount ); // DEBUG SYMM
+ if(nbCount>0) {
+ nbTotWeights = vWeights[weightIndex].val[0];
+ //errMsg("EE I", PRINT_IJK<<" "<<weightIndex<<" "<<nbTotWeights);
+ //if(vWeights[weightIndex].val[0] != nbTotWeights) { errMsg("WD","WD"<<vWeights[weightIndex].val[0]<<" "<<nbTotWeights); }
+ FORDF1 {
+ int ni=i+D::dfVecX[l], nj=j+D::dfVecY[l], nk=k+D::dfVecZ[l];
+ if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) {
+ LbmFloat change = -1.0;
+ if(nbTotWeights>0.0) {
+ //if(nbWeights[l] != vWeights[weightIndex].val[l]) { errMsg("WD","WD"<<nbWeights[l]<<" "<<vWeights[weightIndex].val[l]); } // DEBUG
+ change = massChange * ( nbWeights[l]/nbTotWeights );
+ } else {
+ change = (LbmFloat)(massChange/(LbmFloat)nbCount);
+ }
+ QCELL(workLev, ni,nj,nk, workSet, dMass) += change;
+ }
+ }
+ massChange = 0.0;
+ weightIndex++;
+ } else {
+ // Problem! no interface neighbors
+ D::mFixMass += massChange;
+ //TTT mNumProblems++;
+ //errMsg(" EMPT PROBLEM ", PRINT_IJK<<" "<<D::mFixMass);
+ }
+
+ // finally... make it empty
+ // already done? RFLAG(workLev,i,j,k, workSet) = CFEmpty;
+ QCELL(workLev,i,j,k, workSet, dMass) = 0.0;
+ QCELL(workLev,i,j,k, workSet, dFfrac) = 0.0;
+ }
+ for( vector<LbmPoint>::iterator iter=mListEmpty.begin();
+ iter != mListEmpty.end(); iter++ ) {
+ int i=iter->x, j=iter->y, k=iter->z;
+ RFLAG(workLev,i,j,k, otherSet) = CFEmpty;
+ /*QCELL(workLev,i,j,k, otherSet, dMass) = 0.0;
+ QCELL(workLev,i,j,k, otherSet, dFfrac) = 0.0; // COMPRT OFF */
+ }
+
+
+ // check if some of the new interface cells can be removed again
+ // never happens !!! not necessary
+ // calculate ffrac for new IF cells NEW
+
+ // how many are really new interface cells?
+ int numNewIf = 0;
+ for( vector<LbmPoint>::iterator iter=mListNewInter.begin();
+ iter != mListNewInter.end(); iter++ ) {
+ int i=iter->x, j=iter->y, k=iter->z;
+ if(!(RFLAG(workLev,i,j,k, workSet)&CFInter)) {
+ continue;
+ // FIXME remove from list?
+ }
+ numNewIf++;
+ }
+
+ // redistribute mass, reinit flags
+ float newIfFac = 1.0/(LbmFloat)numNewIf;
+ for( vector<LbmPoint>::iterator iter=mListNewInter.begin();
+ iter != mListNewInter.end(); iter++ ) {
+ int i=iter->x, j=iter->y, k=iter->z;
+ if(!(RFLAG(workLev,i,j,k, workSet)&CFInter)) {
+ //errMsg("???"," "<<PRINT_IJK);
+ continue;
+ }
+
+ QCELL(workLev,i,j,k, workSet, dMass) += (D::mFixMass * newIfFac);
+
+ int nbored = 0;
+ FORDF1 { nbored |= RFLAG_NB(workLev, i,j,k, workSet,l); }
+ if((nbored & CFFluid)==0) { RFLAG(workLev,i,j,k, workSet) |= CFNoNbFluid; }
+ if((nbored & CFEmpty)==0) { RFLAG(workLev,i,j,k, workSet) |= CFNoNbEmpty; }
+
+ if(!(RFLAG(workLev,i,j,k, otherSet)&CFInter)) {
+ RFLAG(workLev,i,j,k, workSet) = (CellFlagType)(RFLAG(workLev,i,j,k, workSet) | CFNoDelete);
+ }
+ if(debugFlagreinit) errMsg("NEWIF", PRINT_IJK<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" f"<< RFLAG(workLev,i,j,k, workSet)<<" wl"<<workLev );
+ }
+
+ // reinit fill fraction
+ for( vector<LbmPoint>::iterator iter=mListNewInter.begin();
+ iter != mListNewInter.end(); iter++ ) {
+ int i=iter->x, j=iter->y, k=iter->z;
+ if(!(RFLAG(workLev,i,j,k, workSet)&CFInter)) { continue; }
+
+ LbmFloat nrho = 0.0;
+ FORDF0 { nrho += QCELL(workLev, i,j,k, workSet, l); }
+ QCELL(workLev,i,j,k, workSet, dFfrac) = QCELL(workLev,i,j,k, workSet, dMass)/nrho;
+ QCELL(workLev,i,j,k, workSet, dFlux) = FLUX_INIT;
+ }
+
+ if(mListNewInter.size()>0){
+ //errMsg("FixMassDisted"," fm:"<<D::mFixMass<<" nif:"<<mListNewInter.size() );
+ D::mFixMass = 0.0;
+ }
+
+ // empty lists for next step
+ mListFull.clear();
+ mListEmpty.clear();
+ mListNewInter.clear();
+} // reinitFlags
+
+
+
+//! for raytracing
+template<class D>
+void LbmFsgrSolver<D>::prepareVisualization( void ) {
+ int lev = mMaxRefine;
+ int workSet = mLevel[lev].setCurr;
+
+ //make same prepareVisualization and getIsoSurface...
+#if LBMDIM==2
+ // 2d, place in the middle of isofield slice (k=2)
+# define ZKD1 0
+ // 2d z offset = 2, lbmGetData adds 1, so use one here
+# define ZKOFF 1
+ // reset all values...
+ for(int k= 0; k< 5; ++k)
+ for(int j=0;j<mLevel[lev].lSizey-0;j++)
+ for(int i=0;i<mLevel[lev].lSizex-0;i++) {
+ *D::mpIso->lbmGetData(i,j,ZKOFF)=0.0;
+ }
+#else // LBMDIM==2
+ // 3d, use normal bounds
+# define ZKD1 1
+# define ZKOFF k
+ // reset all values...
+ for(int k= getForZMinBnd(lev); k< getForZMaxBnd(lev); ++k)
+ for(int j=0;j<mLevel[lev].lSizey-0;j++)
+ for(int i=0;i<mLevel[lev].lSizex-0;i++) {
+ *D::mpIso->lbmGetData(i,j,ZKOFF)=0.0;
+ }
+#endif // LBMDIM==2
+
+
+
+ // add up...
+ float val = 0.0;
+ for(int k= getForZMin1(lev); k< getForZMax1(lev); ++k)
+ for(int j=1;j<mLevel[lev].lSizey-1;j++)
+ for(int i=1;i<mLevel[lev].lSizex-1;i++) {
+
+ //continue; // OFF DEBUG
+ if(RFLAG(lev, i,j,k,workSet)&(CFBnd|CFEmpty)) {
+ continue;
+ } else
+ if( (RFLAG(lev, i,j,k,workSet)&CFInter) && (!(RFLAG(lev, i,j,k,workSet)&CFNoNbEmpty)) ){
+ // no empty nb interface cells are treated as full
+ val = (QCELL(lev, i,j,k,workSet, dFfrac));
+ } else {
+ // fluid?
+ val = 1.0; ///27.0;
+ } // */
+
+ *D::mpIso->lbmGetData( i-1 , j-1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[0] );
+ *D::mpIso->lbmGetData( i , j-1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[1] );
+ *D::mpIso->lbmGetData( i+1 , j-1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[2] );
+
+ *D::mpIso->lbmGetData( i-1 , j ,ZKOFF-ZKD1) += ( val * mIsoWeight[3] );
+ *D::mpIso->lbmGetData( i , j ,ZKOFF-ZKD1) += ( val * mIsoWeight[4] );
+ *D::mpIso->lbmGetData( i+1 , j ,ZKOFF-ZKD1) += ( val * mIsoWeight[5] );
+
+ *D::mpIso->lbmGetData( i-1 , j+1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[6] );
+ *D::mpIso->lbmGetData( i , j+1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[7] );
+ *D::mpIso->lbmGetData( i+1 , j+1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[8] );
+
+
+ *D::mpIso->lbmGetData( i-1 , j-1 ,ZKOFF ) += ( val * mIsoWeight[9] );
+ *D::mpIso->lbmGetData( i , j-1 ,ZKOFF ) += ( val * mIsoWeight[10] );
+ *D::mpIso->lbmGetData( i+1 , j-1 ,ZKOFF ) += ( val * mIsoWeight[11] );
+
+ *D::mpIso->lbmGetData( i-1 , j ,ZKOFF ) += ( val * mIsoWeight[12] );
+ *D::mpIso->lbmGetData( i , j ,ZKOFF ) += ( val * mIsoWeight[13] );
+ *D::mpIso->lbmGetData( i+1 , j ,ZKOFF ) += ( val * mIsoWeight[14] );
+
+ *D::mpIso->lbmGetData( i-1 , j+1 ,ZKOFF ) += ( val * mIsoWeight[15] );
+ *D::mpIso->lbmGetData( i , j+1 ,ZKOFF ) += ( val * mIsoWeight[16] );
+ *D::mpIso->lbmGetData( i+1 , j+1 ,ZKOFF ) += ( val * mIsoWeight[17] );
+
+
+ *D::mpIso->lbmGetData( i-1 , j-1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[18] );
+ *D::mpIso->lbmGetData( i , j-1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[19] );
+ *D::mpIso->lbmGetData( i+1 , j-1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[20] );
+
+ *D::mpIso->lbmGetData( i-1 , j ,ZKOFF+ZKD1) += ( val * mIsoWeight[21] );
+ *D::mpIso->lbmGetData( i , j ,ZKOFF+ZKD1)+= ( val * mIsoWeight[22] );
+ *D::mpIso->lbmGetData( i+1 , j ,ZKOFF+ZKD1) += ( val * mIsoWeight[23] );
+
+ *D::mpIso->lbmGetData( i-1 , j+1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[24] );
+ *D::mpIso->lbmGetData( i , j+1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[25] );
+ *D::mpIso->lbmGetData( i+1 , j+1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[26] );
+ }
+
+ // update preview, remove 2d?
+ if(mOutputSurfacePreview) {
+ //int previewSize = mOutputSurfacePreview;
+ int pvsx = (int)(mPreviewFactor*D::mSizex);
+ int pvsy = (int)(mPreviewFactor*D::mSizey);
+ int pvsz = (int)(mPreviewFactor*D::mSizez);
+ //float scale = (float)D::mSizex / previewSize;
+ LbmFloat scalex = (LbmFloat)D::mSizex/(LbmFloat)pvsx;
+ LbmFloat scaley = (LbmFloat)D::mSizey/(LbmFloat)pvsy;
+ LbmFloat scalez = (LbmFloat)D::mSizez/(LbmFloat)pvsz;
+ for(int k= 0; k< ((D::cDimension==3) ? (pvsz-1):1) ; ++k)
+ for(int j=0;j< pvsy;j++)
+ for(int i=0;i< pvsx;i++) {
+ *mpPreviewSurface->lbmGetData(i,j,k) = *D::mpIso->lbmGetData( (int)(i*scalex), (int)(j*scaley), (int)(k*scalez) );
+ }
+ // set borders again...
+ for(int k= 0; k< ((D::cDimension == 3) ? (pvsz-1):1) ; ++k) {
+ for(int j=0;j< pvsy;j++) {
+ *mpPreviewSurface->lbmGetData(0,j,k) = *D::mpIso->lbmGetData( 0, (int)(j*scaley), (int)(k*scalez) );
+ *mpPreviewSurface->lbmGetData(pvsx-1,j,k) = *D::mpIso->lbmGetData( D::mSizex-1, (int)(j*scaley), (int)(k*scalez) );
+ }
+ for(int i=0;i< pvsx;i++) {
+ *mpPreviewSurface->lbmGetData(i,0,k) = *D::mpIso->lbmGetData( (int)(i*scalex), 0, (int)(k*scalez) );
+ *mpPreviewSurface->lbmGetData(i,pvsy-1,k) = *D::mpIso->lbmGetData( (int)(i*scalex), D::mSizey-1, (int)(k*scalez) );
+ }
+ }
+ if(D::cDimension == 3) {
+ // only for 3D
+ for(int j=0;j<pvsy;j++)
+ for(int i=0;i<pvsx;i++) {
+ *mpPreviewSurface->lbmGetData(i,j,0) = *D::mpIso->lbmGetData( (int)(i*scalex), (int)(j*scaley) , 0);
+ *mpPreviewSurface->lbmGetData(i,j,pvsz-1) = *D::mpIso->lbmGetData( (int)(i*scalex), (int)(j*scaley) , D::mSizez-1);
+ }
+ } // borders done...
+ }
+
+ // correction
+ return;
+}
+
+
+/*****************************************************************************
+ * demo functions
+ *****************************************************************************/
+
+template<class D>
+void LbmFsgrSolver<D>::getIsofieldWeighted(float *iso) {
+ //errMsg("XxxX", " "<<( szx+ISOCORR) );
+ float val;
+ int szx = mLevel[mMaxRefine].lSizex;
+ int szy = mLevel[mMaxRefine].lSizey;
+ int szz = mLevel[mMaxRefine].lSizez;
+ int oz = (szx+ISOCORR)*(szy+ISOCORR);
+ int oy = (szx+ISOCORR);
+ //int wcnt = 0;
+
+ // reset all values...
+ const LbmFloat initVal = -0.42;
+ for(int i=0;i<(szz+ISOCORR)*(szy+ISOCORR)*(szx+ISOCORR);i++) {
+ iso[i] = initVal;
+ }
+
+ // add up...
+ FSGR_FORIJK1(mMaxRefine) {
+ if(RFLAG(mMaxRefine, i,j,k,mLevel[mMaxRefine].setOther)&CFFluid) {
+ val = 1.0; ///27.0;
+ } else
+ //if(RFLAG(mMaxRefine, i,j,k,mLevel[mMaxRefine].setOther)&CFBnd) {
+ //continue;
+ //val = initVal + 0.05;
+ //val = (initVal + 0.05) * -1.0;
+ //} else
+ if(RFLAG(mMaxRefine, i,j,k,mLevel[mMaxRefine].setOther)&CFInter) {
+ val = (QCELL(mMaxRefine, i,j,k,mLevel[mMaxRefine].setOther, dFfrac)); // (1.0/27.0);
+ } else {
+ // bnd, empty, etc...
+ continue;
+ }
+
+ /*
+ // */
+
+ const int index =((k)+1)*oz + ((j)+1)*oy + (i)+1;
+ iso[ index -oz -oy -1 ] += ( val * mIsoWeight[0] );
+ iso[ index -oz -oy ] += ( val * mIsoWeight[1] );
+ iso[ index -oz -oy +1 ] += ( val * mIsoWeight[2] );
+
+ iso[ index -oz -1 ] += ( val * mIsoWeight[3] );
+ iso[ index -oz ] += ( val * mIsoWeight[4] );
+ iso[ index -oz +1 ] += ( val * mIsoWeight[5] );
+
+ iso[ index -oz +oy -1 ] += ( val * mIsoWeight[6] );
+ iso[ index -oz +oy ] += ( val * mIsoWeight[7] );
+ iso[ index -oz +oy +1 ] += ( val * mIsoWeight[8] );
+
+
+ iso[ index -oy -1 ] += ( val * mIsoWeight[9] );
+ iso[ index -oy ] += ( val * mIsoWeight[10] );
+ iso[ index -oy +1 ] += ( val * mIsoWeight[11] );
+
+ iso[ index -1 ] += ( val * mIsoWeight[12] );
+ iso[ index ] += ( val * mIsoWeight[13] );
+ iso[ index +1 ] += ( val * mIsoWeight[14] );
+
+ iso[ index +oy -1 ] += ( val * mIsoWeight[15] );
+ iso[ index +oy ] += ( val * mIsoWeight[16] );
+ iso[ index +oy +1 ] += ( val * mIsoWeight[17] );
+
+
+ iso[ index +oz -oy -1 ] += ( val * mIsoWeight[18] );
+ iso[ index +oz -oy ] += ( val * mIsoWeight[19] );
+ iso[ index +oz -oy +1 ] += ( val * mIsoWeight[20] );
+
+ iso[ index +oz -1 ] += ( val * mIsoWeight[21] );
+ iso[ index +oz ] += ( val * mIsoWeight[22] );
+ iso[ index +oz +1 ] += ( val * mIsoWeight[23] );
+
+ iso[ index +oz +oy -1 ] += ( val * mIsoWeight[24] );
+ iso[ index +oz +oy ] += ( val * mIsoWeight[25] );
+ iso[ index +oz +oy +1 ] += ( val * mIsoWeight[26] );
+ }
+
+ return;
+}
+
+template<class D>
+void LbmFsgrSolver<D>::addDrop(bool active, float mx, float my) {
+ mDropping = active;
+ mDropX = mx;
+ mDropY = my;
+}
+
+template<class D>
+void LbmFsgrSolver<D>::initDrop(float mx, float my) {
+ // invert for convenience
+ mx = 1.0-mx;
+ int workSet = mLevel[mMaxRefine].setCurr;
+
+ int px = (int)(mLevel[mMaxRefine].lSizex * mx);
+ int py = (int)(mLevel[mMaxRefine].lSizey * mDropHeight);
+ int pz = (int)(mLevel[mMaxRefine].lSizez * my);
+ int rad = (int)(mDropSize*mLevel[mMaxRefine].lSizex) + 1;
+ //errMsg("Rad", " "<<rad);
+
+ // check bounds
+ const int offset = 1;
+ const float forceFill = 1.0;
+ if( (px-rad)<=offset ) px = rad + offset;
+ if( (px+rad)>=mLevel[mMaxRefine].lSizex-1 ) px = mLevel[mMaxRefine].lSizex-offset-rad-1;
+ if( (py-rad)<=offset ) py = rad + offset;
+ if( (py+rad)>=mLevel[mMaxRefine].lSizey-1 ) py = mLevel[mMaxRefine].lSizey-offset-rad-1;
+ if( (pz-rad)<=offset ) pz = rad + offset;
+ if( (pz+rad)>=mLevel[mMaxRefine].lSizez-1 ) pz = mLevel[mMaxRefine].lSizez-offset-rad-1;
+
+ mUpdateFVHeight=true;
+ //errMsg("T", " \n\n\n"<<D::mStepCnt<<" \n\n\n");
+ if(mDropMode==-1) { return; }
+
+ if(mDropMode==0) {
+ // inflow
+ if((py-4)<=offset) py = 4+offset;
+ //errMsg(" ", " py"<<py<<" "<<mDropHeight );
+ for(int k= pz-rad; k<= pz+rad; k++) {
+ for(int j= py-1; j<= py+1; j++) {
+ for(int i= px-rad; i<= px+rad; i++) {
+ float dz = pz-k;
+ //float dy = py-j;
+ float dx = px-i;
+ if( (dx*dx+dz*dz) > (float)(rad*rad) ) continue;
+ LbmFloat fill = forceFill; //rad - sqrt(dx*dx+dz*dz);
+
+ if(RFLAG(mMaxRefine, i,j,k,workSet)&(CFFluid)) {
+ } else if(RFLAG(mMaxRefine, i,j,k,workSet)&(CFInter)) {
+ if(QCELL(mMaxRefine, i,j,k,workSet, dMass) < 0.75) {
+ initVelocityCell(mMaxRefine, i,j,k, CFInter, 1.0, fill, mDropSpeed);
+ }
+ } else if(RFLAG(mMaxRefine, i,j,k,workSet)&(CFEmpty)) {
+ initVelocityCell(mMaxRefine, i,j,k, CFInter, 1.0, fill, mDropSpeed);
+ } else {
+ }
+
+ }
+ }
+ }
+
+ // stream - continue dropping
+ return;
+
+ } else
+ if( (mDropMode==1) || (mDropMode==2) ) {
+ mDropping = false;
+
+ // mode 2 - only single drops
+ if(mDropMode==2) {
+ for(int k= pz-rad-offset; k<= pz+rad+offset; k++)
+ for(int j= py-rad-offset; j<= py+rad+offset; j++)
+ for(int i= px-rad-offset; i<= px+rad+offset; i++) {
+ // make sure no fluid cells near...
+ if(RFLAG(mMaxRefine, i,j,k,workSet)&(CFBnd)) continue;
+ if(RFLAG(mMaxRefine, i,j,k,workSet)&(CFEmpty)) continue;
+ if(RFLAG(mMaxRefine, i,j,k,workSet)&(CFInter)) continue;
+ return;
+ }
+ }
+
+ // single drops
+ for(int k= pz-rad-offset; k<= pz+rad+offset; k++)
+ for(int j= py-rad-offset; j<= py+rad+offset; j++)
+ for(int i= px-rad-offset; i<= px+rad+offset; i++) {
+ if(RFLAG(mMaxRefine, i,j,k,workSet)&(CFBnd)) continue;
+ float dz = pz-k;
+ float dy = py-j;
+ float dx = px-i;
+ if( dx*dx+dy*dy+dz*dz > (float)(rad*rad) ) {
+ if(mDropMode==1) {
+ // overwrite everything...
+ initEmptyCell(mMaxRefine, i,j,k, CFEmpty, 0.0, 0.0);
+ }
+ continue;
+ }
+ LbmFloat fill = rad - sqrt(dx*dx+dy*dy+dz*dz);
+ if(fill > 1.0) fill = 1.0;
+
+ initEmptyCell(mMaxRefine, i,j,k, CFFluid, 1.0, fill);
+ }
+
+ for(int k= pz-rad-offset-1; k<= pz+rad+offset+1; k++)
+ for(int j= py-rad-offset-1; j<= py+rad+offset+1; j++)
+ for(int i= px-rad-offset-1; i<= px+rad+offset+1; i++) {
+ if(i<1) continue;
+ if(i>=(mLevel[mMaxRefine].lSizex-2) ) continue;
+ if(j<1) continue;
+ if(j>=(mLevel[mMaxRefine].lSizey-2) ) continue;
+ if(k<1) continue;
+ if(k>=(mLevel[mMaxRefine].lSizez-2) ) continue;
+ if(RFLAG(mMaxRefine, i,j,k,workSet)&(CFBnd)) continue;
+
+ if( (RFLAG(mMaxRefine, i,j,k,workSet )&(CFFluid)) ) {
+ bool emptyNb = false;
+ FORDF1 {
+ int ni=i+D::dfVecX[l], nj=j+D::dfVecY[l], nk=k+D::dfVecZ[l];
+ if(RFLAG(mMaxRefine, ni,nj,nk, workSet) & CFEmpty ){
+ emptyNb = true;
+ }
+ }
+ if(emptyNb) {
+ RFLAG(mMaxRefine, i,j,k,workSet ) = CFInter;
+ }
+ }
+ }
+ } // single drop
+}
+
+ //! avg. used cell count stats
+template<class D>
+void LbmFsgrSolver<D>::printCellStats() {
+ debMsgStd("CellStats", DM_NOTIFY, "Min:"<<mMinNoCells<<" Max:"<<mMaxNoCells<<
+ " Avg:"<< (int)(mAvgNumUsedCells/(long long int)D::mStepCnt) , 1);
+}
+template<class D>
+int LbmFsgrSolver<D>::checkGfxEndTime() {
+ //errMsg("LbmFsgrSolver","GfxEndTime "<<mGfxEndTime<<" "<<mSimulationTime<<" steps:"<<D::mStepCnt);
+ //errMsg(" "," e"<<mGfxEndTime<<" s"<<mSimulationTime);
+ if((mGfxEndTime>0.0) && (mSimulationTime>mGfxEndTime)) {
+ errMsg("LbmFsgrSolver","GfxEndTime "<<mSimulationTime<<" steps:"<<D::mStepCnt);
+ return true;
+ //printCellStats();
+ //exit(1);
+ }
+ return false;
+}
+
+
+
+
+/*****************************************************************************
+ * move the particles
+ * uses updated velocities from mSetOther
+ *****************************************************************************/
+template<class D>
+void LbmFsgrSolver<D>::advanceParticles(ParticleTracer *partt ) {
+ partt = NULL; // remove warning
+}
+
+
+/******************************************************************************
+ * reset particle positions to default
+ *****************************************************************************/
+/*! init particle positions */
+template<class D>
+int LbmFsgrSolver<D>::initParticles(ParticleTracer *partt) {
+ partt = NULL; // remove warning
+ return 0;
+}
+
+
+/*****************************************************************************/
+/*! internal quick print function (for debugging) */
+/*****************************************************************************/
+template<class D>
+void
+LbmFsgrSolver<D>::printLbmCell(int level, int i, int j, int k, int set) {
+ stdCellId *newcid = new stdCellId;
+ newcid->level = level;
+ newcid->x = i;
+ newcid->y = j;
+ newcid->z = k;
+
+ // this function is not called upon clicking, then its from setMouseClick
+ ::debugPrintNodeInfo< LbmFsgrSolver<D> >( this, newcid, D::mNodeInfoString, set );
+
+ delete newcid;
+}
+template<class D>
+void
+LbmFsgrSolver<D>::debugMarkCellCall(int level, int vi,int vj,int vk) {
+ stdCellId *newcid = new stdCellId;
+ newcid->level = level;
+ newcid->x = vi;
+ newcid->y = vj;
+ newcid->z = vk;
+ addCellToMarkedList( newcid );
+}
+
+
+/*****************************************************************************/
+// implement CellIterator<UniformFsgrCellIdentifier> interface
+/*****************************************************************************/
+
+
+
+// values from guiflkt.cpp
+extern double guiRoiSX, guiRoiSY, guiRoiSZ, guiRoiEX, guiRoiEY, guiRoiEZ;
+extern int guiRoiMaxLev, guiRoiMinLev;
+#define CID_SX (int)( (mLevel[cid->level].lSizex-1) * guiRoiSX )
+#define CID_SY (int)( (mLevel[cid->level].lSizey-1) * guiRoiSY )
+#define CID_SZ (int)( (mLevel[cid->level].lSizez-1) * guiRoiSZ )
+
+#define CID_EX (int)( (mLevel[cid->level].lSizex-1) * guiRoiEX )
+#define CID_EY (int)( (mLevel[cid->level].lSizey-1) * guiRoiEY )
+#define CID_EZ (int)( (mLevel[cid->level].lSizez-1) * guiRoiEZ )
+
+template<class D>
+CellIdentifierInterface*
+LbmFsgrSolver<D>::getFirstCell( ) {
+ int level = mMaxRefine;
+
+#if LBMDIM==3
+ if(mMaxRefine>0) { level = mMaxRefine-1; } // NO1HIGHESTLEV DEBUG
+#endif
+ level = guiRoiMaxLev;
+ if(level>mMaxRefine) level = mMaxRefine;
+
+ //errMsg("LbmFsgrSolver::getFirstCell","Celliteration started...");
+ stdCellId *cid = new stdCellId;
+ cid->level = level;
+ cid->x = CID_SX;
+ cid->y = CID_SY;
+ cid->z = CID_SZ;
+ return cid;
+}
+
+template<class D>
+typename LbmFsgrSolver<D>::stdCellId*
+LbmFsgrSolver<D>::convertBaseCidToStdCid( CellIdentifierInterface* basecid) {
+ //stdCellId *cid = dynamic_cast<stdCellId*>( basecid );
+ stdCellId *cid = (stdCellId*)( basecid );
+ return cid;
+}
+
+template<class D>
+void
+LbmFsgrSolver<D>::advanceCell( CellIdentifierInterface* basecid) {
+ stdCellId *cid = convertBaseCidToStdCid(basecid);
+ if(cid->getEnd()) return;
+
+ //debugOut(" ADb "<<cid->x<<","<<cid->y<<","<<cid->z<<" e"<<cid->getEnd(), 10);
+ cid->x++;
+ if(cid->x > CID_EX){ cid->x = CID_SX; cid->y++;
+ if(cid->y > CID_EY){ cid->y = CID_SY; cid->z++;
+ if(cid->z > CID_EZ){
+ cid->level--;
+ cid->x = CID_SX;
+ cid->y = CID_SY;
+ cid->z = CID_SZ;
+ if(cid->level < guiRoiMinLev) {
+ cid->level = guiRoiMaxLev;
+ cid->setEnd( true );
+ }
+ }
+ }
+ }
+ //debugOut(" ADa "<<cid->x<<","<<cid->y<<","<<cid->z<<" e"<<cid->getEnd(), 10);
+}
+
+template<class D>
+bool
+LbmFsgrSolver<D>::noEndCell( CellIdentifierInterface* basecid) {
+ stdCellId *cid = convertBaseCidToStdCid(basecid);
+ return (!cid->getEnd());
+}
+
+template<class D>
+void
+LbmFsgrSolver<D>::deleteCellIterator( CellIdentifierInterface** cid ) {
+ delete *cid;
+ *cid = NULL;
+}
+
+template<class D>
+CellIdentifierInterface*
+LbmFsgrSolver<D>::getCellAt( ntlVec3Gfx pos ) {
+ //int cellok = false;
+ pos -= (D::mvGeoStart);
+
+ LbmFloat mmaxsize = mLevel[mMaxRefine].nodeSize;
+ for(int level=mMaxRefine; level>=0; level--) { // finest first
+ //for(int level=0; level<=mMaxRefine; level++) { // coarsest first
+ LbmFloat nsize = mLevel[level].nodeSize;
+ int x,y,z;
+ //LbmFloat nsize = getCellSize(NULL)[0]*2.0;
+ x = (int)((pos[0]-0.5*mmaxsize) / nsize );
+ y = (int)((pos[1]-0.5*mmaxsize) / nsize );
+ z = (int)((pos[2]-0.5*mmaxsize) / nsize );
+ if(D::cDimension==2) z = 0;
+
+ // double check...
+ //int level = mMaxRefine;
+ if(x<0) continue;
+ if(y<0) continue;
+ if(z<0) continue;
+ if(x>=mLevel[level].lSizex) continue;
+ if(y>=mLevel[level].lSizey) continue;
+ if(z>=mLevel[level].lSizez) continue;
+
+ /*if( (RFLAG(level, x,y,z, mLevel[level].setCurr)&(CFFluid|CFInter)) ){
+ // ok...
+ } else {
+ // comment out to always retrieve finest cells ( not working )
+ continue;
+ }
+ // O */
+
+ // only return fluid/if cells
+ /*if( (RFLAG(level, x,y,z, mLevel[level].setCurr)&(CFUnused|CFGrFromFine|CFGrFromCoarse)) ){
+ continue;
+ } // */
+
+ // return fluid/if/border cells
+ if( ( (RFLAG(level, x,y,z, mLevel[level].setCurr)&(CFUnused)) ) ||
+ ( (level<mMaxRefine) && (RFLAG(level, x,y,z, mLevel[level].setCurr)&(CFUnused|CFEmpty)) ) ) {
+ continue;
+ } // */
+
+ stdCellId *newcid = new stdCellId;
+ newcid->level = level;
+ newcid->x = x;
+ newcid->y = y;
+ newcid->z = z;
+ //errMsg("cellAt",D::mName<<" "<<pos<<" l"<<level<<":"<<x<<","<<y<<","<<z<<" "<<convertFlags2String(RFLAG(level, x,y,z, mLevel[level].setCurr)) );
+
+ return newcid;
+ }
+
+ return NULL;
+}
+
+
+// INFO functions
+
+template<class D>
+int
+LbmFsgrSolver<D>::getCellSet ( CellIdentifierInterface* basecid) {
+ stdCellId *cid = convertBaseCidToStdCid(basecid);
+ return mLevel[cid->level].setCurr;
+ //return mLevel[cid->level].setOther;
+}
+
+template<class D>
+int
+LbmFsgrSolver<D>::getCellLevel ( CellIdentifierInterface* basecid) {
+ stdCellId *cid = convertBaseCidToStdCid(basecid);
+ return cid->level;
+}
+
+template<class D>
+ntlVec3Gfx
+LbmFsgrSolver<D>::getCellOrigin ( CellIdentifierInterface* basecid) {
+ ntlVec3Gfx ret;
+
+ stdCellId *cid = convertBaseCidToStdCid(basecid);
+ ntlVec3Gfx cs( mLevel[cid->level].nodeSize );
+ if(D::cDimension==2) { cs[2] = 0.0; }
+
+ if(D::cDimension==2) {
+ ret =(D::mvGeoStart -(cs*0.5) + ntlVec3Gfx( cid->x *cs[0], cid->y *cs[1], (D::mvGeoEnd[2]-D::mvGeoStart[2])*0.5 )
+ + ntlVec3Gfx(0.0,0.0,cs[1]*-0.25)*cid->level )
+ +getCellSize(basecid);
+ } else {
+ ret =(D::mvGeoStart -(cs*0.5) + ntlVec3Gfx( cid->x *cs[0], cid->y *cs[1], cid->z *cs[2] ))
+ +getCellSize(basecid);
+ }
+ return (ret);
+}
+
+template<class D>
+ntlVec3Gfx
+LbmFsgrSolver<D>::getCellSize ( CellIdentifierInterface* basecid) {
+ // return half size
+ stdCellId *cid = convertBaseCidToStdCid(basecid);
+ ntlVec3Gfx retvec( mLevel[cid->level].nodeSize * 0.5 );
+ // 2d display as rectangles
+ if(D::cDimension==2) { retvec[2] = 0.0; }
+ return (retvec);
+}
+
+template<class D>
+LbmFloat
+LbmFsgrSolver<D>::getCellDensity ( CellIdentifierInterface* basecid,int set) {
+ stdCellId *cid = convertBaseCidToStdCid(basecid);
+
+ LbmFloat rho = 0.0;
+ FORDF0 {
+ rho += QCELL(cid->level, cid->x,cid->y,cid->z, set, l);
+ }
+ return ((rho-1.0) * mLevel[cid->level].simCellSize / mLevel[cid->level].stepsize) +1.0; // normal
+ //return ((rho-1.0) * D::mpParam->getCellSize() / D::mpParam->getStepTime()) +1.0;
+}
+
+template<class D>
+LbmVec
+LbmFsgrSolver<D>::getCellVelocity ( CellIdentifierInterface* basecid,int set) {
+ stdCellId *cid = convertBaseCidToStdCid(basecid);
+
+ LbmFloat ux,uy,uz;
+ ux=uy=uz= 0.0;
+ FORDF0 {
+ ux += D::dfDvecX[l]* QCELL(cid->level, cid->x,cid->y,cid->z, set, l);
+ uy += D::dfDvecY[l]* QCELL(cid->level, cid->x,cid->y,cid->z, set, l);
+ uz += D::dfDvecZ[l]* QCELL(cid->level, cid->x,cid->y,cid->z, set, l);
+ }
+ LbmVec vel(ux,uy,uz);
+ // TODO fix...
+ return (vel * mLevel[cid->level].simCellSize / mLevel[cid->level].stepsize * D::mDebugVelScale); // normal
+}
+
+template<class D>
+LbmFloat
+LbmFsgrSolver<D>::getCellDf( CellIdentifierInterface* basecid,int set, int dir) {
+ stdCellId *cid = convertBaseCidToStdCid(basecid);
+ return QCELL(cid->level, cid->x,cid->y,cid->z, set, dir);
+}
+template<class D>
+LbmFloat
+LbmFsgrSolver<D>::getCellMass( CellIdentifierInterface* basecid,int set) {
+ stdCellId *cid = convertBaseCidToStdCid(basecid);
+ return QCELL(cid->level, cid->x,cid->y,cid->z, set, dMass);
+}
+template<class D>
+LbmFloat
+LbmFsgrSolver<D>::getCellFill( CellIdentifierInterface* basecid,int set) {
+ stdCellId *cid = convertBaseCidToStdCid(basecid);
+ if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&CFInter) return QCELL(cid->level, cid->x,cid->y,cid->z, set, dFfrac);
+ if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&CFFluid) return 1.0;
+ return 0.0;
+ //return QCELL(cid->level, cid->x,cid->y,cid->z, set, dFfrac);
+}
+template<class D>
+CellFlagType
+LbmFsgrSolver<D>::getCellFlag( CellIdentifierInterface* basecid,int set) {
+ stdCellId *cid = convertBaseCidToStdCid(basecid);
+ return RFLAG(cid->level, cid->x,cid->y,cid->z, set);
+}
+
+template<class D>
+LbmFloat
+LbmFsgrSolver<D>::getEquilDf( int l ) {
+ return D::dfEquil[l];
+}
+
+template<class D>
+int
+LbmFsgrSolver<D>::getDfNum( ) {
+ return D::cDfNum;
+}
+
+#if LBM_USE_GUI==1
+//! show simulation info (implement SimulationObject pure virtual func)
+template<class D>
+void
+LbmFsgrSolver<D>::debugDisplay(fluidDispSettings *set){
+ lbmDebugDisplay< LbmFsgrSolver<D> >( set, this );
+}
+#endif
+
+
+#define LBMFSGRSOLVER_H
+#endif
+
+
diff --git a/intern/elbeem/intern/lbmfunctions.h b/intern/elbeem/intern/lbmfunctions.h
new file mode 100644
index 00000000000..e799d108205
--- /dev/null
+++ b/intern/elbeem/intern/lbmfunctions.h
@@ -0,0 +1,351 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * All code distributed as part of El'Beem is covered by the version 2 of the
+ * GNU General Public License. See the file COPYING for details.
+ * Copyright 2003-2005 Nils Thuerey
+ *
+ * Combined 2D/3D Lattice Boltzmann Solver templated helper functions
+ *
+ *****************************************************************************/
+#ifndef LBMFUNCTIONS_H
+
+
+#if LBM_USE_GUI==1
+#endif
+
+
+#if LBM_USE_GUI==1
+
+//! display a single node
+template<typename D>
+void
+debugDisplayNode(fluidDispSettings *dispset, D *lbm, typename D::CellIdentifier cell ) {
+ //debugOut(" DD: "<<cell->getAsString() , 10);
+ ntlVec3Gfx org = lbm->getCellOrigin( cell );
+ ntlVec3Gfx halfsize = lbm->getCellSize( cell );
+ int set = lbm->getCellSet( cell );
+ //debugOut(" DD: "<<cell->getAsString()<<" "<< (dispset->type) , 10);
+
+ bool showcell = true;
+ int linewidth = 1;
+ ntlColor col(0.5);
+ LbmFloat cscale = dispset->scale;
+
+ switch(dispset->type) {
+ case FLUIDDISPNothing: {
+ showcell = false;
+ } break;
+ case FLUIDDISPCelltypes: {
+ CellFlagType flag = lbm->getCellFlag(cell, set );
+ cscale = 0.5;
+
+ if(flag& CFInvalid ) { if(!guiShowInvalid ) return; }
+ if(flag& CFUnused ) { if(!guiShowInvalid ) return; }
+ if(flag& CFEmpty ) { if(!guiShowEmpty ) return; }
+ if(flag& CFInter ) { if(!guiShowInterface) return; }
+ if(flag& CFNoDelete ) { if(!guiShowNoDelete ) return; }
+ if(flag& CFBnd ) { if(!guiShowBnd ) return; }
+
+ // only dismiss one of these types
+ if(flag& CFGrFromCoarse) { if(!guiShowCoarseInner ) return; } // inner not really interesting
+ else
+ if(flag& CFGrFromFine) { if(!guiShowCoarseBorder ) return; }
+ else
+ if(flag& CFFluid ) { if(!guiShowFluid ) return; }
+
+
+ if(flag& CFNoDelete) { // TEST SOLVER debug, mark nodel cells
+ glLineWidth( linewidth );
+ ntlColor col(0.7,0.0,0.0);
+ glColor3f( col[0], col[1], col[2]);
+ ntlVec3Gfx s = org-(halfsize * 0.1);
+ ntlVec3Gfx e = org+(halfsize * 0.1);
+ drawCubeWire( s,e );
+ }
+
+ /*if(flag& CFAccelerator) {
+ cscale = 0.55;
+ col = ntlColor(0,1,0);
+ //showcell=false; // DEBUG
+ } */
+ if(flag& CFInvalid) {
+ cscale = 0.50;
+ col = ntlColor(0.0,0,0.0);
+ //showcell=false; // DEBUG
+ }
+ /*else if(flag& CFSpeedSet) {
+ cscale = 0.55;
+ col = ntlColor(0.2,1,0.2);
+ //showcell=false; // DEBUG
+ }*/
+ else if(flag& CFBnd) {
+ cscale = 0.59;
+ col = ntlColor(0.0);
+ col = ntlColor(0.4); // DEBUG
+ //if(lbm->getSizeZ()>2) { showcell=false; } // DEBUG, 3D no obstacles
+ }
+
+ /*else if(flag& CFIfFluid) { // TEST SOLVER if inner fluid if
+ cscale = 0.55;
+ col = ntlColor(0,1,0);
+ }
+ else if(flag& CFIfEmpty) { // TEST SOLVER if outer empty if
+ cscale = 0.55;
+ col = ntlColor(0,0.5,0.5);
+ }*/
+ else if(flag& CFInter) {
+ cscale = 0.55;
+ col = ntlColor(0,1,1);
+
+ } else if(flag& CFGrFromCoarse) {
+ // draw as - with marker
+ ntlColor col2(0.0,1.0,0.3);
+ glColor3f( col2[0], col2[1], col2[2]);
+ ntlVec3Gfx s = org-(halfsize * 0.4);
+ ntlVec3Gfx e = org+(halfsize * 0.4);
+ drawCubeWire( s,e );
+ cscale = 0.5;
+ //col = ntlColor(0,0,1);
+ showcell=false; // DEBUG
+ }
+ else if(flag& CFFluid) {
+ cscale = 0.5;
+ /*if(flag& CFCoarseInner) {
+ col = ntlColor(0.3, 0.3, 1.0);
+ } else */
+ if(flag& CFGrToFine) {
+ glLineWidth( linewidth );
+ ntlColor col2(0.5,0.0,0.5);
+ glColor3f( col2[0], col2[1], col2[2]);
+ ntlVec3Gfx s = org-(halfsize * 0.31);
+ ntlVec3Gfx e = org+(halfsize * 0.31);
+ drawCubeWire( s,e );
+ col = ntlColor(0,0,1);
+ }
+ if(flag& CFGrFromFine) {
+ glLineWidth( linewidth );
+ ntlColor col2(1.0,1.0,0.0);
+ glColor3f( col2[0], col2[1], col2[2]);
+ ntlVec3Gfx s = org-(halfsize * 0.56);
+ ntlVec3Gfx e = org+(halfsize * 0.56);
+ drawCubeWire( s,e );
+ col = ntlColor(0,0,1);
+ } else if(flag& CFGrFromCoarse) {
+ // draw as fluid with marker
+ ntlColor col2(0.0,1.0,0.3);
+ glColor3f( col2[0], col2[1], col2[2]);
+ ntlVec3Gfx s = org-(halfsize * 0.41);
+ ntlVec3Gfx e = org+(halfsize * 0.41);
+ drawCubeWire( s,e );
+ col = ntlColor(0,0,1);
+ } else {
+ col = ntlColor(0,0,1);
+ //showcell=false; // DEBUG
+ }
+ }
+ else if(flag& CFEmpty) {
+ showcell=false;
+ }
+
+ // smaller for new lbmqt
+ //cscale *= 0.5;
+
+ } break;
+ case FLUIDDISPVelocities: {
+ // dont use cube display
+ LbmVec vel = lbm->getCellVelocity( cell, set );
+ glBegin(GL_LINES);
+ glColor3f( 0.0,0.0,0.0 );
+ glVertex3f( org[0], org[1], org[2] );
+ org += vec2G(vel * 10.0 * cscale);
+ glColor3f( 1.0,1.0,1.0 );
+ glVertex3f( org[0], org[1], org[2] );
+ glEnd();
+ showcell = false;
+ } break;
+ case FLUIDDISPCellfills: {
+ CellFlagType flag = lbm->getCellFlag( cell,set );
+ cscale = 0.5;
+
+ if(flag& CFFluid) {
+ cscale = 0.75;
+ col = ntlColor(0,0,0.5);
+ }
+ else if(flag& CFInter) {
+ cscale = 0.75 * lbm->getCellMass(cell,set);
+ col = ntlColor(0,1,1);
+ }
+ else {
+ showcell=false;
+ }
+
+ if( ABS(lbm->getCellMass(cell,set)) < 10.0 ) {
+ cscale = 0.75 * lbm->getCellMass(cell,set);
+ } else {
+ showcell = false;
+ }
+ if(cscale>0.0) {
+ col = ntlColor(0,1,1);
+ } else {
+ col = ntlColor(1,1,0);
+ }
+ // TODO
+ } break;
+ case FLUIDDISPDensity: {
+ LbmFloat rho = lbm->getCellDensity(cell,set);
+ cscale = rho*rho * 0.25;
+ col = ntlColor( MIN(0.5+cscale,1.0) , MIN(0.0+cscale,1.0), MIN(0.0+cscale,1.0) );
+ cscale *= 2.0;
+ } break;
+ case FLUIDDISPGrid: {
+ cscale = 0.59;
+ col = ntlColor(1.0);
+ } break;
+ default: {
+ cscale = 0.5;
+ col = ntlColor(1.0,0.0,0.0);
+ } break;
+ }
+
+ if(!showcell) return;
+ glLineWidth( linewidth );
+ glColor4f( col[0], col[1], col[2], 0.0);
+
+ ntlVec3Gfx s = org-(halfsize * cscale);
+ ntlVec3Gfx e = org+(halfsize * cscale);
+ //if(D::cDimension==2) {
+ //s[2] = e[2] = (s[2]+e[2])*0.5;
+ //}
+ drawCubeWire( s,e );
+}
+
+//! debug display function
+// D has to implement the CellIterator interface
+template<typename D>
+void
+lbmDebugDisplay(fluidDispSettings *dispset, D *lbm) {
+ //je nach solver...?
+ if(!dispset->on) return;
+ glDisable( GL_LIGHTING ); // dont light lines
+
+ typename D::CellIdentifier cid = lbm->getFirstCell();
+ for(; lbm->noEndCell( cid );
+ lbm->advanceCell( cid ) ) {
+ // display...
+#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+ ::debugDisplayNode<>(dispset, lbm, cid );
+#else
+ debugDisplayNode<D>(dispset, lbm, cid );
+#endif
+ }
+ delete cid;
+
+ glEnable( GL_LIGHTING ); // dont light lines
+}
+
+//! debug display function
+// D has to implement the CellIterator interface
+template<typename D>
+void
+lbmMarkedCellDisplay(D *lbm) {
+ fluidDispSettings dispset;
+ // trick - display marked cells as grid displa -> white, big
+ dispset.type = FLUIDDISPGrid;
+ dispset.on = true;
+ glDisable( GL_LIGHTING ); // dont light lines
+
+ typename D::CellIdentifier cid = lbm->markedGetFirstCell();
+ for(; lbm->markedNoEndCell( cid );
+ lbm->markedAdvanceCell( cid ) ) {
+ // display... FIXME? this is a bit inconvenient...
+ //MarkedCellIdentifier *mid = dynamic_cast<MarkedCellIdentifier *>( cid );
+#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+ //::debugDisplayNode<>(&dispset, lbm, mid->mpCell );
+ ::debugDisplayNode<>(&dispset, lbm, cid );
+#else
+ //debugDisplayNode<D>(&dispset, lbm, mid->mpCell );
+ debugDisplayNode<D>(&dispset, lbm, cid );
+#endif
+ }
+ delete cid;
+
+ glEnable( GL_LIGHTING ); // dont light lines
+}
+
+#endif
+
+//! display a single node
+template<typename D>
+void
+debugPrintNodeInfo(D *lbm, typename D::CellIdentifier cell, string printInfo,
+ // force printing of one set? default = -1 = off
+ int forceSet=-1) {
+ bool printDF = false;
+ bool printRho = false;
+ bool printVel = false;
+ bool printFlag = false;
+ bool printGeom = false;
+ bool printMass=false;
+ bool printBothSets = false;
+
+ for(size_t i=0; i<printInfo.length()-0; i++) {
+ char what = printInfo[i];
+ switch(what) {
+ case '+': // all on
+ printDF = true; printRho = true; printVel = true; printFlag = true; printGeom = true; printMass = true;
+ printBothSets = true; break;
+ case '-': // all off
+ printDF = false; printRho = false; printVel = false; printFlag = false; printGeom = false; printMass = false;
+ printBothSets = false; break;
+ case 'd': printDF = true; break;
+ case 'r': printRho = true; break;
+ case 'v': printVel = true; break;
+ case 'f': printFlag = true; break;
+ case 'g': printGeom = true; break;
+ case 'm': printMass = true; break;
+ case 's': printBothSets = true; break;
+ default: errMsg("debugPrintNodeInfo","Invalid node info id "<<what); exit(1);
+ }
+ }
+
+ ntlVec3Gfx org = lbm->getCellOrigin( cell );
+ ntlVec3Gfx halfsize = lbm->getCellSize( cell );
+ int set = lbm->getCellSet( cell );
+ debMsgStd("debugPrintNodeInfo",DM_NOTIFY, "Printing cell info '"<<printInfo<<"' for node: "<<cell->getAsString()<<" from "<<lbm->getName()<<" currSet:"<<set , 1);
+ if(printGeom) debMsgStd(" ",DM_MSG, "Org:"<<org<<" Halfsize:"<<halfsize<<" ", 1);
+
+ int setmax = 2;
+ if(!printBothSets) setmax = 1;
+ if(forceSet>=0) setmax = 1;
+
+ for(int s=0; s<setmax; s++) {
+ int workset = set;
+ if(s==1){ workset = (set^1); }
+ if(forceSet>=0) workset = forceSet;
+ debMsgStd(" ",DM_MSG, "Printing set:"<<workset<<" orgSet:"<<set, 1);
+
+ if(printDF) {
+ for(int l=0; l<lbm->getDfNum(); l++) { // FIXME ??
+ debMsgStd(" ",DM_MSG, " Df"<<l<<": "<<lbm->getCellDf(cell,workset,l), 1);
+ }
+ }
+ if(printRho) {
+ debMsgStd(" ",DM_MSG, " Rho: "<<lbm->getCellDensity(cell,workset), 1);
+ }
+ if(printVel) {
+ debMsgStd(" ",DM_MSG, " Vel: "<<lbm->getCellVelocity(cell,workset), 1);
+ }
+ if(printFlag) {
+ CellFlagType flag = lbm->getCellFlag(cell,workset);
+ debMsgStd(" ",DM_MSG, " Flg: "<< flag<<" "<<convertFlags2String( flag ) <<" "<<convertCellFlagType2String( flag ), 1);
+ }
+ if(printMass) {
+ debMsgStd(" ",DM_MSG, " Mss: "<<lbm->getCellMass(cell,workset), 1);
+ }
+ }
+}
+
+#define LBMFUNCTIONS_H
+#endif
+
diff --git a/intern/elbeem/intern/lbminterface.cpp b/intern/elbeem/intern/lbminterface.cpp
new file mode 100644
index 00000000000..975fcebeb2d
--- /dev/null
+++ b/intern/elbeem/intern/lbminterface.cpp
@@ -0,0 +1,716 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * All code distributed as part of El'Beem is covered by the version 2 of the
+ * GNU General Public License. See the file COPYING for details.
+ * Copyright 2003-2005 Nils Thuerey
+ *
+ * Combined 2D/3D Lattice Boltzmann Interface Class
+ * contains stuff to be statically compiled
+ *
+ *****************************************************************************/
+
+/* LBM Files */
+#include "lbmdimensions.h"
+#include "lbminterface.h"
+#include "lbmfunctions.h"
+#include "ntl_scene.h"
+#include "ntl_ray.h"
+#include "typeslbm.h"
+
+
+/*****************************************************************************/
+//! common variables
+
+/*****************************************************************************/
+/*! class for solver templating - 3D implementation D3Q19 */
+
+ //! how many dimensions?
+ const int LbmD3Q19::cDimension = 3;
+
+ // Wi factors for collide step
+ const LbmFloat LbmD3Q19::cCollenZero = (1.0/3.0);
+ const LbmFloat LbmD3Q19::cCollenOne = (1.0/18.0);
+ const LbmFloat LbmD3Q19::cCollenSqrtTwo = (1.0/36.0);
+
+ //! threshold value for filled/emptied cells
+ const LbmFloat LbmD3Q19::cMagicNr2 = 1.0005;
+ const LbmFloat LbmD3Q19::cMagicNr2Neg = -0.0005;
+ const LbmFloat LbmD3Q19::cMagicNr = 1.010001;
+ const LbmFloat LbmD3Q19::cMagicNrNeg = -0.010001;
+
+ //! size of a single set of distribution functions
+ const int LbmD3Q19::cDfNum = 19;
+ //! direction vector contain vecs for all spatial dirs, even if not used for LBM model
+ const int LbmD3Q19::cDirNum = 27;
+
+ //const string LbmD3Q19::dfString[ cDfNum ] = {
+ const char* LbmD3Q19::dfString[ cDfNum ] = {
+ " C", " N"," S"," E"," W"," T"," B",
+ "NE","NW","SE","SW",
+ "NT","NB","ST","SB",
+ "ET","EB","WT","WB"
+ };
+
+ const LbmD3Q19::dfDir LbmD3Q19::dfNorm[ cDfNum ] = {
+ cDirC, cDirN, cDirS, cDirE, cDirW, cDirT, cDirB,
+ cDirNE, cDirNW, cDirSE, cDirSW,
+ cDirNT, cDirNB, cDirST, cDirSB,
+ cDirET, cDirEB, cDirWT, cDirWB
+ };
+
+ const LbmD3Q19::dfDir LbmD3Q19::dfInv[ cDfNum ] = {
+ cDirC, cDirS, cDirN, cDirW, cDirE, cDirB, cDirT,
+ cDirSW, cDirSE, cDirNW, cDirNE,
+ cDirSB, cDirST, cDirNB, cDirNT,
+ cDirWB, cDirWT, cDirEB, cDirET
+ };
+
+ const int LbmD3Q19::dfRefX[ cDfNum ] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ cDirSE, cDirSW, cDirNE, cDirNW,
+ 0, 0, 0, 0,
+ cDirEB, cDirET, cDirWB, cDirWT
+ };
+
+ const int LbmD3Q19::dfRefY[ cDfNum ] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ cDirNW, cDirNE, cDirSW, cDirSE,
+ cDirNB, cDirNT, cDirSB, cDirST,
+ 0, 0, 0, 0
+ };
+
+ const int LbmD3Q19::dfRefZ[ cDfNum ] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ cDirST, cDirSB, cDirNT, cDirNB,
+ cDirWT, cDirWB, cDirET, cDirEB
+ };
+
+ // Vector Order 3D:
+ // 0 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
+ // 0, 0, 0, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1,-1, 1,-1, 1,-1, 1,-1
+ // 0, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1
+ // 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 1,-1, 1,-1, 1,-1, 1,-1, 1, 1, 1, 1, -1,-1,-1,-1
+
+ const int LbmD3Q19::dfVecX[ cDirNum ] = {
+ 0, 0,0, 1,-1, 0,0,
+ 1,-1,1,-1,
+ 0,0,0,0,
+ 1,1,-1,-1,
+ 1,-1, 1,-1,
+ 1,-1, 1,-1,
+ };
+ const int LbmD3Q19::dfVecY[ cDirNum ] = {
+ 0, 1,-1, 0,0,0,0,
+ 1,1,-1,-1,
+ 1,1,-1,-1,
+ 0,0,0,0,
+ 1, 1,-1,-1,
+ 1, 1,-1,-1
+ };
+ const int LbmD3Q19::dfVecZ[ cDirNum ] = {
+ 0, 0,0,0,0,1,-1,
+ 0,0,0,0,
+ 1,-1,1,-1,
+ 1,-1,1,-1,
+ 1, 1, 1, 1,
+ -1,-1,-1,-1
+ };
+
+ const LbmFloat LbmD3Q19::dfDvecX[ cDirNum ] = {
+ 0, 0,0, 1,-1, 0,0,
+ 1,-1,1,-1,
+ 0,0,0,0,
+ 1,1,-1,-1,
+ 1,-1, 1,-1,
+ 1,-1, 1,-1
+ };
+ const LbmFloat LbmD3Q19::dfDvecY[ cDirNum ] = {
+ 0, 1,-1, 0,0,0,0,
+ 1,1,-1,-1,
+ 1,1,-1,-1,
+ 0,0,0,0,
+ 1, 1,-1,-1,
+ 1, 1,-1,-1
+ };
+ const LbmFloat LbmD3Q19::dfDvecZ[ cDirNum ] = {
+ 0, 0,0,0,0,1,-1,
+ 0,0,0,0,
+ 1,-1,1,-1,
+ 1,-1,1,-1,
+ 1, 1, 1, 1,
+ -1,-1,-1,-1
+ };
+
+ /* principal directions */
+ const int LbmD3Q19::princDirX[ 2*LbmD3Q19::cDimension ] = {
+ 1,-1, 0,0, 0,0
+ };
+ const int LbmD3Q19::princDirY[ 2*LbmD3Q19::cDimension ] = {
+ 0,0, 1,-1, 0,0
+ };
+ const int LbmD3Q19::princDirZ[ 2*LbmD3Q19::cDimension ] = {
+ 0,0, 0,0, 1,-1
+ };
+
+ /*! arrays for les model coefficients, inited in lbmsolver constructor */
+ LbmFloat LbmD3Q19::lesCoeffDiag[ (cDimension-1)*(cDimension-1) ][ cDirNum ];
+ LbmFloat LbmD3Q19::lesCoeffOffdiag[ cDimension ][ cDirNum ];
+
+
+ const LbmFloat LbmD3Q19::dfLength[ cDfNum ]= {
+ cCollenZero,
+ cCollenOne, cCollenOne, cCollenOne,
+ cCollenOne, cCollenOne, cCollenOne,
+ cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo,
+ cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo,
+ cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo
+ };
+
+ /* precalculated equilibrium dfs, inited in lbmsolver constructor */
+ LbmFloat LbmD3Q19::dfEquil[ cDfNum ];
+
+// D3Q19 end
+
+
+
+/*****************************************************************************/
+/*! class for solver templating - 2D implementation D2Q9 */
+
+ //! how many dimensions?
+ const int LbmD2Q9::cDimension = 2;
+
+ //! Wi factors for collide step
+ const LbmFloat LbmD2Q9::cCollenZero = (4.0/9.0);
+ const LbmFloat LbmD2Q9::cCollenOne = (1.0/9.0);
+ const LbmFloat LbmD2Q9::cCollenSqrtTwo = (1.0/36.0);
+
+ //! threshold value for filled/emptied cells
+ const LbmFloat LbmD2Q9::cMagicNr2 = 1.0005;
+ const LbmFloat LbmD2Q9::cMagicNr2Neg = -0.0005;
+ const LbmFloat LbmD2Q9::cMagicNr = 1.010001;
+ const LbmFloat LbmD2Q9::cMagicNrNeg = -0.010001;
+
+ //! size of a single set of distribution functions
+ const int LbmD2Q9::cDfNum = 9;
+ const int LbmD2Q9::cDirNum = 9;
+
+ //const string LbmD2Q9::dfString[ cDfNum ] = {
+ const char* LbmD2Q9::dfString[ cDfNum ] = {
+ " C",
+ " N", " S", " E", " W",
+ "NE", "NW", "SE","SW"
+ };
+
+ const LbmD2Q9::dfDir LbmD2Q9::dfNorm[ cDfNum ] = {
+ cDirC,
+ cDirN, cDirS, cDirE, cDirW,
+ cDirNE, cDirNW, cDirSE, cDirSW
+ };
+
+ const LbmD2Q9::dfDir LbmD2Q9::dfInv[ cDfNum ] = {
+ cDirC,
+ cDirS, cDirN, cDirW, cDirE,
+ cDirSW, cDirSE, cDirNW, cDirNE
+ };
+
+ const int LbmD2Q9::dfRefX[ cDfNum ] = {
+ 0,
+ 0, 0, 0, 0,
+ cDirSE, cDirSW, cDirNE, cDirNW
+ };
+
+ const int LbmD2Q9::dfRefY[ cDfNum ] = {
+ 0,
+ 0, 0, 0, 0,
+ cDirNW, cDirNE, cDirSW, cDirSE
+ };
+
+ const int LbmD2Q9::dfRefZ[ cDfNum ] = {
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0
+ };
+
+ // Vector Order 2D:
+ // 0 1 2 3 4 5 6 7 8
+ // 0, 0,0, 1,-1, 1,-1,1,-1
+ // 0, 1,-1, 0,0, 1,1,-1,-1
+
+ const int LbmD2Q9::dfVecX[ cDirNum ] = {
+ 0,
+ 0,0, 1,-1,
+ 1,-1,1,-1
+ };
+ const int LbmD2Q9::dfVecY[ cDirNum ] = {
+ 0,
+ 1,-1, 0,0,
+ 1,1,-1,-1
+ };
+ const int LbmD2Q9::dfVecZ[ cDirNum ] = {
+ 0, 0,0,0,0, 0,0,0,0
+ };
+
+ const LbmFloat LbmD2Q9::dfDvecX[ cDirNum ] = {
+ 0,
+ 0,0, 1,-1,
+ 1,-1,1,-1
+ };
+ const LbmFloat LbmD2Q9::dfDvecY[ cDirNum ] = {
+ 0,
+ 1,-1, 0,0,
+ 1,1,-1,-1
+ };
+ const LbmFloat LbmD2Q9::dfDvecZ[ cDirNum ] = {
+ 0, 0,0,0,0, 0,0,0,0
+ };
+
+ const int LbmD2Q9::princDirX[ 2*LbmD2Q9::cDimension ] = {
+ 1,-1, 0,0
+ };
+ const int LbmD2Q9::princDirY[ 2*LbmD2Q9::cDimension ] = {
+ 0,0, 1,-1
+ };
+ const int LbmD2Q9::princDirZ[ 2*LbmD2Q9::cDimension ] = {
+ 0,0, 0,0
+ };
+
+
+ /*! arrays for les model coefficients, inited in lbmsolver constructor */
+ LbmFloat LbmD2Q9::lesCoeffDiag[ (cDimension-1)*(cDimension-1) ][ cDirNum ];
+ LbmFloat LbmD2Q9::lesCoeffOffdiag[ cDimension ][ cDirNum ];
+
+
+ const LbmFloat LbmD2Q9::dfLength[ cDfNum ]= {
+ cCollenZero,
+ cCollenOne, cCollenOne, cCollenOne, cCollenOne,
+ cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo
+ };
+
+ /* precalculated equilibrium dfs, inited in lbmsolver constructor */
+ LbmFloat LbmD2Q9::dfEquil[ cDfNum ];
+
+// D2Q9 end
+
+
+
+/******************************************************************************
+ * Interface Constructor
+ *****************************************************************************/
+LbmSolverInterface::LbmSolverInterface() :
+ mPanic( false ),
+ mSizex(10), mSizey(10), mSizez(10),
+ mStepCnt( 0 ),
+ mFixMass( 0.0 ),
+ mOmega( 1.0 ),
+ mGravity(0.0),
+ mSurfaceTension( 0.0 ),
+ mInitialMass (0.0),
+ mBoundaryEast( (CellFlagType)(CFBnd) ),mBoundaryWest( (CellFlagType)(CFBnd) ),mBoundaryNorth( (CellFlagType)(CFBnd) ),
+ mBoundarySouth( (CellFlagType)(CFBnd) ),mBoundaryTop( (CellFlagType)(CFBnd) ),mBoundaryBottom( (CellFlagType)(CFBnd) ),
+ mInitDone( false ),
+ mInitDensityGradient( false ),
+ mpAttrs( NULL ), mpParam( NULL ),
+ mNumParticlesLost(0), mNumInvalidDfs(0), mNumFilledCells(0), mNumEmptiedCells(0), mNumUsedCells(0), mMLSUPS(0),
+ mDebugVelScale( 1.0 ), mNodeInfoString("+"),
+ mRandom( 5123 ),
+ mvGeoStart(-1.0), mvGeoEnd(1.0),
+ mPerformGeoInit( false ),
+ mName("lbm_default") ,
+ mpIso( NULL ), mIsoValue(0.49999),
+ mSilent(false) ,
+ mGeoInitId( 0 ),
+ mpGiTree( NULL ),
+ mAccurateGeoinit(0),
+ mpGiObjects( NULL ), mGiObjInside(), mpGlob( NULL )
+{
+#if ELBEEM_BLENDER==1
+ mSilent = true;
+#endif
+}
+
+
+/*******************************************************************************/
+/*! parse a boundary flag string */
+CellFlagType LbmSolverInterface::readBoundaryFlagInt(string name, int defaultValue, string source,string target, bool needed) {
+ string val = mpAttrs->readString(name, "", source, target, needed);
+ if(!strcmp(val.c_str(),"")) {
+ // no value given...
+ return CFEmpty;
+ }
+ if(!strcmp(val.c_str(),"bnd_no")) {
+ return (CellFlagType)( CFBnd );
+ }
+ if(!strcmp(val.c_str(),"bnd_free")) {
+ return (CellFlagType)( CFBnd );
+ }
+ if(!strcmp(val.c_str(),"fluid")) {
+ /* might be used for some in/out flow cases */
+ return (CellFlagType)( CFFluid );
+ }
+ errorOut("LbmStdSolver::readBoundaryFlagInt error: Invalid value '"<<val<<"' " );
+# if LBM_STRICT_DEBUG==1
+ exit(1);
+# endif
+ return defaultValue;
+}
+
+/*******************************************************************************/
+/*! parse standard attributes */
+void LbmSolverInterface::parseStdAttrList() {
+ if(!mpAttrs) {
+ errorOut("LbmStdSolver::parseAttrList error: mpAttrs pointer not initialized!");
+ exit(1); }
+
+ // st currently unused
+ //mSurfaceTension = mpAttrs->readFloat("d_surfacetension", mSurfaceTension, "LbmStdSolver", "mSurfaceTension", false);
+ mBoundaryEast = readBoundaryFlagInt("boundary_east", mBoundaryEast, "LbmStdSolver", "mBoundaryEast", false);
+ mBoundaryWest = readBoundaryFlagInt("boundary_west", mBoundaryWest, "LbmStdSolver", "mBoundaryWest", false);
+ mBoundaryNorth = readBoundaryFlagInt("boundary_north", mBoundaryNorth,"LbmStdSolver", "mBoundaryNorth", false);
+ mBoundarySouth = readBoundaryFlagInt("boundary_south", mBoundarySouth,"LbmStdSolver", "mBoundarySouth", false);
+ mBoundaryTop = readBoundaryFlagInt("boundary_top", mBoundaryTop,"LbmStdSolver", "mBoundaryTop", false);
+ mBoundaryBottom= readBoundaryFlagInt("boundary_bottom", mBoundaryBottom,"LbmStdSolver", "mBoundaryBottom", false);
+
+ LbmVec sizeVec(mSizex,mSizey,mSizez);
+ sizeVec = vec2L( mpAttrs->readVec3d("size", vec2P(sizeVec), "LbmStdSolver", "sizeVec", false) );
+ mSizex = (int)sizeVec[0];
+ mSizey = (int)sizeVec[1];
+ mSizez = (int)sizeVec[2];
+ mpParam->setSize(mSizex, mSizey, mSizez ); // param needs size in any case
+
+ mInitDensityGradient = mpAttrs->readBool("initdensitygradient", mInitDensityGradient,"LbmStdSolver", "mInitDensityGradient", false);
+ mPerformGeoInit = mpAttrs->readBool("geoinit", mPerformGeoInit,"LbmStdSolver", "mPerformGeoInit", false);
+ mGeoInitId = mpAttrs->readInt("geoinitid", mGeoInitId,"LbmStdSolver", "mGeoInitId", false);
+ mIsoValue = mpAttrs->readFloat("isovalue", mIsoValue, "LbmOptSolver","mIsoValue", false );
+
+ mDebugVelScale = mpAttrs->readFloat("debugvelscale", mDebugVelScale,"LbmStdSolver", "mDebugVelScale", false);
+ mNodeInfoString = mpAttrs->readString("nodeinfo", mNodeInfoString, "SimulationLbm","mNodeInfoString", false );
+}
+
+
+/*******************************************************************************/
+/*! geometry initialization */
+/*******************************************************************************/
+
+/*****************************************************************************/
+/*! init tree for certain geometry init */
+void LbmSolverInterface::initGeoTree(int id) {
+ if(mpGlob == NULL) { errorOut("LbmSolverInterface::initGeoTree error: Requires globals!"); exit(1); }
+ mGeoInitId = id;
+ ntlScene *scene = mpGlob->getScene();
+ mpGiObjects = scene->getObjects();
+ mGiObjInside.resize( mpGiObjects->size() );
+ mGiObjDistance.resize( mpGiObjects->size() );
+ for(size_t i=0; i<mpGiObjects->size(); i++) {
+ if((*mpGiObjects)[i]->getGeoInitIntersect()) mAccurateGeoinit=true;
+ }
+ debMsgStd("LbmSolverInterface::initGeoTree",DM_MSG,"Accurate geo init: "<<mAccurateGeoinit, 9)
+
+ if(mpGiTree != NULL) delete mpGiTree;
+ char treeFlag = (1<<(mGeoInitId+4));
+ mpGiTree = new ntlTree( 20, 4, // warning - fixed values for depth & maxtriangles here...
+ scene, treeFlag );
+}
+
+/*****************************************************************************/
+/*! destroy tree etc. when geometry init done */
+void LbmSolverInterface::freeGeoTree() {
+ if(mpGiTree != NULL) {
+ delete mpGiTree;
+ mpGiTree = NULL;
+ }
+}
+
+
+/*****************************************************************************/
+/*! check for a certain flag type at position org */
+bool LbmSolverInterface::geoInitCheckPointInside(ntlVec3Gfx org, int flags, int &OId, gfxReal &distance) {
+ // shift ve ctors to avoid rounding errors
+ org += ntlVec3Gfx(0.0001);
+ ntlVec3Gfx dir = ntlVec3Gfx(0.999999,0.0,0.0);
+ OId = -1;
+ ntlRay ray(org, dir, 0, 1.0, mpGlob);
+ //int insCnt = 0;
+ bool done = false;
+ bool inside = false;
+ //errMsg("III"," start org"<<org<<" dir"<<dir);
+ //int insID = ray.getID();
+ for(size_t i=0; i<mGiObjInside.size(); i++) { mGiObjInside[i] = 0; }
+ // if not inside, return distance to first hit
+ gfxReal firstHit=-1.0;
+
+ if(mAccurateGeoinit) {
+ while(!done) {
+ // find first inside intersection
+ ntlTriangle *triIns = NULL;
+ distance = -1.0;
+ ntlVec3Gfx normal(0.0);
+ mpGiTree->intersect(ray,distance,normal, triIns, flags, true);
+ if(triIns) {
+ ntlVec3Gfx norg = ray.getOrigin() + ray.getDirection()*distance;
+ LbmFloat orientation = dot(normal, dir);
+ OId = triIns->getObjectId();
+ if(orientation<=0.0) {
+ // outside hit
+ normal *= -1.0;
+ mGiObjInside[OId]++;
+ mGiObjDistance[OId] = -1.0;
+ //errMsg("IIO"," oid:"<<OId<<" org"<<org<<" norg"<<norg);
+ } else {
+ // inside hit
+ mGiObjInside[OId]++;
+ mGiObjDistance[OId] = distance;
+ //errMsg("III"," oid:"<<OId<<" org"<<org<<" norg"<<norg);
+ }
+ norg += normal * getVecEpsilon();
+ ray = ntlRay(norg, dir, 0, 1.0, mpGlob);
+ if(firstHit<0.0) firstHit = distance;
+ //if((OId<0) && ())
+ //insCnt++;
+ /*
+ // check outside intersect
+ LbmFloat orientation = dot(normal, dir);
+ if(orientation<=0.0) {
+ // do more thorough checks... advance ray
+ ntlVec3Gfx norg = ray.getOrigin() + ray.getDirection()*distance;
+ norg += normal * (-1.0 * getVecEpsilon());
+ ray = ntlRay(norg, dir, 0, 1.0, mpGlob);
+ insCnt++;
+ errMsg("III"," oid:"<<OId<<" org"<<org<<" norg"<<norg<<" insCnt"<<insCnt);
+ } else {
+ if(insCnt>0) {
+ // we have entered this obj before?
+ ntlVec3Gfx norg = ray.getOrigin() + ray.getDirection()*distance;
+ norg += normal * (-1.0 * getVecEpsilon());
+ ray = ntlRay(norg, dir, 0, 1.0, mpGlob);
+ insCnt--;
+ errMsg("IIIS"," oid:"<<OId<<" org"<<org<<" norg"<<norg<<" insCnt"<<insCnt);
+ } else {
+ // first inside intersection -> ok
+ OId = triIns->getObjectId();
+ done = inside = true;
+ }
+ }
+ */
+ } else {
+ // no more intersections... return false
+ done = true;
+ //if(insCnt%2) inside=true;
+ }
+ }
+
+ distance = -1.0;
+ for(size_t i=0; i<mGiObjInside.size(); i++) {
+ //errMsg("CHIII","i"<<i<<" ins="<<mGiObjInside[i]<<" t"<<mGiObjDistance[i]<<" d"<<distance);
+ if(((mGiObjInside[i]%2)==1)&&(mGiObjDistance[i]>0.0)) {
+ if(distance<0.0) {
+ // first intersection -> good
+ distance = mGiObjDistance[i];
+ OId = i;
+ inside = true;
+ } else {
+ if(distance>mGiObjDistance[i]) {
+ // more than one intersection -> use closest one
+ distance = mGiObjDistance[i];
+ OId = i;
+ inside = true;
+ }
+ }
+ }
+ }
+ if(!inside) {
+ distance = firstHit;
+ }
+
+ return inside;
+ } else {
+
+ // find first inside intersection
+ ntlTriangle *triIns = NULL;
+ distance = -1.0;
+ ntlVec3Gfx normal(0.0);
+ mpGiTree->intersect(ray,distance,normal, triIns, flags, true);
+ if(triIns) {
+ // check outside intersect
+ LbmFloat orientation = dot(normal, dir);
+ if(orientation<=0.0) return false;
+
+ OId = triIns->getObjectId();
+ return true;
+ }
+ return false;
+ }
+}
+
+/*****************************************************************************/
+/*! get max. velocity of all objects to initialize as fluid regions */
+ntlVec3Gfx LbmSolverInterface::getGeoMaxInitialVelocity() {
+ ntlScene *scene = mpGlob->getScene();
+ mpGiObjects = scene->getObjects();
+ ntlVec3Gfx max(0.0);
+
+ for(int i=0; i< (int)mpGiObjects->size(); i++) {
+ if( (*mpGiObjects)[i]->getGeoInitType() & FGI_FLUID ){
+ ntlVec3Gfx ovel = (*mpGiObjects)[i]->getInitialVelocity();
+ if( normNoSqrt(ovel) > normNoSqrt(max) ) { max = ovel; }
+ //errMsg("IVT","i"<<i<<" "<< (*mpGiObjects)[i]->getInitialVelocity() ); // DEBUG
+ }
+ }
+ //errMsg("IVT","max "<<" "<< max ); // DEBUG
+ // unused !? mGiInsideCnt.resize( mpGiObjects->size() );
+
+ return max;
+}
+
+
+/*******************************************************************************/
+/*! "traditional" initialization */
+/*******************************************************************************/
+
+
+/*****************************************************************************/
+// handle generic test cases (currently only reset geo init)
+bool LbmSolverInterface::initGenericTestCases() {
+ bool initTypeFound = false;
+ LbmSolverInterface::CellIdentifier cid = getFirstCell();
+ // deprecated! - only check for invalid cells...
+
+ // this is the default init - check if the geometry flag init didnt
+ initTypeFound = true;
+
+ while(noEndCell(cid)) {
+ // check node
+ if( (getCellFlag(cid,0)==CFInvalid) || (getCellFlag(cid,1)==CFInvalid) ) {
+ warnMsg("LbmSolverInterface::initGenericTestCases","GeoInit produced invalid Flag at "<<cid->getAsString()<<"!" );
+ }
+ advanceCell( cid );
+ }
+
+ deleteCellIterator( &cid );
+ return initTypeFound;
+}
+
+
+/*******************************************************************************/
+/*! cell iteration functions */
+/*******************************************************************************/
+
+
+
+
+/*****************************************************************************/
+//! add cell to mMarkedCells list
+void
+LbmSolverInterface::addCellToMarkedList( CellIdentifierInterface *cid ) {
+ for(size_t i=0; i<mMarkedCells.size(); i++) {
+ // check if cids alreay in
+ if( mMarkedCells[i]->equal(cid) ) return;
+ mMarkedCells[i]->setEnd(false);
+ }
+ mMarkedCells.push_back( cid );
+ cid->setEnd(true);
+}
+
+/*****************************************************************************/
+//! marked cell iteration methods
+CellIdentifierInterface*
+LbmSolverInterface::markedGetFirstCell( ) {
+ /*MarkedCellIdentifier *newcid = new MarkedCellIdentifier();
+ if(mMarkedCells.size() < 1){
+ newcid->setEnd( true );
+ } else {
+ newcid->mpCell = mMarkedCells[0];
+ }
+ return newcid;*/
+ return NULL;
+}
+
+void
+LbmSolverInterface::markedAdvanceCell( CellIdentifierInterface* basecid ) {
+ if(!basecid) return;
+ basecid->setEnd( true );
+ /*MarkedCellIdentifier *cid = dynamic_cast<MarkedCellIdentifier*>( basecid );
+ CellIdentifierInterface *cid = basecid;
+ cid->mIndex++;
+ if(cid->mIndex >= (int)mMarkedCells.size()) {
+ cid->setEnd( true );
+ }
+ cid->mpCell = mMarkedCells[ cid->mIndex ];
+ */
+}
+
+bool
+LbmSolverInterface::markedNoEndCell( CellIdentifierInterface* cid ) {
+ if(!cid) return false;
+ return(! cid->getEnd() );
+}
+
+void LbmSolverInterface::markedClearList() {
+ // FIXME free cids?
+ mMarkedCells.clear();
+}
+
+/*******************************************************************************/
+/*! string helper functions */
+/*******************************************************************************/
+
+
+
+// 32k
+std::string convertSingleFlag2String(CellFlagType cflag) {
+ CellFlagType flag = cflag;
+ if(flag == CFUnused ) return string("cCFUnused");
+ if(flag == CFEmpty ) return string("cCFEmpty");
+ if(flag == CFBnd ) return string("cCFBnd");
+ if(flag == CFNoInterpolSrc ) return string("cCFNoInterpolSrc");
+ if(flag == CFFluid ) return string("cCFFluid");
+ if(flag == CFInter ) return string("cCFInter");
+ if(flag == CFNoNbFluid ) return string("cCFNoNbFluid");
+ if(flag == CFNoNbEmpty ) return string("cCFNoNbEmpty");
+ if(flag == CFNoDelete ) return string("cCFNoDelete");
+ if(flag == CFNoBndFluid ) return string("cCFNoBndFluid");
+ if(flag == CFBndMARK ) return string("cCFBndMARK");
+ if(flag == CFGrNorm ) return string("cCFGrNorm");
+ if(flag == CFGrFromFine ) return string("cCFGrFromFine");
+ if(flag == CFGrFromCoarse ) return string("cCFGrFromCoarse");
+ if(flag == CFGrCoarseInited ) return string("cCFGrCoarseInited");
+ if(flag == CFInvalid ) return string("cfINVALID");
+
+ std::ostringstream mult;
+ int val = 0;
+ if(flag != 0) {
+ while(! (flag&1) ) {
+ flag = flag>>1;
+ val++;
+ }
+ } else {
+ val = -1;
+ }
+ mult << "cfUNKNOWN_" << val <<"_TYPE";
+ return mult.str();
+}
+
+//! helper function to convert flag to string (for debuggin)
+std::string convertCellFlagType2String( CellFlagType cflag ) {
+ int flag = cflag;
+
+ const int jmax = sizeof(CellFlagType)*8;
+ bool somefound = false;
+ std::ostringstream mult;
+ mult << "[";
+ for(int j=0; j<jmax ; j++) {
+ if(flag& (1<<j)) {
+ if(somefound) mult << "|";
+ mult << convertSingleFlag2String( (CellFlagType)(1<<j) ); // this call should always be _non_-recursive
+ somefound = true;
+ }
+ };
+ mult << "]";
+
+ // return concatenated string
+ if(somefound) return mult.str();
+
+ // empty?
+ return string("[emptyCFT]");
+}
+
diff --git a/intern/elbeem/intern/lbminterface.h b/intern/elbeem/intern/lbminterface.h
new file mode 100644
index 00000000000..22626954728
--- /dev/null
+++ b/intern/elbeem/intern/lbminterface.h
@@ -0,0 +1,564 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * All code distributed as part of El'Beem is covered by the version 2 of the
+ * GNU General Public License. See the file COPYING for details.
+ * Copyright 2003-2005 Nils Thuerey
+ *
+ * Header for Combined 2D/3D Lattice Boltzmann Interface Class
+ *
+ *****************************************************************************/
+#ifndef LBMINTERFACE_H
+#define LBMINTERFACE_H
+
+//! include gui support?
+#ifndef NOGUI
+#define LBM_USE_GUI 1
+#else
+#define LBM_USE_GUI 0
+#endif
+
+#if LBM_USE_GUI==1
+#define USE_GLUTILITIES
+// for debug display
+#include <GL/gl.h>
+#include "../gui/guifuncs.h"
+#endif
+
+#include <sstream>
+#include "utilities.h"
+#include "ntl_bsptree.h"
+#include "ntl_geometryobject.h"
+#include "ntl_rndstream.h"
+#include "parametrizer.h"
+#include "attributes.h"
+#include "particletracer.h"
+#include "isosurface.h"
+
+// use which fp-precision for LBM? 1=float, 2=double
+#ifdef PRECISION_LBM_SINGLE
+#define LBM_PRECISION 1
+#else
+#ifdef PRECISION_LBM_DOUBLE
+#define LBM_PRECISION 2
+#else
+// default to floats
+#define LBM_PRECISION 1
+#endif
+#endif
+
+// default to 3dim
+#ifndef LBMDIM
+#define LBMDIM 3
+#endif // LBMDIM
+
+#if LBM_PRECISION==1
+/* low precision for LBM solver */
+typedef float LbmFloat;
+typedef ntlVec3f LbmVec;
+#define LBM_EPSILON (1e-5)
+#else
+/* standard precision for LBM solver */
+typedef double LbmFloat;
+typedef ntlVec3d LbmVec;
+#define LBM_EPSILON (1e-10)
+#endif
+
+// conversions (lbm and parametrizer)
+template<class T> inline LbmVec vec2L(T v) { return LbmVec(v[0],v[1],v[2]); }
+template<class T> inline ParamVec vec2P(T v) { return ParamVec(v[0],v[1],v[2]); }
+
+
+// bubble id type
+typedef int BubbleId;
+
+// for both short int/char
+// 1
+#define CFUnused (1<< 0)
+// 2
+#define CFEmpty (1<< 1)
+// 4
+#define CFBnd (1<< 2)
+// 8, force symmetry for flag reinit
+#define CFNoInterpolSrc (1<< 3)
+// 16
+#define CFFluid (1<< 4)
+// 32
+#define CFInter (1<< 5)
+// 64
+#define CFNoNbFluid (1<< 6)
+// 128
+#define CFNoNbEmpty (1<< 7)
+// 256
+#define CFNoDelete (1<< 8)
+
+// 512
+#define CFNoBndFluid (1<< 9)
+// 1024
+#define CFBndMARK (1<<10)
+
+//! refinement tags
+// cell treated normally on coarser grids
+// 2048
+#define CFGrNorm (1<<11)
+// border cells to be interpolated from finer grid
+// 4096
+#define CFGrFromFine (1<<12)
+// 8192
+#define CFGrFromCoarse (1<<13)
+// 16384
+#define CFGrCoarseInited (1<<14)
+// 32k (aux marker, no real action)
+#define CFGrToFine (1<<15)
+
+// nk
+#define CFInvalid (CellFlagType)(1<<31)
+
+// use 16bit flag types
+//#define CellFlagType unsigned short int
+// use 32bit flag types
+#define CellFlagType unsigned long int
+
+
+/*****************************************************************************/
+/*! a single lbm cell */
+/* the template is only needed for
+ * dimension dependend constants e.g.
+ * number of df's in model */
+template<typename D>
+class LbmCellTemplate {
+ public:
+ LbmFloat df[ 27 ]; // be on the safe side here...
+ LbmFloat rho;
+ LbmVec vel;
+ LbmFloat mass;
+ CellFlagType flag;
+ BubbleId bubble;
+ LbmFloat ffrac;
+
+ //! test if a flag is set
+ inline bool test(CellFlagType t) {
+ return ((flag & t)==t);
+ }
+ //! test if any of the given flags is set
+ inline bool testAny(CellFlagType t) {
+ return ((flag & t)!=0);
+ }
+ //! test if the cell is empty
+ inline bool isEmpty() {
+ return (flag == CFEmpty);
+ }
+
+ //! init default values for a certain flag type
+ inline void initDefaults(CellFlagType type) {
+ flag = type;
+ vel = LbmVec(0.0);
+ for(int l=0; l<D::cDfNum;l++) df[l] = D::dfEquil[l];
+
+ if(type & CFFluid) {
+ rho = mass = ffrac = 1.0;
+ bubble = -1;
+ }
+ else if(type & CFInter) {
+ rho = mass = ffrac = 0.0;
+ bubble = 0;
+ }
+ else if(type & CFBnd) {
+ rho = mass = ffrac = 0.0;
+ bubble = -1;
+ }
+ else if(type & CFEmpty) {
+ rho = mass = ffrac = 0.0;
+ bubble = 0;
+ } else {
+ // ?
+ rho = mass = ffrac = 0.0;
+ bubble = -1;
+ }
+ }
+
+ //TODO add init method?
+};
+
+
+/* struct for the coordinates of a cell in the grid */
+typedef struct {
+ int x,y,z;
+} LbmPoint;
+
+
+/* struct for the coordinates of a cell in the grid */
+typedef struct {
+ char active; // bubble in use, oder may be overwritten?
+ LbmFloat volume; // volume of this bubble (0 vor atmosphere)
+ LbmFloat mass; // "mass" of bubble
+ int i,j,k; // index of a cell in the bubble
+} LbmBubble;
+
+
+
+
+//! choose which data to display
+#define FLUIDDISPINVALID 0
+#define FLUIDDISPNothing 1
+#define FLUIDDISPCelltypes 2
+#define FLUIDDISPVelocities 3
+#define FLUIDDISPCellfills 4
+#define FLUIDDISPDensity 5
+#define FLUIDDISPGrid 6
+#define FLUIDDISPSurface 7
+
+//! settings for a debug display
+typedef struct fluidDispSettings_T {
+ int type; // what to display
+ bool on; // display enabled?
+ float scale; // additional scale param
+} fluidDispSettings;
+
+
+
+/*****************************************************************************/
+//! cell identifier interface
+class CellIdentifierInterface {
+ public:
+ //! reset constructor
+ CellIdentifierInterface() : mEnd (false) { };
+ //! virtual destructor
+ virtual ~CellIdentifierInterface() {};
+
+ //! return node as string (with some basic info)
+ virtual std::string getAsString() = 0;
+
+ //! compare cids
+ virtual bool equal(CellIdentifierInterface* other) = 0;
+
+ //! set/get end flag
+ inline void setEnd(bool set){ mEnd = set; }
+ inline bool getEnd( ) { return mEnd; }
+
+ protected:
+
+ //! has the grid been traversed?
+ bool mEnd;
+
+};
+
+
+/*****************************************************************************/
+/*! marked cell access class *
+class MarkedCellIdentifier :
+ public CellIdentifierInterface
+{
+ public:
+ //! cell pointer
+ CellIdentifierInterface *mpCell;
+ //! location in mMarkedCells vector
+ int mIndex;
+
+ //! reset constructor
+ MarkedCellIdentifier() :
+ mpCell( NULL ), mIndex(0)
+ { };
+
+ // implement CellIdentifierInterface
+ virtual std::string getAsString() {
+ std::ostringstream ret;
+ ret <<"{MC i"<<mIndex<<" }";
+ return ret.str();
+ }
+
+ virtual bool equal(CellIdentifierInterface* other) {
+ MarkedCellIdentifier *cid = dynamic_cast<MarkedCellIdentifier *>( other );
+ if(!cid) return false;
+ if( mpCell==cid->mpCell ) return true;
+ return false;
+ }
+}; */
+
+
+
+/*****************************************************************************/
+/*! class defining abstract function interface */
+/* has to provide iterating functionality */
+class LbmSolverInterface
+{
+ public:
+ //! Constructor
+ LbmSolverInterface();
+ //! Destructor
+ virtual ~LbmSolverInterface() { };
+ //! id string of solver
+ virtual string getIdString() = 0;
+
+ /*! finish the init with config file values (allocate arrays...) */
+ virtual bool initialize( ntlTree *tree, vector<ntlGeometryObject*> *objects ) = 0;
+ /*! generic test case setup using iterator interface */
+ bool initGenericTestCases();
+
+ /*! parse a boundary flag string */
+ CellFlagType readBoundaryFlagInt(string name, int defaultValue, string source,string target, bool needed);
+ /*! parse standard attributes */
+ void parseStdAttrList();
+ /*! initilize variables fom attribute list (should at least call std parse) */
+ virtual void parseAttrList() = 0;
+
+ virtual void step() = 0;
+ virtual void prepareVisualization() { /* by default off */ };
+
+ /*! particle handling */
+ virtual int initParticles(ParticleTracer *partt) = 0;
+ virtual void advanceParticles(ParticleTracer *partt ) = 0;
+ /*! get surface object (NULL if no surface) */
+ ntlGeometryObject* getSurfaceGeoObj() { return mpIso; }
+
+ /*! debug object display */
+ virtual vector<ntlGeometryObject*> getDebugObjects() { vector<ntlGeometryObject*> empty(0); return empty; }
+
+#if LBM_USE_GUI==1
+ /*! show simulation info */
+ virtual void debugDisplay(fluidDispSettings *) = 0;
+#endif
+
+ /*! init tree for certain geometry init */
+ void initGeoTree(int id);
+ /*! destroy tree etc. when geometry init done */
+ void freeGeoTree();
+ /*! get fluid init type at certain position */
+ // DEPRECATED CellFlagType geoInitGetPointType(ntlVec3Gfx org, ntlVec3Gfx nodesize, ntlGeometryObject **mpObj, gfxReal &distance);
+ /*! check for a certain flag type at position org (needed for e.g. quadtree refinement) */
+ bool geoInitCheckPointInside(ntlVec3Gfx org, int flags, int &OId, gfxReal &distance);
+ /*! set render globals, for scene/tree access */
+ void setRenderGlobals(ntlRenderGlobals *glob) { mpGlob = glob; };
+ /*! get max. velocity of all objects to initialize as fluid regions */
+ ntlVec3Gfx getGeoMaxInitialVelocity();
+
+ /* rt interface functions */
+ unsigned int getIsoVertexCount() { return mpIso->getIsoVertexCount(); }
+ unsigned int getIsoIndexCount() { return mpIso->getIsoIndexCount(); }
+ char* getIsoVertexArray() { return mpIso->getIsoVertexArray(); }
+ unsigned int *getIsoIndexArray() { return mpIso->getIsoIndexArray(); }
+ void triangulateSurface() { return mpIso->triangulate(); }
+ // drop stuff
+ //virtual void addDrop(bool active, float mx, float my) = 0;
+ //! avg. used cell count stats
+ //virtual void printCellStats() = 0;
+ //! check end time for gfx ani
+ //virtual int checkGfxEndTime() = 0;
+ //virtual int getGfxGeoSetup() = 0;
+
+ /* access functions */
+
+ /*! return grid sizes */
+ int getSizeX( void ) { return mSizex; }
+ int getSizeY( void ) { return mSizey; }
+ int getSizeZ( void ) { return mSizez; }
+ /*! return grid sizes */
+ void setSizeX( int ns ) { mSizex = ns; }
+ void setSizeY( int ns ) { mSizey = ns; }
+ void setSizeZ( int ns ) { mSizez = ns; }
+
+ /*! set attr list pointer */
+ void setAttrList(AttributeList *set) { mpAttrs = set; }
+ /*! Returns the attribute list pointer */
+ inline AttributeList *getAttributeList() { return mpAttrs; }
+
+ /*! set parametrizer pointer */
+ inline void setParametrizer(Parametrizer *set) { mpParam = set; }
+ /*! get parametrizer pointer */
+ inline Parametrizer *getParametrizer() { return mpParam; }
+
+ /*! set density gradient init from e.g. init test cases */
+ inline void setInitDensityGradient(bool set) { mInitDensityGradient = set; }
+
+ /*! access geometry start vector */
+ inline void setGeoStart(ntlVec3Gfx set) { mvGeoStart = set; }
+ inline ntlVec3Gfx getGeoStart() const { return mvGeoStart; }
+
+ /*! access geometry end vector */
+ inline void setGeoEnd(ntlVec3Gfx set) { mvGeoEnd = set; }
+ inline ntlVec3Gfx getGeoEnd() const { return mvGeoEnd; }
+
+ /*! access name string */
+ inline void setName(string set) { mName = set; }
+ inline string getName() const { return mName; }
+
+ /*! access string for node info debugging output */
+ inline string getNodeInfoString() const { return mNodeInfoString; }
+
+ /*! get panic flag */
+ inline bool getPanic() { return mPanic; }
+
+ //! set silent mode?
+ inline void setSilent(bool set){ mSilent = set; }
+
+
+ // cell iterator interface
+
+ // cell id type
+ typedef CellIdentifierInterface* CellIdentifier;
+
+ //! cell iteration methods
+ virtual CellIdentifierInterface* getFirstCell( ) = 0;
+ virtual void advanceCell( CellIdentifierInterface* ) = 0;
+ virtual bool noEndCell( CellIdentifierInterface* ) = 0;
+ //! clean up iteration, this should be called, when the iteration is not completely finished
+ virtual void deleteCellIterator( CellIdentifierInterface** ) = 0;
+
+ //! find cell at a given position (returns NULL if not in domain)
+ virtual CellIdentifierInterface* getCellAt( ntlVec3Gfx pos ) = 0;
+
+ //! return node information
+ virtual int getCellSet ( CellIdentifierInterface* ) = 0;
+ virtual ntlVec3Gfx getCellOrigin ( CellIdentifierInterface* ) = 0;
+ virtual ntlVec3Gfx getCellSize ( CellIdentifierInterface* ) = 0;
+ virtual int getCellLevel ( CellIdentifierInterface* ) = 0;
+ virtual LbmFloat getCellDensity ( CellIdentifierInterface*,int ) = 0;
+ virtual LbmVec getCellVelocity ( CellIdentifierInterface*,int ) = 0;
+ /*! get equilibrium distribution functions */
+ virtual LbmFloat getEquilDf ( int ) = 0;
+ /*! get number of distribution functions */
+ virtual int getDfNum ( ) = 0;
+ /*! redundant cell functions */
+ virtual LbmFloat getCellDf ( CellIdentifierInterface* ,int set, int dir) = 0;
+ virtual LbmFloat getCellMass ( CellIdentifierInterface* ,int set) = 0;
+ virtual LbmFloat getCellFill ( CellIdentifierInterface* ,int set) = 0;
+ virtual CellFlagType getCellFlag ( CellIdentifierInterface* ,int set) = 0;
+
+
+ // debugging cell marker functions
+
+ //! add cell to mMarkedCells list
+ void addCellToMarkedList( CellIdentifierInterface *cid );
+ //! marked cell iteration methods
+ CellIdentifierInterface* markedGetFirstCell( );
+ void markedAdvanceCell( CellIdentifierInterface* pcid );
+ bool markedNoEndCell( CellIdentifierInterface* cid );
+ void markedClearList();
+
+#ifndef LBMDIM
+ LBMDIM has to be defined
+#endif
+#if LBMDIM==2
+ //! minimal and maximal z-coords (for 2D/3D loops) , this is always 0-1 for 2D
+ int getForZMinBnd() { return 0; };
+ int getForZMaxBnd() { return 1; };
+ int getForZMin1() { return 0; };
+ int getForZMax1() { return 1; };
+#else // LBMDIM==2
+ //! minimal and maximal z-coords (for 2D/3D loops)
+ int getForZMinBnd() { return 0; };
+ int getForZMaxBnd() { return getSizeZ()-0; };
+ int getForZMin1() { return 1; };
+ int getForZMax1() { return getSizeZ()-1; };
+#endif // LBMDIM==2
+
+
+ protected:
+
+ /*! abort simulation on error... */
+ bool mPanic;
+
+
+ /*! Size of the array in x,y,z direction */
+ int mSizex, mSizey, mSizez;
+
+
+ /*! step counter */
+ int mStepCnt;
+
+ /*! mass change from one step to the next, for extreme cases fix globally */
+ LbmFloat mFixMass;
+
+ // deprecated param vars
+ /*! omega for lbm */
+ LbmFloat mOmega;
+ /*! gravity strength in neg. z direction */
+ LbmVec mGravity;
+ /*! Surface tension of the fluid */
+ LbmFloat mSurfaceTension;
+
+
+ /*! initial mass to display changes */
+ LbmFloat mInitialMass;
+ /* boundary inits */
+ CellFlagType mBoundaryEast, mBoundaryWest,
+ mBoundaryNorth, mBoundarySouth,
+ mBoundaryTop, mBoundaryBottom;
+
+ /*! initialization from config file done? */
+ int mInitDone;
+
+ /*! init density gradient? */
+ bool mInitDensityGradient;
+
+ /*! pointer to the attribute list */
+ AttributeList *mpAttrs;
+
+ /*! get parameters from this parametrize in finishInit */
+ Parametrizer *mpParam;
+
+ /*! number of particles lost so far */
+ int mNumParticlesLost;
+ /*! number of particles lost so far */
+ int mNumInvalidDfs;
+ /*! no of filled/emptied cells per time step */
+ int mNumFilledCells, mNumEmptiedCells;
+ /*! counter number of used cells for performance */
+ int mNumUsedCells;
+ /*! MLSUPS counter */
+ LbmFloat mMLSUPS;
+ /*! debug - velocity output scaling factor */
+ LbmFloat mDebugVelScale;
+ /*! string for node info debugging output */
+ string mNodeInfoString;
+
+
+ /*! an own random stream */
+ ntlRandomStream mRandom;
+
+
+ // geo init vars
+ // TODO deprecate SimulationObject vars
+
+ /*! for display - start and end vectors for geometry */
+ ntlVec3Gfx mvGeoStart, mvGeoEnd;
+
+ /*! perform geometry init? */
+ bool mPerformGeoInit;
+ /*! perform accurate geometry init? */
+ bool mAccurateGeoinit;
+
+ /*! name of this lbm object (for debug output) */
+ string mName;
+
+ //! Mcubes object for surface reconstruction
+ IsoSurface *mpIso;
+ /*! isolevel value for marching cubes surface reconstruction */
+ LbmFloat mIsoValue;
+
+ //! debug output?
+ bool mSilent;
+
+ /*! geometry init id */
+ int mGeoInitId;
+ /*! tree object for geomerty initialization */
+ ntlTree *mpGiTree;
+ /*! object vector for geo init */
+ vector<ntlGeometryObject*> *mpGiObjects;
+ /*! inside which objects? */
+ vector<int> mGiObjInside;
+ /*! inside which objects? */
+ vector<gfxReal> mGiObjDistance;
+ /*! remember globals */
+ ntlRenderGlobals *mpGlob;
+
+ // list for marked cells
+ std::vector<CellIdentifierInterface *> mMarkedCells;
+};
+
+
+//! helper function to convert flag to string (for debuggin)
+std::string convertCellFlagType2String( CellFlagType flag );
+std::string convertSingleFlag2String(CellFlagType cflag);
+
+#endif // LBMINTERFACE_H
diff --git a/intern/elbeem/intern/mcubes_tables.h b/intern/elbeem/intern/mcubes_tables.h
new file mode 100644
index 00000000000..48f9768b9d8
--- /dev/null
+++ b/intern/elbeem/intern/mcubes_tables.h
@@ -0,0 +1,298 @@
+
+/* which edges are needed ? */
+/* cf. http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/ */
+static const short mcEdgeTable[256]={
+ 0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
+ 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
+ 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
+ 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
+ 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c,
+ 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
+ 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac,
+ 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
+ 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c,
+ 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
+ 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc,
+ 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
+ 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c,
+ 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
+ 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc ,
+ 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
+ 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
+ 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
+ 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
+ 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
+ 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
+ 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
+ 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
+ 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
+ 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
+ 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
+ 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
+ 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
+ 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
+ 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
+ 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
+ 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 };
+
+/* triangles for the 256 intersection possibilities */
+/* cf. http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/ */
+static const short mcTriTable[256][16] = {
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
+ {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
+ {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
+ {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
+ {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
+ {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
+ {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
+ {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
+ {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
+ {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
+ {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
+ {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
+ {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
+ {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
+ {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
+ {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
+ {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
+ {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
+ {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
+ {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
+ {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
+ {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
+ {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
+ {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
+ {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
+ {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
+ {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
+ {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
+ {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
+ {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
+ {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
+ {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
+ {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
+ {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
+ {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
+ {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
+ {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
+ {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
+ {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
+ {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
+ {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
+ {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
+ {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
+ {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
+ {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
+ {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
+ {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
+ {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
+ {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
+ {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
+ {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
+ {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
+ {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
+ {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
+ {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
+ {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
+ {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
+ {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
+ {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
+ {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
+ {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
+ {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
+ {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
+ {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
+ {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
+ {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
+ {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
+ {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
+ {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
+ {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
+ {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
+ {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
+ {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
+ {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
+ {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
+ {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
+ {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
+ {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
+ {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
+ {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
+ {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
+ {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
+ {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
+ {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
+ {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
+ {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
+ {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
+ {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
+ {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
+ {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
+ {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
+ {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
+ {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
+ {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
+ {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
+ {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
+ {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
+ {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
+ {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
+ {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
+ {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
+ {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
+ {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
+ {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
+ {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
+ {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
+ {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
+ {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
+ {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
+ {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
+ {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
+ {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
+ {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
+ {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
+ {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
+ {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
+ {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
+ {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
+ {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
+ {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
+ {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
+ {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
+ {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
+ {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
+ {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
+ {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
+ {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
+ {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
+ {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
+ {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
+ {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
+ {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
+ {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
+ {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
+ {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
+ {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
+ {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
+ {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
+ {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
+ {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
+ {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
+ {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
+ {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
+ {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
+ {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
+ {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
+ {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
+ {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
+ {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
+ {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
+ {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
+ {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
+ {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
+ {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
+ {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
+ {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
+ {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
+ {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
+ {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
+ {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
+ {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
+ {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
+ {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
+ {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
+ {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 3, 8, -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}
+};
+
diff --git a/intern/elbeem/intern/ntl_blenderdumper.cpp b/intern/elbeem/intern/ntl_blenderdumper.cpp
new file mode 100644
index 00000000000..535a13c214a
--- /dev/null
+++ b/intern/elbeem/intern/ntl_blenderdumper.cpp
@@ -0,0 +1,216 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Replaces std. raytracer, and only dumps time dep. objects to disc
+ *
+ *****************************************************************************/
+
+
+#include <fstream>
+#include <sys/types.h>
+
+#include "utilities.h"
+#include "ntl_matrices.h"
+#include "ntl_blenderdumper.h"
+#include "ntl_scene.h"
+
+#include <zlib.h>
+
+
+
+/******************************************************************************
+ * Constructor
+ *****************************************************************************/
+ntlBlenderDumper::ntlBlenderDumper(string filename, bool commandlineMode) :
+ ntlRaytracer(filename,commandlineMode),
+ mpTrafo(NULL)
+{
+ ntlRenderGlobals *glob = mpGlob;
+ AttributeList *pAttrs = glob->getBlenderAttributes();
+ mpTrafo = new ntlMat4Gfx(0.0);
+ mpTrafo->initId();
+ (*mpTrafo) = pAttrs->readMat4Gfx("transform" , (*mpTrafo), "ntlBlenderDumper","mpTrafo", false );
+
+ //for(int i=0; i<4;i++) { for(int j=0; j<4;j++) { errMsg("T"," "<<i<<","<<j<<" "<<mpTrafo->value[i][j]); } } // DEBUG
+}
+
+
+
+/******************************************************************************
+ * Destructor
+ *****************************************************************************/
+ntlBlenderDumper::~ntlBlenderDumper()
+{
+ delete mpTrafo;
+}
+
+/******************************************************************************
+ * Only dump time dep. objects to file
+ *****************************************************************************/
+int ntlBlenderDumper::renderScene( void )
+{
+ char nrStr[5]; /* nr conversion */
+ ntlRenderGlobals *glob = mpGlob;
+ ntlScene *scene = mpGlob->getScene();
+ bool debugOut = true;
+ bool otherOut = true;
+#if ELBEEM_BLENDER==1
+ debugOut = false;
+ otherOut = false;
+#endif // ELBEEM_BLENDER==1
+
+ // output path
+ /*std::ostringstream ecrpath("");
+ ecrpath << "/tmp/ecr_" << getpid() <<"/";
+ // make sure the dir exists
+ std::ostringstream ecrpath_create("");
+ ecrpath_create << "mkdir " << ecrpath.str();
+ system( ecrpath_create.str().c_str() );
+ // */
+
+ vector<string> hideObjs; // geom shaders to hide
+ vector<string> gmName; // gm names
+ vector<string> gmMat; // materials for gm
+ int numGMs = 0; // no. of .obj models created
+
+ if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_NOTIFY,"Dumping geometry data", 1);
+ long startTime = getTime();
+
+ /* check if picture already exists... */
+ snprintf(nrStr, 5, "%04d", glob->getAniCount() );
+
+ // local scene vars
+ vector<ntlTriangle> Triangles;
+ vector<ntlVec3Gfx> Vertices;
+ vector<ntlVec3Gfx> VertNormals;
+
+ /* init geometry array, first all standard objects */
+ int idCnt = 0; // give IDs to objects
+ for (vector<ntlGeometryClass*>::iterator iter = scene->getGeoClasses()->begin();
+ iter != scene->getGeoClasses()->end(); iter++) {
+ if(!(*iter)->getVisible()) continue;
+ int tid = (*iter)->getTypeId();
+
+ if(tid & GEOCLASSTID_OBJECT) {
+ // normal geom. objects dont change... -> ignore
+ //if(buildInfo) debMsgStd("ntlBlenderDumper::BuildScene",DM_MSG,"added GeoObj "<<geoobj->getName(), 8 );
+ }
+ if(tid & GEOCLASSTID_SHADER) {
+ ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter); //dynamic_cast<ntlGeometryShader*>(*iter);
+ hideObjs.push_back( (*iter)->getName() );
+ for (vector<ntlGeometryObject*>::iterator siter = geoshad->getObjectsBegin();
+ siter != geoshad->getObjectsEnd();
+ siter++) {
+ if(debugOut) debMsgStd("ntlBlenderDumper::BuildScene",DM_MSG,"added shader geometry "<<(*siter)->getName(), 8);
+
+ // only dump geo shader objects
+ Triangles.clear();
+ Vertices.clear();
+ VertNormals.clear();
+ (*siter)->initialize( mpGlob );
+ (*siter)->getTriangles(&Triangles, &Vertices, &VertNormals, idCnt);
+ idCnt ++;
+
+ // always dump mesh, even empty ones...
+ //if(Vertices.size() <= 0) continue;
+ //if(Triangles.size() <= 0) continue;
+
+ for(size_t i=0; i<Vertices.size(); i++) {
+ Vertices[i] = (*mpTrafo) * Vertices[i];
+ }
+
+ // dump to binary file
+ std::ostringstream boutfilename("");
+ //boutfilename << ecrpath.str() << glob->getOutFilename() <<"_"<< (*siter)->getName() <<"_" << nrStr << ".obj";
+ boutfilename << glob->getOutFilename() <<"_"<< (*siter)->getName() <<"_" << nrStr << ".bobj";
+ if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"B-Dumping: "<< (*siter)->getName()
+ <<", triangles:"<<Triangles.size()<<", vertices:"<<Vertices.size()<<
+ " to "<<boutfilename.str() , 7);
+ bool isPreview = false;
+ if( (*siter)->getName().find( "preview" ) != string::npos) {
+ isPreview = true;
+ }
+ boutfilename << ".gz";
+
+ // compress all bobj's except for preview ones...
+ gzFile gzf;
+ if(isPreview) {
+ gzf = gzopen(boutfilename.str().c_str(), "wb1");
+ } else {
+ gzf = gzopen(boutfilename.str().c_str(), "wb9");
+ }
+ if (!gzf) {
+ errMsg("ntlBlenderDumper::renderScene","Unable to open output '"<<boutfilename<<"' ");
+ return 1; }
+
+ int wri;
+ float wrf;
+ if(sizeof(wri)!=4) { errMsg("ntlBlenderDumper::renderScene","Invalid int size"); return 1; }
+ wri = Vertices.size();
+ gzwrite(gzf, &wri, sizeof(wri));
+ for(size_t i=0; i<Vertices.size(); i++) {
+ for(int j=0; j<3; j++) {
+ wrf = Vertices[i][j];
+ gzwrite(gzf, &wrf, sizeof(wrf)); }
+ }
+
+ // should be the same as Vertices.size
+ wri = VertNormals.size();
+ gzwrite(gzf, &wri, sizeof(wri));
+ for(size_t i=0; i<VertNormals.size(); i++) {
+ for(int j=0; j<3; j++) {
+ wrf = VertNormals[i][j];
+ gzwrite(gzf, &wrf, sizeof(wrf)); }
+ }
+
+ wri = Triangles.size();
+ gzwrite(gzf, &wri, sizeof(wri));
+ for(size_t i=0; i<Triangles.size(); i++) {
+ for(int j=0; j<3; j++) {
+ wri = Triangles[i].getPoints()[j];
+ gzwrite(gzf, &wri, sizeof(wri)); }
+ }
+ gzclose( gzf );
+ if(otherOut)
+ debMsgDirect(" Wrote: '"<<boutfilename.str()<<"'. ");
+ numGMs++;
+ }
+ }
+
+ }
+
+ // output ecr config file
+ if(numGMs>0) {
+ if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"Objects dumped: "<<numGMs, 10);
+ } else {
+ errMsg("ntlBlenderDumper::renderScene","No objects to dump! Aborting...");
+#if ELBEEM_BLENDER==1
+ // TODO ... D::mPanic=1;
+ return 1;
+#else // ELBEEM_BLENDER==1
+ exit(1);
+#endif // ELBEEM_BLENDER==1
+ }
+
+ /* next frame */
+ //glob->setAniCount( glob->getAniCount() +1 );
+ long stopTime = getTime();
+ if(debugOut)
+ debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"Scene #"<<nrStr<<" dump time: "<< getTimeString(stopTime-startTime) <<" ", 10);
+
+ // still render for preview...
+ if(debugOut) {
+ debMsgStd("ntlBlenderDumper::renderScene",DM_NOTIFY,"Performing preliminary render", 1);
+ ntlRaytracer::renderScene(); }
+ else {
+ // next frame
+ glob->setAniCount( glob->getAniCount() +1 );
+ }
+
+ return 0;
+}
+
+
+
diff --git a/intern/elbeem/intern/ntl_blenderdumper.h b/intern/elbeem/intern/ntl_blenderdumper.h
new file mode 100644
index 00000000000..0178feff145
--- /dev/null
+++ b/intern/elbeem/intern/ntl_blenderdumper.h
@@ -0,0 +1,34 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Replaces std. raytracer, and only dumps time dep. objects to disc, header
+ *
+ *****************************************************************************/
+#ifndef NTL_BLENDERDUMPER_H
+#include "ntl_raytracer.h"
+
+template<class Scalar> class ntlMatrix4x4;
+
+class ntlBlenderDumper :
+ public ntlRaytracer
+{
+public:
+ /*! Constructor */
+ ntlBlenderDumper(string filename, bool commandlineMode);
+ /*! Destructor */
+ virtual ~ntlBlenderDumper( void );
+
+ /*! render scene (a single pictures) */
+ virtual int renderScene( void );
+
+protected:
+
+ //! transform matrix
+ ntlMatrix4x4<gfxReal> *mpTrafo;
+};
+
+#define NTL_BLENDERDUMPER_H
+#endif
+
diff --git a/intern/elbeem/intern/ntl_bsptree.cpp b/intern/elbeem/intern/ntl_bsptree.cpp
new file mode 100644
index 00000000000..d9c1539f7b8
--- /dev/null
+++ b/intern/elbeem/intern/ntl_bsptree.cpp
@@ -0,0 +1,668 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Tree container for fast triangle intersects
+ *
+ *****************************************************************************/
+
+
+#include "ntl_bsptree.h"
+#include "ntl_scene.h"
+#include "utilities.h"
+
+#include <algorithm>
+
+/*! Static global variable for sorting direction */
+int globalSortingAxis;
+/*! Access to points array for sorting */
+vector<ntlVec3Gfx> *globalSortingPoints;
+
+#define TREE_DOUBLEI 300
+
+/* try axis selection? */
+bool chooseAxis = 0;
+/* do median search? */
+int doSort = 0;
+
+
+//! struct for a single node in the bsp tree
+class BSPNode {
+ public:
+ ntlVec3Gfx min,max; /* AABB for node */
+ vector<ntlTriangle *> *members; /* stored triangles */
+ BSPNode *child[2]; /* pointer to children nodes */
+ char axis; /* division axis */
+ char cloneVec; /* is this vector a clone? */
+
+ //! check if node is a leaf
+ inline bool isLeaf() const {
+ return (child[0] == NULL);
+ }
+};
+
+
+//! an element node stack
+class BSPStackElement {
+ public:
+ //! tree node
+ BSPNode *node;
+ //! min and maximum distance along axis
+ gfxReal mindist, maxdist;
+};
+
+//! bsp tree stack
+class BSPStack {
+ public:
+ //! current stack element
+ int stackPtr;
+ //! stack storage
+ BSPStackElement elem[ BSP_STACK_SIZE ];
+};
+
+//! triangle bounding box for quick tree subdivision
+class TriangleBBox {
+ public:
+ //! start and end of triangle bounding box
+ ntlVec3Gfx start, end;
+};
+
+
+/******************************************************************************
+ * calculate tree statistics
+ *****************************************************************************/
+void calcStats(BSPNode *node, int depth, int &noLeafs, gfxReal &avgDepth, gfxReal &triPerLeaf,int &totalTris)
+{
+ if(node->members != NULL) {
+ totalTris += node->members->size();
+ }
+ //depth = 15; // DBEUG!
+
+ if( (node->child[0]==NULL) && (node->child[1]==NULL) ) {
+ // leaf
+ noLeafs++;
+ avgDepth += depth;
+ triPerLeaf += node->members->size();
+ } else {
+ for(int i=0;i<2;i++)
+ calcStats(node->child[i], depth+1, noLeafs, avgDepth, triPerLeaf, totalTris);
+ }
+}
+
+
+
+/******************************************************************************
+ * triangle comparison function for median search
+ *****************************************************************************/
+bool lessTriangleAverage(const ntlTriangle *x, const ntlTriangle *y)
+{
+ return x->getAverage(globalSortingAxis) < y->getAverage(globalSortingAxis);
+}
+
+
+/******************************************************************************
+ * triangle AABB intersection
+ *****************************************************************************/
+bool ntlTree::checkAABBTriangle(ntlVec3Gfx &min, ntlVec3Gfx &max, ntlTriangle *tri)
+{
+ // test only BB of triangle
+ TriangleBBox *bbox = &mpTBB[ tri->getBBoxId() ];
+ if( bbox->end[0] < min[0] ) return false;
+ if( bbox->start[0] > max[0] ) return false;
+ if( bbox->end[1] < min[1] ) return false;
+ if( bbox->start[1] > max[1] ) return false;
+ if( bbox->end[2] < min[2] ) return false;
+ if( bbox->start[2] > max[2] ) return false;
+ return true;
+}
+
+
+
+
+
+
+
+/******************************************************************************
+ * Default constructor
+ *****************************************************************************/
+ntlTree::ntlTree() :
+ mStart(0.0), mEnd(0.0), mMaxDepth( 5 ), mMaxListLength( 5 ), mpRoot( NULL) ,
+ mpNodeStack( NULL), mpVertices( NULL ), mpVertNormals( NULL ), mpTriangles( NULL ),
+ mCurrentDepth(0), mCurrentNodes(0), mTriDoubles(0)
+{
+ errorOut( "ntlTree Cons: Uninitialized BSP Tree!\n" );
+ exit(1);
+}
+
+
+/******************************************************************************
+ * Constructor with init
+ *****************************************************************************/
+//ntlTree::ntlTree(int depth, int objnum, vector<ntlVec3Gfx> *vertices, vector<ntlVec3Gfx> *normals, vector<ntlTriangle> *trilist) :
+ntlTree::ntlTree(int depth, int objnum, ntlScene *scene, int triFlagMask) :
+ mStart(0.0), mEnd(0.0), mMaxDepth( depth ), mMaxListLength( objnum ), mpRoot( NULL) ,
+ mpNodeStack( NULL), mpTBB( NULL ),
+ mTriangleMask( 0xFFFF ),
+ mCurrentDepth(0), mCurrentNodes(0)
+{
+ // init scene data pointers
+ mpVertices = scene->getVertexPointer();
+ mpVertNormals = scene->getVertexNormalPointer();
+ mpTriangles = scene->getTrianglePointer();
+ mTriangleMask = triFlagMask;
+
+ if(mpTriangles == NULL) {
+ errorOut( "ntlTree Cons: no triangle list!\n");
+ exit(1);
+ }
+ if(mpTriangles->size() == 0) {
+ warnMsg( "ntlTree::ntlTree","No triangles ("<< mpTriangles->size() <<")!\n");
+ mStart = mEnd = ntlVec3Gfx(0,0,0);
+ return;
+ }
+ if(depth>=BSP_STACK_SIZE) {
+ errMsg( "ntlTree::ntlTree","Depth to high ("<< mMaxDepth <<")!\n" );
+ exit(1);
+ }
+
+ /* check triangles (a bit inefficient, but we dont know which vertices belong
+ to this tree), and generate bounding boxes */
+ mppTriangles = new vector<ntlTriangle *>;
+ int noOfTriangles = mpTriangles->size();
+ mpTBB = new TriangleBBox[ noOfTriangles ];
+ int bbCount = 0;
+ mStart = mEnd = (*mpVertices)[ mpTriangles->front().getPoints()[0] ];
+ for (vector<ntlTriangle>::iterator iter = mpTriangles->begin();
+ iter != mpTriangles->end();
+ iter++ ) {
+ // discard triangles that dont match mask
+ //errorOut(" d "<<(int)(*iter).getFlags() <<" "<< (int)mTriangleMask );
+ if( ((int)(*iter).getFlags() & (int)mTriangleMask) == 0 ) {
+ continue;
+ }
+
+ // test? TODO
+ ntlVec3Gfx tnormal = (*mpVertNormals)[ (*iter).getPoints()[0] ]+
+ (*mpVertNormals)[ (*iter).getPoints()[1] ]+
+ (*mpVertNormals)[ (*iter).getPoints()[2] ];
+ ntlVec3Gfx triangleNormal = (*iter).getNormal();
+ if( equal(triangleNormal, ntlVec3Gfx(0.0)) ) continue;
+ if( equal( tnormal, ntlVec3Gfx(0.0)) ) continue;
+ // */
+
+ ntlVec3Gfx bbs, bbe;
+ for(int i=0;i<3;i++) {
+ int index = (*iter).getPoints()[i];
+ ntlVec3Gfx tp = (*mpVertices)[ index ];
+ if(tp[0] < mStart[0]) mStart[0]= tp[0];
+ if(tp[0] > mEnd[0]) mEnd[0]= tp[0];
+ if(tp[1] < mStart[1]) mStart[1]= tp[1];
+ if(tp[1] > mEnd[1]) mEnd[1]= tp[1];
+ if(tp[2] < mStart[2]) mStart[2]= tp[2];
+ if(tp[2] > mEnd[2]) mEnd[2]= tp[2];
+ if(i==0) {
+ bbs = bbe = tp;
+ } else {
+ if( tp[0] < bbs[0] ) bbs[0] = tp[0];
+ if( tp[0] > bbe[0] ) bbe[0] = tp[0];
+ if( tp[1] < bbs[1] ) bbs[1] = tp[1];
+ if( tp[1] > bbe[1] ) bbe[1] = tp[1];
+ if( tp[2] < bbs[2] ) bbs[2] = tp[2];
+ if( tp[2] > bbe[2] ) bbe[2] = tp[2];
+ }
+ }
+ mppTriangles->push_back( &(*iter) );
+
+ // add BB
+ mpTBB[ bbCount ].start = bbs;
+ mpTBB[ bbCount ].end = bbe;
+ (*iter).setBBoxId( bbCount );
+ bbCount++;
+ }
+
+
+
+ /* slighlty enlarge bounding tolerance for tree
+ to avoid problems with triangles paralell to slabs */
+ mStart -= ntlVec3Gfx( getVecEpsilon() );
+ mEnd += ntlVec3Gfx( getVecEpsilon() );
+
+ /* init root node and stack */
+ mpNodeStack = new BSPStack;
+ mpRoot = new BSPNode;
+ mpRoot->min = mStart;
+ mpRoot->max = mEnd;
+ mpRoot->axis = AXIS_X;
+ mpRoot->members = mppTriangles;
+ mpRoot->child[0] = mpRoot->child[1] = NULL;
+ mpRoot->cloneVec = 0;
+ globalSortingPoints = mpVertices;
+ mpTriDist = new char[ mppTriangles->size() ];
+
+ /* create tree */
+ debugOutInter( "Generating BSP Tree... (Nodes "<< mCurrentNodes <<
+ ", Depth "<<mCurrentDepth<< ") ", 2, 2000 );
+ subdivide(mpRoot, 0, AXIS_X);
+ debMsgStd("ntlTree::ntlTree",DM_MSG,"Generated Tree: Nodes "<< mCurrentNodes <<
+ ", Depth "<<mCurrentDepth<< " with "<<noOfTriangles<<" triangles", 2 );
+
+ delete [] mpTriDist;
+ delete [] mpTBB;
+ mpTriDist = NULL;
+ mpTBB = NULL;
+
+ /* calculate some stats about tree */
+ int noLeafs = 0;
+ gfxReal avgDepth = 0.0;
+ gfxReal triPerLeaf = 0.0;
+ int totalTris = 0;
+
+ calcStats(mpRoot,0, noLeafs, avgDepth, triPerLeaf, totalTris);
+ avgDepth /= (gfxReal)noLeafs;
+ triPerLeaf /= (gfxReal)noLeafs;
+ debMsgStd("ntlTree::ntlTree",DM_MSG,"Tree ("<<doSort<<","<<chooseAxis<<") Stats: Leafs:"<<noLeafs<<", avgDepth:"<<avgDepth<<
+ ", triPerLeaf:"<<triPerLeaf<<", triDoubles:"<<mTriDoubles<<", totalTris:"<<totalTris
+ //<<" T"<< (totalTris%3) // 0=ich, 1=f, 2=a
+ , 2 );
+
+}
+
+/******************************************************************************
+ * Destructor
+ *****************************************************************************/
+ntlTree::~ntlTree()
+{
+ /* delete tree, and all members except for the root node */
+ deleteNode(mpRoot);
+ if(mpNodeStack) delete mpNodeStack;
+}
+
+
+/******************************************************************************
+ * subdivide tree
+ *****************************************************************************/
+void ntlTree::subdivide(BSPNode *node, int depth, int axis)
+{
+ int nextAxis; /* next axis to partition */
+ int allTriDistSet = (1<<0)|(1<<1); // all mpTriDist flags set?
+ //errorOut(" "<<node<<" depth:"<<depth<<" m:"<<node->members->size() <<" "<<node->min<<" - "<<node->max );
+
+ if(depth>mCurrentDepth) mCurrentDepth = depth;
+ node->child[0] = node->child[1] = NULL;
+ if( ( (int)node->members->size() > mMaxListLength) &&
+ (depth < mMaxDepth )
+ && (node->cloneVec<10)
+ ) {
+
+ gfxReal planeDiv = 0.499999; // position of plane division
+
+ // determine next subdivision axis
+ int newaxis = 0;
+ gfxReal extX = node->max[0]-node->min[0];
+ gfxReal extY = node->max[1]-node->min[1];
+ gfxReal extZ = node->max[2]-node->min[2];
+
+ if( extY>extX ) {
+ if( extZ>extY ) {
+ newaxis = 2;
+ } else {
+ newaxis = 1;
+ }
+ } else {
+ if( extZ>extX ) {
+ newaxis = 2;
+ } else {
+ newaxis = 0;
+ }
+ }
+ axis = node->axis = newaxis;
+
+ // init child nodes
+ for( int i=0; i<2; i++) {
+ /* status output */
+ mCurrentNodes++;
+ if(mCurrentNodes % 13973 ==0) {
+ debugOutInter( "NTL Generating BSP Tree ("<<doSort<<","<<chooseAxis<<") ... (Nodes "<< mCurrentNodes <<
+ ", Depth "<<mCurrentDepth<< ") " , 2, 2000);
+ }
+
+ /* create new node */
+ node->child[i] = new BSPNode;
+ node->child[i]->min = node->min;
+ node->child[i]->max = node->max;
+ node->child[i]->max = node->max;
+ node->child[i]->child[0] = NULL;
+ node->child[i]->child[1] = NULL;
+ node->child[i]->members = NULL;
+ nextAxis = (axis+1)%3;
+ node->child[i]->axis = nextAxis;
+
+ /* current division plane */
+ if(!i) {
+ node->child[i]->min[axis] = node->min[axis];
+ node->child[i]->max[axis] = node->min[axis] + planeDiv*
+ (node->max[axis]-node->min[axis]);
+ } else {
+ node->child[i]->min[axis] = node->min[axis] + planeDiv*
+ (node->max[axis]-node->min[axis]);
+ node->child[i]->max[axis] = node->max[axis];
+ }
+ }
+
+
+ /* process the two children */
+ int thisTrisFor[2] = {0,0};
+ int thisTriDoubles[2] = {0,0};
+ for(int t=0;t<(int)node->members->size();t++) mpTriDist[t] = 0;
+ for( int i=0; i<2; i++) {
+ /* distribute triangles */
+ int t = 0;
+ for (vector<ntlTriangle *>::iterator iter = node->members->begin();
+ iter != node->members->end(); iter++ ) {
+
+ /* add triangle, check bounding box axis */
+ TriangleBBox *bbox = &mpTBB[ (*iter)->getBBoxId() ];
+ bool intersect = true;
+ if( bbox->end[axis] < node->child[i]->min[axis] ) intersect = false;
+ else if( bbox->start[axis] > node->child[i]->max[axis] ) intersect = false;
+ if(intersect) {
+ // add flag to vector
+ mpTriDist[t] |= (1<<i);
+ // count no. of triangles for vector init
+ thisTrisFor[i]++;
+ }
+
+ if(mpTriDist[t] == allTriDistSet) {
+ thisTriDoubles[i]++;
+ mTriDoubles++; // TODO check for small geo tree??
+ }
+ t++;
+ } /* end of loop over all triangles */
+ } // i
+
+ /* distribute triangles */
+ bool haveCloneVec[2] = {false, false};
+ for( int i=0; i<2; i++) {
+ /*if(thisTriDoubles[i] == (int)node->members->size()) {
+ node->child[i]->members = node->members;
+ node->child[i]->cloneVec = (node->cloneVec+1);
+ haveCloneVec[i] = true;
+ } else */
+ {
+ node->child[i]->members = new vector<ntlTriangle *>( thisTrisFor[i] );
+ node->child[i]->cloneVec = 0;
+ }
+ }
+
+ int tind0 = 0;
+ int tind1 = 0;
+ if( (!haveCloneVec[0]) || (!haveCloneVec[1]) ){
+ int t = 0; // triangle index counter
+ for (vector<ntlTriangle *>::iterator iter = node->members->begin();
+ iter != node->members->end(); iter++ ) {
+ if(!haveCloneVec[0]) {
+ if( (mpTriDist[t] & 1) == 1) {
+ (*node->child[0]->members)[tind0] = (*iter); // dont use push_back for preinited size!
+ tind0++;
+ }
+ }
+ if(!haveCloneVec[1]) {
+ if( (mpTriDist[t] & 2) == 2) {
+ (*node->child[1]->members)[tind1] = (*iter); // dont use push_back for preinited size!
+ tind1++;
+ }
+ }
+
+ //if(depth>38) errorOut(" N d"<<depth<<" t"<<t<<" td"<<(int)mpTriDist[t]<<" S"<<(int)allTriDistSet);
+ t++;
+ } /* end of loop over all triangles */
+ }
+ //D errorOut( " MMM"<<i<<": "<<(unsigned int)(node->child[i]->members->size())<<" "<<thisTrisFor[i]<<" tind"<<tind[i] ); // DEBG!
+
+ // subdivide children
+ for( int i=0; i<2; i++) {
+ /* recurse */
+ subdivide( node->child[i], depth+1, nextAxis );
+ }
+
+ /* if we are here, this are childs, so we dont need the members any more... */
+ /* delete unecessary members */
+ if( (!haveCloneVec[0]) && (!haveCloneVec[1]) && (node->cloneVec == 0) ){ // ??? FIXME?
+ //if( (!haveCloneVec[0]) && (!haveCloneVec[1]) ){
+ delete node->members;
+ }
+ else {
+ errMsg("LLLLLLLL","ASD"); }
+ node->members = NULL;
+
+ } /* subdivision necessary */
+}
+
+/******************************************************************************
+ * intersect ray with BSPtree
+ *****************************************************************************/
+void ntlTree::intersect(const ntlRay &ray, gfxReal &distance,
+ ntlVec3Gfx &normal,
+ ntlTriangle *&tri,
+ int flags, bool forceNonsmooth) const
+{
+ gfxReal mint = GFX_REAL_MAX; /* current minimal t */
+ ntlVec3Gfx retnormal; /* intersection (interpolated) normal */
+ gfxReal mintu=0.0, mintv=0.0; /* u,v for min t intersection */
+
+ BSPNode *curr, *nearChild, *farChild; /* current node and children */
+ gfxReal planedist, mindist, maxdist;
+ ntlVec3Gfx pos;
+
+ ntlTriangle *hit = NULL;
+ tri = NULL;
+
+ ray.intersectCompleteAABB(mStart,mEnd,mindist,maxdist);
+
+ if((maxdist < 0.0) ||
+ (mindist == GFX_REAL_MAX) ||
+ (maxdist == GFX_REAL_MAX) ) {
+ distance = -1.0;
+ return;
+ }
+ mindist -= getVecEpsilon();
+ maxdist += getVecEpsilon();
+
+ /* stack init */
+ mpNodeStack->elem[0].node = NULL;
+ mpNodeStack->stackPtr = 1;
+
+ curr = mpRoot;
+ mint = GFX_REAL_MAX;
+ while(curr != NULL) {
+
+ while( !curr->isLeaf() ) {
+ planedist = distanceToPlane(curr, curr->child[0]->max, ray );
+ getChildren(curr, ray.getOrigin(), nearChild, farChild );
+
+ // check ray direction for small plane distances
+ if( (planedist>-getVecEpsilon() )&&(planedist< getVecEpsilon() ) ) {
+ // ray origin on intersection plane
+ planedist = 0.0;
+ if(ray.getDirection()[curr->axis]>getVecEpsilon() ) {
+ // larger coords
+ curr = curr->child[1];
+ } else if(ray.getDirection()[curr->axis]<-getVecEpsilon() ) {
+ // smaller coords
+ curr = curr->child[0];
+ } else {
+ // paralell, order doesnt really matter are min/max/plane ok?
+ mpNodeStack->elem[ mpNodeStack->stackPtr ].node = curr->child[0];
+ mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist;
+ mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist;
+ (mpNodeStack->stackPtr)++;
+ curr = curr->child[1];
+ maxdist = planedist;
+ }
+ } else {
+ // normal ray
+ if( (planedist>maxdist) || (planedist<0.0-getVecEpsilon() ) ) {
+ curr = nearChild;
+ } else if(planedist < mindist) {
+ curr = farChild;
+ } else {
+ mpNodeStack->elem[ mpNodeStack->stackPtr ].node = farChild;
+ mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist;
+ mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist;
+ (mpNodeStack->stackPtr)++;
+
+ curr = nearChild;
+ maxdist = planedist;
+ }
+ }
+ }
+
+
+ /* intersect with current node */
+ for (vector<ntlTriangle *>::iterator iter = curr->members->begin();
+ iter != curr->members->end(); iter++ ) {
+
+ /* check for triangle flags before intersecting */
+ if((!flags) || ( ((*iter)->getFlags() & flags) > 0 )) {
+
+ if( ((*iter)->getLastRay() == ray.getID() )&&((*iter)->getLastRay()>0) ) {
+ // was already intersected...
+ } else {
+ // we still need to intersect this triangle
+ gfxReal u=0.0,v=0.0, t=-1.0;
+ ray.intersectTriangle( mpVertices, (*iter), t,u,v);
+ (*iter)->setLastRay( ray.getID() );
+
+ if( (t > 0.0) && (t<mint) ) {
+ mint = t;
+ hit = (*iter);
+ mintu = u; mintv = v;
+
+ if((ray.getRenderglobals())&&(ray.getRenderglobals()->getDebugOut() > 5)) { // DEBUG!!!
+ errorOut("Tree tri hit at "<<t<<","<<mint<<" triangle: "<<PRINT_TRIANGLE( (*hit), (*mpVertices) ) );
+ gfxReal u1=0.0,v1=0.0, t1=-1.0;
+ ray.intersectTriangle( mpVertices, hit, t1,u1,v1);
+ errorOut("Tree second test1 :"<<t1<<" u1:"<<u1<<" v1:"<<v1 );
+ if(t==GFX_REAL_MAX) errorOut( "Tree MAX t " );
+ //errorOut( mpVertices[ (*iter).getPoints()[0] ][0] );
+ }
+
+ //retnormal = -(e2-e0).crossProd(e1-e0); // DEBUG
+
+ }
+ }
+
+ } // flags check
+ }
+
+ /* check if intersection is valid */
+ if( (mint>0.0) && (mint < GFX_REAL_MAX) ) {
+ pos = ray.getOrigin() + ray.getDirection()*mint;
+
+ if( (pos[0] >= curr->min[0]) && (pos[0] <= curr->max[0]) &&
+ (pos[1] >= curr->min[1]) && (pos[1] <= curr->max[1]) &&
+ (pos[2] >= curr->min[2]) && (pos[2] <= curr->max[2]) )
+ {
+
+ if(forceNonsmooth) {
+ // calculate triangle normal
+ ntlVec3Gfx e0,e1,e2;
+ e0 = (*mpVertices)[ hit->getPoints()[0] ];
+ e1 = (*mpVertices)[ hit->getPoints()[1] ];
+ e2 = (*mpVertices)[ hit->getPoints()[2] ];
+ retnormal = cross( -(e2-e0), (e1-e0) );
+ } else {
+ // calculate interpolated normal
+ retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+
+ (*mpVertNormals)[ hit->getPoints()[1] ]*mintu +
+ (*mpVertNormals)[ hit->getPoints()[2] ]*mintv;
+ }
+ normalize(retnormal);
+ normal = retnormal;
+ distance = mint;
+ tri = hit;
+ return;
+ }
+ }
+
+ (mpNodeStack->stackPtr)--;
+ curr = mpNodeStack->elem[ mpNodeStack->stackPtr ].node;
+ mindist = mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist;
+ maxdist = mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist;
+ } /* traverse tree */
+
+ if(mint == GFX_REAL_MAX) {
+ distance = -1.0;
+ } else {
+ if((ray.getRenderglobals())&&(ray.getRenderglobals()->getDebugOut() > 5)) { // DEBUG!!!
+ errorOut("Intersection outside BV ");
+ }
+
+ // intersection outside the BSP bounding volumes might occur due to roundoff...
+ //retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+ (*mpVertNormals)[ hit->getPoints()[1] ]*mintu + (*mpVertNormals)[ hit->getPoints()[2] ]*mintv;
+ if(forceNonsmooth) {
+ // calculate triangle normal
+ ntlVec3Gfx e0,e1,e2;
+ e0 = (*mpVertices)[ hit->getPoints()[0] ];
+ e1 = (*mpVertices)[ hit->getPoints()[1] ];
+ e2 = (*mpVertices)[ hit->getPoints()[2] ];
+ retnormal = cross( -(e2-e0), (e1-e0) );
+ } else {
+ // calculate interpolated normal
+ retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+
+ (*mpVertNormals)[ hit->getPoints()[1] ]*mintu +
+ (*mpVertNormals)[ hit->getPoints()[2] ]*mintv;
+ }
+
+ normalize(retnormal);
+ normal = retnormal;
+ distance = mint;
+ tri = hit;
+ }
+ return;
+}
+
+
+/******************************************************************************
+ * distance to plane function for nodes
+ *****************************************************************************/
+gfxReal ntlTree::distanceToPlane(BSPNode *curr, ntlVec3Gfx plane, ntlRay ray) const
+{
+ return ( (plane[curr->axis]-ray.getOrigin()[curr->axis]) / ray.getDirection()[curr->axis] );
+}
+
+
+/******************************************************************************
+ * return ordering of children nodes relatice to origin point
+ *****************************************************************************/
+void ntlTree::getChildren(BSPNode *curr, ntlVec3Gfx origin, BSPNode *&near, BSPNode *&far) const
+{
+ if(curr->child[0]->max[ curr->axis ] >= origin[ curr->axis ]) {
+ near = curr->child[0];
+ far = curr->child[1];
+ } else {
+ near = curr->child[1];
+ far = curr->child[0];
+ }
+}
+
+
+/******************************************************************************
+ * delete a node of the tree with all sub nodes
+ * dont delete root members
+ *****************************************************************************/
+void ntlTree::deleteNode(BSPNode *curr)
+{
+ if(!curr) return;
+
+ if(curr->child[0] != NULL)
+ deleteNode(curr->child[0]);
+ if(curr->child[1] != NULL)
+ deleteNode(curr->child[1]);
+
+ if(curr->members != NULL) delete curr->members;
+ delete curr;
+}
+
+
diff --git a/intern/elbeem/intern/ntl_bsptree.h b/intern/elbeem/intern/ntl_bsptree.h
new file mode 100644
index 00000000000..396499838c4
--- /dev/null
+++ b/intern/elbeem/intern/ntl_bsptree.h
@@ -0,0 +1,121 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Tree container for fast triangle intersects
+ *
+ *****************************************************************************/
+
+
+#ifndef NTL_TREE_HH
+#define NTL_TREE_HH
+
+#include "ntl_vector3dim.h"
+#include "ntl_ray.h"
+#include "ntl_triangle.h"
+
+
+#define AXIS_X 0
+#define AXIS_Y 1
+#define AXIS_Z 2
+
+#define BSP_STACK_SIZE 50
+
+
+//! bsp tree stack classes, defined in ntl_bsptree.cpp,
+// detailed definition unnecesseary here
+class BSPNode;
+class BSPStackElement;
+class BSPStack;
+class TriangleBBox;
+
+
+//! Class for a bsp tree for triangles
+class ntlTree
+{
+ public:
+
+ //! Default constructor
+ ntlTree();
+ //! Constructor with init
+ ntlTree(int depth, int objnum, ntlScene *scene, int triFlagMask);
+ //! Destructor
+ ~ntlTree();
+
+ //! subdivide tree
+ void subdivide(BSPNode *node, int depth, int axis);
+
+ //! intersect ray with BSPtree
+ void intersect(const ntlRay &ray, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri, int flags, bool forceNonsmooth) const;
+
+ //! Returns number of nodes
+ int getCurrentNodes( void ) { return mCurrentNodes; }
+
+ protected:
+
+ // check if a triangle is in a node
+ bool checkAABBTriangle(ntlVec3Gfx &min, ntlVec3Gfx &max, ntlTriangle *tri);
+
+
+ // VARs
+
+ //! distance to plane function for nodes
+ gfxReal distanceToPlane(BSPNode *curr, ntlVec3Gfx plane, ntlRay ray) const;
+
+ //! return ordering of children nodes relatice to origin point
+ void getChildren(BSPNode *curr, ntlVec3Gfx origin, BSPNode *&near, BSPNode *&far) const;
+
+ //! delete a node of the tree with all sub nodes, dont delete root members
+ void deleteNode(BSPNode *curr);
+
+ //inline bool isLeaf(BSPNode *node) const { return (node->child[0] == NULL); }
+
+
+ //! AABB for tree
+ ntlVec3Gfx mStart,mEnd;
+
+ //! maximum depth of tree
+ int mMaxDepth;
+
+ //! maximum number of objects in one node
+ int mMaxListLength;
+
+ //! root node pointer
+ BSPNode *mpRoot;
+
+ //! stack for the node pointers
+ BSPStack *mpNodeStack;
+ //stack<BSPNode *> nodestack;
+
+ //! pointer to vertex array
+ vector<ntlVec3Gfx> *mpVertices;
+
+ //! pointer to vertex array
+ vector<ntlVec3Gfx> *mpVertNormals;
+
+ //! vector for all the triangles
+ vector<ntlTriangle> *mpTriangles;
+ vector<ntlTriangle *> *mppTriangles;
+
+ //! temporary array for triangle distribution to nodes
+ char *mpTriDist;
+
+ //! temporary array for triangle bounding boxes
+ TriangleBBox *mpTBB;
+
+ //! triangle mask - include only triangles that match mask
+ int mTriangleMask;
+
+ //! Status vars (max depth, # of current nodes)
+ int mCurrentDepth, mCurrentNodes;
+
+ //! duplicated triangles, inited during subdivide
+ int mTriDoubles;
+
+};
+
+
+#endif
+
+
diff --git a/intern/elbeem/intern/ntl_geometrybox.cpp b/intern/elbeem/intern/ntl_geometrybox.cpp
new file mode 100644
index 00000000000..449e2801cde
--- /dev/null
+++ b/intern/elbeem/intern/ntl_geometrybox.cpp
@@ -0,0 +1,302 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * A simple box object
+ *
+ *****************************************************************************/
+
+#include "ntl_geometrybox.h"
+#include "ntl_ray.h"
+#include "ntl_scene.h"
+
+
+/******************************************************************************
+ * Default Constructor
+ *****************************************************************************/
+ntlGeometryBox::ntlGeometryBox( void ) :
+ ntlGeometryObject(),
+ mvStart( 0.0 ),
+ mvEnd( 1.0 ),
+ mRefinement(0)
+{
+}
+
+/******************************************************************************
+ * Init Constructor
+ *****************************************************************************/
+/*ntlGeometryBox::ntlGeometryBox( ntlVec3Gfx start, ntlVec3Gfx end ) :
+ ntlGeometryObject(),
+ mvStart( start ),
+ mvEnd( end ),
+ mRefinement(0)
+{
+}*/
+
+/*****************************************************************************/
+/* Init refinement attribute */
+/*****************************************************************************/
+void ntlGeometryBox::initialize(ntlRenderGlobals *glob) {
+ ntlGeometryObject::initialize(glob);
+ //READATTR(ntlGeometryBox, mRefinement, refine, Int, false);
+ mRefinement = mpAttrs->readInt("refine", mRefinement,"ntlGeometryBox", "mRefinement", false);
+
+ checkBoundingBox(mvStart,mvEnd, "ntlGeometryBox::initialize");
+}
+
+
+/******************************************************************************
+ *
+ *****************************************************************************/
+void
+ntlGeometryBox::getTriangles( vector<ntlTriangle> *triangles,
+ vector<ntlVec3Gfx> *vertices,
+ vector<ntlVec3Gfx> *normals, int objectId )
+{
+ int doBack = 1;
+ int doFront = 1;
+ int doTop = 1;
+ int doBottom = 1;
+ int doLeft = 1;
+ int doRight = 1;
+
+ /*int mRefinement = 0;
+ string refineAttr("refine");
+ if(mpAttrs->exists(refineAttr)) {
+ mRefinement = mpAttrs->find(refineAttr)->getAsInt();
+ //debugOut("GeoBox Ref set to '"<< mpAttrs->find(refineAttr)->getCompleteString() <<"' " , 3);
+ mpAttrs->find(refineAttr)->setUsed(true);
+ }*/
+
+ if(mRefinement==0) {
+ gfxReal s0 = mvStart[0];
+ gfxReal s1 = mvStart[1];
+ gfxReal s2 = mvStart[2];
+ gfxReal e0 = mvEnd[0];
+ gfxReal e1 = mvEnd[1];
+ gfxReal e2 = mvEnd[2];
+ ntlVec3Gfx p1,p2,p3;
+ ntlVec3Gfx n1,n2,n3;
+
+ /* front plane */
+ if(doFront) {
+ n1 = n2 = n3 = ntlVec3Gfx( 0.0, 0.0, -1.0 );
+ p1 = ntlVec3Gfx( s0, s1, s2 );
+ p3 = ntlVec3Gfx( e0, s1, s2 );
+ p2 = ntlVec3Gfx( s0, e1, s2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ p1 = ntlVec3Gfx( e0, e1, s2 );
+ p3 = ntlVec3Gfx( s0, e1, s2 );
+ p2 = ntlVec3Gfx( e0, s1, s2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ }
+
+ /* back plane k */
+ if(doBack) {
+ n1 = n2 = n3 = ntlVec3Gfx( 0.0, 0.0, 1.0 );
+ p1 = ntlVec3Gfx( s0, s1, e2 );
+ p3 = ntlVec3Gfx( s0, e1, e2 );
+ p2 = ntlVec3Gfx( e0, s1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ p1 = ntlVec3Gfx( s0, e1, e2 );
+ p3 = ntlVec3Gfx( e0, e1, e2 );
+ p2 = ntlVec3Gfx( e0, s1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ }
+
+ /* bottom plane k */
+ if(doBottom) {
+ n1 = n2 = n3 = ntlVec3Gfx( 0.0, -1.0, 0.0 );
+ p1 = ntlVec3Gfx( e0, s1, s2 );
+ p3 = ntlVec3Gfx( s0, s1, s2 );
+ p2 = ntlVec3Gfx( s0, s1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ p1 = ntlVec3Gfx( s0, s1, e2 );
+ p3 = ntlVec3Gfx( e0, s1, e2 );
+ p2 = ntlVec3Gfx( e0, s1, s2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ }
+
+ /* top plane k */
+ if(doTop) {
+ n1 = n2 = n3 = ntlVec3Gfx( 0.0, 1.0, 0.0 );
+ p1 = ntlVec3Gfx( e0, e1, e2 );
+ p2 = ntlVec3Gfx( e0, e1, s2 );
+ p3 = ntlVec3Gfx( s0, e1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ p1 = ntlVec3Gfx( s0, e1, s2 );
+ p2 = ntlVec3Gfx( s0, e1, e2 );
+ p3 = ntlVec3Gfx( e0, e1, s2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ }
+
+ /* left plane k */
+ if(doLeft) {
+ n1 = n2 = n3 = ntlVec3Gfx( -1.0, 0.0, 0.0 );
+ p1 = ntlVec3Gfx( s0, s1, e2 );
+ p3 = ntlVec3Gfx( s0, s1, s2 );
+ p2 = ntlVec3Gfx( s0, e1, s2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ p1 = ntlVec3Gfx( s0, e1, s2 );
+ p3 = ntlVec3Gfx( s0, e1, e2 );
+ p2 = ntlVec3Gfx( s0, s1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ }
+
+ /* right plane k */
+ if(doRight) {
+ n1 = n2 = n3 = ntlVec3Gfx( 1.0, 0.0, 0.0 );
+ p1 = ntlVec3Gfx( e0, e1, e2 );
+ p3 = ntlVec3Gfx( e0, e1, s2 );
+ p2 = ntlVec3Gfx( e0, s1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ p1 = ntlVec3Gfx( e0, e1, s2 );
+ p3 = ntlVec3Gfx( e0, s1, s2 );
+ p2 = ntlVec3Gfx( e0, s1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ }
+
+ } else {
+ // refined box
+ gfxReal S0 = mvStart[0];
+ gfxReal S1 = mvStart[1];
+ gfxReal S2 = mvStart[2];
+ gfxReal v0 = (mvEnd[0]-mvStart[0])/(gfxReal)(mRefinement+1);
+ gfxReal v1 = (mvEnd[1]-mvStart[1])/(gfxReal)(mRefinement+1);
+ gfxReal v2 = (mvEnd[2]-mvStart[2])/(gfxReal)(mRefinement+1);
+ ntlVec3Gfx p1,p2,p3;
+ ntlVec3Gfx n1,n2,n3;
+
+ for(int i=0; i<=mRefinement; i++)
+ for(int j=0; j<=mRefinement; j++) {
+ gfxReal s0 = S0 + i*v0;
+ gfxReal s1 = S1 + j*v1;
+ gfxReal s2 = S2;
+ gfxReal e0 = S0 + (i+1.0)*v0;
+ gfxReal e1 = S1 + (j+1.0)*v1;
+ /* front plane */
+ if(doFront) {
+ n1 = n2 = n3 = ntlVec3Gfx( 0.0, 0.0, -1.0 );
+ p1 = ntlVec3Gfx( s0, s1, s2 );
+ p3 = ntlVec3Gfx( e0, s1, s2 );
+ p2 = ntlVec3Gfx( s0, e1, s2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ p1 = ntlVec3Gfx( e0, e1, s2 );
+ p3 = ntlVec3Gfx( s0, e1, s2 );
+ p2 = ntlVec3Gfx( e0, s1, s2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ }
+ } // i,j
+ for(int i=0; i<=mRefinement; i++)
+ for(int j=0; j<=mRefinement; j++) {
+ gfxReal s0 = S0 + i*v0;
+ gfxReal s1 = S1 + j*v1;
+ gfxReal e0 = S0 + (i+1.0)*v0;
+ gfxReal e1 = S1 + (j+1.0)*v1;
+ gfxReal e2 = S2 + (mRefinement+1.0)*v2;
+ /* back plane k */
+ if(doBack) {
+ n1 = n2 = n3 = ntlVec3Gfx( 0.0, 0.0, 1.0 );
+ p1 = ntlVec3Gfx( s0, s1, e2 );
+ p3 = ntlVec3Gfx( s0, e1, e2 );
+ p2 = ntlVec3Gfx( e0, s1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ p1 = ntlVec3Gfx( s0, e1, e2 );
+ p3 = ntlVec3Gfx( e0, e1, e2 );
+ p2 = ntlVec3Gfx( e0, s1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ }
+ }
+
+ for(int i=0; i<=mRefinement; i++)
+ for(int j=0; j<=mRefinement; j++) {
+
+ gfxReal s0 = S0 + i*v0;
+ gfxReal s1 = S1;
+ gfxReal s2 = S2 + j*v2;
+ gfxReal e0 = S0 + (i+1.0)*v0;
+ gfxReal e2 = S2 + (j+1.0)*v2;
+ /* bottom plane k */
+ if(doBottom) {
+ n1 = n2 = n3 = ntlVec3Gfx( 0.0, -1.0, 0.0 );
+ p1 = ntlVec3Gfx( e0, s1, s2 );
+ p3 = ntlVec3Gfx( s0, s1, s2 );
+ p2 = ntlVec3Gfx( s0, s1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ p1 = ntlVec3Gfx( s0, s1, e2 );
+ p3 = ntlVec3Gfx( e0, s1, e2 );
+ p2 = ntlVec3Gfx( e0, s1, s2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ }
+ }
+
+ for(int i=0; i<=mRefinement; i++)
+ for(int j=0; j<=mRefinement; j++) {
+
+ gfxReal s0 = S0 + i*v0;
+ gfxReal s2 = S2 + j*v2;
+ gfxReal e0 = S0 + (i+1.0)*v0;
+ gfxReal e1 = S1 + (mRefinement+1.0)*v1;
+ gfxReal e2 = S2 + (j+1.0)*v2;
+ /* top plane k */
+ if(doTop) {
+ n1 = n2 = n3 = ntlVec3Gfx( 0.0, 1.0, 0.0 );
+ p1 = ntlVec3Gfx( e0, e1, e2 );
+ p2 = ntlVec3Gfx( e0, e1, s2 );
+ p3 = ntlVec3Gfx( s0, e1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ p1 = ntlVec3Gfx( s0, e1, s2 );
+ p2 = ntlVec3Gfx( s0, e1, e2 );
+ p3 = ntlVec3Gfx( e0, e1, s2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ }
+ }
+
+ for(int i=0; i<=mRefinement; i++)
+ for(int j=0; j<=mRefinement; j++) {
+ gfxReal s0 = S0;
+ gfxReal s1 = S1 + i*v1;
+ gfxReal s2 = S2 + j*v2;
+ gfxReal e1 = S1 + (i+1.0)*v1;
+ gfxReal e2 = S2 + (j+1.0)*v2;
+ /* left plane k */
+ if(doLeft) {
+ n1 = n2 = n3 = ntlVec3Gfx( -1.0, 0.0, 0.0 );
+ p1 = ntlVec3Gfx( s0, s1, e2 );
+ p3 = ntlVec3Gfx( s0, s1, s2 );
+ p2 = ntlVec3Gfx( s0, e1, s2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ p1 = ntlVec3Gfx( s0, e1, s2 );
+ p3 = ntlVec3Gfx( s0, e1, e2 );
+ p2 = ntlVec3Gfx( s0, s1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ }
+ }
+
+ for(int i=0; i<=mRefinement; i++)
+ for(int j=0; j<=mRefinement; j++) {
+ gfxReal s1 = S1 + i*v1;
+ gfxReal s2 = S2 + j*v2;
+ gfxReal e0 = S0 + (mRefinement+1.0)*v0;
+ gfxReal e1 = S1 + (i+1.0)*v1;
+ gfxReal e2 = S2 + (j+1.0)*v2;
+ /* right plane k */
+ if(doRight) {
+ n1 = n2 = n3 = ntlVec3Gfx( 1.0, 0.0, 0.0 );
+ p1 = ntlVec3Gfx( e0, e1, e2 );
+ p3 = ntlVec3Gfx( e0, e1, s2 );
+ p2 = ntlVec3Gfx( e0, s1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ p1 = ntlVec3Gfx( e0, e1, s2 );
+ p3 = ntlVec3Gfx( e0, s1, s2 );
+ p2 = ntlVec3Gfx( e0, s1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ }
+ }
+
+ } // do ref
+
+}
+
+
diff --git a/intern/elbeem/intern/ntl_geometrybox.h b/intern/elbeem/intern/ntl_geometrybox.h
new file mode 100644
index 00000000000..114c253a106
--- /dev/null
+++ b/intern/elbeem/intern/ntl_geometrybox.h
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * A simple box object
+ *
+ *****************************************************************************/
+
+#ifndef NTL_GEOBOX_HH
+#define NTL_GEOBOX_HH
+
+#include "ntl_geometryobject.h"
+
+
+/*! A simple box object generatedd by 12 triangles */
+class ntlGeometryBox : public ntlGeometryObject
+{
+
+ public:
+ /* Init constructor */
+ ntlGeometryBox( void );
+ /* Init constructor */
+ //ntlGeometryBox( ntlVec3Gfx start, ntlVec3Gfx end );
+
+ //! Return type id
+ virtual int getTypeId() { return GEOCLASSTID_BOX; }
+
+ virtual void getTriangles( vector<ntlTriangle> *triangles,
+ vector<ntlVec3Gfx> *vertices,
+ vector<ntlVec3Gfx> *normals, int objectId );
+
+ /*! for easy GUI detection get start of axis aligned bounding box, return NULL of no BB */
+ virtual inline ntlVec3Gfx *getBBStart() { return &mvStart; }
+ virtual inline ntlVec3Gfx *getBBEnd() { return &mvEnd; }
+
+ /*! Init refinement attribute */
+ virtual void initialize(ntlRenderGlobals *glob);
+
+ private:
+
+ /*! Start and end points of box */
+ ntlVec3Gfx mvStart, mvEnd;
+
+ /*! refinement factor */
+ int mRefinement;
+
+
+ public:
+
+ /* Access methods */
+ /*! Access start vector */
+ inline ntlVec3Gfx getStart( void ){ return mvStart; }
+ inline void setStart( const ntlVec3Gfx &set ){ mvStart = set; }
+ /*! Access end vector */
+ inline ntlVec3Gfx getEnd( void ){ return mvEnd; }
+ inline void setEnd( const ntlVec3Gfx &set ){ mvEnd = set; }
+
+};
+
+
+
+#endif
diff --git a/intern/elbeem/intern/ntl_geometryclass.h b/intern/elbeem/intern/ntl_geometryclass.h
new file mode 100644
index 00000000000..145f36bbc5f
--- /dev/null
+++ b/intern/elbeem/intern/ntl_geometryclass.h
@@ -0,0 +1,92 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Base class for geometry shaders and objects
+ *
+ *****************************************************************************/
+
+
+#ifndef NTL_GEOMETRYCLASS_H
+#define NTL_GEOMETRYCLASS_H
+
+#include "attributes.h"
+
+//! geometry class type ids
+#define GEOCLASSTID_OBJECT 1
+#define GEOCLASSTID_SHADER 2
+#define GEOCLASSTID_BOX (GEOCLASSTID_OBJECT| 4)
+#define GEOCLASSTID_OBJMODEL (GEOCLASSTID_OBJECT| 8)
+#define GEOCLASSTID_SPHERE (GEOCLASSTID_OBJECT| 16)
+
+class ntlGeometryClass
+{
+
+ public:
+
+ //! Default constructor
+ inline ntlGeometryClass() :
+ mVisible( 1 ), mName( "[ObjNameUndef]" ),
+ mpAttrs( NULL )
+ {
+ mpAttrs = new AttributeList("objAttrs");
+ };
+
+ //! Default destructor
+ virtual ~ntlGeometryClass() {
+ delete mpAttrs;
+ };
+
+ //! Return type id
+ virtual int getTypeId() = 0;
+
+ /*! Set the object name */
+ inline void setName(string set) { mName = set; }
+ /*! Get the object name */
+ inline string getName( void ) { return mName; }
+
+ /*! Sets the visibility attribute
+ * visibility can be determined at shader _and_ object level , hiding a shader
+ * means comepletely decativating it */
+ inline void setVisible(int set) { mVisible=set; }
+ /*! Returns the visibility attribute */
+ inline int getVisible() const { return mVisible; }
+
+ /*! Sets the attribute list pointer */
+ inline void setAttributeList(AttributeList *set) { mpAttrs=set; }
+ /*! Returns the attribute list pointer */
+ inline AttributeList *getAttributeList() { return mpAttrs; }
+
+ /*! for easy GUI detection get start of axis aligned bounding box, return NULL of no BB */
+ virtual inline ntlVec3Gfx *getBBStart() { return NULL; }
+ virtual inline ntlVec3Gfx *getBBEnd() { return NULL; }
+
+ /*! GUI - this function is called for selected objects to display debugging information with OpenGL */
+ virtual void drawDebugDisplay() { /* do nothing by default */ }
+ /*! GUI - this function is called for selected objects to display interactive information with OpenGL */
+ virtual void drawInteractiveDisplay() { /* do nothing by default */ }
+ /*! GUI - handle mouse movement for selection */
+ virtual void setMousePos(int ,int , ntlVec3Gfx , ntlVec3Gfx ) { /* do nothing by default */ }
+ /*! GUI - notify object that mouse was clicked at last pos */
+ virtual void setMouseClick() { /* do nothing by default */ }
+
+ protected:
+
+ /*! Object visible on/off */
+ int mVisible;
+
+ /*! Name of this object */
+ string mName;
+
+ /*! configuration attributes */
+ AttributeList *mpAttrs;
+
+ private:
+
+};
+
+
+
+#endif
+
diff --git a/intern/elbeem/intern/ntl_geometrymodel.cpp b/intern/elbeem/intern/ntl_geometrymodel.cpp
new file mode 100644
index 00000000000..5dfe86b8027
--- /dev/null
+++ b/intern/elbeem/intern/ntl_geometrymodel.cpp
@@ -0,0 +1,204 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * A simple box object
+ *
+ *****************************************************************************/
+
+#include "ntl_geometrymodel.h"
+#include "ntl_ray.h"
+#include "ntl_scene.h"
+#include "zlib.h"
+
+#ifdef WIN32
+#ifndef strncasecmp
+#define strncasecmp(a,b,c) strcmp(a,b)
+#endif
+#endif // WIN32
+
+
+/******************************************************************************
+ * Default Constructor
+ *****************************************************************************/
+ntlGeometryObjModel::ntlGeometryObjModel( void ) :
+ ntlGeometryObject(),
+ mvStart( 0.0 ), mvEnd( 1.0 ),
+ mLoaded( false ),
+ mTriangles(), mVertices(), mNormals()
+{
+}
+
+/******************************************************************************
+ * Destructor
+ *****************************************************************************/
+ntlGeometryObjModel::~ntlGeometryObjModel()
+{
+ if(!mLoaded) {
+ errMsg("ntlGeometryObjModel","delete obj...");
+ }
+}
+
+
+/*****************************************************************************/
+/* Init attributes etc. of this object */
+/*****************************************************************************/
+void ntlGeometryObjModel::initialize(ntlRenderGlobals *glob)
+{
+ ntlGeometryObject::initialize(glob);
+ mFilename = mpAttrs->readString("filename", mFilename,"ntlGeometryObjModel", "mFilename", true);
+
+ if(mFilename == "") {
+ errMsg("ntlGeometryObjModel::getTriangles","Filename not given!");
+ return;
+ }
+
+ const char *suffix = strrchr(mFilename.c_str(), '.');
+ if (suffix) {
+ if (!strncasecmp(suffix, ".obj", 4)) {
+ errMsg("ntlGeometryObjModel::getTriangles",".obj files not supported!");
+ return;
+ } else if (!strncasecmp(suffix, ".gz", 3)) {
+ //mType = 1; // assume its .bobj.gz
+ } else if (!strncasecmp(suffix, ".bobj", 5)) {
+ //mType = 1;
+ }
+ }
+
+ // continue with standard obj
+ if(loadBobjModel(mFilename)==0) mLoaded=1;
+ if(!mLoaded) {
+ debMsgStd("ntlGeometryObjModel",DM_WARNING,"Unable to load object file '"<<mFilename<<"' !", 0);
+ }
+}
+
+
+/* defines */
+#define T(x) model->triangles[(x)]
+
+/******************************************************************************
+ *
+ *****************************************************************************/
+void
+ntlGeometryObjModel::getTriangles( vector<ntlTriangle> *triangles,
+ vector<ntlVec3Gfx> *vertices,
+ vector<ntlVec3Gfx> *normals, int objectId )
+{
+ if(!mLoaded) { // invalid type...
+ return;
+ }
+
+ for(int i=0; i<(int)mTriangles.size(); i+=3) {
+ int trip[3];
+ trip[0] = mTriangles[i+0];
+ trip[1] = mTriangles[i+1];
+ trip[2] = mTriangles[i+2];
+ sceneAddTriangle(
+ mVertices[trip[0]], mVertices[trip[1]], mVertices[trip[2]],
+ mNormals[trip[0]], mNormals[trip[1]], mNormals[trip[2]],
+ ntlVec3Gfx(0.0), 1 ); /* normal unused */
+ }
+ // bobj
+ return;
+}
+
+
+
+/******************************************************************************
+ * load model from .obj file
+ *****************************************************************************/
+
+int ntlGeometryObjModel::loadBobjModel(string filename)
+{
+ const bool debugPrint=false;
+ gzFile gzf;
+ gzf = gzopen(filename.c_str(), "rb");
+ if (!gzf) {
+ errMsg("ntlGeometryObjModel::loadBobjModel","Reading GZ_BOBJ, Unable to open '"<< filename <<"'...\n" );
+#if ELBEEM_BLENDER==1
+ exit(1);
+#else // ELBEEM_BLENDER==1
+ return 1;
+#endif // ELBEEM_BLENDER==1
+ }
+
+ int wri;
+ int gotbytes = -1;
+ gotbytes = gzread(gzf, &wri, sizeof(wri) );
+ if(gotbytes != sizeof(int)){ errMsg("Reading GZ_BOBJ"," Invalid readNV size "<< wri); goto gzreaderror; }
+ if(sizeof(wri)!=4) { // paranoia check
+ errMsg("Reading GZ_BOBJ"," Invalid int size "<< wri);
+ goto gzreaderror;
+ }
+ if(wri<0 || wri>1e9) {
+ errMsg("Reading GZ_BOBJ"," invalid num vertices "<< wri);
+ goto gzreaderror;
+ }
+ mVertices.clear();
+ mVertices.resize( wri );
+ for(int i=0; i<wri; i++) {
+ float x[3];
+ for(int j=0; j<3; j++) {
+ gotbytes = gzread(gzf, &(x[j]), sizeof( (x[j]) ) );
+ if(gotbytes != sizeof(float)){ errMsg("Reading GZ_BOBJ"," Invalid readV size "<< wri); goto gzreaderror; } // CHECK
+ }
+ mVertices[i] = ntlVec3Gfx(x[0],x[1],x[2]);
+ }
+ if(debugPrint) errMsg("NV"," "<<wri<<" "<< mVertices.size() );
+
+ // should be the same as Vertices.size
+ gotbytes = gzread(gzf, &wri, sizeof(wri) );
+ if(gotbytes != sizeof(int)){ errMsg("Reading GZ_BOBJ","Invalid readNN size "<< wri); goto gzreaderror; }
+ if(wri<0 || wri>1e9) {
+ errMsg("Reading GZ_BOBJ","invalid num normals "<< wri);
+ goto gzreaderror;
+ }
+ mNormals.clear();
+ mNormals.resize( wri );
+ for(int i=0; i<wri; i++) {
+ float n[3];
+ for(int j=0; j<3; j++) {
+ gotbytes = gzread(gzf, &(n[j]), sizeof( (n[j]) ) );
+ if(gotbytes != sizeof(float)){ errMsg("Reading GZ_BOBJ","Invalid readN size "<< wri); goto gzreaderror; }
+ }
+ mNormals[i] = ntlVec3Gfx(n[0],n[1],n[2]);
+ }
+ if(debugPrint) errMsg("NN"," "<<wri<<" "<< mNormals.size() );
+
+ gotbytes = gzread(gzf, &wri, sizeof(wri) );
+ if(gotbytes != sizeof(int)){ errMsg("Reading GZ_BOBJ","Invalid readNT size "<< wri); goto gzreaderror; }
+ if(wri<0 || wri>1e9) {
+ errMsg("Reading GZ_BOBJ","invalid num normals "<< wri);
+ goto gzreaderror;
+ }
+ mTriangles.resize( 3*wri );
+ for(int i=0; i<wri; i++) {
+ int tri[3];
+ for(int j=0; j<3; j++) {
+ gotbytes = gzread(gzf, &(tri[j]), sizeof( (tri[j]) ) );
+ if(gotbytes != sizeof(int)){ errMsg("Reading GZ_BOBJ","Invalid readT size "<< wri); goto gzreaderror; }
+ }
+ mTriangles[3*i+0] = tri[0];
+ mTriangles[3*i+1] = tri[1];
+ mTriangles[3*i+2] = tri[2];
+ }
+ if(debugPrint) errMsg("NT"," "<<wri<<" "<< mTriangles.size() );
+
+ debMsgStd("ntlGeometryObjModel::loadBobjModel",DM_MSG, "File '"<<filename<<"' loaded, #Vertices: "<<mVertices.size()<<", #Normals: "<<mNormals.size()<<", #Triangles: "<<(mTriangles.size()/3)<<" ", 1 );
+
+ gzclose( gzf );
+ return 0;
+gzreaderror:
+ gzclose( gzf );
+#if ELBEEM_BLENDER==1
+ errMsg("ntlGeometryObjModel::loadBobjModel","Reading GZ_BOBJ, Unable to load '"<< filename <<"', exiting...\n" );
+ exit(1);
+#else // ELBEEM_BLENDER==1
+ return 1;
+#endif // ELBEEM_BLENDER==1
+}
+
+
+
+
diff --git a/intern/elbeem/intern/ntl_geometrymodel.h b/intern/elbeem/intern/ntl_geometrymodel.h
new file mode 100644
index 00000000000..c98e7d72fe6
--- /dev/null
+++ b/intern/elbeem/intern/ntl_geometrymodel.h
@@ -0,0 +1,71 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * A model laoded from Wavefront .obj file
+ *
+ *****************************************************************************/
+#ifndef NTL_GEOMODEL_H
+#define NTL_GEOMODEL_H
+
+#include "ntl_geometryobject.h"
+
+/*! A simple box object generatedd by 12 triangles */
+class ntlGeometryObjModel : public ntlGeometryObject
+{
+ public:
+ /* Init constructor */
+ ntlGeometryObjModel( void );
+ /* Init constructor */
+ //ntlGeometryObjModel( ntlVec3Gfx start, ntlVec3Gfx end );
+ /* Destructor */
+ virtual ~ntlGeometryObjModel( void );
+
+ //! Return type id
+ virtual int getTypeId() { return GEOCLASSTID_OBJMODEL; }
+
+ /*! Filename setting etc. */
+ virtual void initialize(ntlRenderGlobals *glob);
+
+
+ /* create triangles from obj */
+ virtual void getTriangles( vector<ntlTriangle> *triangles,
+ vector<ntlVec3Gfx> *vertices,
+ vector<ntlVec3Gfx> *normals, int objectId );
+
+ /*! load model from .bobj file, returns !=0 upon error */
+ int loadBobjModel(string filename);
+
+ private:
+
+ /*! Start and end points of box */
+ ntlVec3Gfx mvStart, mvEnd;
+
+ /*! was the model loaded? */
+ bool mLoaded;
+
+ /*! filename of the obj file */
+ string mFilename;
+
+ /*! for bobj models */
+ vector<int> mTriangles;
+ vector<ntlVec3Gfx> mVertices;
+ vector<ntlVec3Gfx> mNormals;
+
+ public:
+
+ /* Access methods */
+ /*! Access start vector */
+ inline ntlVec3Gfx getStart( void ){ return mvStart; }
+ inline void setStart( const ntlVec3Gfx &set ){ mvStart = set; }
+ /*! Access end vector */
+ inline ntlVec3Gfx getEnd( void ){ return mvEnd; }
+ inline void setEnd( const ntlVec3Gfx &set ){ mvEnd = set; }
+
+ /*! set data file name */
+ inline void setFilename(string set) { mFilename = set; }
+};
+
+#endif
+
diff --git a/intern/elbeem/intern/ntl_geometryobject.cpp b/intern/elbeem/intern/ntl_geometryobject.cpp
new file mode 100644
index 00000000000..ed71a57856c
--- /dev/null
+++ b/intern/elbeem/intern/ntl_geometryobject.cpp
@@ -0,0 +1,128 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * a geometry object
+ * all other geometry objects are derived from this one
+ *
+ *****************************************************************************/
+
+
+#include "ntl_geometryobject.h"
+#include "ntl_renderglobals.h"
+
+// for FGI
+#include "ntl_scene.h"
+
+
+
+/*****************************************************************************/
+/* Default constructor */
+/*****************************************************************************/
+ntlGeometryObject::ntlGeometryObject() :
+ mpMaterial( NULL ),
+ mMaterialName( "default" ),
+ mCastShadows( 1 ),
+ mReceiveShadows( 1 ),
+ mGeoInitId( -1 ), mGeoInitType( 0 ),
+ mInitialVelocity(0.0),
+ mGeoInitIntersect(false)
+{
+};
+
+
+/*****************************************************************************/
+/* Default destructor */
+/*****************************************************************************/
+ntlGeometryObject::~ntlGeometryObject()
+{
+}
+
+/*****************************************************************************/
+/* Init attributes etc. of this object */
+/*****************************************************************************/
+void ntlGeometryObject::initialize(ntlRenderGlobals *glob)
+{
+ //debugOut("ntlGeometryObject::initialize: '"<<getName()<<"' ", 10);
+
+ mGeoInitId = mpAttrs->readInt("geoinitid", mGeoInitId,"ntlGeometryObject", "mGeoInitId", false);
+ mGeoInitIntersect = mpAttrs->readInt("geoinit_intersect", mGeoInitIntersect,"ntlGeometryObject", "mGeoInitIntersect", false);
+ if(mGeoInitId>=0) {
+ string initStr = mpAttrs->readString("geoinittype", "", "ntlGeometryObject", "mGeoInitType", false);
+ if(initStr== "fluid") {
+ mGeoInitType = FGI_FLUID;
+ } else
+ if((initStr== "bnd_no") || (initStr=="bnd_noslip")) {
+ mGeoInitType = FGI_BNDNO;
+ } else
+ if((initStr== "bnd_free") || (initStr=="bnd_freeslip")) {
+ mGeoInitType = FGI_BNDFREE;
+ } else
+ if((initStr== "acc") || (initStr=="accelerator")) {
+ mGeoInitType = FGI_ACC;
+ ntlVec3d force = mpAttrs->readVec3d("geoinitforce", ntlVec3d(0.0), "ntlGeometryObject", "mGeoInitForce", true);
+ errMsg("ntlGeometryObject::initialize","Deprectated acc object used!"); exit(1);
+ } else
+ if((initStr== "set") || (initStr=="speedset")) {
+ mGeoInitType = FGI_SPEEDSET;
+ ntlVec3d force = mpAttrs->readVec3d("geoinitforce", ntlVec3d(0.0), "ntlGeometryObject", "mGeoInitForce", true);
+ errMsg("ntlGeometryObject::initialize","Deprectated speedset object used!"); exit(1);
+ } else
+ // not so nice - define refinement types...
+ if(initStr== "p1") {
+ mGeoInitType = FGI_REFP1;
+ } else
+ if(initStr== "p2") {
+ mGeoInitType = FGI_REFP2;
+ } else
+ if(initStr== "p3") {
+ mGeoInitType = FGI_REFP3;
+ // nothing found
+ } else {
+ errorOut("ntlGeometryObject::initialize error: Unkown 'geoinittype' value: '"<< initStr <<"' ");
+ exit(1);
+ }
+ }
+
+ int geoActive = mpAttrs->readInt("geoinitactive", 1,"ntlGeometryObject", "mGeoInitId", false);
+ if(!geoActive) {
+ // disable geo init again...
+ mGeoInitId = -1;
+ }
+ mInitialVelocity = vec2G( mpAttrs->readVec3d("initial_velocity", vec2D(mInitialVelocity),"ntlGeometryObject", "mInitialVelocity", false));
+
+ // override cfg types
+ mVisible = mpAttrs->readBool("visible", mVisible,"ntlGeometryObject", "mVisible", false);
+ mReceiveShadows = mpAttrs->readBool("recv_shad", mReceiveShadows,"ntlGeometryObject", "mReceiveShadows", false);
+ mCastShadows = mpAttrs->readBool("cast_shad", mCastShadows,"ntlGeometryObject", "mCastShadows", false);
+
+ // init material
+ searchMaterial( glob->getMaterials() );
+}
+
+
+/*****************************************************************************/
+/* Search the material for this object from the material list */
+/*****************************************************************************/
+void ntlGeometryObject::searchMaterial(vector<ntlMaterial *> *mat)
+{
+ //errorOut("my: "<<mMaterialName); // DEBUG
+ /* search the list... */
+ int i=0;
+ for (vector<ntlMaterial*>::iterator iter = mat->begin();
+ iter != mat->end(); iter++) {
+ //if(strcmp(mMaterialName, (*iter)->getName()) == 0) { // DEBUG
+ if( mMaterialName == (*iter)->getName() ) {
+ //warnMsg("ntlGeometryObject::searchMaterial","for obj '"<<getName()<<"' found - '"<<(*iter)->getName()<<"' "<<i); // DEBUG
+ mpMaterial = (*iter);
+ return;
+ }
+ i++;
+ }
+ errMsg("ntlGeometryObject::searchMaterial","Unknown material '"<<mMaterialName<<"' ! ");
+ exit(1);
+}
+
+
+
diff --git a/intern/elbeem/intern/ntl_geometryobject.h b/intern/elbeem/intern/ntl_geometryobject.h
new file mode 100644
index 00000000000..31c786cb751
--- /dev/null
+++ b/intern/elbeem/intern/ntl_geometryobject.h
@@ -0,0 +1,104 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * a geometry object
+ * all other geometry objects are derived from this one
+ *
+ *****************************************************************************/
+#ifndef NTL_GEOMETRYOBJECT_HH
+
+#include "ntl_geometryclass.h"
+#include "ntl_material.h"
+#include "ntl_triangle.h"
+class ntlRay;
+class ntlRenderGlobals;
+
+
+class ntlGeometryObject : public ntlGeometryClass
+{
+
+ public:
+ //! Default constructor
+ ntlGeometryObject();
+ //! Default destructor
+ virtual ~ntlGeometryObject();
+
+ //! Return type id
+ virtual int getTypeId() { return GEOCLASSTID_OBJECT; }
+
+ /*! Get the triangles from this object */
+ virtual void getTriangles( vector<ntlTriangle> *triangles,
+ vector<ntlVec3Gfx> *vertices,
+ vector<ntlVec3Gfx> *normals, int objectId ) = 0;
+
+ /*! Init attributes etc. of this object */
+ virtual void initialize(ntlRenderGlobals *glob);
+
+ /*! Search the material for this object from the material list */
+ void searchMaterial(vector<ntlMaterial *> *mat);
+
+ /* Acces methods */
+ /*! Set the property of this object */
+ inline void setMaterial(ntlMaterial *p) { mpMaterial = p; }
+ /*! Get the surface property of this object */
+ inline ntlMaterial *getMaterial( void ) { return mpMaterial; }
+ /*! Set the object property name */
+ inline void setMaterialName(string set) { mMaterialName = set; }
+ /*! Get the object property name */
+ inline string getMaterialName( void ) { return mMaterialName; }
+
+ /*! Sets the receive shadows attribute */
+ inline void setReceiveShadows(int set) { mReceiveShadows=set; }
+ /*! Returns the receive shadows attribute */
+ inline int getReceiveShadows() const { return mReceiveShadows; }
+
+ /*! Sets the cast shadows attribute */
+ inline void setCastShadows(int set) { mCastShadows=set; }
+ /*! Returns the cast shadows attribute */
+ inline int getCastShadows() const { return mCastShadows; }
+
+ /*! Returns the geo init id */
+ inline int getGeoInitId() const { return mGeoInitId; }
+ /*! Returns the geo init typ */
+ inline int getGeoInitType() const { return mGeoInitType; }
+
+ /*! Set/get the cast initial veocity attribute */
+ inline void setInitialVelocity(ntlVec3Gfx set) { mInitialVelocity=set; }
+ inline ntlVec3Gfx getInitialVelocity() const { return mInitialVelocity; }
+
+ /*! Set/get the intersect init flag */
+ inline bool getGeoInitIntersect() const { return mGeoInitIntersect; }
+ inline void setGeoInitIntersect(bool set) { mGeoInitIntersect=set; }
+
+ protected:
+
+ /*! Point to a property object describing the surface of this object */
+ ntlMaterial *mpMaterial;
+
+ /*! Name of the surcace property */
+ string mMaterialName;
+
+ /*! Cast shadows on/off */
+ int mCastShadows;
+ /*! REceive shadows on/off */
+ int mReceiveShadows;
+
+ /* fluid init data */
+ /*! id of fluid init (is used in solver initialization) */
+ int mGeoInitId;
+ /*! fluid object type (fluid, obstacle, accelerator etc.) */
+ int mGeoInitType;
+ /*! initial velocity for fluid objects */
+ ntlVec3Gfx mInitialVelocity;
+ /*! perform more accurate intersecting geo init for this object? */
+ bool mGeoInitIntersect;
+
+ public:
+
+};
+
+#define NTL_GEOMETRYOBJECT_HH
+#endif
+
diff --git a/intern/elbeem/intern/ntl_geometryshader.h b/intern/elbeem/intern/ntl_geometryshader.h
new file mode 100644
index 00000000000..ef7608f68e0
--- /dev/null
+++ b/intern/elbeem/intern/ntl_geometryshader.h
@@ -0,0 +1,50 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Interface for a geometry shader
+ *
+ *****************************************************************************/
+#ifndef NTL_GEOMETRYSHADER_H
+#define NTL_GEOMETRYSHADER_H
+
+#include "ntl_geometryclass.h"
+class ntlGeometryObject;
+class ntlRenderGlobals;
+
+class ntlGeometryShader :
+ public ntlGeometryClass
+{
+
+ public:
+
+ //! Default constructor
+ inline ntlGeometryShader() :
+ ntlGeometryClass() {};
+ //! Default destructor
+ virtual ~ntlGeometryShader() {};
+
+ //! Return type id
+ virtual int getTypeId() { return GEOCLASSTID_SHADER; }
+
+ /*! Initialize object, should return !=0 upon error */
+ virtual int initializeShader() = 0;
+
+ /*! Do further object initialization after all geometry has been constructed, should return !=0 upon error */
+ virtual int postGeoConstrInit(ntlRenderGlobals *glob) { return 0; };
+
+ /*! Get start iterator for all objects */
+ virtual std::vector<ntlGeometryObject *>::iterator getObjectsBegin() { return mObjects.begin(); }
+ /*! Get end iterator for all objects */
+ virtual std::vector<ntlGeometryObject *>::iterator getObjectsEnd() { return mObjects.end(); }
+
+ protected:
+
+ //! vector for the objects
+ std::vector<ntlGeometryObject *> mObjects;
+
+};
+
+#endif
+
diff --git a/intern/elbeem/intern/ntl_geometrysphere.cpp b/intern/elbeem/intern/ntl_geometrysphere.cpp
new file mode 100644
index 00000000000..66d9625d1f8
--- /dev/null
+++ b/intern/elbeem/intern/ntl_geometrysphere.cpp
@@ -0,0 +1,229 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * A simple sphere object
+ *
+ *****************************************************************************/
+
+#include "ntl_geometrysphere.h"
+#include "ntl_ray.h"
+#include "ntl_scene.h"
+
+
+/******************************************************************************
+ * Default Constructor
+ *****************************************************************************/
+ntlGeometrySphere::ntlGeometrySphere() :
+ ntlGeometryObject(),
+ mvCenter( 0.0 ),
+ mRadius( 1.0 ),
+ mRefPolar(5), mRefAzim(5)
+{
+}
+
+
+/*****************************************************************************/
+/* Init attributes */
+/*****************************************************************************/
+void ntlGeometrySphere::initialize(ntlRenderGlobals *glob) {
+ ntlGeometryObject::initialize(glob);
+
+ mvCenter = vec2G(mpAttrs->readVec3d("center", vec2D(mvCenter) ,"ntlGeometrySphere", "mvCenter", false));
+ mRadius = mpAttrs->readFloat("radius", mRadius ,"ntlGeometrySphere", "mRadius", false);
+ mRefPolar = mpAttrs->readInt ("refpolar", mRefPolar,"ntlGeometrySphere", "mRefPolar", false);
+ mRefAzim = mpAttrs->readInt ("refazim", mRefAzim ,"ntlGeometrySphere", "mRefAzim", false);
+ if(mRefPolar<1) mRefPolar = 1;
+ if(mRefAzim<1) mRefAzim = 1;
+ mRefAzim *= 4;
+
+ mvBBStart = mvCenter - ntlVec3Gfx(mRadius);
+ mvBBEnd = mvCenter + ntlVec3Gfx(mRadius);
+}
+
+
+/******************************************************************************
+ *
+ *****************************************************************************/
+
+ntlVec3Gfx getSphereCoord(gfxReal radius, gfxReal phi, gfxReal theta) {
+ return ntlVec3Gfx(
+ radius * cos(theta) * sin(phi),
+ radius * sin(theta) * sin(phi),
+ radius * cos(phi)
+ );
+};
+
+void
+ntlGeometrySphere::getTriangles( vector<ntlTriangle> *triangles,
+ vector<ntlVec3Gfx> *vertices,
+ vector<ntlVec3Gfx> *normals, int objectId )
+{
+
+ gfxReal phiD = 0.5* M_PI/ (gfxReal)mRefPolar;
+ gfxReal thetaD = 2.0* M_PI/ (gfxReal)mRefAzim;
+ gfxReal phi = 0.0;
+ for(int i=0; i<mRefPolar; i++) {
+ gfxReal theta = 0.0;
+ for(int j=0; j<mRefAzim; j++) {
+ ntlVec3Gfx p1,p2,p3;
+ ntlVec3Gfx n1,n2,n3;
+
+ p1 = getSphereCoord(mRadius, phi , theta );
+ p2 = getSphereCoord(mRadius, phi+phiD, theta );
+ p3 = getSphereCoord(mRadius, phi+phiD, theta+thetaD );
+ n1 = getNormalized(p1);
+ n2 = getNormalized(p2);
+ n3 = getNormalized(p3);
+ //n3 = n2 = n1;
+ p1 += mvCenter;
+ p2 += mvCenter;
+ p3 += mvCenter;
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+
+ n1[2] *= -1.0;
+ n2[2] *= -1.0;
+ n3[2] *= -1.0;
+ p1[2] -= mvCenter[2];
+ p2[2] -= mvCenter[2];
+ p3[2] -= mvCenter[2];
+ p1[2] *= -1.0;
+ p2[2] *= -1.0;
+ p3[2] *= -1.0;
+ p1[2] += mvCenter[2];
+ p2[2] += mvCenter[2];
+ p3[2] += mvCenter[2];
+ sceneAddTriangle( p1,p3,p2, n1,n3,n2, ntlVec3Gfx(0.0), 1 );
+
+ p1 = getSphereCoord(mRadius, phi , theta );
+ p3 = getSphereCoord(mRadius, phi , theta+thetaD );
+ p2 = getSphereCoord(mRadius, phi+phiD, theta+thetaD );
+ n1 = getNormalized(p1);
+ n2 = getNormalized(p2);
+ n3 = getNormalized(p3);
+ //n3 = n2 = n1;
+ p1 += mvCenter;
+ p2 += mvCenter;
+ p3 += mvCenter;
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+
+ n1[2] *= -1.0;
+ n2[2] *= -1.0;
+ n3[2] *= -1.0;
+ p1[2] -= mvCenter[2];
+ p2[2] -= mvCenter[2];
+ p3[2] -= mvCenter[2];
+ p1[2] *= -1.0;
+ p2[2] *= -1.0;
+ p3[2] *= -1.0;
+ p1[2] += mvCenter[2];
+ p2[2] += mvCenter[2];
+ p3[2] += mvCenter[2];
+ sceneAddTriangle( p1,p3,p2, n1,n3,n2, ntlVec3Gfx(0.0), 1 );
+
+ theta += thetaD;
+ }
+ phi += phiD;
+ }
+
+ int doBack = 0;
+ int doFront = 0;
+ int doTop = 0;
+ int doBottom = 0;
+ int doLeft = 0;
+ int doRight = 0;
+ ntlVec3Gfx mvStart = mvBBStart;
+ ntlVec3Gfx mvEnd = mvBBEnd;
+
+ gfxReal s0 = mvStart[0];
+ gfxReal s1 = mvStart[1];
+ gfxReal s2 = mvStart[2];
+ gfxReal e0 = mvEnd[0];
+ gfxReal e1 = mvEnd[1];
+ gfxReal e2 = mvEnd[2];
+ ntlVec3Gfx p1,p2,p3;
+ ntlVec3Gfx n1,n2,n3;
+
+ /* front plane */
+ if(doFront) {
+ n1 = n2 = n3 = ntlVec3Gfx( 0.0, 0.0, -1.0 );
+ p1 = ntlVec3Gfx( s0, s1, s2 );
+ p3 = ntlVec3Gfx( e0, s1, s2 );
+ p2 = ntlVec3Gfx( s0, e1, s2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ p1 = ntlVec3Gfx( e0, e1, s2 );
+ p3 = ntlVec3Gfx( s0, e1, s2 );
+ p2 = ntlVec3Gfx( e0, s1, s2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ }
+
+ /* back plane k */
+ if(doBack) {
+ n1 = n2 = n3 = ntlVec3Gfx( 0.0, 0.0, 1.0 );
+ p1 = ntlVec3Gfx( s0, s1, e2 );
+ p3 = ntlVec3Gfx( s0, e1, e2 );
+ p2 = ntlVec3Gfx( e0, s1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ p1 = ntlVec3Gfx( s0, e1, e2 );
+ p3 = ntlVec3Gfx( e0, e1, e2 );
+ p2 = ntlVec3Gfx( e0, s1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ }
+
+ /* bottom plane k */
+ if(doBottom) {
+ n1 = n2 = n3 = ntlVec3Gfx( 0.0, -1.0, 0.0 );
+ p1 = ntlVec3Gfx( e0, s1, s2 );
+ p3 = ntlVec3Gfx( s0, s1, s2 );
+ p2 = ntlVec3Gfx( s0, s1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ p1 = ntlVec3Gfx( s0, s1, e2 );
+ p3 = ntlVec3Gfx( e0, s1, e2 );
+ p2 = ntlVec3Gfx( e0, s1, s2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ }
+
+ /* top plane k */
+ if(doTop) {
+ n1 = n2 = n3 = ntlVec3Gfx( 0.0, 1.0, 0.0 );
+ p1 = ntlVec3Gfx( e0, e1, e2 );
+ p2 = ntlVec3Gfx( e0, e1, s2 );
+ p3 = ntlVec3Gfx( s0, e1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ p1 = ntlVec3Gfx( s0, e1, s2 );
+ p2 = ntlVec3Gfx( s0, e1, e2 );
+ p3 = ntlVec3Gfx( e0, e1, s2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ }
+
+ /* left plane k */
+ if(doLeft) {
+ n1 = n2 = n3 = ntlVec3Gfx( -1.0, 0.0, 0.0 );
+ p1 = ntlVec3Gfx( s0, s1, e2 );
+ p3 = ntlVec3Gfx( s0, s1, s2 );
+ p2 = ntlVec3Gfx( s0, e1, s2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ p1 = ntlVec3Gfx( s0, e1, s2 );
+ p3 = ntlVec3Gfx( s0, e1, e2 );
+ p2 = ntlVec3Gfx( s0, s1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ }
+
+ /* right plane k */
+ if(doRight) {
+ n1 = n2 = n3 = ntlVec3Gfx( 1.0, 0.0, 0.0 );
+ p1 = ntlVec3Gfx( e0, e1, e2 );
+ p3 = ntlVec3Gfx( e0, e1, s2 );
+ p2 = ntlVec3Gfx( e0, s1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ p1 = ntlVec3Gfx( e0, e1, s2 );
+ p3 = ntlVec3Gfx( e0, s1, s2 );
+ p2 = ntlVec3Gfx( e0, s1, e2 );
+ sceneAddTriangle( p1,p2,p3, n1,n2,n3, ntlVec3Gfx(0.0), 1 );
+ }
+
+
+}
+
+
diff --git a/intern/elbeem/intern/ntl_geometrysphere.h b/intern/elbeem/intern/ntl_geometrysphere.h
new file mode 100644
index 00000000000..6d19e7366fd
--- /dev/null
+++ b/intern/elbeem/intern/ntl_geometrysphere.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * A simple sphere object
+ *
+ *****************************************************************************/
+
+#ifndef NTL_GEOSPHERE_H
+
+#include "ntl_geometryobject.h"
+
+
+/*! A simple box object generatedd by 12 triangles */
+class ntlGeometrySphere : public ntlGeometryObject
+{
+
+ public:
+ /* Init constructor */
+ ntlGeometrySphere( void );
+
+ //! Return type id
+ virtual int getTypeId() { return GEOCLASSTID_SPHERE; }
+
+ virtual void getTriangles( vector<ntlTriangle> *triangles,
+ vector<ntlVec3Gfx> *vertices,
+ vector<ntlVec3Gfx> *normals, int objectId );
+
+ /*! for easy GUI detection get start of axis aligned bounding box, return NULL of no BB */
+ virtual inline ntlVec3Gfx *getBBStart() { return &mvBBStart; }
+ virtual inline ntlVec3Gfx *getBBEnd() { return &mvBBEnd; }
+
+ /*! Init refinement attribute */
+ virtual void initialize(ntlRenderGlobals *glob);
+
+ private:
+
+ /*! Center of the sphere */
+ ntlVec3Gfx mvCenter;
+
+ /*! radius */
+ gfxReal mRadius;
+
+ /*! refinement factor along polar angle */
+ int mRefPolar;
+ /*! refinement factor per segment (azimuthal angle) */
+ int mRefAzim;
+
+ /*! Start and end points of bounding box */
+ ntlVec3Gfx mvBBStart, mvBBEnd;
+
+ public:
+
+ /* Access methods */
+ /*! Access start vector */
+ inline ntlVec3Gfx getCenter( void ){ return mvCenter; }
+ inline void setCenter( const ntlVec3Gfx &set ){ mvCenter = set; }
+
+};
+
+
+
+#define NTL_GEOSPHERE_H
+#endif
diff --git a/intern/elbeem/intern/ntl_image.cpp b/intern/elbeem/intern/ntl_image.cpp
new file mode 100644
index 00000000000..bf1aa61890a
--- /dev/null
+++ b/intern/elbeem/intern/ntl_image.cpp
@@ -0,0 +1,13 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * a templated image class
+ *
+ *****************************************************************************/
+
+#include "ntl_image.h"
+
+
+
diff --git a/intern/elbeem/intern/ntl_image.h b/intern/elbeem/intern/ntl_image.h
new file mode 100644
index 00000000000..497c68a7139
--- /dev/null
+++ b/intern/elbeem/intern/ntl_image.h
@@ -0,0 +1,167 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * a templated image class
+ *
+ *****************************************************************************/
+
+#ifndef NTL_IMAGE_HH
+#define NTL_IMAGE_HH
+
+#include "ntl_vector3dim.h"
+#include "utilities.h"
+
+
+template<class Value>
+class ntlImage
+{
+public:
+ /*! Default constructor */
+ ntlImage();
+ /*! Init constructor */
+ ntlImage(int x,int y, Value def);
+ /*! Destructor, delete contents */
+ ~ntlImage();
+
+ /*! Write the image to a ppm file */
+ void writePpm(const char* name);
+
+ /*! normalize values into range 0..1 */
+ void normalize( void );
+
+ /*! Get a pixel from the image */
+ inline Value get(int x, int y) { return mpC[y*mSizex+x]; }
+
+ /*! Set a pixel in the image */
+ inline void set(int x, int y, Value set) { mpC[y*mSizex+x] = set; }
+
+protected:
+private:
+
+ /*! size in x dimension */
+ int mSizex;
+
+ /*! size in y dimension */
+ int mSizey;
+
+ /*! Image contents */
+ Value *mpC;
+
+};
+
+
+/*! Default constructor */
+template<class Value>
+ntlImage<Value>::ntlImage()
+{
+ mSizex = 0;
+ mSizey = 0;
+ mpC = NULL;
+}
+
+/*! Init constructor */
+template<class Value>
+ntlImage<Value>::ntlImage(int x,int y,Value def)
+{
+ mSizex = x;
+ mSizey = y;
+ mpC = new Value[x*y];
+
+ for(int i=0;i<(x*y);i++) mpC[i] = def;
+}
+
+/*! Destructor, delete contents */
+template<class Value>
+ntlImage<Value>::~ntlImage()
+{
+ if(mpC != NULL) {
+ delete [] mpC;
+ }
+}
+
+
+/*! Write the image to a ppm file */
+template<class Value>
+void ntlImage<Value>::writePpm(const char* name)
+{
+ /* write file */
+ /* open output file */
+ FILE *outfile;
+ if ( (outfile = fopen(name,"w")) == NULL ) {
+ errorOut( "ntlImage::writePpm ERROR: Open out file failed "<<name<<"!\n" );
+ return;
+ }
+
+ int maxColVal = 255;
+
+ /* write ppm header */
+ fprintf(outfile,"P3\n%d %d\n%d\n",mSizex,mSizey, maxColVal );
+
+ /* get min max values */
+ Value min = mpC[0];
+ Value max = mpC[0];
+ for(int j=0;j<(mSizey*mSizex);j++) {
+ if(mpC[j]<min) min = mpC[j];
+ if(mpC[j]>max) max = mpC[j];
+ }
+
+ /* check colors for overflow */
+ for(int j=0;j<mSizey;j++) {
+ for(int i=0;i<mSizex;i++) {
+
+ Value grey;
+ if(max-min>0) {
+ grey = 1.0-(mpC[j*mSizex+i]-min)/(max-min);
+ } else { grey = 1.0; }
+ //mpC[j*mSizex+i] /= max;
+ ntlColor col = ntlColor(grey,grey,grey);
+ unsigned int cCol[3];
+ for (unsigned int cc=0; cc<3; cc++) {
+ if(col[cc] <= 0.0)
+ cCol[cc] = 0;
+ else if(col[cc] >= 1.0)
+ cCol[cc] = maxColVal;
+ else
+ cCol[cc] = (unsigned int)(maxColVal * col[cc]);
+ }
+
+ /* write pixel to ppm file */
+ fprintf(outfile,"%4d %4d %4d ",cCol[0],cCol[1],cCol[2]);
+
+ } /* foreach x */
+
+ fprintf(outfile,"\n");
+ } /* foreach y */
+
+ /* clean up */
+ fclose(outfile);
+}
+
+
+
+/*! Write the image to a ppm file */
+template<class Value>
+void ntlImage<Value>::normalize( void )
+{
+ /* get min max values */
+ Value min = mpC[0];
+ Value max = mpC[0];
+ for(int j=0;j<(mSizey*mSizex);j++) {
+ if(mpC[j]<min) min = mpC[j];
+ if(mpC[j]>max) max = mpC[j];
+ }
+
+ /* check colors for overflow */
+ for(int j=0;j<mSizey;j++) {
+ for(int i=0;i<mSizex;i++) {
+ Value grey = 1.0-(mpC[j*mSizex+i]-min)/(max-min);
+ mpC[j*mSizex+i] = grey;
+ } /* foreach x */
+ } /* foreach y */
+}
+
+
+#endif
+
diff --git a/intern/elbeem/intern/ntl_lightobject.cpp b/intern/elbeem/intern/ntl_lightobject.cpp
new file mode 100644
index 00000000000..88fc3b4502e
--- /dev/null
+++ b/intern/elbeem/intern/ntl_lightobject.cpp
@@ -0,0 +1,143 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * a light object
+ *
+ *****************************************************************************/
+
+
+#include "ntl_lightobject.h"
+#include "ntl_ray.h"
+#include "ntl_scene.h"
+#include "ntl_renderglobals.h"
+
+
+/******************************************************************************
+ * Default Constructor
+ *****************************************************************************/
+ntlLightObject::ntlLightObject(ntlRenderGlobals *glob) :
+ mpGlob( glob ),
+ mActive( 1 ),
+ mCastShadows( 1 ),
+ mcColor( ntlColor(1.0) ),
+ mvPosition( ntlVec3Gfx(0.0) )
+{
+ // nothing to do...
+}
+
+
+/******************************************************************************
+ * Constructor with parameters
+ *****************************************************************************/
+ntlLightObject::ntlLightObject(ntlRenderGlobals *glob, const ntlColor& col) :
+ mpGlob( glob ),
+ mActive( 1 ),
+ mCastShadows( 1 ),
+ mcColor( col )
+{
+ // nothing to do...
+}
+
+
+
+/******************************************************************************
+ * Destructor
+ *****************************************************************************/
+ntlLightObject::~ntlLightObject()
+{
+ // nothing to do...
+}
+
+
+
+/******************************************************************************
+ * Determine color contribution of a lightsource (Phong model)
+ * Specular part is returned in seperate parameter and added later
+ *****************************************************************************/
+const ntlColor
+ntlLightObject::getShadedColor(const ntlRay &reflectedRay, const ntlVec3Gfx lightDir,
+ ntlMaterial *surf, ntlColor &highlight) const
+{
+ gfxReal ldot = dot(lightDir, reflectedRay.getNormal()); /* equals cos( angle(L,N) ) */
+ ntlColor reflected_color = ntlColor(0.0); /* adds up to total reflected color */
+ if(mpGlob->getDebugOut() > 5) errorOut("Lighting dir:"<<lightDir<<" norm:"<<reflectedRay.getNormal()<<" "<<ldot );
+
+ /* lambertian reflection model */
+ if (ldot > 0.0) {
+ //ldot *= -1.0;
+ reflected_color += surf->getDiffuseRefl() * (getColor() * ldot );
+
+ /* specular part */
+ /* specular reflection only makes sense, when the light is facing the surface,
+ as the highlight is supposed to be a reflection of the lightsource, it cannot
+ be reflected on surfaces with ldot<=0, as this means the arc between light
+ and normal is more than 90 degrees. If this isn't done, ugly moiree patterns appear
+ in the highlights, and refractions have strange patterns due to highlights on the
+ inside of the surface */
+ gfxReal spec = dot(reflectedRay.getDirection(), lightDir); // equals cos( angle(R,L) )
+ if((spec > 0.0) && (surf->getSpecular()>0)) {
+ spec = pow( spec, surf->getSpecExponent() ); /* phong exponent */
+ highlight += getColor() * surf->getSpecular() * spec;
+ //errorOut( " "<< surf->getName() <<" S "<<highlight<<" "<<spec<<" "<<surf->getSpecular()<<" "<<surf->getSpecExponent() );
+ }
+
+ }
+
+ return ntlColor(reflected_color);
+}
+
+
+// omni light implementation
+
+
+/******************************************************************************
+ *! prepare shadow maps if necessary
+ *****************************************************************************/
+void ntlLightObject::prepare( bool doCaustics )
+{
+ if(!mActive) { return; }
+}
+
+
+/******************************************************************************
+ * Illuminate the given point on an object
+ *****************************************************************************/
+ntlColor ntlLightObject::illuminatePoint(ntlRay &reflectedRay, ntlGeometryObject *closest,
+ ntlColor &highlight )
+{
+ /* is this light active? */
+ if(!mActive) { return ntlColor(0.0); }
+
+ gfxReal visibility = 1.0; // how much of light is visible
+ ntlVec3Gfx intersectionPos = reflectedRay.getOrigin();
+ ntlColor current_color = ntlColor(0.0);
+ ntlMaterial *clossurf = closest->getMaterial();
+
+ ntlVec3Gfx lightDir = (mvPosition - intersectionPos);
+ gfxReal lightDirNorm = normalize(lightDir);
+
+ // where is the lightsource ?
+ ntlRay rayOfLight(intersectionPos, lightDir, 0, 1.0, mpGlob );
+
+ if( (mCastShadows)&&(closest->getReceiveShadows()) ) {
+ ntlTriangle *tri;
+ ntlVec3Gfx triNormal;
+ gfxReal trit;
+ mpGlob->getScene()->intersectScene(rayOfLight, trit, triNormal, tri, TRI_CASTSHADOWS);
+ if(( trit>0 )&&( trit<lightDirNorm )) visibility = 0.0;
+ if(mpGlob->getDebugOut() > 5) errorOut("Omni lighting with "<<visibility );
+ }
+
+ /* is light partly visible ? */
+ if (visibility>0.0) {
+ ntlColor highTemp(0.0); // temporary highlight color to multiply highTemp with offFac
+ current_color = getShadedColor(reflectedRay, lightDir, clossurf, highTemp) * visibility;
+ highlight += highTemp * visibility;
+ if(mpGlob->getDebugOut() > 5) errorOut("Omni lighting color "<<current_color );
+ }
+ return current_color;
+}
+
+
diff --git a/intern/elbeem/intern/ntl_lightobject.h b/intern/elbeem/intern/ntl_lightobject.h
new file mode 100644
index 00000000000..6b753223bce
--- /dev/null
+++ b/intern/elbeem/intern/ntl_lightobject.h
@@ -0,0 +1,120 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * a light object
+ * default omni light implementation
+ *
+ *****************************************************************************/
+#ifndef NTL_LIGHTOBJECT_HH
+#define NTL_LIGHTOBJECT_HH
+
+#include "ntl_vector3dim.h"
+#include "ntl_material.h"
+#include "ntl_image.h"
+class ntlRay;
+class ntlRenderGlobals;
+class ntlGeometryObject;
+
+
+
+/* shadow map directions */
+#define LSM_RIGHT 0
+#define LSM_LEFT 1
+#define LSM_UP 2
+#define LSM_DOWN 3
+#define LSM_FRONT 4
+#define LSM_BACK 5
+
+/*! Basic object for lights, all other light are derived from this one */
+class ntlLightObject
+{
+public:
+ /* CONSTRUCTORS */
+ /*! Default constructor */
+ ntlLightObject(ntlRenderGlobals *glob);
+ /*! Constructor with parameters */
+ ntlLightObject(ntlRenderGlobals *glob, const ntlColor& col);
+ /*! Destructor */
+ virtual ~ntlLightObject();
+
+ /*! prepare light for rendering (for example shadow maps) */
+ virtual void prepare( bool );
+
+ /*! do the illumination... */
+ virtual ntlColor illuminatePoint(ntlRay &reflectedRay,
+ ntlGeometryObject *closest,
+ ntlColor &highlight);
+ /*! shade the point */
+ const ntlColor
+ getShadedColor(const ntlRay &reflectedray, ntlVec3Gfx lightDir,
+ ntlMaterial *surf, ntlColor &highlight) const;
+
+
+ /* access methods */
+ /*! Access the active flag */
+ inline void setActive(bool set) { mActive = set; }
+ inline bool getActive() const { return mActive; }
+ /*! Access the shadow flag */
+ inline void setCastShadows(bool set) { mCastShadows = set; }
+ inline bool getCastShadows() const { return mCastShadows; }
+ /*! Access the light color */
+ inline void setColor(ntlColor set) { mcColor = set; }
+ inline ntlColor getColor() const { return mcColor; }
+
+ /*! Access the omni light position */
+ void setPosition(ntlVec3Gfx set) { mvPosition = set; }
+ ntlVec3Gfx getPosition() const { return mvPosition; }
+ /*! Init the shadow map */
+ void setShadowMap(int setx, int sety, int sampling) { mUseShadowMap = true; mSMSizeX = setx; mSMSizeY = sety; mSMSampling = sampling; }
+ /*! Init the caustics map */
+ void setCausticsMap(int setx, int sety ) { mUseCausticsMap = true; mCMSizeX = setx; mCMSizeY = sety; }
+
+
+protected:
+ /*! render globals */
+ ntlRenderGlobals *mpGlob;
+
+ /*! is this light acitve? */
+ bool mActive;
+
+ /*! does it cast shadows? */
+ bool mCastShadows;
+
+ /*! color of this light */
+ ntlColor mcColor;
+
+ /*! light position */
+ ntlVec3Gfx mvPosition;
+
+ /*! shadow map active? */
+ int mUseShadowMap;
+
+ /*! shadow map size */
+ int mSMSizeX;
+ int mSMSizeY;
+
+ /*! Sampling value for shadow map filtering */
+ int mSMSampling;
+
+ /*! Images for shadow map */
+ ntlImage<gfxReal> *mpShadowMap[6];
+
+
+ /*! caustics map active? */
+ int mUseCausticsMap;
+
+ /*! caustics map size */
+ int mCMSizeX;
+ int mCMSizeY;
+
+ /*! Images for caustics map */
+ ntlImage<char> *mpCausticsMap[6];
+
+private:
+
+};
+
+#endif
+
diff --git a/intern/elbeem/intern/ntl_material.h b/intern/elbeem/intern/ntl_material.h
new file mode 100644
index 00000000000..4a136225790
--- /dev/null
+++ b/intern/elbeem/intern/ntl_material.h
@@ -0,0 +1,203 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * a geometry object
+ * all other geometry objects are derived from this one
+ *
+ *****************************************************************************/
+#ifndef NTL_MATERIAL_HH
+#define NTL_MATERIAL_HH
+
+#include "ntl_vector3dim.h"
+class ntlRay;
+
+
+//! Properties of an geo object, describing the reflection properties of the surface
+class ntlMaterial
+{
+public:
+ // CONSTRUCTORS
+ //! Default constructor
+ inline ntlMaterial( void );
+ //! Constructor with parameters
+ /*! Sets reflectance, ambient reflection, specular intensity
+ * specular exponent, mirror intensity
+ * transparency, refraction index */
+ inline ntlMaterial( string name,
+ const ntlColor& Ref, const ntlColor& Amb,
+ gfxReal Spec, gfxReal Exp, gfxReal Mirror,
+ gfxReal Trans, gfxReal Refrac, gfxReal TAdd,
+ const ntlColor& Att, int fres);
+ //! Desctructor
+ ~ntlMaterial() {};
+
+ //! Calculate reflectance and refratance from Fresnel's law
+ inline void calculateFresnel(const ntlVec3Gfx &dir, const ntlVec3Gfx &normal, gfxReal refIndex,
+ gfxReal &refl, gfxReal &trans );
+
+protected:
+
+ /* name of the material */
+ string mName;
+
+ //! Vector for reflectance of each color component (used in shade() of ray object)
+ ntlColor mDiffuseRefl;
+ //! Ambient reflectance
+ ntlColor mAmbientRefl;
+ //! Specular reflection intensity
+ gfxReal mSpecular;
+ //! Specular phong exponent
+ gfxReal mSpecExponent;
+ //! Mirror intensity
+ gfxReal mMirror;
+
+ //! Transparence
+ gfxReal mTransparence;
+ //! Refraction index, nu(Air) is assumed 1
+ gfxReal mRefracIndex;
+ //! Should transparence be additive?
+ gfxReal mTransAdditive;
+ //! Color dependent transparency attentuation factors (negative logarithm stored)
+ ntlColor mTransAttCol;
+ //! Should the transparence and reflectivity be determined by fresnel?
+ int mFresnel;
+
+
+public:
+ // access methods
+
+ //! Returns the material name
+ inline string getName() { return mName; }
+ //! Returns the reflectance
+ inline ntlColor getDiffuseRefl() const { return ntlColor(mDiffuseRefl); }
+ //! Returns the ambience
+ inline ntlColor getAmbientRefl() const { return ntlColor(mAmbientRefl); }
+ //! Returns the specular component
+ inline gfxReal getSpecular() const { return mSpecular; }
+ //! Returns the specular exponent component
+ inline gfxReal getSpecExponent() const { return mSpecExponent; }
+ //! Returns the mirror component
+ inline gfxReal getMirror() const { return mMirror; }
+ //! Returns the transparence component
+ inline gfxReal getTransparence() const { return mTransparence; }
+ //! Returns the refraction index component
+ inline gfxReal getRefracIndex() const { return mRefracIndex; }
+ //! Returns the transparency additive factor component
+ inline gfxReal getTransAdditive() const { return mTransAdditive; }
+ //! Returns the transparency attentuation
+ inline ntlColor getTransAttCol() const { return mTransAttCol; }
+ //! Get Fresnel flag
+ inline int getFresnel( void ) { return mFresnel; }
+
+
+
+ //! Returns the mat name
+ inline void setName(string set) { mName = set; }
+ //! Returns the reflectance
+ inline void setDiffuseRefl(ntlColor set) { mDiffuseRefl=set; }
+ //! Returns the ambience
+ inline void setAmbientRefl(ntlColor set) { mAmbientRefl=set; }
+ //! Returns the specular component
+ inline void setSpecular(gfxReal set) { mSpecular=set; }
+ //! Returns the specular exponent component
+ inline void setSpecExponent(gfxReal set) { mSpecExponent=set; }
+ //! Returns the mirror component
+ inline void setMirror(gfxReal set) { mMirror=set; }
+ //! Returns the transparence component
+ inline void setTransparence(gfxReal set) { mTransparence=set; }
+ //! Returns the refraction index component
+ inline void setRefracIndex(gfxReal set) { mRefracIndex=set; }
+ //! Returns the transparency additive factor component
+ inline void setTransAdditive(gfxReal set) { mTransAdditive=set; }
+ //! Returns the transparency attentuation
+ inline void setTransAttCol(ntlColor set) {
+ ntlColor setlog = ntlColor( -log(set[0]), -log(set[1]), -log(set[2]) );
+ mTransAttCol=setlog; }
+ //! Set Fresnel on/off
+ inline void setFresnel(int set) { mFresnel = set; }
+
+};
+
+
+
+
+/******************************************************************************
+ * Default constructor
+ *****************************************************************************/
+inline ntlMaterial::ntlMaterial( void ) :
+ mName( "default" ),
+ mDiffuseRefl(0.5,0.5,0.5), mAmbientRefl(0.0,0.0,0.0),
+ mSpecular(0.0), mSpecExponent(0.0), mMirror(0.0),
+ mTransparence(0.0), mRefracIndex(0.0), mTransAdditive(0.0), mTransAttCol(0.0),
+ mFresnel( 0 )
+ //mNtfId(0), mNtfFluid(0), mNtfSolid(0)
+{
+ // just do default init...
+}
+
+
+
+/******************************************************************************
+ * Init constructor
+ *****************************************************************************/
+inline
+ntlMaterial::ntlMaterial( string name,
+ const ntlColor& Ref, const ntlColor& Amb,
+ gfxReal Spec, gfxReal SpecEx, gfxReal Mirr,
+ gfxReal Trans, gfxReal Refrac, gfxReal TAdd,
+ const ntlColor& Att, int fres)
+{
+ mName = name;
+ mDiffuseRefl = Ref;
+ mAmbientRefl = Amb;
+ mSpecular = Spec;
+ mSpecExponent = SpecEx;
+ mMirror = Mirr;
+ mTransparence = Trans;
+ mRefracIndex = Refrac;
+ mTransAdditive = TAdd;
+ mTransAttCol = Att;
+ mFresnel = fres;
+}
+
+/******************************************************************************
+ * Macro to define the default surface properties for a newly created object
+ *****************************************************************************/
+#define GET_GLOBAL_DEFAULT_MATERIAL new ntlMaterial( "default",\
+ ntlColor( 0.5 ), ntlColor(0.0), \
+ 1.0, 5.0, 0.0, \
+ 0.0, 1.0, 0.0, \
+ ntlColor( 0.0 ), 0 );
+
+
+
+/******************************************************************************
+ * Calculate reflectance and refratance from Fresnel's law
+ * cf. Glassner p. 46
+ *****************************************************************************/
+inline void
+ntlMaterial::calculateFresnel(const ntlVec3Gfx &dir, const ntlVec3Gfx &normal, gfxReal refIndex,
+ gfxReal &refl, gfxReal &trans)
+{
+ gfxReal c = -dot(dir, normal);
+ if(c<0) {
+ refl = 0.0; trans = 0.0; return;
+ //c = 0.0;
+ }
+
+ gfxReal r0 = ((refIndex-1.0)*(refIndex-1.0)) /
+ ((refIndex+1.0)*(refIndex+1.0));
+ gfxReal omc = (1.0-c);
+ gfxReal r =r0 + (1.0 - r0) * omc*omc*omc*omc*omc;
+
+ //mMirror = r;
+ //mTransparence = (1.0 - r);
+ refl = r;
+ trans = (1.0 - r);
+ //errorOut(" fres ");
+}
+
+
+#endif
diff --git a/intern/elbeem/intern/ntl_matrices.h b/intern/elbeem/intern/ntl_matrices.h
new file mode 100644
index 00000000000..8a70dceb1c7
--- /dev/null
+++ b/intern/elbeem/intern/ntl_matrices.h
@@ -0,0 +1,658 @@
+
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Basic matrix utility include file
+ *
+ *****************************************************************************/
+#ifndef NTL_MATRICES_H
+
+#include "ntl_vector3dim.h"
+
+
+// The basic vector class
+template<class Scalar>
+class ntlMatrix4x4
+{
+public:
+ // Constructor
+ inline ntlMatrix4x4(void );
+ // Copy-Constructor
+ inline ntlMatrix4x4(const ntlMatrix4x4<Scalar> &v );
+ // construct a vector from one Scalar
+ inline ntlMatrix4x4(Scalar);
+ // construct a vector from three Scalars
+ inline ntlMatrix4x4(Scalar, Scalar, Scalar);
+
+ // Assignment operator
+ inline const ntlMatrix4x4<Scalar>& operator= (const ntlMatrix4x4<Scalar>& v);
+ // Assignment operator
+ inline const ntlMatrix4x4<Scalar>& operator= (Scalar s);
+ // Assign and add operator
+ inline const ntlMatrix4x4<Scalar>& operator+= (const ntlMatrix4x4<Scalar>& v);
+ // Assign and add operator
+ inline const ntlMatrix4x4<Scalar>& operator+= (Scalar s);
+ // Assign and sub operator
+ inline const ntlMatrix4x4<Scalar>& operator-= (const ntlMatrix4x4<Scalar>& v);
+ // Assign and sub operator
+ inline const ntlMatrix4x4<Scalar>& operator-= (Scalar s);
+ // Assign and mult operator
+ inline const ntlMatrix4x4<Scalar>& operator*= (const ntlMatrix4x4<Scalar>& v);
+ // Assign and mult operator
+ inline const ntlMatrix4x4<Scalar>& operator*= (Scalar s);
+ // Assign and div operator
+ inline const ntlMatrix4x4<Scalar>& operator/= (const ntlMatrix4x4<Scalar>& v);
+ // Assign and div operator
+ inline const ntlMatrix4x4<Scalar>& operator/= (Scalar s);
+
+
+ // unary operator
+ inline ntlMatrix4x4<Scalar> operator- () const;
+
+ // binary operator add
+ inline ntlMatrix4x4<Scalar> operator+ (const ntlMatrix4x4<Scalar>&) const;
+ // binary operator add
+ inline ntlMatrix4x4<Scalar> operator+ (Scalar) const;
+ // binary operator sub
+ inline ntlMatrix4x4<Scalar> operator- (const ntlMatrix4x4<Scalar>&) const;
+ // binary operator sub
+ inline ntlMatrix4x4<Scalar> operator- (Scalar) const;
+ // binary operator mult
+ inline ntlMatrix4x4<Scalar> operator* (const ntlMatrix4x4<Scalar>&) const;
+ // binary operator mult
+ inline ntlVector3Dim<Scalar> operator* (const ntlVector3Dim<Scalar>&) const;
+ // binary operator mult
+ inline ntlMatrix4x4<Scalar> operator* (Scalar) const;
+ // binary operator div
+ inline ntlMatrix4x4<Scalar> operator/ (Scalar) const;
+
+ // init function
+ //! init identity matrix
+ inline void initId();
+ //! init rotation matrix
+ inline void initTranslation(Scalar x, Scalar y, Scalar z);
+ //! init rotation matrix
+ inline void initRotationX(Scalar rot);
+ inline void initRotationY(Scalar rot);
+ inline void initRotationZ(Scalar rot);
+ //! init scaling matrix
+ inline void initScaling(Scalar scale);
+ inline void initScaling(Scalar x, Scalar y, Scalar z);
+
+ //! public to avoid [][] operators
+ Scalar value[4][4]; //< Storage of vector values
+
+
+protected:
+
+};
+
+
+
+//------------------------------------------------------------------------------
+// TYPEDEFS
+//------------------------------------------------------------------------------
+
+// a 3D vector for graphics output, typically float?
+//typedef ntlMatrix4x4<float> ntlVec3Gfx;
+
+//typedef ntlMatrix4x4<double> ntlMat4d;
+typedef ntlMatrix4x4<double> ntlMat4d;
+
+// a 3D vector with single precision
+typedef ntlMatrix4x4<float> ntlMat4f;
+
+// a 3D vector with grafix precision
+typedef ntlMatrix4x4<gfxReal> ntlMat4Gfx;
+
+// a 3D integer vector
+typedef ntlMatrix4x4<int> ntlMat4i;
+
+
+
+
+
+//------------------------------------------------------------------------------
+// STREAM FUNCTIONS
+//------------------------------------------------------------------------------
+
+
+
+/*************************************************************************
+ Outputs the object in human readable form using the format
+ [x,y,z]
+ */
+template<class Scalar>
+std::ostream&
+operator<<( std::ostream& os, const ntlMatrix4x4<Scalar>& m )
+{
+ for(int i=0; i<4; i++) {
+ os << '|' << m.value[i][0] << ", " << m.value[i][1] << ", " << m.value[i][2] << ", " << m.value[i][3] << '|';
+ }
+ return os;
+}
+
+
+
+/*************************************************************************
+ Reads the contents of the object from a stream using the same format
+ as the output operator.
+ */
+template<class Scalar>
+std::istream&
+operator>>( std::istream& is, ntlMatrix4x4<Scalar>& m )
+{
+ char c;
+ char dummy[3];
+
+ for(int i=0; i<4; i++) {
+ is >> c >> m.value[i][0] >> dummy >> m.value[i][1] >> dummy >> m.value[i][2] >> dummy >> m.value[i][3] >> c;
+ }
+ return is;
+}
+
+
+//------------------------------------------------------------------------------
+// VECTOR inline FUNCTIONS
+//------------------------------------------------------------------------------
+
+
+
+/*************************************************************************
+ Constructor.
+ */
+template<class Scalar>
+inline ntlMatrix4x4<Scalar>::ntlMatrix4x4( void )
+{
+#ifdef MATRIX_INIT_ZERO
+ for(int i=0; i<4; i++) {
+ for(int j=0; j<4; j++) {
+ value[i][j] = 0.0;
+ }
+ }
+#endif
+}
+
+
+
+/*************************************************************************
+ Copy-Constructor.
+ */
+template<class Scalar>
+inline ntlMatrix4x4<Scalar>::ntlMatrix4x4( const ntlMatrix4x4<Scalar> &v )
+{
+ value[0][0] = v.value[0][0]; value[0][1] = v.value[0][1]; value[0][2] = v.value[0][2]; value[0][3] = v.value[0][3];
+ value[1][0] = v.value[1][0]; value[1][1] = v.value[1][1]; value[1][2] = v.value[1][2]; value[1][3] = v.value[1][3];
+ value[2][0] = v.value[2][0]; value[2][1] = v.value[2][1]; value[2][2] = v.value[2][2]; value[2][3] = v.value[2][3];
+ value[3][0] = v.value[3][0]; value[3][1] = v.value[3][1]; value[3][2] = v.value[3][2]; value[3][3] = v.value[3][3];
+}
+
+
+
+/*************************************************************************
+ Constructor for a vector from a single Scalar. All components of
+ the vector get the same value.
+ \param s The value to set
+ \return The new vector
+ */
+template<class Scalar>
+inline ntlMatrix4x4<Scalar>::ntlMatrix4x4(Scalar s )
+{
+ for(int i=0; i<4; i++) {
+ for(int j=0; j<4; j++) {
+ value[i][j] = s;
+ }
+ }
+}
+
+
+
+/*************************************************************************
+ Copy a ntlMatrix4x4 componentwise.
+ \param v vector with values to be copied
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlMatrix4x4<Scalar>&
+ntlMatrix4x4<Scalar>::operator=( const ntlMatrix4x4<Scalar> &v )
+{
+ value[0][0] = v.value[0][0]; value[0][1] = v.value[0][1]; value[0][2] = v.value[0][2]; value[0][3] = v.value[0][3];
+ value[1][0] = v.value[1][0]; value[1][1] = v.value[1][1]; value[1][2] = v.value[1][2]; value[1][3] = v.value[1][3];
+ value[2][0] = v.value[2][0]; value[2][1] = v.value[2][1]; value[2][2] = v.value[2][2]; value[2][3] = v.value[2][3];
+ value[3][0] = v.value[3][0]; value[3][1] = v.value[3][1]; value[3][2] = v.value[3][2]; value[3][3] = v.value[3][3];
+ return *this;
+}
+
+
+/*************************************************************************
+ Copy a Scalar to each component.
+ \param s The value to copy
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlMatrix4x4<Scalar>&
+ntlMatrix4x4<Scalar>::operator=(Scalar s)
+{
+ for(int i=0; i<4; i++) {
+ for(int j=0; j<4; j++) {
+ value[i][j] = s;
+ }
+ }
+ return *this;
+}
+
+
+/*************************************************************************
+ Add another ntlMatrix4x4 componentwise.
+ \param v vector with values to be added
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlMatrix4x4<Scalar>&
+ntlMatrix4x4<Scalar>::operator+=( const ntlMatrix4x4<Scalar> &v )
+{
+ value[0][0] += v.value[0][0]; value[0][1] += v.value[0][1]; value[0][2] += v.value[0][2]; value[0][3] += v.value[0][3];
+ value[1][0] += v.value[1][0]; value[1][1] += v.value[1][1]; value[1][2] += v.value[1][2]; value[1][3] += v.value[1][3];
+ value[2][0] += v.value[2][0]; value[2][1] += v.value[2][1]; value[2][2] += v.value[2][2]; value[2][3] += v.value[2][3];
+ value[3][0] += v.value[3][0]; value[3][1] += v.value[3][1]; value[3][2] += v.value[3][2]; value[3][3] += v.value[3][3];
+ return *this;
+}
+
+
+/*************************************************************************
+ Add a Scalar value to each component.
+ \param s Value to add
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlMatrix4x4<Scalar>&
+ntlMatrix4x4<Scalar>::operator+=(Scalar s)
+{
+ for(int i=0; i<4; i++) {
+ for(int j=0; j<4; j++) {
+ value[i][j] += s;
+ }
+ }
+ return *this;
+}
+
+
+/*************************************************************************
+ Subtract another vector componentwise.
+ \param v vector of values to subtract
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlMatrix4x4<Scalar>&
+ntlMatrix4x4<Scalar>::operator-=( const ntlMatrix4x4<Scalar> &v )
+{
+ value[0][0] -= v.value[0][0]; value[0][1] -= v.value[0][1]; value[0][2] -= v.value[0][2]; value[0][3] -= v.value[0][3];
+ value[1][0] -= v.value[1][0]; value[1][1] -= v.value[1][1]; value[1][2] -= v.value[1][2]; value[1][3] -= v.value[1][3];
+ value[2][0] -= v.value[2][0]; value[2][1] -= v.value[2][1]; value[2][2] -= v.value[2][2]; value[2][3] -= v.value[2][3];
+ value[3][0] -= v.value[3][0]; value[3][1] -= v.value[3][1]; value[3][2] -= v.value[3][2]; value[3][3] -= v.value[3][3];
+ return *this;
+}
+
+
+/*************************************************************************
+ Subtract a Scalar value from each component.
+ \param s Value to subtract
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlMatrix4x4<Scalar>&
+ntlMatrix4x4<Scalar>::operator-=(Scalar s)
+{
+ for(int i=0; i<4; i++) {
+ for(int j=0; j<4; j++) {
+ value[i][j] -= s;
+ }
+ }
+ return *this;
+}
+
+
+/*************************************************************************
+ Multiply with another vector componentwise.
+ \param v vector of values to multiply with
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlMatrix4x4<Scalar>&
+ntlMatrix4x4<Scalar>::operator*=( const ntlMatrix4x4<Scalar> &v )
+{
+ ntlMatrix4x4<Scalar> nv(0.0);
+ for(int i=0; i<4; i++) {
+ for(int j=0; j<4; j++) {
+
+ for(int k=0;k<4;k++)
+ nv.value[i][j] += (value[i][k] * v.value[k][j]);
+ }
+ }
+ *this = nv;
+ return *this;
+}
+
+
+/*************************************************************************
+ Multiply each component with a Scalar value.
+ \param s Value to multiply with
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlMatrix4x4<Scalar>&
+ntlMatrix4x4<Scalar>::operator*=(Scalar s)
+{
+ for(int i=0; i<4; i++) {
+ for(int j=0; j<4; j++) {
+ value[i][j] *= s;
+ }
+ }
+ return *this;
+}
+
+
+
+/*************************************************************************
+ Divide each component by a Scalar value.
+ \param s Value to divide by
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlMatrix4x4<Scalar>&
+ntlMatrix4x4<Scalar>::operator/=(Scalar s)
+{
+ for(int i=0; i<4; i++) {
+ for(int j=0; j<4; j++) {
+ value[i][j] /= s;
+ }
+ }
+ return *this;
+}
+
+
+//------------------------------------------------------------------------------
+// unary operators
+//------------------------------------------------------------------------------
+
+
+/*************************************************************************
+ Build componentwise the negative this vector.
+ \return The new (negative) vector
+ */
+template<class Scalar>
+inline ntlMatrix4x4<Scalar>
+ntlMatrix4x4<Scalar>::operator-() const
+{
+ ntlMatrix4x4<Scalar> nv;
+ for(int i=0; i<4; i++) {
+ for(int j=0; j<4; j++) {
+ nv[i][j] = -value[i][j];
+ }
+ }
+ return nv;
+}
+
+
+
+//------------------------------------------------------------------------------
+// binary operators
+//------------------------------------------------------------------------------
+
+
+/*************************************************************************
+ Build a vector with another vector added componentwise.
+ \param v The second vector to add
+ \return The sum vector
+ */
+template<class Scalar>
+inline ntlMatrix4x4<Scalar>
+ntlMatrix4x4<Scalar>::operator+( const ntlMatrix4x4<Scalar> &v ) const
+{
+ ntlMatrix4x4<Scalar> nv;
+ for(int i=0; i<4; i++) {
+ for(int j=0; j<4; j++) {
+ nv[i][j] = value[i][j] + v.value[i][j];
+ }
+ }
+ return nv;
+}
+
+
+/*************************************************************************
+ Build a vector with a Scalar value added to each component.
+ \param s The Scalar value to add
+ \return The sum vector
+ */
+template<class Scalar>
+inline ntlMatrix4x4<Scalar>
+ntlMatrix4x4<Scalar>::operator+(Scalar s) const
+{
+ ntlMatrix4x4<Scalar> nv;
+ for(int i=0; i<4; i++) {
+ for(int j=0; j<4; j++) {
+ nv[i][j] = value[i][j] + s;
+ }
+ }
+ return nv;
+}
+
+
+/*************************************************************************
+ Build a vector with another vector subtracted componentwise.
+ \param v The second vector to subtract
+ \return The difference vector
+ */
+template<class Scalar>
+inline ntlMatrix4x4<Scalar>
+ntlMatrix4x4<Scalar>::operator-( const ntlMatrix4x4<Scalar> &v ) const
+{
+ ntlMatrix4x4<Scalar> nv;
+ for(int i=0; i<4; i++) {
+ for(int j=0; j<4; j++) {
+ nv[i][j] = value[i][j] - v.value[i][j];
+ }
+ }
+ return nv;
+}
+
+
+/*************************************************************************
+ Build a vector with a Scalar value subtracted componentwise.
+ \param s The Scalar value to subtract
+ \return The difference vector
+ */
+template<class Scalar>
+inline ntlMatrix4x4<Scalar>
+ntlMatrix4x4<Scalar>::operator-(Scalar s ) const
+{
+ ntlMatrix4x4<Scalar> nv;
+ for(int i=0; i<4; i++) {
+ for(int j=0; j<4; j++) {
+ nv[i][j] = value[i][j] - s;
+ }
+ }
+ return nv;
+}
+
+
+
+/*************************************************************************
+ Build a ntlMatrix4x4 with a Scalar value multiplied to each component.
+ \param s The Scalar value to multiply with
+ \return The product vector
+ */
+template<class Scalar>
+inline ntlMatrix4x4<Scalar>
+ntlMatrix4x4<Scalar>::operator*(Scalar s) const
+{
+ ntlMatrix4x4<Scalar> nv;
+ for(int i=0; i<4; i++) {
+ for(int j=0; j<4; j++) {
+ nv[i][j] = value[i][j] * s;
+ }
+ }
+ return nv;
+}
+
+
+
+
+/*************************************************************************
+ Build a vector divided componentwise by a Scalar value.
+ \param s The Scalar value to divide by
+ \return The ratio vector
+ */
+template<class Scalar>
+inline ntlMatrix4x4<Scalar>
+ntlMatrix4x4<Scalar>::operator/(Scalar s) const
+{
+ ntlMatrix4x4<Scalar> nv;
+ for(int i=0; i<4; i++) {
+ for(int j=0; j<4; j++) {
+ nv[i][j] = value[i][j] / s;
+ }
+ }
+ return nv;
+}
+
+
+
+
+
+/*************************************************************************
+ Build a vector with another vector multiplied by componentwise.
+ \param v The second vector to muliply with
+ \return The product vector
+ */
+template<class Scalar>
+inline ntlMatrix4x4<Scalar>
+ntlMatrix4x4<Scalar>::operator*( const ntlMatrix4x4<Scalar>& v) const
+{
+ ntlMatrix4x4<Scalar> nv(0.0);
+ for(int i=0; i<4; i++) {
+ for(int j=0; j<4; j++) {
+
+ for(int k=0;k<4;k++)
+ nv.value[i][j] += (value[i][k] * v.value[k][j]);
+ }
+ }
+ return nv;
+}
+
+
+template<class Scalar>
+inline ntlVector3Dim<Scalar>
+ntlMatrix4x4<Scalar>::operator*( const ntlVector3Dim<Scalar>& v) const
+{
+ ntlVector3Dim<Scalar> nvec(0.0);
+ for(int i=0; i<3; i++) {
+ for(int j=0; j<3; j++) {
+ nvec[i] += (v[j] * value[i][j]);
+ }
+ }
+ // assume normalized w coord
+ for(int i=0; i<3; i++) {
+ nvec[i] += (1.0 * value[i][3]);
+ }
+ return nvec;
+}
+
+
+
+//------------------------------------------------------------------------------
+// Other helper functions
+//------------------------------------------------------------------------------
+
+//! init identity matrix
+template<class Scalar>
+inline void ntlMatrix4x4<Scalar>::initId()
+{
+ (*this) = (Scalar)(0.0);
+ value[0][0] =
+ value[1][1] =
+ value[2][2] =
+ value[3][3] = (Scalar)(1.0);
+}
+
+//! init rotation matrix
+template<class Scalar>
+inline void ntlMatrix4x4<Scalar>::initTranslation(Scalar x, Scalar y, Scalar z)
+{
+ //(*this) = (Scalar)(0.0);
+ this->initId();
+ value[0][3] = x;
+ value[1][3] = y;
+ value[2][3] = z;
+}
+
+//! init rotation matrix
+template<class Scalar>
+inline void
+ntlMatrix4x4<Scalar>::initRotationX(Scalar rot)
+{
+ double drot = (double)rot;
+ while(drot < 0.0) drot += (M_PI*2.0);
+
+ this->initId();
+ value[1][1] = (Scalar) cos(drot);
+ value[1][2] = (Scalar) sin(drot);
+ value[2][1] = (Scalar)(-sin(drot));
+ value[2][2] = (Scalar) cos(drot);
+}
+template<class Scalar>
+inline void
+ntlMatrix4x4<Scalar>::initRotationY(Scalar rot)
+{
+ double drot = (double)rot;
+ while(drot < 0.0) drot += (M_PI*2.0);
+
+ this->initId();
+ value[0][0] = (Scalar) cos(drot);
+ value[0][2] = (Scalar)(-sin(drot));
+ value[2][0] = (Scalar) sin(drot);
+ value[2][2] = (Scalar) cos(drot);
+}
+template<class Scalar>
+inline void
+ntlMatrix4x4<Scalar>::initRotationZ(Scalar rot)
+{
+ double drot = (double)rot;
+ while(drot < 0.0) drot += (M_PI*2.0);
+
+ this->initId();
+ value[0][0] = (Scalar) cos(drot);
+ value[0][1] = (Scalar) sin(drot);
+ value[1][0] = (Scalar)(-sin(drot));
+ value[1][1] = (Scalar) cos(drot);
+}
+
+//! init scaling matrix
+template<class Scalar>
+inline void
+ntlMatrix4x4<Scalar>::initScaling(Scalar scale)
+{
+ this->initId();
+ value[0][0] = scale;
+ value[1][1] = scale;
+ value[2][2] = scale;
+}
+//! init scaling matrix
+template<class Scalar>
+inline void
+ntlMatrix4x4<Scalar>::initScaling(Scalar x, Scalar y, Scalar z)
+{
+ this->initId();
+ value[0][0] = x;
+ value[1][1] = y;
+ value[2][2] = z;
+}
+
+
+
+
+#define NTL_MATRICES_H
+#endif
+
diff --git a/intern/elbeem/intern/ntl_ray.cpp b/intern/elbeem/intern/ntl_ray.cpp
new file mode 100644
index 00000000000..7b31ba38237
--- /dev/null
+++ b/intern/elbeem/intern/ntl_ray.cpp
@@ -0,0 +1,652 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * main renderer class
+ *
+ *****************************************************************************/
+
+
+#include "ntl_ray.h"
+#include "ntl_scene.h"
+
+
+
+
+/******************************************************************************
+ * Constructor
+ *****************************************************************************/
+ntlRay::ntlRay( void )
+ : mOrigin(0.0)
+ , mDirection(0.0)
+ , mvNormal(0.0)
+ , mDepth(0)
+ , mpGlob(NULL)
+ , mIsRefracted(0)
+{
+ errorOut("ntlRay::ntlRay() Error: don't use uninitialized rays !");
+ exit(-1);
+}
+
+
+/******************************************************************************
+ * Copy - Constructor
+ *****************************************************************************/
+ntlRay::ntlRay( const ntlRay &r )
+{
+ // copy it! initialization is not enough!
+ mOrigin = r.mOrigin;
+ mDirection = r.mDirection;
+ mvNormal = r.mvNormal;
+ mDepth = r.mDepth;
+ mIsRefracted = r.mIsRefracted;
+ mIsReflected = r.mIsReflected;
+ mContribution = r.mContribution;
+ mpGlob = r.mpGlob;
+
+ // get new ID
+ if(mpGlob) {
+ mID = mpGlob->getCounterRays()+1;
+ mpGlob->setCounterRays( mpGlob->getCounterRays()+1 );
+ } else {
+ mID = 0;
+ }
+}
+
+
+/******************************************************************************
+ * Constructor with explicit parameters and global render object
+ *****************************************************************************/
+ntlRay::ntlRay(const ntlVec3Gfx &o, const ntlVec3Gfx &d, unsigned int i, gfxReal contrib, ntlRenderGlobals *glob)
+ : mOrigin( o )
+ , mDirection( d )
+ , mvNormal(0.0)
+ , mDepth( i )
+ , mContribution( contrib )
+ , mpGlob( glob )
+ , mIsRefracted( 0 )
+ , mIsReflected( 0 )
+{
+ // get new ID
+ if(mpGlob) {
+ mID = mpGlob->getCounterRays()+1;
+ mpGlob->setCounterRays( mpGlob->getCounterRays()+1 );
+ } else {
+ mID = 0;
+ }
+}
+
+
+
+/******************************************************************************
+ * Destructor
+ *****************************************************************************/
+ntlRay::~ntlRay()
+{
+ /* nothing to do... */
+}
+
+
+
+/******************************************************************************
+ * AABB
+ *****************************************************************************/
+/* for AABB intersect */
+#define NUMDIM 3
+#define RIGHT 0
+#define LEFT 1
+#define MIDDLE 2
+
+//! intersect ray with AABB
+void ntlRay::intersectFrontAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &retnormal,ntlVec3Gfx &retcoord) const
+{
+ char inside = true; /* inside box? */
+ char hit = false; /* ray hits box? */
+ int whichPlane; /* intersection plane */
+ gfxReal candPlane[NUMDIM]; /* candidate plane */
+ gfxReal quadrant[NUMDIM]; /* quadrants */
+ gfxReal maxT[NUMDIM]; /* max intersection T for planes */
+ ntlVec3Gfx coord; /* intersection point */
+ ntlVec3Gfx dir = mDirection;
+ ntlVec3Gfx origin = mOrigin;
+ ntlVec3Gfx normal(0.0, 0.0, 0.0);
+
+ t = GFX_REAL_MAX;
+
+ /* check intersection planes for AABB */
+ for(int i=0;i<NUMDIM;i++) {
+ if(origin[i] < mStart[i]) {
+ quadrant[i] = LEFT;
+ candPlane [i] = mStart[i];
+ inside = false;
+ } else if(origin[i] > mEnd[i]) {
+ quadrant[i] = RIGHT;
+ candPlane[i] = mEnd[i];
+ inside = false;
+ } else {
+ quadrant[i] = MIDDLE;
+ }
+ }
+
+ /* inside AABB? */
+ if(!inside) {
+ /* get t distances to planes */
+ /* treat too small direction components as paralell */
+ for(int i=0;i<NUMDIM;i++) {
+ if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
+ maxT[i] = (candPlane[i] - origin[i]) / dir[i];
+ } else {
+ maxT[i] = -1;
+ }
+ }
+
+ /* largest max t */
+ whichPlane = 0;
+ for(int i=1;i<NUMDIM;i++) {
+ if(maxT[whichPlane] < maxT[i]) whichPlane = i;
+ }
+
+ /* check final candidate */
+ hit = true;
+ if(maxT[whichPlane] >= 0.0) {
+
+ for(int i=0;i<NUMDIM;i++) {
+ if(whichPlane != i) {
+ coord[i] = origin[i] + maxT[whichPlane] * dir[i];
+ if( (coord[i] < mStart[i]-getVecEpsilon() ) ||
+ (coord[i] > mEnd[i] +getVecEpsilon() ) ) {
+ /* no hit... */
+ hit = false;
+ }
+ }
+ else {
+ coord[i] = candPlane[i];
+ }
+ }
+
+ /* AABB hit... */
+ if( hit ) {
+ t = maxT[whichPlane];
+ if(quadrant[whichPlane]==RIGHT) normal[whichPlane] = 1.0;
+ else normal[whichPlane] = -1.0;
+ }
+ }
+
+
+ } else {
+ /* inside AABB... */
+ t = 0.0;
+ coord = origin;
+ return;
+ }
+
+ if(t == GFX_REAL_MAX) t = -1.0;
+ retnormal = normal;
+ retcoord = coord;
+}
+
+
+
+//! intersect ray with AABB
+void ntlRay::intersectBackAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &retnormal,ntlVec3Gfx &retcoord) const
+{
+ char hit = false; /* ray hits box? */
+ int whichPlane; /* intersection plane */
+ gfxReal candPlane[NUMDIM]; /* candidate plane */
+ gfxReal quadrant[NUMDIM]; /* quadrants */
+ gfxReal maxT[NUMDIM]; /* max intersection T for planes */
+ ntlVec3Gfx coord; /* intersection point */
+ ntlVec3Gfx dir = mDirection;
+ ntlVec3Gfx origin = mOrigin;
+ ntlVec3Gfx normal(0.0, 0.0, 0.0);
+
+ t = GFX_REAL_MAX;
+ for(int i=0;i<NUMDIM;i++) {
+ if(origin[i] < mStart[i]) {
+ quadrant[i] = LEFT;
+ candPlane [i] = mEnd[i];
+ } else if(origin[i] > mEnd[i]) {
+ quadrant[i] = RIGHT;
+ candPlane[i] = mStart[i];
+ } else {
+ if(dir[i] > 0) {
+ quadrant[i] = LEFT;
+ candPlane [i] = mEnd[i];
+ } else
+ if(dir[i] < 0) {
+ quadrant[i] = RIGHT;
+ candPlane[i] = mStart[i];
+ } else {
+ quadrant[i] = MIDDLE;
+ }
+ }
+ }
+
+
+ /* get t distances to planes */
+ /* treat too small direction components as paralell */
+ for(int i=0;i<NUMDIM;i++) {
+ if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
+ maxT[i] = (candPlane[i] - origin[i]) / dir[i];
+ } else {
+ maxT[i] = GFX_REAL_MAX;
+ }
+ }
+
+ /* largest max t */
+ whichPlane = 0;
+ for(int i=1;i<NUMDIM;i++) {
+ if(maxT[whichPlane] > maxT[i]) whichPlane = i;
+ }
+
+ /* check final candidate */
+ hit = true;
+ if(maxT[whichPlane] != GFX_REAL_MAX) {
+
+ for(int i=0;i<NUMDIM;i++) {
+ if(whichPlane != i) {
+ coord[i] = origin[i] + maxT[whichPlane] * dir[i];
+ if( (coord[i] < mStart[i]-getVecEpsilon() ) ||
+ (coord[i] > mEnd[i] +getVecEpsilon() ) ) {
+ /* no hit... */
+ hit = false;
+ }
+ }
+ else {
+ coord[i] = candPlane[i];
+ }
+ }
+
+ /* AABB hit... */
+ if( hit ) {
+ t = maxT[whichPlane];
+
+ if(quadrant[whichPlane]==RIGHT) normal[whichPlane] = 1.0;
+ else normal[whichPlane] = -1.0;
+ }
+ }
+
+
+ if(t == GFX_REAL_MAX) t = -1.0;
+ retnormal = normal;
+ retcoord = coord;
+}
+
+
+
+
+
+//! intersect ray with AABB
+void ntlRay::intersectCompleteAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &tmin, gfxReal &tmax) const
+{
+ char inside = true; /* inside box? */
+ char hit = false; /* ray hits box? */
+ int whichPlane; /* intersection plane */
+ gfxReal candPlane[NUMDIM]; /* candidate plane */
+ gfxReal quadrant[NUMDIM]; /* quadrants */
+ gfxReal maxT[NUMDIM]; /* max intersection T for planes */
+ ntlVec3Gfx coord; /* intersection point */
+ ntlVec3Gfx dir = mDirection;
+ ntlVec3Gfx origin = mOrigin;
+ gfxReal t = GFX_REAL_MAX;
+
+ /* check intersection planes for AABB */
+ for(int i=0;i<NUMDIM;i++) {
+ if(origin[i] < mStart[i]) {
+ quadrant[i] = LEFT;
+ candPlane [i] = mStart[i];
+ inside = false;
+ } else if(origin[i] > mEnd[i]) {
+ quadrant[i] = RIGHT;
+ candPlane[i] = mEnd[i];
+ inside = false;
+ } else {
+ /* intersect with backside */
+ if(dir[i] > 0) {
+ quadrant[i] = LEFT;
+ candPlane [i] = mStart[i];
+ } else
+ if(dir[i] < 0) {
+ quadrant[i] = RIGHT;
+ candPlane[i] = mEnd[i];
+ } else {
+ quadrant[i] = MIDDLE;
+ }
+ }
+ }
+
+ /* get t distances to planes */
+ for(int i=0;i<NUMDIM;i++) {
+ if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
+ maxT[i] = (candPlane[i] - origin[i]) / dir[i];
+ } else {
+ maxT[i] = GFX_REAL_MAX;
+ }
+ }
+
+ /* largest max t */
+ whichPlane = 0;
+ for(int i=1;i<NUMDIM;i++) {
+ if( ((maxT[whichPlane] < maxT[i])&&(maxT[i]!=GFX_REAL_MAX)) ||
+ (maxT[whichPlane]==GFX_REAL_MAX) )
+ whichPlane = i;
+ }
+
+ /* check final candidate */
+ hit = true;
+ if(maxT[whichPlane]<GFX_REAL_MAX) {
+ for(int i=0;i<NUMDIM;i++) {
+ if(whichPlane != i) {
+ coord[i] = origin[i] + maxT[whichPlane] * dir[i];
+ if( (coord[i] < mStart[i]-getVecEpsilon() ) ||
+ (coord[i] > mEnd[i] +getVecEpsilon() ) ) {
+ /* no hit... */
+ hit = false;
+ }
+ }
+ else { coord[i] = candPlane[i]; }
+ }
+
+ /* AABB hit... */
+ if( hit ) {
+ t = maxT[whichPlane];
+ }
+ }
+ tmin = t;
+
+ /* now the backside */
+ t = GFX_REAL_MAX;
+ for(int i=0;i<NUMDIM;i++) {
+ if(origin[i] < mStart[i]) {
+ quadrant[i] = LEFT;
+ candPlane [i] = mEnd[i];
+ } else if(origin[i] > mEnd[i]) {
+ quadrant[i] = RIGHT;
+ candPlane[i] = mStart[i];
+ } else {
+ if(dir[i] > 0) {
+ quadrant[i] = LEFT;
+ candPlane [i] = mEnd[i];
+ } else
+ if(dir[i] < 0) {
+ quadrant[i] = RIGHT;
+ candPlane[i] = mStart[i];
+ } else {
+ quadrant[i] = MIDDLE;
+ }
+ }
+ }
+
+
+ /* get t distances to planes */
+ for(int i=0;i<NUMDIM;i++) {
+ if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
+ maxT[i] = (candPlane[i] - origin[i]) / dir[i];
+ } else {
+ maxT[i] = GFX_REAL_MAX;
+ }
+ }
+
+ /* smallest max t */
+ whichPlane = 0;
+ for(int i=1;i<NUMDIM;i++) {
+ if(maxT[whichPlane] > maxT[i]) whichPlane = i;
+ }
+
+ /* check final candidate */
+ hit = true;
+ if(maxT[whichPlane] != GFX_REAL_MAX) {
+
+ for(int i=0;i<NUMDIM;i++) {
+ if(whichPlane != i) {
+ coord[i] = origin[i] + maxT[whichPlane] * dir[i];
+ if( (coord[i] < mStart[i]-getVecEpsilon() ) ||
+ (coord[i] > mEnd[i] +getVecEpsilon() ) ) {
+ /* no hit... */
+ hit = false;
+ }
+ }
+ else {
+ coord[i] = candPlane[i];
+ }
+ }
+
+ /* AABB hit... */
+ if( hit ) {
+ t = maxT[whichPlane];
+ }
+ }
+
+ tmax = t;
+}
+
+
+
+/******************************************************************************
+ * Determine color of this ray by tracing through the scene
+ *****************************************************************************/
+const ntlColor ntlRay::shade() //const
+{
+ ntlGeometryObject *closest = NULL;
+ gfxReal minT = GFX_REAL_MAX;
+ vector<ntlLightObject*> *lightlist = mpGlob->getLightList();
+ mpGlob->setCounterShades( mpGlob->getCounterShades()+1 );
+ bool intersectionInside = 0;
+ if(mpGlob->getDebugOut() > 5) errorOut(std::endl<<"New Ray: depth "<<mDepth<<", org "<<mOrigin<<", dir "<<mDirection );
+
+ /* check if this ray contributes enough */
+ if(mContribution <= RAY_MINCONTRIB) {
+ //return ntlColor(0.0);
+ }
+
+
+ /* find closes object that intersects */
+ ntlTriangle *tri = NULL;
+ ntlVec3Gfx normal;
+ mpGlob->getScene()->intersectScene(*this, minT, normal, tri, 0);
+ if(minT>0) {
+ closest = mpGlob->getScene()->getObject( tri->getObjectId() );
+ }
+
+ /* object hit... */
+ if (closest != NULL) {
+ //return( ntlColor(1.0) );
+ //normal = tri->getNormal(); // no normal smoothing
+
+ ntlVec3Gfx triangleNormal = tri->getNormal();
+ if( equal(triangleNormal, ntlVec3Gfx(0.0)) ) errorOut("ntlRaytracer warning: trinagle normal= 0 "); // DEBUG
+ /* intersection on inside faces? if yes invert normal afterwards */
+ gfxReal valDN; // = mDirection | normal;
+ valDN = dot(mDirection, triangleNormal);
+ if( valDN > 0.0) {
+ intersectionInside = 1;
+ normal = normal * -1.0;
+ triangleNormal = triangleNormal * -1.0;
+ }
+
+ /* ... -> do reflection */
+ ntlVec3Gfx intersectionPosition(mOrigin + (mDirection * (minT)) );
+ ntlMaterial *clossurf = closest->getMaterial();
+ if(mpGlob->getDebugOut() > 5) {
+ errorOut("Ray hit: at "<<intersectionPosition<<" n:"<<normal<<" dn:"<<valDN<<" ins:"<<intersectionInside<<" cl:"<<((unsigned int)closest) );
+ errorOut(" t1:"<<mpGlob->getScene()->getVertex(tri->getPoints()[0])<<" t2:"<<mpGlob->getScene()->getVertex(tri->getPoints()[1])<<" t3:"<<mpGlob->getScene()->getVertex(tri->getPoints()[2]) );
+ errorOut(" trin:"<<tri->getNormal() );
+ }
+
+ /* current transparence and reflectivity */
+ gfxReal currTrans = clossurf->getTransparence();
+ gfxReal currRefl = clossurf->getMirror();
+
+ /* correct intersectopm position */
+ intersectionPosition += ( triangleNormal*getVecEpsilon() );
+ /* reflection at normal */
+ ntlVec3Gfx reflectedDir = getNormalized( reflectVector(mDirection, normal) );
+ int badRefl = 0;
+ if(dot(reflectedDir, triangleNormal)<0.0 ) {
+ badRefl = 1;
+ if(mpGlob->getDebugOut() > 5) { errorOut("Ray Bad reflection...!"); }
+ }
+
+ /* refraction direction, depending on in/outside hit */
+ ntlVec3Gfx refractedDir;
+ int refRefl = 0;
+ /* refraction at normal is handled by inverting normal before */
+ gfxReal myRefIndex = 1.0;
+ if((currTrans>RAY_THRESHOLD)||(clossurf->getFresnel())) {
+ if(intersectionInside) {
+ myRefIndex = 1.0/clossurf->getRefracIndex();
+ } else {
+ myRefIndex = clossurf->getRefracIndex();
+ }
+
+ refractedDir = refractVector(mDirection, normal, myRefIndex , (gfxReal)(1.0) /* global ref index */, refRefl);
+ }
+
+ /* calculate fresnel? */
+ if(clossurf->getFresnel()) {
+ // for total reflection, just set trans to 0
+ if(refRefl) {
+ currRefl = 1.0; currTrans = 0.0;
+ } else {
+ // calculate fresnel coefficients
+ clossurf->calculateFresnel( mDirection, normal, myRefIndex, currRefl,currTrans );
+ }
+ }
+
+ ntlRay reflectedRay(intersectionPosition, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob);
+ reflectedRay.setNormal( normal );
+ ntlColor currentColor(0.0);
+ ntlColor highlightColor(0.0);
+
+ /* first add reflected ambient color */
+ currentColor += (clossurf->getAmbientRefl() * mpGlob->getAmbientLight() );
+
+ /* calculate lighting, not on the insides of objects... */
+ if(!intersectionInside) {
+ for (vector<ntlLightObject*>::iterator iter = lightlist->begin();
+ iter != lightlist->end();
+ iter++) {
+
+ /* let light illuminate point */
+ currentColor += (*iter)->illuminatePoint( reflectedRay, closest, highlightColor );
+
+ } // for all lights
+ }
+
+ // recurse ?
+ if ((mDepth < mpGlob->getRayMaxDepth() )&&(currRefl>RAY_THRESHOLD)) {
+
+ if(badRefl) {
+ ntlVec3Gfx intersectionPosition2;
+ ntlGeometryObject *closest2 = NULL;
+ gfxReal minT2 = GFX_REAL_MAX;
+ ntlTriangle *tri2 = NULL;
+ ntlVec3Gfx normal2;
+
+ ntlVec3Gfx refractionPosition2(mOrigin + (mDirection * minT) );
+ refractionPosition2 -= (triangleNormal*getVecEpsilon() );
+
+ ntlRay reflectedRay2 = ntlRay(refractionPosition2, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob);
+ mpGlob->getScene()->intersectScene(reflectedRay2, minT2, normal2, tri2, 0);
+ if(minT2>0) {
+ closest2 = mpGlob->getScene()->getObject( tri2->getObjectId() );
+ }
+
+ /* object hit... */
+ if (closest2 != NULL) {
+ ntlVec3Gfx triangleNormal2 = tri2->getNormal();
+ gfxReal valDN2;
+ valDN2 = dot(reflectedDir, triangleNormal2);
+ if( valDN2 > 0.0) {
+ triangleNormal2 = triangleNormal2 * -1.0;
+ intersectionPosition2 = ntlVec3Gfx(intersectionPosition + (reflectedDir * (minT2)) );
+ /* correct intersection position and create new reflected ray */
+ intersectionPosition2 += ( triangleNormal2*getVecEpsilon() );
+ reflectedRay = ntlRay(intersectionPosition2, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob);
+ } else {
+ /*exit(-1);*/
+ // ray seems to work, continue normally ?
+ }
+
+ }
+
+ }
+
+ // add mirror color multiplied by mirror factor of surface
+ if(mpGlob->getDebugOut() > 5) errorOut("Reflected ray from depth "<<mDepth<<", dir "<<reflectedDir );
+ ntlColor reflectedColor = reflectedRay.shade() * currRefl;
+ currentColor += reflectedColor;
+ }
+
+ /* Trace another ray on for transparent objects */
+ if(currTrans > RAY_THRESHOLD) {
+
+ //gfxReal refrac_dn = mDirection | normal;
+ /* position at the other side of the surface, along ray */
+ ntlVec3Gfx refraction_position(mOrigin + (mDirection * minT) );
+ refraction_position += (mDirection * getVecEpsilon());
+ refraction_position -= (triangleNormal*getVecEpsilon() );
+
+ ntlColor refracCol(0.0); /* refracted color */
+
+
+ /* trace refracted ray */
+ ntlRay transRay(refraction_position, refractedDir, mDepth+1, mContribution*currTrans, mpGlob);
+ transRay.setRefracted(1);
+ transRay.setNormal( normal );
+ if(mDepth < mpGlob->getRayMaxDepth() ) {
+ if(!refRefl) {
+ if(mpGlob->getDebugOut() > 5) errorOut("Refracted ray from depth "<<mDepth<<", dir "<<refractedDir );
+ refracCol = transRay.shade();
+ } else {
+ //we shouldnt reach this!
+ if(mpGlob->getDebugOut() > 5) errorOut("Fully reflected ray from depth "<<mDepth<<", dir "<<reflectedDir );
+ refracCol = reflectedRay.shade();
+ }
+ }
+
+ /* calculate color */
+ /* additive transparency "light amplification" */
+ ntlColor add_col = currentColor + refracCol * currTrans;
+ /* subtractive transparency, more realistic */
+ ntlColor sub_col = (refracCol * currTrans) +
+ ( currentColor * (1.0-currTrans) );
+
+ /* mix additive and subtractive */
+ add_col += sub_col;
+ currentColor += (refracCol * currTrans);
+
+ }
+
+
+ /* add highlights (should not be affected by transparence as the diffuse reflections */
+ currentColor += highlightColor;
+
+ /* attentuate as a last step*/
+ //if(currTrans > RAY_THRESHOLD) {
+ /* check if we're on the inside or outside */
+ if(intersectionInside) {
+ gfxReal kr,kg,kb; /* attentuation */
+ /* calculate attentuation */
+ ntlColor attCol = clossurf->getTransAttCol();
+ kr = exp( attCol[0] * minT );
+ kg = exp( attCol[1] * minT );
+ kb = exp( attCol[2] * minT );
+ currentColor = currentColor * ntlColor(kr,kg,kb);
+ }
+
+ /* done... */
+ if(mpGlob->getDebugOut() > 5) { errorOut("Ray "<<mDepth<<" color "<<currentColor ); }
+ return ntlColor(currentColor);
+ }
+
+ /* no object hit -> ray goes to infinity */
+ return mpGlob->getBackgroundCol();
+}
+
+
+
+
+
+
diff --git a/intern/elbeem/intern/ntl_ray.h b/intern/elbeem/intern/ntl_ray.h
new file mode 100644
index 00000000000..c433c45b33d
--- /dev/null
+++ b/intern/elbeem/intern/ntl_ray.h
@@ -0,0 +1,234 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * ray class
+ *
+ *****************************************************************************/
+#ifndef NTL_RAY_HH
+#define NTL_RAY_HH
+
+#include "ntl_vector3dim.h"
+#include "ntl_lightobject.h"
+#include "ntl_geometryobject.h"
+#include "ntl_renderglobals.h"
+
+
+/* Minimum value for refl/refr to be traced */
+#define RAY_THRESHOLD 0.001
+
+#if GFX_PRECISION==1
+// float values
+//! the minimal triangle determinant length
+#define RAY_TRIANGLE_EPSILON (1e-08)
+//! Minimal contribution for rays to be traced on
+#define RAY_MINCONTRIB (1e-04)
+
+#else
+// double values
+//! the minimal triangle determinant length
+#define RAY_TRIANGLE_EPSILON (1e-15)
+//! Minimal contribution for rays to be traced on
+#define RAY_MINCONTRIB (1e-05)
+
+#endif
+
+
+
+//! store data for an intersection of a ray and a triangle
+// NOT YET USED
+class ntlIntersection {
+ public:
+
+ ntlIntersection() :
+ distance(-1.0), normal(0.0),
+ ray(NULL), tri(NULL), flags(0) { };
+
+ gfxReal distance;
+ ntlVec3Gfx normal;
+ ntlRay *ray;
+ ntlTriangle *tri;
+ char flags;
+};
+
+//! the main ray class
+class ntlRay
+{
+public:
+ // CONSTRUCTORS
+ //! Initialize ray memebers, prints error message
+ ntlRay();
+ //! Copy constructor, copy all members
+ ntlRay(const ntlRay &r);
+ //! Explicitly init member variables with global render object
+ ntlRay(const ntlVec3Gfx &o, const ntlVec3Gfx &d, unsigned int i, gfxReal contrib, ntlRenderGlobals *glob);
+ //! Destructor
+ ~ntlRay();
+
+ //! Set the refraction flag for refracted rays
+ inline void setRefracted(unsigned char set) { mIsRefracted = set; }
+ inline void setReflected(unsigned char set) { mIsReflected = set; }
+
+ //! main ray recursion function
+ /*!
+ * First get closest object intersection, return background color if nothing
+ * was hit, else calculate shading and reflection components
+ * and return mixed color */
+ const ntlColor shade() /*const*/;
+
+ /*! Trace a photon through the scene */
+ void tracePhoton(ntlColor) const;
+
+ //! intersect ray with AABB
+ void intersectFrontAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &normal, ntlVec3Gfx &retcoord) const;
+ void intersectBackAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &normal, ntlVec3Gfx &retcoord) const;
+ void intersectCompleteAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &tmin, gfxReal &tmax) const;
+ //! optimized intersect ray with triangle
+ inline void intersectTriangle(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const;
+ //! intersect only with front side
+ inline void intersectTriangleFront(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const;
+ //! intersect ray only with backsides
+ inline void intersectTriangleBack(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const;
+
+ // access methods
+ //! Returns the ray origin
+ inline ntlVec3Gfx getOrigin() const { return ntlVec3Gfx(mOrigin); }
+ //! Returns the ray direction
+ inline ntlVec3Gfx getDirection() const { return ntlVec3Gfx(mDirection); }
+ /*! Returns the ray relfection normal */
+ inline ntlVec3Gfx getNormal() const { return ntlVec3Gfx(mvNormal); }
+ //! Is this ray refracted?
+ inline unsigned char getRefracted() const { return mIsRefracted; }
+ inline unsigned char getReflected() const { return mIsReflected; }
+ /*! Get position along ray */
+ inline ntlVec3Gfx getPositionAt(gfxReal t) const { return (mOrigin+(mDirection*t)); }
+ /*! Get render globals pointer of this ray */
+ inline ntlRenderGlobals *getRenderglobals( void ) const { return mpGlob; }
+ /*! get this ray's ID */
+ inline int getID( void ) const { return mID; }
+
+ /*! Set origin of this ray */
+ inline void setOrigin(ntlVec3Gfx set) { mOrigin = set; }
+ /*! Set direction of this ray */
+ inline void setDirection(ntlVec3Gfx set) { mDirection = set; }
+ /*! Set normal of this ray */
+ inline void setNormal(ntlVec3Gfx set) { mvNormal = set; }
+
+protected:
+ /* Calulates the Lambertian and Specular color for
+ * the given reflection and returns it */
+ const ntlColor getShadedColor(ntlLightObject *light, const ntlRay &reflectedray,
+ const ntlVec3Gfx &normal, ntlMaterial *surf) const;
+
+private:
+ /*! Origin of ray */
+ ntlVec3Gfx mOrigin;
+ /*! Normalized direction vector of ray */
+ ntlVec3Gfx mDirection;
+ /*! For reflected/refracted rays, the normal is stored here */
+ ntlVec3Gfx mvNormal;
+ /*! recursion depth */
+ unsigned int mDepth;
+ /*! How much does this ray contribute to the surface color? abort if too small */
+ gfxReal mContribution;
+
+ /*! Global rendering settings */
+ ntlRenderGlobals *mpGlob;
+
+ /*! If this ray is a refracted one, this flag has to be set
+ * This is necessary to for example also give the background color
+ * to refracted rays. Otherwise things may look strange...
+ */
+ unsigned char mIsRefracted;
+ unsigned char mIsReflected;
+
+ /*! ID of this ray (from renderglobals */
+ int mID;
+
+};
+
+
+
+
+
+/******************************************************************
+ * triangle intersection with triangle pointer,
+ * returns t,u,v by references
+ */
+inline void ntlRay::intersectTriangle(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const
+{
+ /* (cf. moeller&haines, page 305) */
+ t = GFX_REAL_MAX;
+ ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ];
+ ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0;
+ ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0;
+ ntlVec3Gfx p = cross( mDirection, e2 );
+ gfxReal a = dot(e1, p);
+ if((a > -RAY_TRIANGLE_EPSILON)&&(a < RAY_TRIANGLE_EPSILON)) return;
+
+ gfxReal f = 1/a;
+ ntlVec3Gfx s = mOrigin - e0;
+ u = f * dot(s, p);
+ if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return;
+
+ ntlVec3Gfx q = cross( s,e1 );
+ v = f * dot(mDirection, q);
+ if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return;
+
+ t = f * dot(e2, q);
+}
+/******************************************************************
+ * intersect only front or backsides
+ */
+inline void ntlRay::intersectTriangleFront(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const
+{
+ t = GFX_REAL_MAX;
+ ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ];
+ ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0;
+ ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0;
+ ntlVec3Gfx p = cross( mDirection, e2 );
+ gfxReal a = dot(e1, p);
+ //if((a > -RAY_TRIANGLE_EPSILON)&&(a < RAY_TRIANGLE_EPSILON)) return;
+ if(a < RAY_TRIANGLE_EPSILON) return; // cull backsides
+
+ gfxReal f = 1/a;
+ ntlVec3Gfx s = mOrigin - e0;
+ u = f * dot(s, p);
+ if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return;
+
+ ntlVec3Gfx q = cross( s,e1 );
+ v = f * dot(mDirection, q);
+ if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return;
+
+ t = f * dot(e2, q);
+}
+inline void ntlRay::intersectTriangleBack(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const
+{
+ t = GFX_REAL_MAX;
+ ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ];
+ ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0;
+ ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0;
+ ntlVec3Gfx p = cross( mDirection, e2 );
+ gfxReal a = dot(e1, p);
+ //if((a > -RAY_TRIANGLE_EPSILON)&&(a < RAY_TRIANGLE_EPSILON)) return;
+ if(a > -RAY_TRIANGLE_EPSILON) return; // cull frontsides
+
+ gfxReal f = 1/a;
+ ntlVec3Gfx s = mOrigin - e0;
+ u = f * dot(s, p);
+ if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return;
+
+ ntlVec3Gfx q = cross( s,e1 );
+ v = f * dot(mDirection, q);
+ if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return;
+
+ t = f * dot(e2, q);
+}
+
+
+
+
+
+#endif
+
diff --git a/intern/elbeem/intern/ntl_raytracer.cpp b/intern/elbeem/intern/ntl_raytracer.cpp
new file mode 100644
index 00000000000..ccd51a1a69e
--- /dev/null
+++ b/intern/elbeem/intern/ntl_raytracer.cpp
@@ -0,0 +1,726 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Main renderer class
+ *
+ *****************************************************************************/
+
+
+#include <sys/stat.h>
+#include <sstream>
+#include "utilities.h"
+#include "ntl_raytracer.h"
+#include "ntl_scene.h"
+#include "parametrizer.h"
+#include "globals.h"
+
+// for non-threaded renderViz
+#ifndef NOGUI
+#include "../gui/ntl_openglrenderer.h"
+#include "../gui/guifuncs.h"
+#include "../gui/frame.h"
+#endif
+
+
+/* external parser functions from cfgparser.cxx */
+//#include "cfgparse_functions.h"
+
+/* parse given file as config file */
+void parseFile(string filename);
+
+/* set pointers for parsing */
+void setPointers( ntlRenderGlobals *setglob);
+
+
+/******************************************************************************
+ * Constructor
+ *****************************************************************************/
+ntlRaytracer::ntlRaytracer(string filename, bool commandlineMode) :
+ mpGlob(NULL),
+ mpLightList(NULL), mpPropList(NULL), mpSims(NULL),
+ mpOpenGLRenderer(NULL),
+ mStopRenderVisualization( false ),
+ mThreadRunning( false ),
+ mSimulationTime(0.0), mFirstSim(-1),
+ mSingleStepDebug( false )
+{
+ /* create scene storage */
+ mpGlob = new ntlRenderGlobals();
+ mpLightList = new vector<ntlLightObject*>;
+ mpPropList = new vector<ntlMaterial*>;
+ mpSims = new vector<SimulationObject*>;
+
+ mpGlob->setLightList(mpLightList);
+ mpGlob->setMaterials(mpPropList);
+ mpGlob->setSims(mpSims);
+
+ /* init default material */
+ ntlMaterial *def = GET_GLOBAL_DEFAULT_MATERIAL;
+ mpPropList->push_back( def );
+
+ /* init the scene object */
+ ntlScene *scene;
+ scene = new ntlScene( mpGlob );
+ mpGlob->setScene( scene );
+
+ // load config
+ setPointers( getRenderGlobals() );
+ parseFile( filename.c_str() );
+
+
+ // init the scene for the first time
+ long startTime = getTime();
+ scene->buildScene();
+ long stopTime = getTime();
+ debMsgStd("ntlRaytracer::ntlRaytracer",DM_MSG,"Scene build time: "<< getTimeString(stopTime-startTime) <<" ", 10);
+
+ // TODO check simulations, run first steps
+ mFirstSim = -1;
+ if(mpSims->size() > 0) {
+
+ // use values from first simulation as master time scale
+ long startTime = getTime();
+
+ // remember first active sim
+ for(size_t i=0;i<mpSims->size();i++) {
+ if(!(*mpSims)[i]->getVisible()) continue;
+ if((*mpSims)[i]->getPanic()) continue;
+
+ // check largest timestep
+ if(mFirstSim>=0) {
+ if( (*mpSims)[i]->getStepTime() > (*mpSims)[mFirstSim]->getStepTime() ) {
+ mFirstSim = i;
+ debMsgStd("ntlRaytracer::ntlRaytracer",DM_MSG,"First Sim changed: "<<i ,10);
+ }
+ }
+ // check any valid sim
+ if(mFirstSim<0) {
+ mFirstSim = i;
+ debMsgStd("ntlRaytracer::ntlRaytracer",DM_MSG,"First Sim: "<<i ,10);
+ }
+ }
+
+ if(mFirstSim>=0) {
+ debMsgStd("ntlRaytracer::ntlRaytracer",DM_MSG,"Anistart Time: "<<(*mpSims)[mFirstSim]->getStartTime() ,10);
+ while(mSimulationTime < (*mpSims)[mFirstSim]->getStartTime() ) {
+ debMsgStd("ntlRaytracer::ntlRaytracer",DM_MSG,"Anistart Time: "<<(*mpSims)[mFirstSim]->getStartTime()<<" simtime:"<<mSimulationTime ,10);
+ advanceSims();
+ }
+ long stopTime = getTime();
+
+ mSimulationTime += (*mpSims)[mFirstSim]->getStartTime();
+ debMsgStd("ntlRaytracer::ntlRaytracer",DM_MSG,"Time for start simulations times "<<": "<< getTimeString(stopTime-startTime) <<"s ", 1);
+#ifndef NOGUI
+ guiResetSimulationTimeRange( mSimulationTime );
+#endif
+ } else {
+ if(!mpGlob->getSingleFrameMode()) debMsgStd("ntlRaytracer::ntlRaytracer",DM_WARNING,"No active simulations!", 1);
+ }
+ }
+
+#ifndef NOGUI
+ // setup opengl display, save first animation step for start time
+ if(!commandlineMode) {
+ mpOpenGLRenderer = new ntlOpenGLRenderer( mpGlob, scene );
+ }
+#else // NOGUI
+ commandlineMode = true; // remove warning...
+#endif // NOGUI
+}
+
+
+
+/******************************************************************************
+ * Destructor
+ *****************************************************************************/
+ntlRaytracer::~ntlRaytracer()
+{
+ delete mpGlob->getScene();
+ delete mpGlob;
+ delete mpLightList;
+ delete mpPropList;
+ delete mpSims;
+#ifndef NOGUI
+ if(mpOpenGLRenderer) delete mpOpenGLRenderer;
+#endif // NOGUI
+}
+
+/******************************************************************************/
+/*! set single frame rendering to filename */
+void ntlRaytracer::setSingleFrameOut(string singleframeFilename) {
+ mpGlob->setSingleFrameMode(true);
+ mpGlob->setSingleFrameFilename(singleframeFilename);
+}
+
+/******************************************************************************
+ * render a whole animation (command line mode)
+ *****************************************************************************/
+#if ELBEEM_BLENDER==1
+extern "C" {
+ void simulateThreadIncreaseFrame(void);
+}
+#endif // ELBEEM_BLENDER==1
+int ntlRaytracer::renderAnimation( void )
+{
+ // only single pic currently
+ //debMsgStd("ntlRaytracer::renderAnimation : Warning only simulating...",1);
+ if(mpGlob->getAniFrames() < 0) {
+ debMsgStd("ntlRaytracer::renderAnimation",DM_NOTIFY,"No frames to render... ",1);
+ return 1;
+ }
+
+ if(mFirstSim<0) {
+ debMsgStd("ntlRaytracer::renderAnimation",DM_NOTIFY,"No reference animation found...",1);
+ return 1;
+ }
+
+ mThreadRunning = true; // not threaded, but still use the same flags
+ renderScene();
+ for(int i=0; ((i<mpGlob->getAniFrames()) && (!getStopRenderVisualization() )); i++) {
+ advanceSims();
+ renderScene();
+#if ELBEEM_BLENDER==1
+ // update gui display
+ simulateThreadIncreaseFrame();
+#endif // ELBEEM_BLENDER==1
+
+ if(mpSims->size() <= 0) {
+ debMsgStd("ntlRaytracer::renderAnimation",DM_NOTIFY,"No simulations found, stopping...",1);
+ return 1;
+ }
+ }
+ mThreadRunning = false;
+
+ return 0;
+}
+
+/******************************************************************************
+ * render a whole animation (visualization mode)
+ * this function is run in another thread, and communicates
+ * with the parent thread via a mutex
+ *****************************************************************************/
+int ntlRaytracer::renderVisualization( bool multiThreaded )
+{
+#ifndef NOGUI
+ //gfxReal deltat = 0.0015;
+ if(multiThreaded) mThreadRunning = true;
+ while(!getStopRenderVisualization()) {
+
+ if(mpSims->size() <= 0) {
+ debMsgStd("ntlRaytracer::renderVisualization",DM_NOTIFY,"No simulations found, stopping...",1);
+ stopSimulationThread();
+ break;
+ }
+
+ // determine stepsize
+ if(!mSingleStepDebug) {
+ long startTime = getTime();
+ advanceSims();
+ long stopTime = getTime();
+ debMsgStd("ntlRaytracer::renderVisualization",DM_MSG,"Time for "<<mSimulationTime<<": "<< getTimeString(stopTime-startTime) <<"s ", 10);
+ } else {
+ double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getStepTime();
+ singleStepSims(targetTime);
+
+ // check paniced sims (normally done by advanceSims
+ bool allPanic = true;
+ for(size_t i=0;i<mpSims->size();i++) {
+ if(!(*mpSims)[i]->getPanic()) allPanic = false;
+ }
+ if(allPanic) {
+ warnMsg("ntlRaytracer::advanceSims","All sims panicked... stopping thread" );
+ setStopRenderVisualization( true );
+ }
+ //? mSimulationTime = (*mpSims)[mFirstSim]->getCurrentTime();
+ //debMsgStd("ntlRaytracer::renderVisualization : single step mode ", 10);
+ //debMsgStd("", 10 );
+ }
+
+#ifndef NOGUI
+ // save frame
+ if(mpOpenGLRenderer) mpOpenGLRenderer->saveAnimationFrame( mSimulationTime );
+#endif // NOGUI
+
+ // for non-threaded check events
+ if(!multiThreaded) {
+ //if(gpElbeemFrame->ElbeemWindow->visible()) {
+ //if (!Fl::check()) break; // returns immediately
+ //}
+ Fl::check();
+ //gpElbeemFrame->SceneDisplay->doIdleRedraw();
+ gpElbeemFrame->SceneDisplay->doOnlyForcedRedraw();
+ }
+
+ }
+ mThreadRunning = false;
+ stopSimulationRestoreGui();
+#else
+ multiThreaded = false; // remove warning
+#endif
+ return 0;
+}
+/*! render a single step for viz mode */
+int ntlRaytracer::singleStepVisualization( void )
+{
+ mThreadRunning = true;
+ double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getStepTime();
+ singleStepSims(targetTime);
+ mSimulationTime = (*mpSims)[0]->getCurrentTime();
+
+#ifndef NOGUI
+ if(mpOpenGLRenderer) mpOpenGLRenderer->saveAnimationFrame( mSimulationTime );
+ Fl::check();
+ gpElbeemFrame->SceneDisplay->doOnlyForcedRedraw();
+#endif // NOGUI
+
+ mThreadRunning = false;
+#ifndef NOGUI
+ stopSimulationRestoreGui();
+#endif
+ return 0;
+}
+
+// dont use LBM_EPSILON here, time is always double-precision!
+#define LBM_TIME_EPSILON 1e-10
+
+/******************************************************************************
+ * advance simulations by time t
+ *****************************************************************************/
+int ntlRaytracer::advanceSims()
+{
+ //gfxReal currTime[ mpSims->size() ];
+
+ bool done = false;
+ bool allPanic = true;
+ double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getFrameTime();
+ //debMsgStd("ntlRaytracer::advanceSims",DM_MSG,"Advancing sims to "<<targetTime, 10 ); // timedebug
+
+ while(!done) {
+ double nextTargetTime = (*mpSims)[mFirstSim]->getCurrentTime() + (*mpSims)[mFirstSim]->getStepTime();
+ singleStepSims(nextTargetTime);
+
+ // check target times
+ done = true;
+ allPanic = false;
+ for(size_t i=0;i<mpSims->size();i++) {
+ if(!(*mpSims)[i]->getVisible()) continue;
+ if((*mpSims)[i]->getPanic()) allPanic = true; // do any panic now!?
+ //debMsgStd("ntlRaytracer::advanceSims",DM_MSG, " sim "<<i<<" c"<<(*mpSims)[i]->getCurrentTime()<<" p"<<(*mpSims)[i]->getPanic()<<" t"<<targetTime, 10); // debug // timedebug
+ }
+ //if((*mpSims)[mFirstSim]->getCurrentTime() < targetTime) done = false;
+ if( (targetTime - (*mpSims)[mFirstSim]->getCurrentTime()) > LBM_TIME_EPSILON) done=false;
+ if(allPanic) done = true;
+ }
+
+ if(allPanic) {
+ warnMsg("ntlRaytracer::advanceSims","All sims panicked... stopping thread" );
+ setStopRenderVisualization( true );
+ }
+ for(size_t i=0;i<mpSims->size();i++) {
+ SimulationObject *sim = (*mpSims)[i];
+ if(!sim->getVisible()) continue;
+ if(sim->getPanic()) continue;
+ sim->prepareVisualization();
+ }
+
+ return 0;
+}
+
+/* advance simulations by a single step */
+/* dont check target time, if *targetTime==NULL */
+void ntlRaytracer::singleStepSims(double targetTime) {
+ const bool debugTime = false;
+ //double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getStepTime();
+ if(debugTime) errMsg("ntlRaytracer::singleStepSims","Target time: "<<targetTime);
+
+ for(size_t i=0;i<mpSims->size();i++) {
+ SimulationObject *sim = (*mpSims)[i];
+ if(!sim->getVisible()) continue;
+ if(sim->getPanic()) continue;
+ bool done = false;
+ while(!done) {
+ // try to prevent round off errs
+ if(debugTime) errMsg("ntlRaytracer::singleStepSims","Test sim "<<i<<" curt:"<< sim->getCurrentTime()<<" target:"<<targetTime<<" delta:"<<(targetTime - sim->getCurrentTime())<<" stept:"<<sim->getStepTime()<<" leps:"<<LBM_TIME_EPSILON ); // timedebug
+ if( (targetTime - sim->getCurrentTime()) > LBM_TIME_EPSILON) {
+ if(debugTime) errMsg("ntlRaytracer::singleStepSims","Stepping sim "<<i<<" t:"<< sim->getCurrentTime()); // timedebug
+ sim->step();
+ } else {
+ done = true;
+ }
+ }
+ }
+
+ mSimulationTime = (*mpSims)[mFirstSim]->getCurrentTime();
+#ifndef NOGUI
+ if(mpOpenGLRenderer) mpOpenGLRenderer->notifyOfNextStep(mSimulationTime);
+#endif // NOGUI
+}
+
+
+
+
+/******************************************************************************
+ * Render the current scene
+ * uses the global variables from the parser
+ *****************************************************************************/
+int ntlRaytracer::renderScene( void )
+{
+ char nrStr[5]; /* nr conversion */
+ //std::ostringstream outfilename(""); /* ppm file */
+ std::ostringstream outfn_conv(""); /* converted ppm with other suffix */
+ ntlRenderGlobals *glob; /* storage for global rendering parameters */
+ myTime_t timeStart,totalStart,timeEnd; /* measure user running time */
+ myTime_t rendStart,rendEnd; /* measure user rendering time */
+ glob = mpGlob;
+
+ /* check if picture already exists... */
+ if(!glob->getSingleFrameMode() ) {
+ snprintf(nrStr, 5, "%04d", glob->getAniCount() );
+ //outfilename << glob->getOutFilename() <<"_" << nrStr << ".ppm";
+ outfn_conv << glob->getOutFilename() <<"_" << nrStr << ".png";
+
+ //if((mpGlob->getDisplayMode() == DM_RAY)&&(mpGlob->getFrameSkip())) {
+ if(mpGlob->getFrameSkip()) {
+ struct stat statBuf;
+ if(stat(outfn_conv.str().c_str(),&statBuf) == 0) {
+ errorOut("ntlRaytracer::renderscene Warning: file "<<outfn_conv.str()<<" already exists - skipping frame...");
+ glob->setAniCount( glob->getAniCount() +1 );
+ return(2);
+ }
+ } // RAY mode
+ } else {
+ // single frame rendering, overwrite if necessary...
+ outfn_conv << glob->getSingleFrameFilename();
+ }
+
+ /* start program */
+ timeStart = getTime();
+
+ /* build scene geometry */
+ glob->getScene()->prepareScene();
+
+ /* start program */
+ totalStart = getTime();
+
+
+ /* view parameters are currently not animated */
+ /* calculate rays through projection plane */
+ ntlVec3Gfx direction = glob->getLookat() - glob->getEye();
+ /* calculate width of screen using perpendicular triangle diven by
+ * viewing direction and screen plane */
+ gfxReal screenWidth = norm(direction)*tan( (glob->getFovy()*0.5/180.0)*M_PI );
+
+ /* calculate vector orthogonal to up and viewing direction */
+ ntlVec3Gfx upVec = glob->getUpVec();
+ ntlVec3Gfx rightVec( cross(upVec,direction) );
+ normalize(rightVec);
+
+ /* calculate screen plane up vector, perpendicular to viewdir and right vec */
+ upVec = ntlVec3Gfx( cross(rightVec,direction) );
+ normalize(upVec);
+
+ /* check if vectors are valid */
+ if( (equal(upVec,ntlVec3Gfx(0.0))) || (equal(rightVec,ntlVec3Gfx(0.0))) ) {
+ errorOut("NTL ERROR: Invalid viewpoint vectors!\n");
+ return(1);
+ }
+
+ /* length from center to border of screen plane */
+ rightVec *= (screenWidth*glob->getAspect() * -1.0);
+ upVec *= (screenWidth * -1.0);
+
+ /* screen traversal variables */
+ ntlVec3Gfx screenPos; /* current position on virtual screen */
+ int Xres = glob->getResX(); /* X resolution */
+ int Yres = glob->getResY(); /* Y resolution */
+ ntlVec3Gfx rightStep = (rightVec/(Xres/2.0)); /* one step right for a pixel */
+ ntlVec3Gfx upStep = (upVec/(Yres/2.0)); /* one step up for a pixel */
+
+
+ /* anti alias init */
+ char showAAPic = 0;
+ int aaDepth = glob->getAADepth();
+ int aaLength;
+ if(aaDepth>=0) aaLength = (2<<aaDepth);
+ else aaLength = 0;
+ float aaSensRed = 0.1;
+ float aaSensGreen = 0.1;
+ float aaSensBlue = 0.1;
+ int aaArrayX = aaLength*Xres+1;
+ int aaArrayY = ( aaLength+1 );
+ ntlColor *aaCol = new ntlColor[ aaArrayX*aaArrayY ];
+ char *aaUse = new char[ aaArrayX*aaArrayY ];
+
+ /* picture storage */
+ int picX = Xres;
+ int picY = Yres;
+ if(showAAPic) {
+ picX = Xres *aaLength+1;
+ picY = Yres *aaLength+1;
+ }
+ ntlColor *finalPic = new ntlColor[picX * picY];
+
+
+ /* reset picture vars */
+ for(int j=0;j<aaArrayY;j++) {
+ for(int i=0;i<aaArrayX;i++) {
+ aaCol[j*aaArrayX+i] = ntlColor(0.0, 0.0, 0.0);
+ aaUse[j*aaArrayX+i] = 0;
+ }
+ }
+ for(int j=0;j<picY;j++) {
+ for(int i=0;i<picX;i++) {
+ finalPic[j*picX+i] = ntlColor(0.0, 0.0, 0.0);
+ }
+ }
+
+ /* loop over all y lines in screen, from bottom to top because
+ * ppm format wants 0,0 top left */
+ rendStart = getTime();
+ glob->setCounterShades(0);
+ glob->setCounterSceneInter(0);
+ for (int scanline=Yres ; scanline > 0 ; --scanline) {
+
+ debugOutInter( "ntlRaytracer::renderScene: Line "<<scanline<<
+ " ("<< ((Yres-scanline)*100/Yres) <<"%) ", 2, 2000 );
+ screenPos = glob->getLookat() + upVec*((2.0*scanline-Yres)/Yres)
+ - rightVec;
+
+ /* loop over all pixels in line */
+ for (int sx=0 ; sx < Xres ; ++sx) {
+
+ if((sx==glob->getDebugPixelX())&&(scanline==(Yres-glob->getDebugPixelY()) )) {
+ // DEBUG!!!
+ glob->setDebugOut(10);
+ } else glob->setDebugOut(0);
+
+ /* compute ray from eye through current pixel into scene... */
+ ntlColor col;
+ if(aaDepth<0) {
+ ntlVec3Gfx dir(screenPos - glob->getEye());
+ ntlRay the_ray(glob->getEye(), getNormalized(dir), 0, 1.0, glob );
+
+ /* ...and trace it */
+ col = the_ray.shade();
+ } else {
+ /* anti alias */
+ int ai,aj; /* position in grid */
+ int aOrg = sx*aaLength; /* grid offset x */
+ int currStep = aaLength; /* step size */
+ char colDiff = 1; /* do colors still differ too much? */
+ ntlColor minCol,maxCol; /* minimum and maximum Color Values */
+ minCol = ntlColor(1.0,1.0,1.0);
+ maxCol = ntlColor(0.0,0.0,0.0);
+
+ while((colDiff) && (currStep>0)) {
+ colDiff = 0;
+
+ for(aj = 0;aj<=aaLength;aj+= currStep) {
+ for(ai = 0;ai<=aaLength;ai+= currStep) {
+
+ /* shade pixel if not done */
+ if(aaUse[aj*aaArrayX +ai +aOrg] == 0) {
+ aaUse[aj*aaArrayX +ai +aOrg] = 1;
+ ntlVec3Gfx aaPos( screenPos +
+ (rightStep * (ai- aaLength/2)/(gfxReal)aaLength ) +
+ (upStep * (aj- aaLength/2)/(gfxReal)aaLength ) );
+
+ ntlVec3Gfx dir(aaPos - glob->getEye());
+ ntlRay the_ray(glob->getEye(), getNormalized(dir), 0, 1.0, glob );
+
+ /* ...and trace it */
+ ntlColor newCol= the_ray.shade();
+ aaCol[aj*aaArrayX +ai +aOrg]= newCol;
+ } /* not used? */
+
+ }
+ }
+
+ /* check color differences */
+ for(aj = 0;aj<aaLength;aj+= currStep) {
+ for(ai = 0;ai<aaLength;ai+= currStep) {
+
+ char thisColDiff = 0;
+ if(
+ (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] -
+ aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][0])> aaSensRed ) ||
+ (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] -
+ aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][1])> aaSensGreen ) ||
+ (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] -
+ aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][2])> aaSensBlue ) ) {
+ thisColDiff = 1;
+ } else
+ if(
+ (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] -
+ aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][0])> aaSensRed ) ||
+ (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] -
+ aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][1])> aaSensGreen ) ||
+ (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] -
+ aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][2])> aaSensBlue ) ) {
+ thisColDiff = 1;
+ } else
+ if(
+ (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] -
+ aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][0])> aaSensRed ) ||
+ (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] -
+ aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][1])> aaSensGreen ) ||
+ (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] -
+ aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][2])> aaSensBlue ) ) {
+ thisColDiff = 1;
+ }
+
+ //colDiff =1;
+ if(thisColDiff) {
+ /* set diff flag */
+ colDiff = thisColDiff;
+ for(int bj=aj;bj<=aj+currStep;bj++) {
+ for(int bi=ai;bi<=ai+currStep;bi++) {
+ if(aaUse[bj*aaArrayX +bi +aOrg]==2) {
+ //if(showAAPic)
+ aaUse[bj*aaArrayX +bi +aOrg] = 0;
+ }
+ }
+ }
+ } else {
+ /* set all values */
+ ntlColor avgCol = (
+ aaCol[(aj+0 )*aaArrayX +(ai+0 ) +aOrg] +
+ aaCol[(aj+0 )*aaArrayX +(ai+currStep) +aOrg] +
+ aaCol[(aj+currStep)*aaArrayX +(ai+0 ) +aOrg] +
+ aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg] ) *0.25;
+ for(int bj=aj;bj<=aj+currStep;bj++) {
+ for(int bi=ai;bi<=ai+currStep;bi++) {
+ if(aaUse[bj*aaArrayX +bi +aOrg]==0) {
+ aaCol[bj*aaArrayX +bi +aOrg] = avgCol;
+ aaUse[bj*aaArrayX +bi +aOrg] = 2;
+ }
+ }
+ }
+ } /* smaller values set */
+
+ }
+ }
+
+ /* half step size */
+ currStep /= 2;
+
+ } /* repeat until diff not too big */
+
+ /* get average color */
+ gfxReal colNum = 0.0;
+ col = ntlColor(0.0, 0.0, 0.0);
+ for(aj = 0;aj<=aaLength;aj++) {
+ for(ai = 0;ai<=aaLength;ai++) {
+ col += aaCol[aj*aaArrayX +ai +aOrg];
+ colNum += 1.0;
+ }
+ }
+ col /= colNum;
+
+ }
+
+ /* mark pixels with debugging */
+ if( glob->getDebugOut() > 0) col = ntlColor(0,1,0);
+
+ /* store pixel */
+ if(!showAAPic) {
+ finalPic[(scanline-1)*picX+sx] = col;
+ }
+ screenPos += rightStep;
+
+ } /* foreach x */
+
+ /* init aa array */
+ if(showAAPic) {
+ for(int j=0;j<=aaArrayY-1;j++) {
+ for(int i=0;i<=aaArrayX-1;i++) {
+ if(aaUse[j*aaArrayX +i]==1) finalPic[((scanline-1)*aaLength +j)*picX+i][0] = 1.0;
+ }
+ }
+ }
+
+ for(int i=0;i<aaArrayX;i++) {
+ aaCol[(aaArrayY-1)*aaArrayX+i] = aaCol[0*aaArrayX+i];
+ aaUse[(aaArrayY-1)*aaArrayX+i] = aaUse[0*aaArrayX+i];
+ }
+ for(int j=0;j<aaArrayY-1;j++) {
+ for(int i=0;i<aaArrayX;i++) {
+ aaCol[j*aaArrayX+i] = ntlColor(0.0, 0.0, 0.0);
+ aaUse[j*aaArrayX+i] = 0;
+ }
+ }
+
+ } /* foreach y */
+ rendEnd = getTime();
+
+
+ /* write png file */
+ {
+ int w = picX;
+ int h = picY;
+
+ unsigned rowbytes = w*4;
+ unsigned char *screenbuf, **rows;
+ screenbuf = (unsigned char*)malloc( h*rowbytes );
+ rows = (unsigned char**)malloc( h*sizeof(unsigned char*) );
+ unsigned char *filler = screenbuf;
+
+ // cutoff color values 0..1
+ for(int j=0;j<h;j++) {
+ for(int i=0;i<w;i++) {
+ ntlColor col = finalPic[j*w+i];
+ for (unsigned int cc=0; cc<3; cc++) {
+ if(col[cc] <= 0.0) col[cc] = 0.0;
+ if(col[cc] >= 1.0) col[cc] = 1.0;
+ }
+ *filler = (unsigned char)( col[0]*255.0 );
+ filler++;
+ *filler = (unsigned char)( col[1]*255.0 );
+ filler++;
+ *filler = (unsigned char)( col[2]*255.0 );
+ filler++;
+ *filler = (unsigned char)( 255.0 );
+ filler++; // alpha channel
+ }
+ }
+
+ for(int i = 0; i < h; i++) rows[i] = &screenbuf[ (h - i - 1)*rowbytes ];
+#ifndef NOPNG
+ writePng(outfn_conv.str().c_str(), rows, w, h);
+#else // NOPNG
+ debMsgStd("ntlRaytracer::renderScene",DM_NOTIFY, "No PNG linked, no picture...", 1);
+#endif // NOPNG
+ }
+
+
+ // next frame
+ glob->setAniCount( glob->getAniCount() +1 );
+
+ // done
+ timeEnd = getTime();
+
+ char resout[1024];
+ snprintf(resout,1024, "NTL Done %s, frame %d/%d (%s scene, %s raytracing, %s total, %d shades, %d i.s.'s)!\n",
+ outfn_conv.str().c_str(), (glob->getAniCount()), (glob->getAniFrames()+1),
+ getTimeString(totalStart-timeStart).c_str(), getTimeString(rendEnd-rendStart).c_str(), getTimeString(timeEnd-timeStart).c_str(),
+ glob->getCounterShades(),
+ glob->getCounterSceneInter() );
+ debMsgStd("ntlRaytracer::renderScene",DM_MSG, resout, 1 );
+
+ /* clean stuff up */
+ delete [] aaCol;
+ delete [] aaUse;
+ delete [] finalPic;
+ glob->getScene()->cleanupScene();
+
+ if(mpGlob->getSingleFrameMode() ) {
+ debMsgStd("ntlRaytracer::renderScene",DM_NOTIFY, "Single frame mode done...", 1 );
+ exit(1);
+ }
+ return 0;
+}
+
+
+
diff --git a/intern/elbeem/intern/ntl_raytracer.h b/intern/elbeem/intern/ntl_raytracer.h
new file mode 100644
index 00000000000..3f36fabaf92
--- /dev/null
+++ b/intern/elbeem/intern/ntl_raytracer.h
@@ -0,0 +1,105 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Main renderer class
+ *
+ *****************************************************************************/
+#ifndef NTL_RAYTRACER_HH
+#define NTL_RAYTRACER_HH
+
+#include "ntl_vector3dim.h"
+#include "ntl_ray.h"
+#include "ntl_geometryobject.h"
+#include "ntl_lightobject.h"
+#include "ntl_renderglobals.h"
+#include "ntl_material.h"
+#include "simulation_object.h"
+class ntlOpenGLRenderer;
+
+class ntlRaytracer
+{
+ public:
+ /*! Constructor */
+ ntlRaytracer(string filename, bool commandlineMode);
+ /*! Destructor */
+ virtual ~ntlRaytracer( void );
+
+ /*! render a whole animation (command line mode) */
+ int renderAnimation( void );
+ /*! render a whole animation (visualization mode) */
+ int renderVisualization( bool );
+ /*! render a single step for viz mode */
+ int singleStepVisualization( void );
+ /*! advance simulations by time frame time */
+ int advanceSims();
+ /*! advance simulations by a single step */
+ void singleStepSims(double targetTime);
+
+ /*! set stop rend viz flag */
+ void setStopRenderVisualization(bool set) { mStopRenderVisualization = set; }
+ /*! should the rendering viz thread be stopped? */
+ bool getStopRenderVisualization() { return mStopRenderVisualization; }
+
+ /*! render scene (a single pictures) */
+ virtual int renderScene( void );
+
+ /*! display world with opengl */
+ //int draw( void );
+ /*! set single frame rendering to filename */
+ void setSingleFrameOut( string singleframeFilename );
+
+ /* access functions */
+
+ /*! set&get render globals */
+ inline void setRenderGlobals( ntlRenderGlobals *set) { mpGlob = set; }
+ inline ntlRenderGlobals *getRenderGlobals( void ) { return mpGlob; }
+
+ /*! set&get render globals */
+ inline void setSimulationTime( double set) { mSimulationTime = set; }
+ inline double getSimulationTime( void ) { return mSimulationTime; }
+
+ /*! set&get single step debug mode */
+ inline void setSingleStepDebug( bool set) { mSingleStepDebug = set; }
+ inline bool getSingleStepDebug( void ) { return mSingleStepDebug; }
+
+ /*! &get simulation object vector (debugging) */
+ inline vector<SimulationObject*> *getSimulations( void ) { return mpSims; }
+
+ /*! get opengl renderer */
+ inline ntlOpenGLRenderer *getOpenGLRenderer() { return mpOpenGLRenderer; }
+
+ private:
+
+ protected:
+
+ /*! global render settings needed almost everywhere */
+ ntlRenderGlobals *mpGlob;
+
+ /*! a list of lights in the scene (geometry is store in ntl_scene) */
+ vector<ntlLightObject*> *mpLightList;
+ /*! surface materials */
+ vector<ntlMaterial*> *mpPropList;
+ /*! sims list */
+ vector<SimulationObject*> *mpSims;
+
+ /*! opengl display */
+ ntlOpenGLRenderer *mpOpenGLRenderer;
+
+ /*! stop rend viz? */
+ bool mStopRenderVisualization;
+
+ /*! rend viz thread currently running? */
+ bool mThreadRunning;
+
+ /*! remember the current simulation time */
+ double mSimulationTime;
+ /*! first simulation that is valid */
+ int mFirstSim;
+
+ /*! single step mode for debugging */
+ bool mSingleStepDebug;
+};
+
+#endif
diff --git a/intern/elbeem/intern/ntl_renderglobals.h b/intern/elbeem/intern/ntl_renderglobals.h
new file mode 100644
index 00000000000..dc999f2c92f
--- /dev/null
+++ b/intern/elbeem/intern/ntl_renderglobals.h
@@ -0,0 +1,371 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * main renderer class
+ *
+ *****************************************************************************/
+#ifndef NTL_RENDERGLOBALS_HH
+#define NTL_RENDERGLOBALS_HH
+
+
+#include "ntl_vector3dim.h"
+#include "ntl_rndstream.h"
+#include "ntl_geometryobject.h"
+#include "ntl_material.h"
+#include "ntl_lightobject.h"
+class ntlScene;
+class SimulationObject;
+
+
+
+//! Display mode
+#define DM_VIZ 0
+#define DM_RAY 1
+#define DM_LBM 2
+
+
+
+//! Class that handles global rendering parameters
+class ntlRenderGlobals
+{
+ public:
+ //! Standard constructor
+ inline ntlRenderGlobals();
+ //! Destructor
+ ~ntlRenderGlobals();
+
+ //! Returns the scene manager
+ inline ntlScene *getScene(void) { return mpScene; }
+ //! Set the scene manager
+ inline void setScene(ntlScene *set) { mpScene = set;}
+
+ //! Returns the object list
+ //inline vector<ntlGeometryObject*> *getObjectList(void) { return mpObjList; }
+ //! Set the object list
+ //inline void setObjectList(vector<ntlGeometryObject*> *set) { mpObjList = set;}
+
+ //! Returns the light object list
+ inline vector<ntlLightObject*> *getLightList(void) { return mpLightList; }
+ //! Set the light list
+ inline void setLightList(vector<ntlLightObject*> *set) { mpLightList = set;}
+
+ //! Returns the property object list
+ inline vector<ntlMaterial*> *getMaterials(void) { return mpMaterials; }
+ //! Set the property list
+ inline void setMaterials(vector<ntlMaterial*> *set) { mpMaterials = set;}
+
+ //! Returns the list of simulations
+ inline vector<SimulationObject*> *getSims(void) { return mpSims; }
+ //! Set the pointer to the list of simulations
+ inline void setSims(vector<SimulationObject*> *set) { mpSims = set;}
+
+ //! Set the x resolution
+ inline void setResX(unsigned int set) { mResX = set; }
+ //! Set the y resolution
+ inline void setResY(unsigned int set) { mResY = set; }
+ //! Set the anti-aliasing depth
+ inline void setAADepth(int set) { mAADepth = set; }
+ //! Set the max color value
+ inline void setMaxColVal(unsigned int set) { mMaxColVal = set; }
+ //! Set the maximum ray recursion
+ inline void setRayMaxDepth(unsigned int set) { mRayMaxDepth = set; }
+ //! Set the eye point
+ inline void setEye(ntlVec3Gfx set) { mvEye = set; }
+ //! Set the look at vector
+ inline void setLookat(ntlVec3Gfx set) { mvLookat = set; }
+ //! Set the up vector
+ inline void setUpVec(ntlVec3Gfx set) { mvUpvec = set; }
+ //! Set the image aspect
+ inline void setAspect(float set) { mAspect = set; }
+ //! Set the field of view
+ inline void setFovy(float set) { mFovy = set; }
+ //! Set the background color
+ inline void setBackgroundCol(ntlColor set) { mcBackgr = set; }
+ //! Set the ambient lighting color
+ inline void setAmbientLight(ntlColor set) { mcAmbientLight = set; }
+ //! Set the debug output var
+ inline void setDebugOut(int set) { mDebugOut = set; }
+
+ //! Set the animation start time
+ inline void setAniStart(int set) { mAniStart = set; }
+ //! Set the animation number of frames
+ inline void setAniFrames(int set) { mAniFrames = set; }
+ //! Set the animation
+ inline void setAniCount(int set) { mAniCount = set; }
+ //! Set the lbmsolver animation step size
+ inline void setAniFrameTime(int set) { mAniFrameTime=set; }
+ //! Set the ray counter
+ inline void setCounterRays(int set) { mCounterRays = set; }
+ //! Set the ray shades counter
+ inline void setCounterShades(int set) { mCounterShades = set; }
+ //! Set the scenen intersection counter
+ inline void setCounterSceneInter(int set) { mCounterSceneInter = set; }
+ //! Set if existing frames should be skipped
+ inline void setFrameSkip(int set) { mFrameSkip = set; }
+
+ //! Set the outfilename
+ inline void setOutFilename(string set) { mOutFilename = set; }
+
+ //! get Maximum depth for BSP tree
+ inline void setTreeMaxDepth( int set ) { mTreeMaxDepth = set; }
+ //! get Maxmimum nr of triangles per BSP tree node
+ inline void setTreeMaxTriangles( int set ) { mTreeMaxTriangles = set; }
+
+ //! set the enable flag of the test sphere
+ inline void setTestSphereEnabled( bool set ) { mTestSphereEnabled = set; }
+ //! set the center of the test sphere
+ inline void setTestSphereCenter( ntlVec3Gfx set ) { mTestSphereCenter = set; }
+ //! set the radius of the test sphere
+ inline void setTestSphereRadius( gfxReal set ) { mTestSphereRadius = set; }
+ //! set the material name of the test sphere
+ inline void setTestSphereMaterialName( char* set ) { mTestSphereMaterialName = set; }
+ //! set debugging pixel coordinates
+ inline void setDebugPixel( int setx, int sety ) { mDebugPixelX = setx; mDebugPixelY = sety; }
+ //! set test mode flag
+ inline void setTestMode( bool set ) { mTestMode = set; }
+ //! set single frame mode flag
+ inline void setSingleFrameMode(bool set) {mSingleFrameMode = set; };
+ //! set single frame mode filename
+ inline void setSingleFrameFilename(string set) {mSingleFrameFilename = set; };
+
+
+ //! Return the x resolution
+ inline unsigned int getResX(void) { return mResX; }
+ //! Return the y resolution
+ inline unsigned int getResY(void) { return mResY; }
+ //! Return the anti-aliasing depth
+ inline int getAADepth(void) { return mAADepth; }
+ //! Return the max color value for ppm
+ inline unsigned int getMaxColVal(void) { return mMaxColVal; }
+ //! Return the maximum ray recursion
+ inline unsigned int getRayMaxDepth(void) { return mRayMaxDepth; }
+ //! Return the eye point
+ inline ntlVec3Gfx getEye(void) { return mvEye; }
+ //! Return the look at vector
+ inline ntlVec3Gfx getLookat(void) { return mvLookat; }
+ //! Return the up vector
+ inline ntlVec3Gfx getUpVec(void) { return mvUpvec; }
+ //! Return the image aspect
+ inline float getAspect(void) { return mAspect; }
+ //! Return the field of view
+ inline float getFovy(void) { return mFovy; }
+ //! Return the background color
+ inline ntlColor getBackgroundCol(void) { return mcBackgr; }
+ //! Return the ambient color
+ inline ntlColor getAmbientLight(void) { return mcAmbientLight; }
+ //! Return the debug mode setting
+ inline int getDebugOut(void) { return mDebugOut; }
+
+ //! Return the animation start time
+ inline int getAniStart(void) { return mAniStart; }
+ //! Return the animation frame number
+ inline int getAniFrames(void) { return mAniFrames; }
+ //! Return the animation counter
+ inline int getAniCount(void) { return mAniCount; }
+ //! Return the ray counter
+ inline int getCounterRays(void) { return mCounterRays; }
+ //! Return the ray shades counter
+ inline int getCounterShades(void) { return mCounterShades; }
+ //! Return the scene intersection counter
+ inline int getCounterSceneInter(void) { return mCounterSceneInter; }
+ /*! Get auto run time variable */
+ inline int getAniFrameTime( void ) { return mAniFrameTime; }
+ //! Check if existing frames should be skipped
+ inline int getFrameSkip( void ) { return mFrameSkip; }
+
+
+ //! Return the outfilename
+ inline string getOutFilename(void) { return mOutFilename; }
+
+ //! get Maximum depth for BSP tree
+ inline int getTreeMaxDepth( void ) { return mTreeMaxDepth; }
+ //! get Maxmimum nr of triangles per BSP tree node
+ inline int getTreeMaxTriangles( void ) { return mTreeMaxTriangles; }
+
+ //! get open gl attribute list
+ inline AttributeList* getOpenGlAttributes( void ) { return mpOpenGlAttr; }
+ //! get blender output attribute list
+ inline AttributeList* getBlenderAttributes( void ) { return mpBlenderAttr; }
+
+ //! is the test sphere enabled?
+ inline bool getTestSphereEnabled( void ) { return mTestSphereEnabled; }
+ //! get the center of the test sphere
+ inline ntlVec3Gfx getTestSphereCenter( void ) { return mTestSphereCenter; }
+ //! get the radius of the test sphere
+ inline gfxReal getTestSphereRadius( void) { return mTestSphereRadius; }
+ //! get the materialname of the test sphere
+ inline char *getTestSphereMaterialName( void) { return mTestSphereMaterialName; }
+ //! get the debug pixel coordinate
+ inline int getDebugPixelX( void ) { return mDebugPixelX; }
+ //! get the debug pixel coordinate
+ inline int getDebugPixelY( void ) { return mDebugPixelY; }
+ //! get test mode flag
+ inline bool getTestMode( void ) { return mTestMode; }
+ //! set single frame mode flag
+ inline bool getSingleFrameMode() { return mSingleFrameMode; };
+ //! set single frame mode filename
+ inline string getSingleFrameFilename() { return mSingleFrameFilename; };
+
+
+ // random number functions
+ //! init random numbers for photon directions
+ inline void initRandomDirections( int seed ) { if(mpRndDirections) delete mpRndDirections; mpRndDirections = new ntlRandomStream( seed ); }
+ //! get the next random photon direction
+ inline ntlVec3Gfx getRandomDirection( void );
+ //! init random numbers for russian roulette
+ inline void initRandomRoulette( int seed ) { if(mpRndRoulette) delete mpRndRoulette; mpRndRoulette = new ntlRandomStream( seed ); }
+ //! get the next random number for russion roulette
+ inline gfxReal getRandomRoulette( void ) { return mpRndRoulette->getGfxReal(); }
+
+
+protected:
+
+private:
+
+ /*! Scene storage */
+ ntlScene *mpScene;
+
+ //! List of geometry objects
+ //vector<ntlGeometryObject*> *mpObjList;
+ //! List of light objects
+ vector<ntlLightObject*> *mpLightList;
+ //! List of surface properties
+ vector<ntlMaterial*> *mpMaterials;
+ /*! storage for simulations */
+ vector<SimulationObject*> *mpSims;
+
+ //! resolution of the picture
+ unsigned int mResX, mResY;
+ //! Anti-Aliasing depth
+ int mAADepth;
+ //! max color value for ppm
+ unsigned int mMaxColVal;
+ /* Maximal ray recursion depth */
+ int mRayMaxDepth;
+ //! The eye point
+ ntlVec3Gfx mvEye;
+ //! The look at point
+ ntlVec3Gfx mvLookat;
+ //! The up vector
+ ntlVec3Gfx mvUpvec;
+ //! The image aspect = Xres/Yres
+ float mAspect;
+ //! The horizontal field of view
+ float mFovy;
+ //! The background color
+ ntlColor mcBackgr;
+ //! The ambient color
+ ntlColor mcAmbientLight;
+ //! how much debug output is needed? off by default
+ char mDebugOut;
+
+
+ //! animation properties, start time
+ int mAniStart;
+ //! animation properties, number of frames to render
+ int mAniFrames;
+ //! animation status, current frame number
+ int mAniCount;
+ /*! no. of steps for auto run (lbmsolver steps) */
+ int mAniFrameTime;
+ /*! Should existing picture frames be skipped? */
+ int mFrameSkip;
+
+
+ //! count the total number of rays created (also used for ray ID's)
+ int mCounterRays;
+ //! count the total number of rays shaded
+ int mCounterShades;
+ //! count the total number of scene intersections
+ int mCounterSceneInter;
+
+ /*! filename of output pictures (without suffix or numbers) */
+ string mOutFilename;
+
+ //! get Maximum depth for BSP tree
+ int mTreeMaxDepth;
+ //! get Maxmimum nr of triangles per BSP tree node
+ int mTreeMaxTriangles;
+
+ //! attribute list for opengl renderer
+ AttributeList *mpOpenGlAttr;
+ //! attribute list for blender output
+ AttributeList *mpBlenderAttr;
+
+
+ //! Enable test sphere?
+ bool mTestSphereEnabled;
+ //! Center of the test sphere
+ ntlVec3Gfx mTestSphereCenter;
+ //! Radius of the test sphere
+ gfxReal mTestSphereRadius;
+ //! Materialname of the test sphere
+ char *mTestSphereMaterialName;
+ //! coordinates of the debugging pixel
+ int mDebugPixelX, mDebugPixelY;
+
+ //! test mode for quick rendering activated?, inited in ntl_scene::buildScene
+ bool mTestMode;
+
+ //! single frame flag
+ bool mSingleFrameMode;
+ //! filename for single frame mode
+ string mSingleFrameFilename;
+
+ /*! Two random number streams for photon generation (one for the directions, the other for russion roulette) */
+ ntlRandomStream *mpRndDirections, *mpRndRoulette;
+
+};
+
+
+
+
+/*****************************************************************************/
+/* Constructor with standard value init */
+inline ntlRenderGlobals::ntlRenderGlobals() :
+ mpLightList( NULL ), mpMaterials( NULL ), mpSims( NULL ),
+ mResX(320), mResY(200), mAADepth(-1), mMaxColVal(255),
+ mRayMaxDepth( 5 ),
+ mvEye(0.0,0.0,5.0), mvLookat(0.0,0.0,0.0), mvUpvec(0.0,1.0,0.0),
+ mAspect(320.0/200.0),
+ mFovy(45), mcBackgr(0.0,0.0,0.0), mcAmbientLight(0.0,0.0,0.0),
+ mDebugOut( 0 ),
+ mAniStart(0), mAniFrames( -1 ), mAniCount( 0 ),
+ mAniFrameTime(10), mFrameSkip( 0 ),
+ mCounterRays( 0 ), mCounterShades( 0 ), mCounterSceneInter( 0 ),
+ mOutFilename( "pic" ),
+ mTreeMaxDepth( 30 ), mTreeMaxTriangles( 30 ),
+ mpOpenGlAttr(NULL),
+ mpBlenderAttr(NULL),
+ mTestSphereEnabled( false ),
+ mDebugPixelX( -1 ), mDebugPixelY( -1 ), mTestMode(false),
+ mSingleFrameMode(false), mSingleFrameFilename(""),
+ mpRndDirections( NULL ), mpRndRoulette( NULL )
+{
+ // create internal attribute list for opengl renderer
+ mpOpenGlAttr = new AttributeList("__ntlOpenGLRenderer");
+ mpBlenderAttr = new AttributeList("__ntlBlenderAttr");
+};
+
+
+/*****************************************************************************/
+/* Destructor */
+inline ntlRenderGlobals::~ntlRenderGlobals() {
+ if(mpOpenGlAttr) delete mpOpenGlAttr;
+ if(mpBlenderAttr) delete mpBlenderAttr;
+}
+
+
+/*****************************************************************************/
+//! get the next random photon direction
+inline ntlVec3Gfx ntlRenderGlobals::getRandomDirection( void ) {
+ return ntlVec3Gfx(
+ (mpRndDirections->getGfxReal()-0.5),
+ (mpRndDirections->getGfxReal()-0.5),
+ (mpRndDirections->getGfxReal()-0.5) );
+}
+
+#endif
+
diff --git a/intern/elbeem/intern/ntl_rndstream.h b/intern/elbeem/intern/ntl_rndstream.h
new file mode 100644
index 00000000000..9eaa9093a0b
--- /dev/null
+++ b/intern/elbeem/intern/ntl_rndstream.h
@@ -0,0 +1,127 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * A seperate random number stream (e.g. for photon tracing)
+ * (cf. Numerical recipes in C, sec. ed., p 283, Knuth method)
+ *
+ *****************************************************************************/
+#ifndef NTL_RANDOMSTREAM_H
+
+
+//! some big number
+#define MBIG 1000000000
+
+//! modify initial seed
+#define MSEED 161803398
+
+//! minimum value - no idea why this is a define?
+#define MZ 0
+
+//! for normalization to 0..1
+#define FAC (1.0/MBIG)
+
+
+/*! a stream of random numbers using Knuth's portable method */
+class ntlRandomStream
+{
+public:
+ /*! Default constructor */
+ inline ntlRandomStream(long seed);
+ /*! Destructor */
+ ~ntlRandomStream() {}
+
+ /*! get a random number from the stream */
+ inline double getDouble( void );
+
+#ifdef HAVE_GFXTYPES
+ //! gfx random functions
+
+ /*! get a random number from the stream */
+ inline gfxReal getGfxReal( void );
+#endif
+
+private:
+
+ /*! random number state */
+ long idnum;
+
+ /*! pointers into number table */
+ int inext, inextp;
+ /*! store seed and number for subtraction */
+ long ma[56];
+
+};
+
+
+/* init random stream tables */
+inline ntlRandomStream::ntlRandomStream(long seed)
+{
+ idnum = seed;
+
+ long mj = MSEED - (idnum < 0 ? -idnum : idnum);
+ mj %= MBIG;
+ ma[55] = mj;
+ long mk = 1;
+
+ // init table once, otherwise strange results...
+ for(int i=0;i<=55;i++) ma[i] = (i*i+seed);
+
+ // init table in random order
+ for(int i=1;i<=54;i++) {
+ int ii = (21*i) % 56;
+ ma[ii] = mk;
+ mk = mj - mk;
+ if(mk < MZ) mk += MBIG;
+ mj = ma[ii];
+ }
+
+ // "warm up" generator
+ for(int k=1;k<=4;k++)
+ for(int i=1;i<=55;i++) {
+ ma[i] -= ma[1+ (i+30) % 55];
+ if(ma[i] < MZ) ma[i] += MBIG;
+ }
+
+ inext = 0;
+ inextp = 31; // the special "31"
+ idnum = 1;
+}
+
+
+/* return one random value */
+inline double ntlRandomStream::getDouble( void )
+{
+ if( ++inext == 56) inext = 1;
+ if( ++inextp == 56) inextp = 1;
+
+ // generate by subtaction
+ long mj = ma[inext] - ma[inextp];
+
+ // check range
+ if(mj < MZ) mj += MBIG;
+ ma[ inext ] = mj;
+ return (double)(mj * FAC);
+}
+
+#ifdef HAVE_GFXTYPES
+/* return one random value */
+inline gfxReal ntlRandomStream::getGfxReal( void )
+{
+ if( ++inext == 56) inext = 1;
+ if( ++inextp == 56) inextp = 1;
+
+ // generate by subtaction
+ long mj = ma[inext] - ma[inextp];
+
+ // check range
+ if(mj < MZ) mj += MBIG;
+ ma[ inext ] = mj;
+ return (gfxReal)(mj * FAC);
+}
+#endif
+
+#define NTL_RANDOMSTREAM_H
+#endif
+
diff --git a/intern/elbeem/intern/ntl_scene.cpp b/intern/elbeem/intern/ntl_scene.cpp
new file mode 100644
index 00000000000..87148776697
--- /dev/null
+++ b/intern/elbeem/intern/ntl_scene.cpp
@@ -0,0 +1,239 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Scene object, that contains and manages all geometry objects
+ *
+ *****************************************************************************/
+
+#include "utilities.h"
+#include "ntl_scene.h"
+#include "ntl_geometryobject.h"
+#include "ntl_geometryshader.h"
+//#include <sys/times.h>
+
+
+
+
+
+/******************************************************************************
+ * Constructor
+ *****************************************************************************/
+ntlScene::ntlScene( ntlRenderGlobals *glob ) :
+ mpGlob( glob ),
+ mpTree( NULL ),
+ mDisplayListId( -1 ),
+ mSceneBuilt( false ), mFirstInitDone( false )
+{
+}
+
+
+/******************************************************************************
+ * Destructor
+ *****************************************************************************/
+ntlScene::~ntlScene()
+{
+ cleanupScene();
+
+ // cleanup lists
+ for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin();
+ iter != mGeos.end(); iter++) {
+ delete (*iter);
+ }
+ for (vector<ntlLightObject*>::iterator iter = mpGlob->getLightList()->begin();
+ iter != mpGlob->getLightList()->end(); iter++) {
+ delete (*iter);
+ }
+ for (vector<ntlMaterial*>::iterator iter = mpGlob->getMaterials()->begin();
+ iter != mpGlob->getMaterials()->end(); iter++) {
+ delete (*iter);
+ }
+}
+
+
+/******************************************************************************
+ * Build the scene arrays (obj, tris etc.)
+ *****************************************************************************/
+void ntlScene::buildScene( void )
+{
+ const bool buildInfo=false;
+ mObjects.clear();
+ /* init geometry array, first all standard objects */
+ for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin();
+ iter != mGeos.end(); iter++) {
+ bool geoinit = false;
+ int tid = (*iter)->getTypeId();
+ if(tid & GEOCLASSTID_OBJECT) {
+ ntlGeometryObject *geoobj = (ntlGeometryObject*)(*iter);
+ geoinit = true;
+ mObjects.push_back( geoobj );
+ if(buildInfo) debMsgStd("ntlScene::BuildScene",DM_MSG,"added GeoObj "<<geoobj->getName(), 5 );
+ }
+ //if(geoshad) {
+ if(tid & GEOCLASSTID_SHADER) {
+ ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter);
+ geoinit = true;
+ if(!mFirstInitDone) {
+ // only on first init
+ geoshad->initializeShader();
+ }
+ for (vector<ntlGeometryObject*>::iterator siter = geoshad->getObjectsBegin();
+ siter != geoshad->getObjectsEnd();
+ siter++) {
+ if(buildInfo) debMsgStd("ntlScene::BuildScene",DM_MSG,"added shader geometry "<<(*siter)->getName(), 5 );
+ mObjects.push_back( (*siter) );
+ }
+ }
+
+ if(!geoinit) {
+ errMsg("ntlScene::BuildScene","Invalid geometry class!");
+ exit(1);
+ }
+ }
+
+ // collect triangles
+ mTriangles.clear();
+ mVertices.clear();
+ mVertNormals.clear();
+
+ /* for test mode deactivate transparencies etc. */
+ if( mpGlob->getTestMode() ) {
+ debugOut("ntlScene::buildScene : Test Mode activated!", 2);
+ // assign random colors to dark materials
+ int matCounter = 0;
+ ntlColor stdCols[] = { ntlColor(0,0,1.0), ntlColor(0,1.0,0), ntlColor(1.0,0.7,0) , ntlColor(0.7,0,0.6) };
+ int stdColNum = 4;
+ for (vector<ntlMaterial*>::iterator iter = mpGlob->getMaterials()->begin();
+ iter != mpGlob->getMaterials()->end(); iter++) {
+ (*iter)->setTransparence(0.0);
+ (*iter)->setMirror(0.0);
+ (*iter)->setFresnel(false);
+ // too dark?
+ if( norm((*iter)->getDiffuseRefl()) <0.01) {
+ (*iter)->setDiffuseRefl( stdCols[matCounter] );
+ matCounter ++;
+ matCounter = matCounter%stdColNum;
+ }
+ }
+
+ // restrict output file size to 400
+ float downscale = 1.0;
+ if(mpGlob->getResX() > 400){ downscale = 400.0/(float)mpGlob->getResX(); }
+ if(mpGlob->getResY() > 400){
+ float downscale2 = 400.0/(float)mpGlob->getResY();
+ if(downscale2<downscale) downscale=downscale2;
+ }
+ mpGlob->setResX( (int)(mpGlob->getResX() * downscale) );
+ mpGlob->setResY( (int)(mpGlob->getResY() * downscale) );
+
+ }
+
+ /* collect triangles from objects */
+ int idCnt = 0; // give IDs to objects
+ for (vector<ntlGeometryObject*>::iterator iter = mObjects.begin();
+ iter != mObjects.end();
+ iter++) {
+ /* only add visible objects */
+ (*iter)->initialize( mpGlob );
+ (*iter)->getTriangles(&mTriangles, &mVertices, &mVertNormals, idCnt);
+ idCnt ++;
+ }
+
+
+ /* calculate triangle normals, and initialize flags */
+ for (vector<ntlTriangle>::iterator iter = mTriangles.begin();
+ iter != mTriangles.end();
+ iter++) {
+
+ // calculate normal from triangle points
+ ntlVec3Gfx normal =
+ cross( (ntlVec3Gfx)( (mVertices[(*iter).getPoints()[2]] - mVertices[(*iter).getPoints()[0]]) *-1.0), // BLITZ minus sign right??
+ (ntlVec3Gfx)(mVertices[(*iter).getPoints()[1]] - mVertices[(*iter).getPoints()[0]]) );
+ normalize(normal);
+ (*iter).setNormal( normal );
+ }
+
+
+
+ // scene geometry built
+ mSceneBuilt = true;
+
+ // init shaders that require complete geometry
+ if(!mFirstInitDone) {
+ // only on first init
+ for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin();
+ iter != mGeos.end(); iter++) {
+ if( (*iter)->getTypeId() & GEOCLASSTID_SHADER ) {
+ ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter);
+ geoshad->postGeoConstrInit( mpGlob );
+ }
+ }
+ mFirstInitDone = true;
+ }
+
+ // check unused attributes (for classes and objects!)
+ for (vector<ntlGeometryObject*>::iterator iter = mObjects.begin(); iter != mObjects.end(); iter++) {
+ if((*iter)->getAttributeList()->checkUnusedParams()) {
+ debMsgStd("ntlScene::buildScene",DM_WARNING,"Unused params for object '"<< (*iter)->getName() <<"' !", 1 );
+ (*iter)->getAttributeList()->print(); // DEBUG
+ exit(1);
+ }
+ }
+ for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin(); iter != mGeos.end(); iter++) {
+ if((*iter)->getAttributeList()->checkUnusedParams()) {
+ debMsgStd("ntlScene::buildScene",DM_WARNING,"Unused params for object '"<< (*iter)->getName() <<"' !", 1 );
+ (*iter)->getAttributeList()->print(); // DEBUG
+ exit(1);
+ }
+ }
+
+}
+
+/******************************************************************************
+ * Prepare the scene triangles and maps for raytracing
+ *****************************************************************************/
+void ntlScene::prepareScene( void )
+{
+ /* init triangles... */
+ buildScene();
+ // what for currently not used ???
+ if(mpTree != NULL) delete mpTree;
+ mpTree = new ntlTree( mpGlob->getTreeMaxDepth(), mpGlob->getTreeMaxTriangles(),
+ this, TRI_GEOMETRY );
+
+ //debMsgStd("ntlScene::prepareScene",DM_MSG,"Stats - tris:"<< (int)mTriangles.size()<<" verts:"<<mVertices.size()<<" vnorms:"<<mVertNormals.size(), 5 );
+}
+/******************************************************************************
+ * Do some memory cleaning, when frame is finished
+ *****************************************************************************/
+void ntlScene::cleanupScene( void )
+{
+ mObjects.clear();
+ mTriangles.clear();
+ mVertices.clear();
+ mVertNormals.clear();
+
+ if(mpTree != NULL) delete mpTree;
+ mpTree = NULL;
+}
+
+
+/******************************************************************************
+ * Intersect a ray with the scene triangles
+ *****************************************************************************/
+void ntlScene::intersectScene(const ntlRay &r, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri,int flags) const
+{
+ distance = -1.0;
+ mpGlob->setCounterSceneInter( mpGlob->getCounterSceneInter()+1 );
+ mpTree->intersect(r, distance, normal, tri, flags, false);
+}
+
+
+
+
+
+
+
+
+
diff --git a/intern/elbeem/intern/ntl_scene.h b/intern/elbeem/intern/ntl_scene.h
new file mode 100644
index 00000000000..9e7a8dfbdea
--- /dev/null
+++ b/intern/elbeem/intern/ntl_scene.h
@@ -0,0 +1,186 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Scene object, that contains and manages all geometry objects
+ *
+ *****************************************************************************/
+#ifndef NTL_SCENE_HH
+#define NTL_SCENE_HH
+
+#include <sstream>
+#include "ntl_vector3dim.h"
+#include "ntl_material.h"
+#include "ntl_geometryclass.h"
+#include "ntl_triangle.h"
+#include "ntl_bsptree.h"
+class ntlRay;
+class ntlGeometryObject;
+
+/*! fluid geometry init types */
+#define FGI_FLAGSTART 16
+#define FGI_FLUID (1<<(FGI_FLAGSTART+0))
+#define FGI_NO_FLUID (1<<(FGI_FLAGSTART+1))
+#define FGI_BNDNO (1<<(FGI_FLAGSTART+2))
+#define FGI_BNDFREE (1<<(FGI_FLAGSTART+3))
+#define FGI_NO_BND (1<<(FGI_FLAGSTART+4))
+#define FGI_ACC (1<<(FGI_FLAGSTART+5))
+#define FGI_NO_ACC (1<<(FGI_FLAGSTART+6))
+#define FGI_SPEEDSET (1<<(FGI_FLAGSTART+7))
+#define FGI_NO_SPEEDSET (1<<(FGI_FLAGSTART+8))
+
+#define FGI_ALLBOUNDS (FGI_BNDNO | FGI_BNDFREE)
+
+#define FGI_REFP1 (1<<(FGI_FLAGSTART+0))
+#define FGI_REFP2 (1<<(FGI_FLAGSTART+1))
+#define FGI_REFP3 (1<<(FGI_FLAGSTART+2))
+
+#define FGI_ALLREFS (FGI_REFP1 | FGI_REFP2 | FGI_REFP3)
+
+
+//! convenience macro for adding triangles
+#define sceneAddTriangle(p1,p2,p3, pn1,pn2,pn3, trin, smooth) {\
+ \
+ ntlTriangle tri;\
+ int tempVert;\
+ \
+ if(normals->size() != vertices->size()) {\
+ errorOut("getTriangles Error for '"<<mName<<"': Vertices and normals sizes to not match!!!");\
+ exit(1); }\
+ \
+ vertices->push_back( p1 ); \
+ normals->push_back( pn1 ); \
+ tempVert = normals->size()-1;\
+ tri.getPoints()[0] = tempVert;\
+ \
+ vertices->push_back( p2 ); \
+ normals->push_back( pn2 ); \
+ tempVert = normals->size()-1;\
+ tri.getPoints()[1] = tempVert;\
+ \
+ vertices->push_back( p3 ); \
+ normals->push_back( pn3 ); \
+ tempVert = normals->size()-1;\
+ tri.getPoints()[2] = tempVert;\
+ \
+ \
+ /* init flags */\
+ int flag = 0; \
+ if(getVisible()){ flag |= TRI_GEOMETRY; }\
+ if(getCastShadows() ) { \
+ flag |= TRI_CASTSHADOWS; } \
+ if( (getMaterial()->getMirror()>0.0) || \
+ (getMaterial()->getTransparence()>0.0) || \
+ (getMaterial()->getFresnel()>0.0) ) { \
+ flag |= TRI_MAKECAUSTICS; } \
+ else { \
+ flag |= TRI_NOCAUSTICS; } \
+ \
+ /* init geo init id */\
+ int geoiId = getGeoInitId(); \
+ if(geoiId > 0) { \
+ flag |= (1<< (geoiId+4)); \
+ flag |= mGeoInitType; \
+ } \
+ \
+ tri.setFlags( flag );\
+ \
+ /* triangle normal missing */\
+ tri.setNormal( trin );\
+ tri.setSmoothNormals( smooth );\
+ tri.setObjectId( objectId );\
+ triangles->push_back( tri ); \
+ }\
+
+
+
+class ntlScene
+{
+public:
+ /* CONSTRUCTORS */
+ /*! Default constructor */
+ ntlScene( ntlRenderGlobals *glob );
+ /*! Default destructor */
+ ~ntlScene();
+
+ /*! Add an object to the scene */
+ inline void addGeoClass(ntlGeometryClass *geo) { mGeos.push_back( geo ); }
+
+ /*! Acces a certain object */
+ inline ntlGeometryObject *getObject(int id) {
+ if(!mSceneBuilt) { errMsg("ntlScene::getObject","Scene not inited!"); exit(1); }
+ return mObjects[id]; }
+
+ /*! Acces object array */
+ inline vector<ntlGeometryObject*> *getObjects() {
+ if(!mSceneBuilt) { errMsg("ntlScene::getObjects[]","Scene not inited!"); exit(1); }
+ return &mObjects; }
+
+ /*! Acces geo class array */
+ inline vector<ntlGeometryClass*> *getGeoClasses() {
+ if(!mSceneBuilt) { errMsg("ntlScene::getGeoClasses[]","Scene not inited!"); exit(1); }
+ return &mGeos; }
+
+ /*! draw scene with opengl */
+ //void draw();
+
+ /*! Build the scene arrays */
+ void buildScene( void );
+
+ //! Prepare the scene triangles and maps for raytracing
+ void prepareScene( void );
+ //! Do some memory cleaning, when frame is finished
+ void cleanupScene( void );
+
+ /*! Intersect a ray with the scene triangles */
+ void intersectScene(const ntlRay &r, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri, int flags) const;
+
+ /*! return a vertex */
+ ntlVec3Gfx getVertex(int index) { return mVertices[index]; }
+
+ // for tree generation
+ /*! return pointer to vertices vector */
+ vector<ntlVec3Gfx> *getVertexPointer( void ) { return &mVertices; }
+ /*! return pointer to vertices vector */
+ vector<ntlVec3Gfx> *getVertexNormalPointer( void ) { return &mVertNormals; }
+ /*! return pointer to vertices vector */
+ vector<ntlTriangle> *getTrianglePointer( void ) { return &mTriangles; }
+
+private:
+
+ /*! Global settings */
+ ntlRenderGlobals *mpGlob;
+
+ /*! List of geometry classes */
+ vector<ntlGeometryClass *> mGeos;
+
+ /*! List of geometry objects */
+ vector<ntlGeometryObject *> mObjects;
+
+ /*! List of triangles */
+ vector<ntlTriangle> mTriangles;
+ /*! List of vertices */
+ vector<ntlVec3Gfx> mVertices;
+ /*! List of normals */
+ vector<ntlVec3Gfx> mVertNormals;
+ /*! List of triangle normals */
+ vector<ntlVec3Gfx> mTriangleNormals;
+
+ /*! Tree to store quickly intersect triangles */
+ ntlTree *mpTree;
+
+ /*! id of dislpay list for raytracer stuff */
+ int mDisplayListId;
+
+ /*! was the scene successfully built? only then getObject(i) requests are valid */
+ bool mSceneBuilt;
+
+ /*! shader/obj initializations are only done on first init */
+ bool mFirstInitDone;
+
+};
+
+
+#endif
+
diff --git a/intern/elbeem/intern/ntl_triangle.h b/intern/elbeem/intern/ntl_triangle.h
new file mode 100644
index 00000000000..7f1c7f1595e
--- /dev/null
+++ b/intern/elbeem/intern/ntl_triangle.h
@@ -0,0 +1,183 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * a single triangle
+ *
+ *****************************************************************************/
+#ifndef NTL_TRIANGLE_HH
+#define NTL_TRIANGLE_HH
+
+
+#include "ntl_vector3dim.h"
+#include "ntl_material.h"
+class ntlRay;
+
+
+/*! Triangle flag defines */
+#define TRI_GEOMETRY (1<<0)
+#define TRI_CASTSHADOWS (1<<1)
+#define TRI_MAKECAUSTICS (1<<2)
+#define TRI_NOCAUSTICS (1<<3)
+
+
+class ntlTriangle
+{
+public:
+ /* CONSTRUCTORS */
+ /*! Default constructor */
+ inline ntlTriangle( void );
+ /*! Constructor with parameters */
+ inline ntlTriangle(int *p, bool smooth, int obj, ntlVec3Gfx norm, int setflags);
+ /*! Copy - Constructor */
+ inline ntlTriangle(const ntlTriangle &tri);
+ /*! Destructor */
+ inline ~ntlTriangle() {}
+
+ /* Access methods */
+
+ /*! Acces to points of triangle */
+ inline int *getPoints( void ) { return mPoints; }
+ /*! Acces normal smoothing */
+ inline bool getSmoothNormals( void ) const { return mSmoothNormals; }
+ inline void setSmoothNormals( bool set){ mSmoothNormals = set; }
+ /*! Access object */
+ inline int getObjectId( void ) const { return mObjectId; }
+ inline void setObjectId( int set) { mObjectId = set; }
+ /*! Acces normal index */
+ inline ntlVec3Gfx getNormal( void ) const { return mNormal; }
+ inline void setNormal( ntlVec3Gfx set ) { mNormal = set; }
+ /*! Acces flags */
+ inline int getFlags( void ) const { return mFlags; }
+ inline void setFlags( int set ) { mFlags = set; }
+ /*! Access last intersection ray ID */
+ inline int getLastRay( void ) const { return mLastRay; }
+ inline void setLastRay( int set ) { mLastRay = set; }
+ /*! Acces bbox id */
+ inline int getBBoxId( void ) const { return mBBoxId; }
+ inline void setBBoxId( int set ) { mBBoxId = set; }
+
+ /*! Get average of the three points for this axis */
+ inline gfxReal getAverage( int axis ) const;
+
+ /*! operator < for sorting, uses global sorting axis */
+ inline friend bool operator<(const ntlTriangle &lhs, const ntlTriangle &rhs);
+ /*! operator > for sorting, uses global sorting axis */
+ inline friend bool operator>(const ntlTriangle &lhs, const ntlTriangle &rhs);
+
+protected:
+
+private:
+
+ /*! indices to the three points of the triangle */
+ int mPoints[3];
+
+ /*! bounding box id (for tree generation), -1 if invalid */
+ int mBBoxId;
+
+ /*! Should the normals of this triangle get smoothed? */
+ bool mSmoothNormals;
+
+ /*! Id of parent object */
+ int mObjectId;
+
+ /*! Index to normal (for not smooth triangles) */
+ //int mNormalIndex; ??
+ ntlVec3Gfx mNormal;
+
+ /*! Flags for object attributes cast shadows, make caustics etc. */
+ int mFlags;
+
+ /*! ID of last ray that an intersection was calculated for */
+ int mLastRay;
+
+};
+
+
+
+
+/******************************************************************************
+ * Default Constructor
+ *****************************************************************************/
+ntlTriangle::ntlTriangle( void ) :
+ mBBoxId(-1),
+ mLastRay( 0 )
+{
+ mPoints[0] = mPoints[1] = mPoints[2] = 0;
+ mSmoothNormals = 0;
+ mObjectId = 0;
+ mNormal = ntlVec3Gfx(0.0);
+ mFlags = 0;
+}
+
+
+/******************************************************************************
+ * Constructor
+ *****************************************************************************/
+ntlTriangle::ntlTriangle(int *p, bool smooth, int obj, ntlVec3Gfx norm, int setflags) :
+ mBBoxId(-1),
+ mLastRay( 0 )
+{
+ mPoints[0] = p[0];
+ mPoints[1] = p[1];
+ mPoints[2] = p[2];
+ mSmoothNormals = smooth;
+ mObjectId = obj;
+ mNormal = norm;
+ mFlags = setflags;
+}
+
+
+/******************************************************************************
+ * Copy Constructor
+ *****************************************************************************/
+ntlTriangle::ntlTriangle(const ntlTriangle &tri) :
+ mBBoxId(-1),
+ mLastRay( 0 )
+{
+ mPoints[0] = tri.mPoints[0];
+ mPoints[1] = tri.mPoints[1];
+ mPoints[2] = tri.mPoints[2];
+ mSmoothNormals = tri.mSmoothNormals;
+ mObjectId = tri.mObjectId;
+ mNormal = tri.mNormal;
+ mFlags = tri.mFlags;
+}
+
+
+
+
+/******************************************************************************
+ * Triangle sorting functions
+ *****************************************************************************/
+
+/* variables imported from ntl_bsptree.cc, necessary for using the stl sort funtion */
+/* Static global variable for sorting direction */
+extern int globalSortingAxis;
+/* Access to points array for sorting */
+extern vector<ntlVec3Gfx> *globalSortingPoints;
+
+
+gfxReal ntlTriangle::getAverage( int axis ) const
+{
+ return ( ( (*globalSortingPoints)[ mPoints[0] ][axis] +
+ (*globalSortingPoints)[ mPoints[1] ][axis] +
+ (*globalSortingPoints)[ mPoints[2] ][axis] )/3.0);
+}
+
+bool operator<(const ntlTriangle &lhs,const ntlTriangle &rhs)
+{
+ return ( lhs.getAverage(globalSortingAxis) <
+ rhs.getAverage(globalSortingAxis) );
+}
+
+bool operator>(const ntlTriangle &lhs,const ntlTriangle &rhs)
+{
+ return ( lhs.getAverage(globalSortingAxis) >
+ rhs.getAverage(globalSortingAxis) );
+}
+
+
+#endif
+
diff --git a/intern/elbeem/intern/ntl_vector3dim.h b/intern/elbeem/intern/ntl_vector3dim.h
new file mode 100644
index 00000000000..7fb3e71b2d3
--- /dev/null
+++ b/intern/elbeem/intern/ntl_vector3dim.h
@@ -0,0 +1,1032 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Basic vector class used everywhere, either blitz or inlined GRAPA class
+ *
+ *****************************************************************************/
+#ifndef NTL_VECTOR3DIM_H
+#define NTL_VECTOR3DIM_H
+
+// this serves as the main include file
+// for all kinds of stuff that might be required
+// under windos there seem to be strange
+// errors when including the STL header too
+// late...
+#include <iostream>
+#include <map>
+#include <vector>
+#include <string>
+#include <sstream>
+using std::map;
+using std::vector;
+using std::string;
+#include <math.h>
+#include <string.h>
+
+#ifdef __APPLE_CC__
+// apple
+#else
+#ifdef WIN32
+
+// windos, hardcoded limits for now...
+// windos fixes...
+// for windos MSVC compiler...
+#ifndef __FLT_MAX__
+#define __FLT_MAX__ 3.402823466e+38f
+#endif // __FLT_MAX__
+#ifndef __DBL_MAX__
+#define __DBL_MAX__ 1.7976931348623158e+308
+#endif // __DBL_MAX__
+#ifndef bool
+#define bool int
+#endif
+#ifndef false
+#define false 0
+#endif
+#ifndef true
+#define true 1
+#endif
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#ifndef M_PI
+#define M_PI 3.1415926536
+#endif
+
+#else // WIN32
+
+// linux etc...
+#include <values.h>
+
+#endif // WIN32
+#endif // __APPLE_CC__
+
+
+
+
+// basic inlined vector class
+template<class Scalar>
+class ntlVector3Dim
+{
+public:
+ // Constructor
+ inline ntlVector3Dim(void );
+ // Copy-Constructor
+ inline ntlVector3Dim(const ntlVector3Dim<Scalar> &v );
+ inline ntlVector3Dim(const float *);
+ inline ntlVector3Dim(const double *);
+ // construct a vector from one Scalar
+ inline ntlVector3Dim(Scalar);
+ // construct a vector from three Scalars
+ inline ntlVector3Dim(Scalar, Scalar, Scalar);
+
+ // get address of array for OpenGL
+ Scalar *getAddress() { return value; }
+
+ // Assignment operator
+ inline const ntlVector3Dim<Scalar>& operator= (const ntlVector3Dim<Scalar>& v);
+ // Assignment operator
+ inline const ntlVector3Dim<Scalar>& operator= (Scalar s);
+ // Assign and add operator
+ inline const ntlVector3Dim<Scalar>& operator+= (const ntlVector3Dim<Scalar>& v);
+ // Assign and add operator
+ inline const ntlVector3Dim<Scalar>& operator+= (Scalar s);
+ // Assign and sub operator
+ inline const ntlVector3Dim<Scalar>& operator-= (const ntlVector3Dim<Scalar>& v);
+ // Assign and sub operator
+ inline const ntlVector3Dim<Scalar>& operator-= (Scalar s);
+ // Assign and mult operator
+ inline const ntlVector3Dim<Scalar>& operator*= (const ntlVector3Dim<Scalar>& v);
+ // Assign and mult operator
+ inline const ntlVector3Dim<Scalar>& operator*= (Scalar s);
+ // Assign and div operator
+ inline const ntlVector3Dim<Scalar>& operator/= (const ntlVector3Dim<Scalar>& v);
+ // Assign and div operator
+ inline const ntlVector3Dim<Scalar>& operator/= (Scalar s);
+
+
+ // unary operator
+ inline ntlVector3Dim<Scalar> operator- () const;
+
+ // binary operator add
+ inline ntlVector3Dim<Scalar> operator+ (const ntlVector3Dim<Scalar>&) const;
+ // binary operator add
+ inline ntlVector3Dim<Scalar> operator+ (Scalar) const;
+ // binary operator sub
+ inline ntlVector3Dim<Scalar> operator- (const ntlVector3Dim<Scalar>&) const;
+ // binary operator sub
+ inline ntlVector3Dim<Scalar> operator- (Scalar) const;
+ // binary operator mult
+ inline ntlVector3Dim<Scalar> operator* (const ntlVector3Dim<Scalar>&) const;
+ // binary operator mult
+ inline ntlVector3Dim<Scalar> operator* (Scalar) const;
+ // binary operator div
+ inline ntlVector3Dim<Scalar> operator/ (const ntlVector3Dim<Scalar>&) const;
+ // binary operator div
+ inline ntlVector3Dim<Scalar> operator/ (Scalar) const;
+
+ // Projection normal to a vector
+ inline ntlVector3Dim<Scalar> getOrthogonalntlVector3Dim() const;
+ // Project into a plane
+ inline const ntlVector3Dim<Scalar>& projectNormalTo(const ntlVector3Dim<Scalar> &v);
+
+ // minimize
+ inline const ntlVector3Dim<Scalar> &minimize(const ntlVector3Dim<Scalar> &);
+ // maximize
+ inline const ntlVector3Dim<Scalar> &maximize(const ntlVector3Dim<Scalar> &);
+
+ // access operator
+ inline Scalar& operator[](unsigned int i);
+ // access operator
+ inline const Scalar& operator[](unsigned int i) const;
+
+protected:
+
+private:
+ Scalar value[3]; //< Storage of vector values
+};
+
+
+
+
+//------------------------------------------------------------------------------
+// STREAM FUNCTIONS
+//------------------------------------------------------------------------------
+
+
+
+/*************************************************************************
+ Outputs the object in human readable form using the format
+ [x,y,z]
+ */
+template<class Scalar>
+std::ostream&
+operator<<( std::ostream& os, const ntlVector3Dim<Scalar>& i )
+{
+ os << '[' << i[0] << ", " << i[1] << ", " << i[2] << ']';
+ return os;
+}
+
+
+
+/*************************************************************************
+ Reads the contents of the object from a stream using the same format
+ as the output operator.
+ */
+template<class Scalar>
+std::istream&
+operator>>( std::istream& is, ntlVector3Dim<Scalar>& i )
+{
+ char c;
+ char dummy[3];
+ is >> c >> i[0] >> dummy >> i[1] >> dummy >> i[2] >> c;
+ return is;
+}
+
+
+//------------------------------------------------------------------------------
+// VECTOR inline FUNCTIONS
+//------------------------------------------------------------------------------
+
+
+
+/*************************************************************************
+ Constructor.
+ */
+template<class Scalar>
+inline ntlVector3Dim<Scalar>::ntlVector3Dim( void )
+{
+ value[0] = value[1] = value[2] = 0;
+}
+
+
+
+/*************************************************************************
+ Copy-Constructor.
+ */
+template<class Scalar>
+inline ntlVector3Dim<Scalar>::ntlVector3Dim( const ntlVector3Dim<Scalar> &v )
+{
+ value[0] = v.value[0];
+ value[1] = v.value[1];
+ value[2] = v.value[2];
+}
+template<class Scalar>
+inline ntlVector3Dim<Scalar>::ntlVector3Dim( const float *value)
+{
+ value[0] = (Scalar)value[0];
+ value[1] = (Scalar)value[1];
+ value[2] = (Scalar)value[2];
+}
+template<class Scalar>
+inline ntlVector3Dim<Scalar>::ntlVector3Dim( const double *value)
+{
+ value[0] = (Scalar)value[0];
+ value[1] = (Scalar)value[1];
+ value[2] = (Scalar)value[2];
+}
+
+
+
+/*************************************************************************
+ Constructor for a vector from a single Scalar. All components of
+ the vector get the same value.
+ \param s The value to set
+ \return The new vector
+ */
+template<class Scalar>
+inline ntlVector3Dim<Scalar>::ntlVector3Dim(Scalar s )
+{
+ value[0]= s;
+ value[1]= s;
+ value[2]= s;
+}
+
+
+/*************************************************************************
+ Constructor for a vector from three Scalars.
+ \param s1 The value for the first vector component
+ \param s2 The value for the second vector component
+ \param s3 The value for the third vector component
+ \return The new vector
+ */
+template<class Scalar>
+inline ntlVector3Dim<Scalar>::ntlVector3Dim(Scalar s1, Scalar s2, Scalar s3)
+{
+ value[0]= s1;
+ value[1]= s2;
+ value[2]= s3;
+}
+
+
+/*************************************************************************
+ Compute the vector product of two 3D vectors
+ \param v Second vector to compute the product with
+ \return A new vector with the product values
+ */
+/*template<class Scalar>
+inline ntlVector3Dim<Scalar>
+ntlVector3Dim<Scalar>::operator^( const ntlVector3Dim<Scalar> &v ) const
+{
+ return ntlVector3Dim<Scalar>(value[1]*v.value[2] - value[2]*v.value[1],
+ value[2]*v.value[0] - value[0]*v.value[2],
+ value[0]*v.value[1] - value[1]*v.value[0]);
+}*/
+
+
+/*************************************************************************
+ Copy a ntlVector3Dim componentwise.
+ \param v vector with values to be copied
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlVector3Dim<Scalar>&
+ntlVector3Dim<Scalar>::operator=( const ntlVector3Dim<Scalar> &v )
+{
+ value[0] = v.value[0];
+ value[1] = v.value[1];
+ value[2] = v.value[2];
+ return *this;
+}
+
+
+/*************************************************************************
+ Copy a Scalar to each component.
+ \param s The value to copy
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlVector3Dim<Scalar>&
+ntlVector3Dim<Scalar>::operator=(Scalar s)
+{
+ value[0] = s;
+ value[1] = s;
+ value[2] = s;
+ return *this;
+}
+
+
+/*************************************************************************
+ Add another ntlVector3Dim componentwise.
+ \param v vector with values to be added
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlVector3Dim<Scalar>&
+ntlVector3Dim<Scalar>::operator+=( const ntlVector3Dim<Scalar> &v )
+{
+ value[0] += v.value[0];
+ value[1] += v.value[1];
+ value[2] += v.value[2];
+ return *this;
+}
+
+
+/*************************************************************************
+ Add a Scalar value to each component.
+ \param s Value to add
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlVector3Dim<Scalar>&
+ntlVector3Dim<Scalar>::operator+=(Scalar s)
+{
+ value[0] += s;
+ value[1] += s;
+ value[2] += s;
+ return *this;
+}
+
+
+/*************************************************************************
+ Subtract another vector componentwise.
+ \param v vector of values to subtract
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlVector3Dim<Scalar>&
+ntlVector3Dim<Scalar>::operator-=( const ntlVector3Dim<Scalar> &v )
+{
+ value[0] -= v.value[0];
+ value[1] -= v.value[1];
+ value[2] -= v.value[2];
+ return *this;
+}
+
+
+/*************************************************************************
+ Subtract a Scalar value from each component.
+ \param s Value to subtract
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlVector3Dim<Scalar>&
+ntlVector3Dim<Scalar>::operator-=(Scalar s)
+{
+ value[0]-= s;
+ value[1]-= s;
+ value[2]-= s;
+ return *this;
+}
+
+
+/*************************************************************************
+ Multiply with another vector componentwise.
+ \param v vector of values to multiply with
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlVector3Dim<Scalar>&
+ntlVector3Dim<Scalar>::operator*=( const ntlVector3Dim<Scalar> &v )
+{
+ value[0] *= v.value[0];
+ value[1] *= v.value[1];
+ value[2] *= v.value[2];
+ return *this;
+}
+
+
+/*************************************************************************
+ Multiply each component with a Scalar value.
+ \param s Value to multiply with
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlVector3Dim<Scalar>&
+ntlVector3Dim<Scalar>::operator*=(Scalar s)
+{
+ value[0] *= s;
+ value[1] *= s;
+ value[2] *= s;
+ return *this;
+}
+
+
+/*************************************************************************
+ Divide by another ntlVector3Dim componentwise.
+ \param v vector of values to divide by
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlVector3Dim<Scalar>&
+ntlVector3Dim<Scalar>::operator/=( const ntlVector3Dim<Scalar> &v )
+{
+ value[0] /= v.value[0];
+ value[1] /= v.value[1];
+ value[2] /= v.value[2];
+ return *this;
+}
+
+
+/*************************************************************************
+ Divide each component by a Scalar value.
+ \param s Value to divide by
+ \return Reference to self
+ */
+template<class Scalar>
+inline const ntlVector3Dim<Scalar>&
+ntlVector3Dim<Scalar>::operator/=(Scalar s)
+{
+ value[0] /= s;
+ value[1] /= s;
+ value[2] /= s;
+ return *this;
+}
+
+
+//------------------------------------------------------------------------------
+// unary operators
+//------------------------------------------------------------------------------
+
+
+/*************************************************************************
+ Build componentwise the negative this vector.
+ \return The new (negative) vector
+ */
+template<class Scalar>
+inline ntlVector3Dim<Scalar>
+ntlVector3Dim<Scalar>::operator-() const
+{
+ return ntlVector3Dim<Scalar>(-value[0], -value[1], -value[2]);
+}
+
+
+
+//------------------------------------------------------------------------------
+// binary operators
+//------------------------------------------------------------------------------
+
+
+/*************************************************************************
+ Build a vector with another vector added componentwise.
+ \param v The second vector to add
+ \return The sum vector
+ */
+template<class Scalar>
+inline ntlVector3Dim<Scalar>
+ntlVector3Dim<Scalar>::operator+( const ntlVector3Dim<Scalar> &v ) const
+{
+ return ntlVector3Dim<Scalar>(value[0]+v.value[0],
+ value[1]+v.value[1],
+ value[2]+v.value[2]);
+}
+
+
+/*************************************************************************
+ Build a vector with a Scalar value added to each component.
+ \param s The Scalar value to add
+ \return The sum vector
+ */
+template<class Scalar>
+inline ntlVector3Dim<Scalar>
+ntlVector3Dim<Scalar>::operator+(Scalar s) const
+{
+ return ntlVector3Dim<Scalar>(value[0]+s,
+ value[1]+s,
+ value[2]+s);
+}
+
+
+/*************************************************************************
+ Build a vector with another vector subtracted componentwise.
+ \param v The second vector to subtract
+ \return The difference vector
+ */
+template<class Scalar>
+inline ntlVector3Dim<Scalar>
+ntlVector3Dim<Scalar>::operator-( const ntlVector3Dim<Scalar> &v ) const
+{
+ return ntlVector3Dim<Scalar>(value[0]-v.value[0],
+ value[1]-v.value[1],
+ value[2]-v.value[2]);
+}
+
+
+/*************************************************************************
+ Build a vector with a Scalar value subtracted componentwise.
+ \param s The Scalar value to subtract
+ \return The difference vector
+ */
+template<class Scalar>
+inline ntlVector3Dim<Scalar>
+ntlVector3Dim<Scalar>::operator-(Scalar s ) const
+{
+ return ntlVector3Dim<Scalar>(value[0]-s,
+ value[1]-s,
+ value[2]-s);
+}
+
+
+
+/*************************************************************************
+ Build a vector with another vector multiplied by componentwise.
+ \param v The second vector to muliply with
+ \return The product vector
+ */
+template<class Scalar>
+inline ntlVector3Dim<Scalar>
+ntlVector3Dim<Scalar>::operator*( const ntlVector3Dim<Scalar>& v) const
+{
+ return ntlVector3Dim<Scalar>(value[0]*v.value[0],
+ value[1]*v.value[1],
+ value[2]*v.value[2]);
+}
+
+
+/*************************************************************************
+ Build a ntlVector3Dim with a Scalar value multiplied to each component.
+ \param s The Scalar value to multiply with
+ \return The product vector
+ */
+template<class Scalar>
+inline ntlVector3Dim<Scalar>
+ntlVector3Dim<Scalar>::operator*(Scalar s) const
+{
+ return ntlVector3Dim<Scalar>(value[0]*s, value[1]*s, value[2]*s);
+}
+
+
+/*************************************************************************
+ Build a vector divided componentwise by another vector.
+ \param v The second vector to divide by
+ \return The ratio vector
+ */
+template<class Scalar>
+inline ntlVector3Dim<Scalar>
+ntlVector3Dim<Scalar>::operator/(const ntlVector3Dim<Scalar>& v) const
+{
+ return ntlVector3Dim<Scalar>(value[0]/v.value[0],
+ value[1]/v.value[1],
+ value[2]/v.value[2]);
+}
+
+
+
+/*************************************************************************
+ Build a vector divided componentwise by a Scalar value.
+ \param s The Scalar value to divide by
+ \return The ratio vector
+ */
+template<class Scalar>
+inline ntlVector3Dim<Scalar>
+ntlVector3Dim<Scalar>::operator/(Scalar s) const
+{
+ return ntlVector3Dim<Scalar>(value[0]/s,
+ value[1]/s,
+ value[2]/s);
+}
+
+
+
+
+
+/*************************************************************************
+ Get a particular component of the vector.
+ \param i Number of Scalar to get
+ \return Reference to the component
+ */
+template<class Scalar>
+inline Scalar&
+ntlVector3Dim<Scalar>::operator[]( unsigned int i )
+{
+ return value[i];
+}
+
+
+/*************************************************************************
+ Get a particular component of a constant vector.
+ \param i Number of Scalar to get
+ \return Reference to the component
+ */
+template<class Scalar>
+inline const Scalar&
+ntlVector3Dim<Scalar>::operator[]( unsigned int i ) const
+{
+ return value[i];
+}
+
+
+
+//------------------------------------------------------------------------------
+// BLITZ compatibility functions
+//------------------------------------------------------------------------------
+
+
+
+/*************************************************************************
+ Compute the scalar product with another vector.
+ \param v The second vector to work with
+ \return The value of the scalar product
+ */
+template<class Scalar>
+inline Scalar dot(const ntlVector3Dim<Scalar> &t, const ntlVector3Dim<Scalar> &v )
+{
+ //return t.value[0]*v.value[0] + t.value[1]*v.value[1] + t.value[2]*v.value[2];
+ return ((t[0]*v[0]) + (t[1]*v[1]) + (t[2]*v[2]));
+}
+
+
+/*************************************************************************
+ Calculate the cross product of this and another vector
+ */
+template<class Scalar>
+inline ntlVector3Dim<Scalar> cross(const ntlVector3Dim<Scalar> &t, const ntlVector3Dim<Scalar> &v)
+{
+ ntlVector3Dim<Scalar> cp(
+ ((t[1]*v[2]) - (t[2]*v[1])),
+ ((t[2]*v[0]) - (t[0]*v[2])),
+ ((t[0]*v[1]) - (t[1]*v[0])) );
+ return cp;
+}
+
+
+
+
+/*************************************************************************
+ Compute a vector that is orthonormal to self. Nothing else can be assumed
+ for the direction of the new vector.
+ \return The orthonormal vector
+ */
+template<class Scalar>
+ntlVector3Dim<Scalar>
+ntlVector3Dim<Scalar>::getOrthogonalntlVector3Dim() const
+{
+ // Determine the component with max. absolute value
+ int max= (fabs(value[0]) > fabs(value[1])) ? 0 : 1;
+ max= (fabs(value[max]) > fabs(value[2])) ? max : 2;
+
+ /*************************************************************************
+ Choose another axis than the one with max. component and project
+ orthogonal to self
+ */
+ ntlVector3Dim<Scalar> vec(0.0);
+ vec[(max+1)%3]= 1;
+ vec.normalize();
+ vec.projectNormalTo(this->getNormalized());
+ return vec;
+}
+
+
+/*************************************************************************
+ Projects the vector into a plane normal to the given vector, which must
+ have unit length. Self is modified.
+ \param v The plane normal
+ \return The projected vector
+ */
+template<class Scalar>
+inline const ntlVector3Dim<Scalar>&
+ntlVector3Dim<Scalar>::projectNormalTo(const ntlVector3Dim<Scalar> &v)
+{
+ Scalar sprod = dot(*this,v);
+ value[0]= value[0] - v.value[0] * sprod;
+ value[1]= value[1] - v.value[1] * sprod;
+ value[2]= value[2] - v.value[2] * sprod;
+ return *this;
+}
+
+
+
+//------------------------------------------------------------------------------
+// Other helper functions
+//------------------------------------------------------------------------------
+
+
+
+/*************************************************************************
+ Minimize the vector, i.e. set each entry of the vector to the minimum
+ of both values.
+ \param pnt The second vector to compare with
+ \return Reference to the modified self
+ */
+template<class Scalar>
+inline const ntlVector3Dim<Scalar> &
+ntlVector3Dim<Scalar>::minimize(const ntlVector3Dim<Scalar> &pnt)
+{
+ for (unsigned int i = 0; i < 3; i++)
+ value[i] = MIN(value[i],pnt[i]);
+ return *this;
+}
+
+
+
+/*************************************************************************
+ Maximize the vector, i.e. set each entry of the vector to the maximum
+ of both values.
+ \param pnt The second vector to compare with
+ \return Reference to the modified self
+ */
+template<class Scalar>
+inline const ntlVector3Dim<Scalar> &
+ntlVector3Dim<Scalar>::maximize(const ntlVector3Dim<Scalar> &pnt)
+{
+ for (unsigned int i = 0; i < 3; i++)
+ value[i] = MAX(value[i],pnt[i]);
+ return *this;
+}
+
+
+
+
+// ----
+
+// a 3D vector with double precision
+typedef ntlVector3Dim<double> ntlVec3d;
+
+// a 3D vector with single precision
+typedef ntlVector3Dim<float> ntlVec3f;
+
+// a 3D integer vector
+typedef ntlVector3Dim<int> ntlVec3i;
+
+// Color uses single precision fp values
+typedef ntlVec3f ntlColor;
+
+/* convert a float to double vector */
+template<class T> inline ntlVec3d vec2D(T v) { return ntlVec3d(v[0],v[1],v[2]); }
+template<class T> inline ntlVec3f vec2F(T v) { return ntlVec3f(v[0],v[1],v[2]); }
+template<class T> inline ntlColor vec2Col(T v) { return ntlColor(v[0],v[1],v[2]); }
+
+
+
+/************************************************************************/
+// graphics vector typing
+
+
+// use which fp-precision for raytracing? 1=float, 2=double
+#define GFX_PRECISION 1
+
+/* VECTOR_EPSILON is the minimal vector length
+ In order to be able to discriminate floating point values near zero, and
+ to be sure not to fail a comparison because of roundoff errors, use this
+ value as a threshold. */
+
+// use which fp-precision for graphics? 1=float, 2=double
+#ifdef PRECISION_GFX_SINGLE
+#define GFX_PRECISION 1
+#else
+#ifdef PRECISION_GFX_DOUBLE
+#define GFX_PRECISION 2
+#else
+// standard precision for graphics
+#ifndef GFX_PRECISION
+#define GFX_PRECISION 1
+#endif
+#endif
+#endif
+
+#if GFX_PRECISION==1
+typedef float gfxReal;
+#define GFX_REAL_MAX __FLT_MAX__
+//#define vecF2Gfx(x) (x)
+//#define vecGfx2F(x) (x)
+//#define vecD2Gfx(x) vecD2F(x)
+//#define vecGfx2D(x) vecF2D(x)
+#define VECTOR_EPSILON (1e-5)
+#else
+typedef double gfxReal;
+#define GFX_REAL_MAX __DBL_MAX__
+//#define vecF2Gfx(x) vecD2F(x)
+//#define vecGfx2F(x) vecF2D(x)
+//#define vecD2Gfx(x) (x)
+//#define vecGfx2D(x) (x)
+#define VECTOR_EPSILON (1e-10)
+#endif
+
+/* fixed double prec. type, for epxlicitly double values */
+typedef double gfxDouble;
+
+// a 3D vector for graphics output, typically float?
+typedef ntlVector3Dim<gfxReal> ntlVec3Gfx;
+
+template<class T> inline ntlVec3Gfx vec2G(T v) { return ntlVec3Gfx(v[0],v[1],v[2]); }
+
+/* get minimal vector length value that can be discriminated. */
+//template<class Scalar> inline Scalar getVecEpsilon()
+inline double getVecEpsilon() { return (double)VECTOR_EPSILON; }
+
+#define HAVE_GFXTYPES
+
+
+
+
+/************************************************************************/
+// HELPER FUNCTIONS, independent of implementation
+/************************************************************************/
+
+#define VECTOR_TYPE ntlVector3Dim<Scalar>
+
+
+/*************************************************************************
+ Compute the length (norm) of the vector.
+ \return The value of the norm
+ */
+template<class Scalar>
+inline Scalar norm( const VECTOR_TYPE &v)
+{
+ Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+ return (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) ? 1. : sqrt(l);
+}
+
+
+/*************************************************************************
+ Same as getNorm but doesnt sqrt
+ */
+template<class Scalar>
+inline Scalar normNoSqrt( const VECTOR_TYPE &v)
+{
+ return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+}
+
+
+/*************************************************************************
+ Compute a normalized vector based on this vector.
+ \return The new normalized vector
+ */
+template<class Scalar>
+inline VECTOR_TYPE getNormalized( const VECTOR_TYPE &v)
+{
+ Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+ if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON)
+ return v; /* normalized "enough"... */
+ else if (l > VECTOR_EPSILON*VECTOR_EPSILON)
+ {
+ Scalar fac = 1./sqrt(l);
+ return VECTOR_TYPE(v[0]*fac, v[1]*fac, v[2]*fac);
+ }
+ else
+ return VECTOR_TYPE((Scalar)0);
+}
+
+
+/*************************************************************************
+ Compute the norm of the vector and normalize it.
+ \return The value of the norm
+ */
+template<class Scalar>
+inline Scalar normalize( VECTOR_TYPE &v)
+{
+ Scalar norm;
+ Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+ if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) {
+ norm = 1.;
+ } else if (l > VECTOR_EPSILON*VECTOR_EPSILON) {
+ norm = sqrt(l);
+ Scalar fac = 1./norm;
+ v[0] *= fac;
+ v[1] *= fac;
+ v[2] *= fac;
+ } else {
+ v[0]= v[1]= v[2]= 0;
+ norm = 0.;
+ }
+ return (Scalar)norm;
+}
+
+
+/*************************************************************************
+ Compute a vector, that is self (as an incoming
+ vector) reflected at a surface with a distinct normal vector. Note
+ that the normal is reversed, if the scalar product with it is positive.
+ \param n The surface normal
+ \return The new reflected vector
+ */
+template<class Scalar>
+inline VECTOR_TYPE reflectVector(const VECTOR_TYPE &t, const VECTOR_TYPE &n)
+{
+ VECTOR_TYPE nn= (dot(t, n) > 0.0) ? (n*-1.0) : n;
+ return ( t - nn * (2.0 * dot(nn, t)) );
+}
+
+
+
+/*************************************************************************
+ * My own refraction calculation
+ * Taken from Glassner's book, section 5.2 (Heckberts method)
+ */
+template<class Scalar>
+inline VECTOR_TYPE refractVector(const VECTOR_TYPE &t, const VECTOR_TYPE &normal, Scalar nt, Scalar nair, int &refRefl)
+{
+ Scalar eta = nair / nt;
+ Scalar n = -dot(t, normal);
+ Scalar tt = 1.0 + eta*eta* (n*n-1.0);
+ if(tt<0.0) {
+ // we have total reflection!
+ refRefl = 1;
+ } else {
+ // normal reflection
+ tt = eta*n - sqrt(tt);
+ return( t*eta + normal*tt );
+ }
+ return t;
+}
+ /*double eta = nair / nt;
+ double n = -((*this) | normal);
+ double t = 1.0 + eta*eta* (n*n-1.0);
+ if(t<0.0) {
+ // we have total reflection!
+ refRefl = 1;
+ } else {
+ // normal reflection
+ t = eta*n - sqrt(t);
+ return( (*this)*eta + normal*t );
+ }
+ return (*this);*/
+
+
+/*************************************************************************
+ Test two ntlVector3Dims for equality based on the equality of their
+ values within a small threshold.
+ \param c The second vector to compare
+ \return TRUE if both are equal
+ \sa getEpsilon()
+ */
+template<class Scalar>
+inline bool equal(const VECTOR_TYPE &v, const VECTOR_TYPE &c)
+{
+ return (ABS(v[0]-c[0]) +
+ ABS(v[1]-c[1]) +
+ ABS(v[2]-c[2]) < VECTOR_EPSILON);
+}
+
+
+/*************************************************************************
+ * Assume this vector is an RGB color, and convert it to HSV
+ */
+template<class Scalar>
+inline void rgbToHsv( VECTOR_TYPE &V )
+{
+ Scalar h=0,s=0,v=0;
+ Scalar maxrgb, minrgb, delta;
+ // convert to hsv...
+ maxrgb = V[0];
+ int maxindex = 1;
+ if(V[2] > maxrgb){ maxrgb = V[2]; maxindex = 2; }
+ if(V[1] > maxrgb){ maxrgb = V[1]; maxindex = 3; }
+ minrgb = V[0];
+ if(V[2] < minrgb) minrgb = V[2];
+ if(V[1] < minrgb) minrgb = V[1];
+
+ v = maxrgb;
+ delta = maxrgb-minrgb;
+
+ if(maxrgb > 0) s = delta/maxrgb;
+ else s = 0;
+
+ h = 0;
+ if(s > 0) {
+ if(maxindex == 1) {
+ h = ((V[1]-V[2])/delta) + 0.0; }
+ if(maxindex == 2) {
+ h = ((V[2]-V[0])/delta) + 2.0; }
+ if(maxindex == 3) {
+ h = ((V[0]-V[1])/delta) + 4.0; }
+ h *= 60.0;
+ if(h < 0.0) h += 360.0;
+ }
+
+ V[0] = h;
+ V[1] = s;
+ V[2] = v;
+}
+
+/*************************************************************************
+ * Assume this vector is HSV and convert to RGB
+ */
+template<class Scalar>
+inline void hsvToRgb( VECTOR_TYPE &V )
+{
+ Scalar h = V[0], s = V[1], v = V[2];
+ Scalar r=0,g=0,b=0;
+ Scalar p,q,t, fracth;
+ int floorh;
+ // ...and back to rgb
+ if(s == 0) {
+ r = g = b = v; }
+ else {
+ h /= 60.0;
+ floorh = (int)h;
+ fracth = h - floorh;
+ p = v * (1.0 - s);
+ q = v * (1.0 - (s * fracth));
+ t = v * (1.0 - (s * (1.0 - fracth)));
+ switch (floorh) {
+ case 0: r = v; g = t; b = p; break;
+ case 1: r = q; g = v; b = p; break;
+ case 2: r = p; g = v; b = t; break;
+ case 3: r = p; g = q; b = v; break;
+ case 4: r = t; g = p; b = v; break;
+ case 5: r = v; g = p; b = q; break;
+ }
+ }
+
+ V[0] = r;
+ V[1] = g;
+ V[2] = b;
+}
+
+
+
+
+#endif /* NTL_VECTOR3DIM_HH */
diff --git a/intern/elbeem/intern/parametrizer.cpp b/intern/elbeem/intern/parametrizer.cpp
new file mode 100644
index 00000000000..fb63126623e
--- /dev/null
+++ b/intern/elbeem/intern/parametrizer.cpp
@@ -0,0 +1,501 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Parameter calculator for the LBM Solver class
+ *
+ *****************************************************************************/
+
+#include <sstream>
+#include "parametrizer.h"
+
+/*! param seen debug string array */
+char *ParamStrings[] = {
+ "RelaxTime",
+ "Reynolds",
+ "Viscosity",
+ "SoundSpeed",
+ "DomainSize",
+ "GravityForce",
+ "TimeLength",
+ "StepTime",
+ "Size",
+ "TimeFactor",
+ "AniFrames",
+ "AniFrameTime",
+ "AniStart",
+ "SurfaceTension",
+ "Density",
+ "CellSize",
+ "GStar",
+ "MaxSpeed",
+ "SimMaxSpeed",
+ "FluidVolHeight",
+ "NormalizedGStar",
+ "PSERR", "PSERR", "PSERR", "PSERR"
+};
+
+
+
+/******************************************************************************
+ * Default constructor
+ *****************************************************************************/
+Parametrizer::Parametrizer( void ) :
+ mSetupType("caro"),
+ mRelaxTime( 1.0 ), mReynolds( 0.0 ),
+ mViscosity( 8.94e-7 ), mSoundSpeed( 1500 ),
+ mDomainSize( 0.1 ), mCellSize( 0.01 ),
+ mGravity(0.0, 0.0, 0.0), mLatticeGravity(0.0, 0.0, 0.0),
+ mStepTime(0.01), mDesiredStepTime(-1.0),
+ mSizex(50), mSizey(50), mSizez(50),
+ mTimeFactor( 1.0 ),
+ mAniFrames(0), mAniFrameTime(0.0), mAniStart(0.0),
+ mExtent(1.0, 1.0, 1.0), mSurfaceTension( 0.0 ),
+ mDensity(1000.0), mGStar(0.0001), mFluidVolumeHeight(0.0),
+ mMaxSpeed(0.0), mSimulationMaxSpeed(0.0),
+ mTadapMaxOmega(1.95), mTadapMaxSpeed(0.1), mTadapLevels(1),
+ mSeenValues( 0 ), mCalculatedValues( 0 )
+ //mActive( false )
+{
+}
+
+
+/******************************************************************************
+ * Destructor
+ *****************************************************************************/
+Parametrizer::~Parametrizer()
+{
+ /* not much to do... */
+}
+
+/******************************************************************************
+ * Init from attr list
+ *****************************************************************************/
+void Parametrizer::parseAttrList()
+{
+ if(!mpAttrs) {
+ errMsg("Parametrizer::parseAttrList", "mpAttrs pointer not initialized!");
+ exit(1);
+ }
+
+ //mActive = mpAttrs->readBool("p_active",mActive, "Parametrizer","mActive", false);
+ mSetupType = mpAttrs->readString("p_setup",mSetupType, "Parametrizer","mSetupType", false);
+ mRelaxTime = mpAttrs->readFloat("p_relaxtime",mRelaxTime, "Parametrizer","mRelaxTime", false);
+ if(getAttributeList()->exists("p_relaxtime")) seenThis( PARAM_RELAXTIME );
+
+ mReynolds = mpAttrs->readFloat("p_reynolds",mReynolds, "Parametrizer","mReynolds", false);
+ if(getAttributeList()->exists("p_reynolds")) seenThis( PARAM_REYNOLDS );
+
+ mViscosity = mpAttrs->readFloat("p_viscosity",mViscosity, "Parametrizer","mViscosity", false);
+ if(getAttributeList()->exists("p_viscosity")) seenThis( PARAM_VISCOSITY );
+
+ mSoundSpeed = mpAttrs->readFloat("p_soundspeed",mSoundSpeed, "Parametrizer","mSoundSpeed", false);
+ if(getAttributeList()->exists("p_soundspeed")) seenThis( PARAM_SOUNDSPEED );
+
+ mDomainSize = mpAttrs->readFloat("p_domainsize",mDomainSize, "Parametrizer","mDomainSize", false);
+ if(getAttributeList()->exists("p_domainsize")) seenThis( PARAM_DOMAINSIZE );
+
+ mGravity = mpAttrs->readVec3d("p_gravity",mGravity, "Parametrizer","mGravity", false);
+ if(getAttributeList()->exists("p_gravity")) seenThis( PARAM_GRAVITY );
+
+ //mTimeLength = mpAttrs->readFloat("p_timelength",mTimeLength, "Parametrizer","mTimeLength", false);
+ //if(getAttributeList()->exists("p_timelength")) seenThis( PARAM_TIMELENGTH );
+
+ mStepTime = mpAttrs->readFloat("p_steptime",mStepTime, "Parametrizer","mStepTime", false);
+ if(getAttributeList()->exists("p_steptime")) seenThis( PARAM_STEPTIME );
+
+ mTimeFactor = mpAttrs->readFloat("p_timefactor",mTimeFactor, "Parametrizer","mTimeFactor", false);
+ if(getAttributeList()->exists("p_timefactor")) seenThis( PARAM_TIMEFACTOR );
+
+ mAniFrames = mpAttrs->readInt("p_aniframes",mAniFrames, "Parametrizer","mAniFrames", false);
+ if(getAttributeList()->exists("p_aniframes")) seenThis( PARAM_ANIFRAMES );
+
+ mAniFrameTime = mpAttrs->readFloat("p_aniframetime",mAniFrameTime, "Parametrizer","mAniFrameTime", false);
+ if(getAttributeList()->exists("p_aniframetime")) seenThis( PARAM_ANIFRAMETIME );
+ if(mAniFrameTime<=0.0) {
+ errMsg("Parametrizer::parseAttrList","Invalid frame time:"<<mAniFrameTime<<", resetting to 0.0001");
+ mAniFrameTime = 0.0001;
+ }
+
+ mAniStart = mpAttrs->readFloat("p_anistart",mAniStart, "Parametrizer","mAniStart", false);
+ if(getAttributeList()->exists("p_anistart")) seenThis( PARAM_ANISTART );
+ if(mAniStart<0.0) {
+ errMsg("Parametrizer::parseAttrList","Invalid start time:"<<mAniStart<<", resetting to 0.0");
+ mAniStart = 0.0;
+ }
+
+ mSurfaceTension = mpAttrs->readFloat("p_surfacetension",mSurfaceTension, "Parametrizer","mSurfaceTension", false);
+ if(getAttributeList()->exists("p_surfacetension")) seenThis( PARAM_SURFACETENSION );
+
+ mDensity = mpAttrs->readFloat("p_density",mDensity, "Parametrizer","mDensity", false);
+ if(getAttributeList()->exists("p_density")) seenThis( PARAM_DENSITY );
+
+ mCellSize = mpAttrs->readFloat("p_cellsize",mCellSize, "Parametrizer","mCellSize", false);
+ if(getAttributeList()->exists("p_cellsize")) seenThis( PARAM_CELLSIZE );
+
+ mGStar = mpAttrs->readFloat("p_gstar",mGStar, "Parametrizer","mGStar", false);
+ if(getAttributeList()->exists("p_gstar")) seenThis( PARAM_GSTAR );
+
+ mNormalizedGStar = mpAttrs->readFloat("p_normgstar",mNormalizedGStar, "Parametrizer","mNormalizedGStar", false);
+ if(getAttributeList()->exists("p_normgstar")) seenThis( PARAM_NORMALIZEDGSTAR );
+
+ mMaxSpeed = mpAttrs->readFloat("p_maxspeed",mMaxSpeed, "Parametrizer","mMaxSpeed", false);
+ if(getAttributeList()->exists("p_maxspeed")) seenThis( PARAM_MAXSPEED );
+
+ mTadapMaxOmega = mpAttrs->readFloat("p_tadapmaxomega",mTadapMaxOmega, "Parametrizer","mTadapMaxOmega", false);
+ mTadapMaxSpeed = mpAttrs->readFloat("p_tadapmaxspeed",mTadapMaxSpeed, "Parametrizer","mTadapMaxSpeed", false);
+}
+
+/******************************************************************************
+ * scale a given speed vector in m/s to lattice values
+ *****************************************************************************/
+ParamVec Parametrizer::calculateAddForce(ParamVec vec, string usage)
+{
+ ParamVec ret = vec * (mStepTime*mStepTime) /mCellSize;
+ debMsgStd("Parametrizer::calculateVector", DM_MSG, "scaled vector = "<<ret<<" for '"<<usage<<"', org = "<<vec<<" dt="<<mStepTime ,10);
+ return ret;
+}
+
+
+/******************************************************************************
+ * calculate size of a single cell
+ *****************************************************************************/
+ParamFloat Parametrizer::calculateCellSize(void)
+{
+ int maxsize = mSizex; // get max size
+ if(mSizey>maxsize) maxsize = mSizey;
+ if(mSizez>maxsize) maxsize = mSizez;
+ ParamFloat cellSize = 1.0 / (ParamFloat)maxsize;
+ return cellSize;
+}
+
+
+/*****************************************************************************/
+/* simple calulation functions */
+/*****************************************************************************/
+
+/*! get omega for LBM */
+ParamFloat Parametrizer::calculateOmega( void ) {
+ //return (mTimeFactor/mRelaxTime);
+ return (1.0/mRelaxTime);
+}
+
+/*! get no. of timesteps for LBM */
+//int calculateNoOfSteps( void ) {
+int Parametrizer::calculateNoOfSteps( ParamFloat timelen ) {
+ return (int)(timelen/mStepTime);
+}
+
+/*! get external force x component */
+ParamVec Parametrizer::calculateGravity( void ) {
+ return mLatticeGravity;
+}
+
+/*! get no of steps for the given length in seconds */
+int Parametrizer::calculateStepsForSecs( ParamFloat s ) {
+ return (int)(s/mStepTime);
+}
+
+/*! get start time of animation */
+int Parametrizer::calculateAniStart( void ) {
+ return (int)(mAniStart/mStepTime);
+}
+
+/*! get no of steps for a singel animation frame */
+int Parametrizer::calculateAniStepsPerFrame( void ) {
+ if(!checkSeenValues(PARAM_ANIFRAMETIME)) {
+ errMsg("Parametrizer::calculateAniStepsPerFrame", " Missing ani frame time argument!");
+ exit(1);
+ }
+ return (int)(mAniFrameTime/mStepTime);
+}
+
+/*! get extent of the domain = (1,1,1) if parametrizer not used, (x,y,z) [m] otherwise */
+ParamVec Parametrizer::calculateExtent( void ) {
+ return mExtent;
+}
+
+/*! get (scaled) surface tension */
+ParamFloat Parametrizer::calculateSurfaceTension( void ) {
+ return mSurfaceTension;
+}
+
+/*! calculate lattice velocity from real world value [m/s] */
+ParamVec Parametrizer::calculateLattVelocityFromRw( ParamVec ivel ) {
+ ParamVec velvec = ivel;
+ velvec /= mCellSize;
+ velvec *= mStepTime;
+ return velvec;
+}
+/*! calculate real world [m/s] velocity from lattice value */
+ParamVec Parametrizer::calculateRwVelocityFromLatt( ParamVec ivel ) {
+ ParamVec velvec = ivel;
+ velvec *= mCellSize;
+ velvec /= mStepTime;
+ return velvec;
+}
+
+
+/*! get the length of a single time step */
+// explicity scaled by time factor for refinement
+// testing purposes (e.g. fsgr solver)
+// not working... done manually in solver
+ParamFloat Parametrizer::getStepTime( void ) {
+ //return mTimeFactor * mStepTime;
+ return mStepTime;
+}
+
+/*! calculate the lattice viscosity */
+ParamFloat Parametrizer::calculateLatticeViscosity( void ) {
+ // check seen values
+ int reqValues = PARAM_VISCOSITY | PARAM_STEPTIME; // |PARAM_CELLSIZE | PARAM_GRAVITY;
+ if(!checkSeenValues( reqValues ) ){
+ errMsg("Parametrizer::calculateLatticeViscosity"," Missing arguments!");
+ }
+ ParamFloat viscStar = mViscosity * mStepTime / (mCellSize*mCellSize);
+ return viscStar;
+}
+
+/*! get g star value with fhvol calculations */
+ParamFloat Parametrizer::getCurrentGStar( void ) {
+ ParamFloat gStar = mGStar; // check? TODO get from mNormalizedGStar?
+ if(mFluidVolumeHeight>0.0) {
+ gStar = mGStar/mFluidVolumeHeight;
+ }
+ return gStar;
+}
+
+/******************************************************************************
+ * function that tries to calculate all the missing values from the given ones
+ * prints errors and returns false if thats not possible
+ *****************************************************************************/
+bool Parametrizer::calculateAllMissingValues( bool silent )
+{
+ bool init = false; // did we init correctly?
+ int valuesChecked = 0;
+ int reqValues;
+
+ // are we active anyway?
+ //if(!mActive) {
+ // not active - so there's nothing to calculate
+ //return true;
+ //}
+
+ // we always need the sizes
+ reqValues = PARAM_SIZE;
+ valuesChecked |= reqValues;
+ if(!checkSeenValues(reqValues)) {
+ errMsg("Parametrizer::calculateAllMissingValues"," Missing size argument!");
+ return false;
+ }
+
+ if(checkSeenValues(PARAM_CELLSIZE)) {
+ errMsg("Parametrizer::calculateAllMissingValues"," Dont explicitly set cell size (use domain size instead)");
+ return false;
+ }
+ if(!checkSeenValues(PARAM_DOMAINSIZE)) {
+ errMsg("Parametrizer::calculateAllMissingValues"," Missing domain size argument!");
+ return false;
+ }
+ int maxsize = mSizex; // get max size
+ if(mSizey>maxsize) maxsize = mSizey;
+ if(mSizez>maxsize) maxsize = mSizez;
+ mCellSize = ( mDomainSize * calculateCellSize() ); // sets mCellSize
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," max domain resolution="<<(maxsize)<<" cells , cellsize="<<mCellSize ,10);
+
+
+ /* Carolin init , see DA for details */
+ //ParamFloat viscMax = 0.7600; // max lattice viscosity
+ //ParamFloat viscMin = 0.0033; // min lattice viscosity
+ ParamFloat maxDeltaT = 0.0;
+ ParamFloat maxSpeed = 0.1; // for reynolds approx
+
+ /* normalized gstar init */
+ reqValues = PARAM_NORMALIZEDGSTAR;
+ valuesChecked |= reqValues;
+ if(checkSeenValues( reqValues ) ){
+ //if(checkSeenValues( PARAM_GSTAR ) ){ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_WARNING," g star value override by normalizedGStar!",1); }
+ mGStar = mNormalizedGStar/maxsize;
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," g star set to "<<mGStar<<" from normalizedGStar="<<mNormalizedGStar ,1);
+ seenThis(PARAM_GSTAR);
+ }
+
+ reqValues = PARAM_GSTAR | PARAM_VISCOSITY;
+ if((checkSeenValues(PARAM_SURFACETENSION))) reqValues |= PARAM_DENSITY; // surface tension optional now...
+ valuesChecked |= reqValues;
+ if(checkSeenValues( reqValues ) ){
+ const ParamFloat gstarReset = 0.0005;
+ if(getCurrentGStar()<=0.0) {
+ errMsg("Parametrizer::calculateAllMissingValues","Invalid Gstar: "<<getCurrentGStar()<<" (set to "<<mGStar<<") ... resetting to "<<gstarReset);
+ mGStar = gstarReset;
+ }
+
+ ParamFloat gStar = getCurrentGStar();
+ if(mFluidVolumeHeight>0.0) {
+ debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," height"<<mFluidVolumeHeight<<" resGStar = "<<gStar, 10);
+ }
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," g star = "<<gStar, 10);
+
+ if(mSetupType=="caro") {
+ if(!checkSeenValues(PARAM_GRAVITY)) {
+ errMsg("Parametrizer::calculateAllMissingValues","Setup type '"<<mSetupType<<"' requires gravity force!");
+ goto failure;
+ }
+ ParamFloat forceStrength = norm(mGravity);
+ if(forceStrength<=0) {
+ errMsg("Parametrizer::calculateAllMissingValues"," Init failed - forceStrength = "<<forceStrength);
+ goto failure;
+ }
+
+ // determine max. delta density per timestep trough gravity force
+ maxDeltaT = sqrt( gStar*mCellSize/forceStrength );
+ } else if(mSetupType=="maxspeed") {
+ // determine max. delta t from maximum speed (explicity set)
+ if((!checkSeenValues(PARAM_MAXSPEED))||(mMaxSpeed<=0.0)) {
+ errMsg("Parametrizer::calculateAllMissingValues","Setup type '"<<mSetupType<<"' requires maximum speed ("<<mMaxSpeed<<") !");
+ goto failure;
+ }
+ ParamFloat maxLatticeSpeed = 0.0333333; //?
+ maxDeltaT = ( maxLatticeSpeed * mCellSize) / mMaxSpeed;
+ maxSpeed = mMaxSpeed;
+ } else if(mSetupType=="falling") {
+ // determine max. delta t from maximum speed that can be caused by falling through the domain
+ errMsg("Parametrizer::calculateAllMissingValues"," NYI setup falling");
+ } else {
+ errMsg("Parametrizer::calculateAllMissingValues","Setup type '"<<mSetupType<<"' unknown!");
+ goto failure;
+ }
+
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," targeted step time = "<<maxDeltaT, 10);
+
+ ParamFloat viscStarFac = mViscosity/(mCellSize*mCellSize);
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," viscStarFac = "<<viscStarFac, 10);
+
+ // FIXME remove for LES?
+ //if( (viscStarFac*maxDeltaT>=viscMin) && (viscStarFac*maxDeltaT<=viscMax) ) {
+ //if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," delta t: "<<viscMin<<" <? "<<maxDeltaT*viscStarFac<<" <? "<<viscMax, 1);
+ //} else {
+ //if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_WARNING," delta t not in valid range: "<<viscMin<<" <? "<<maxDeltaT*viscStarFac<<" <? "<<viscMax, 1);
+ //}
+
+ // time step adaptivty, only for caro with max sim speed
+ ParamFloat setDeltaT = maxDeltaT;
+ if(mDesiredStepTime>0.0) {
+ setDeltaT = mDesiredStepTime;
+ mDesiredStepTime = -1.0;
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," desired step time = "<<setDeltaT, 10);
+ } else if((mSetupType=="caro") && (checkSeenValues( PARAM_SIMMAXSPEED )) ) {
+ // determine minimal delta t by omega max.
+ ParamFloat minDeltaT;
+ ParamFloat maxOmega = mTadapMaxOmega;
+ ParamFloat minRelaxTime = 1.0/maxOmega;
+ for(int lev=1; lev<mTadapLevels; lev++) {
+ // make minRelaxTime larger for each level that exists...
+ minRelaxTime = 2.0 * (minRelaxTime-0.5) + 0.5;
+ }
+ maxOmega = 1.0/minRelaxTime;
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," maxOmega="<<maxOmega<<" minRelaxTime="<<minRelaxTime<<" levels="<<mTadapLevels, 1);
+ // visc-star for min relax time to calculate min delta ta
+ if(mViscosity>0.0) {
+ minDeltaT = ((2.0*minRelaxTime-1.0)/6.0) * mCellSize * mCellSize / mViscosity;
+ } else {
+ // visc=0, this is not physical, but might happen
+ minDeltaT = 0.0;
+ }
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," min delta t = "<<minDeltaT<<" , range = " << (maxDeltaT/minDeltaT) ,1);
+
+ // sim speed + accel shouldnt exceed 0.1?
+ //if(mSimulationMaxSpeed + norm(mGravity*)) { ParamFloat nextmax = 0.1-mSimulationMaxSpeed }
+ mMaxStepTime = maxDeltaT;
+ mMinStepTime = minDeltaT;
+ // only use once...
+ } else {
+ debMsgStd("Parametrizer::calculateAllMissingValues",DM_WARNING,"Warning - setup type set to '"<<mSetupType<<"' ",1);
+ mMaxStepTime = mMinStepTime = setDeltaT;
+ }
+
+ setStepTime( setDeltaT ); // set mStepTime to new value
+
+ //ParamFloat viscStar = mViscosity * mStepTime / (mCellSize*mCellSize);
+ ParamFloat viscStar = calculateLatticeViscosity();
+ mRelaxTime = (6.0 * viscStar + 1) * 0.5;
+ init = true;
+
+ }
+
+ // finish init
+ if(init) {
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," omega = "<<calculateOmega()<<", relax time = "<<mRelaxTime<<", delt="<<mStepTime,1);
+ //debMsgStd("Parametrizer::calculateAllMissingValues: lbm steps = "<<calculateNoOfSteps()<<" ",1);
+
+ if(checkSeenValues(PARAM_GRAVITY)) {
+ ParamFloat forceFactor = (mStepTime *mStepTime)/mCellSize;
+ //if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," given force = "<<PRINT_NTLVEC(mGravity),1);
+ mLatticeGravity = mGravity * forceFactor;
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," gravity force = "<<PRINT_NTLVEC(mGravity)<<", scaled with "<<forceFactor<<" to "<<mLatticeGravity,1);
+ }
+
+ if((checkSeenValues(PARAM_SURFACETENSION))&&(mSurfaceTension>0.0)) {
+ ParamFloat massDelta = 1.0;
+ ParamFloat densityStar = 1.0;
+ massDelta = mDensity / densityStar *mCellSize*mCellSize*mCellSize;
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," massDelta = "<<massDelta, 10);
+
+ mSurfaceTension = mSurfaceTension*mStepTime*mStepTime/massDelta;
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," surface tension = "<<mSurfaceTension<<" ",1);
+ }
+
+ mExtent = ParamVec( mCellSize*mSizex, mCellSize*mSizey, mCellSize*mSizez );
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," domain extent = "<<PRINT_NTLVEC(mExtent)<<"m ",1);
+
+ if(checkSeenValues(PARAM_ANIFRAMETIME)) {
+ if(checkSeenValues(PARAM_ANIFRAMES)) {
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," Warning - ani frame time and ani frames given!", 1);
+ exit(1);
+ }
+ } else {
+ mAniFrameTime = mAniFrames * mStepTime;
+ }
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," ani frame steps = "<<calculateAniStepsPerFrame()<<" ", 1);
+
+ if((checkSeenValues(PARAM_ANISTART))&&(calculateAniStart()>0)) {
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," ani start steps = "<<calculateAniStart()<<" ",1);
+ }
+
+ // calculate reynolds number
+ ParamFloat reynoldsApprox = -1.0;
+ ParamFloat gridSpeed = (maxSpeed*mCellSize/mStepTime);
+ reynoldsApprox = (mDomainSize*gridSpeed) / mViscosity;
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," reynolds number (D="<<mDomainSize<<", assuming V="<<gridSpeed<<")= "<<reynoldsApprox<<" ", 1);
+
+ // everything ok
+ return true;
+ }
+
+failure:
+ errMsg("Parametrizer::calculateAllMissingValues "," invalid configuration!");
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues ",DM_WARNING, " values seen:", 1);
+ for(int i=0;i<PARAM_NUMIDS;i++) {
+ if(checkSeenValues( 1<<i )) {
+ if(!silent) debMsgStd(" ",DM_NOTIFY, ParamStrings[i], 1);
+ }
+ }
+ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues ",DM_WARNING, "values checked but missing:", 1);
+ for(int i=0;i<PARAM_NUMIDS;i++) {
+ if((!checkSeenValues( 1<<i ))&&
+ ( (valuesChecked&(1<<i))==(1<<i)) ) {
+ debMsgStd(" ",DM_IMPORTANT, ParamStrings[i], 1);
+ }
+ }
+
+ // print values?
+ return false;
+}
+
+
+
+
+
+
+
diff --git a/intern/elbeem/intern/parametrizer.h b/intern/elbeem/intern/parametrizer.h
new file mode 100644
index 00000000000..d6a8d9575b9
--- /dev/null
+++ b/intern/elbeem/intern/parametrizer.h
@@ -0,0 +1,369 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Parameter calculator for the LBM Solver class
+ *
+ *****************************************************************************/
+#ifndef MFFSLBM_PARAMETRIZER
+#define MFFSLBM_PARAMETRIZER
+
+
+/* LBM Files */
+#include "utilities.h"
+#include "attributes.h"
+
+/* parametrizer accuracy */
+typedef double ParamFloat;
+typedef ntlVec3d ParamVec;
+
+/*! flags to check which values are known */
+#define PARAM_RELAXTIME (1<< 0)
+#define PARAM_REYNOLDS (1<< 1)
+#define PARAM_VISCOSITY (1<< 2)
+#define PARAM_SOUNDSPEED (1<< 3)
+#define PARAM_DOMAINSIZE (1<< 4)
+#define PARAM_GRAVITY (1<< 5)
+#define PARAM_TIMELENGTH (1<< 6)
+#define PARAM_STEPTIME (1<< 7)
+#define PARAM_SIZE (1<< 8)
+#define PARAM_TIMEFACTOR (1<< 9)
+#define PARAM_ANIFRAMES (1<<10)
+#define PARAM_ANIFRAMETIME (1<<11)
+#define PARAM_ANISTART (1<<12)
+#define PARAM_SURFACETENSION (1<<13)
+#define PARAM_DENSITY (1<<14)
+#define PARAM_CELLSIZE (1<<15)
+#define PARAM_GSTAR (1<<16)
+#define PARAM_MAXSPEED (1<<17)
+#define PARAM_SIMMAXSPEED (1<<18)
+#define PARAM_FLUIDVOLHEIGHT (1<<19)
+#define PARAM_NORMALIZEDGSTAR (1<<20)
+#define PARAM_NUMIDS 21
+
+//! parameters to ignore for parametrizer activation
+#define PARAM_IGNORE (~(PARAM_ANIFRAMES|PARAM_SIZE))
+
+//! output parameter debug message?
+//#define PARAM_DEBUG 1
+
+
+
+/*! Parameter calculator for the LBM Solver class */
+class Parametrizer {
+
+ public:
+ /*! default contructor */
+ Parametrizer();
+
+ /*! destructor */
+ ~Parametrizer();
+
+ /*! Initilize variables fom attribute list */
+ void parseAttrList( void );
+
+ /*! function that tries to calculate all the missing values from the given ones
+ * prints errors and returns false if thats not possible */
+ bool calculateAllMissingValues( bool silent = false );
+ bool oldCalculateAllMissingValues( void );
+ /*! is the parametrizer used at all? */
+ //bool isUsed() { if(!mActive){ return false; } return(mSeenValues!=(~PARAM_IGNORE)); }
+ bool isUsed() { return true; }
+
+ /*! add this flag to the seen values */
+ void seenThis(int seen) { mSeenValues = (mSeenValues | seen);
+#ifdef PARAM_DEBUG
+ errorOut(" seen "<<seen<<endl);
+#endif
+ }
+
+ /*! set the flags integer */
+ void setSeenValues(int set) { mSeenValues = set; }
+ /*! check if the flags are set in the values int */
+ bool checkSeenValues(int check) { /*errorOut( " b"<<((mSeenValues&check)==check) );*/ return ((mSeenValues&check)==check); }
+
+ /*! add this flag to the calculated values */
+ void calculatedThis(int cac) { mCalculatedValues = (mCalculatedValues | cac); /*errorOut(" a "<<seen);*/ }
+ /*! set the calculated flags integer */
+ void setCalculatedValues(int set) { mCalculatedValues = set; }
+ /*! check if the calculated flags are set in the values int */
+ bool checkCalculatedValues(int check) { /*errorOut( " b"<<((mSeenValues&check)==check) );*/ return ((mCalculatedValues&check)==check); }
+
+ /*! scale a given speed vector in m/s to lattice values
+ * usage string is only needed for debugging */
+ ParamVec calculateAddForce(ParamVec vec, string usage);
+
+ /* simple calulation functions */
+ /*! get omega for LBM */
+ ParamFloat calculateOmega( void );
+ /*! get no. of timesteps for LBM */
+ //int calculateNoOfSteps( void ) { return (int)(mTimeLength/mStepTime); }
+ int calculateNoOfSteps( ParamFloat timelen );
+ /*! get external force x component */
+ ParamVec calculateGravity( void );
+ /*! get no of steps for the given length in seconds */
+ int calculateStepsForSecs( ParamFloat s );
+ /*! get start time of animation */
+ int calculateAniStart( void );
+ /*! get no of steps for a singel animation frame */
+ int calculateAniStepsPerFrame( void );
+ /*! get extent of the domain = (1,1,1) if parametrizer not used, (x,y,z) [m] otherwise */
+ ParamVec calculateExtent( void );
+ /*! get (scaled) surface tension */
+ ParamFloat calculateSurfaceTension( void );
+ /*! get time step size for lbm (equals mTimeFactor) */
+ // unused ParamFloat calculateTimestep( void );
+ /*! calculate size of a single cell */
+ ParamFloat calculateCellSize(void);
+ /*! calculate the lattice viscosity */
+ ParamFloat calculateLatticeViscosity(void);
+
+ /*! calculate lattice velocity from real world value [m/s] */
+ ParamVec calculateLattVelocityFromRw( ParamVec ivel );
+ /*! calculate real world [m/s] velocity from lattice value */
+ ParamVec calculateRwVelocityFromLatt( ParamVec ivel );
+
+
+ /*! set relaxation time */
+ void setRelaxTime(ParamFloat set) { mRelaxTime = set; seenThis( PARAM_RELAXTIME ); }
+ /*! get relaxation time */
+ ParamFloat getRelaxTime( void ) { return mRelaxTime; }
+
+ /*! set reynolds number */
+ void setReynolds(ParamFloat set) { mReynolds = set; seenThis( PARAM_REYNOLDS ); }
+ /*! get reynolds number */
+ ParamFloat getReynolds( void ) { return mReynolds; }
+
+ /*! set kinematic viscosity */
+ void setViscosity(ParamFloat set) { mViscosity = set; seenThis( PARAM_VISCOSITY ); }
+ /*! get kinematic viscosity */
+ ParamFloat getViscosity( void ) { return mViscosity; }
+
+ /*! set speed of sound */
+ void setSoundSpeed(ParamFloat set) { mSoundSpeed = set; seenThis( PARAM_SOUNDSPEED ); }
+ /*! get speed of sound */
+ ParamFloat getSoundSpeed( void ) { return mSoundSpeed; }
+
+ /*! set the external force */
+ void setGravity(ParamFloat setx, ParamFloat sety, ParamFloat setz) { mGravity = ParamVec(setx,sety,setz); seenThis( PARAM_GRAVITY ); }
+ void setGravity(ParamVec set) { mGravity = set; seenThis( PARAM_GRAVITY ); }
+
+ /*! set the length of the simulation */
+ //void setTimeLength(ParamFloat set) { mTimeLength = set; seenThis( PARAM_TIMELENGTH ); }
+ /*! get the length of the simulation */
+ //ParamFloat getTimeLength( void ) { return mTimeLength; }
+
+ /*! set the length of a single time step */
+ void setStepTime(ParamFloat set) { mStepTime = set; seenThis( PARAM_STEPTIME ); }
+ /*! get the length of a single time step */
+ ParamFloat getStepTime( void);
+ /*! set a desired step time for rescaling/adaptive timestepping */
+ void setDesiredStepTime(ParamFloat set) { mDesiredStepTime = set; }
+ /*! get the length of a single time step */
+ ParamFloat getMaxStepTime( void ) { return mMaxStepTime; }
+ /*! get the length of a single time step */
+ ParamFloat getMinStepTime( void ) { return mMinStepTime; }
+
+ /*! set the time scaling factor */
+ void setTimeFactor(ParamFloat set) { mTimeFactor = set; seenThis( PARAM_TIMEFACTOR ); }
+ /*! get the time scaling factor */
+ ParamFloat getTimeFactor( void ) { return mTimeFactor; }
+
+ /*! init domain resoultion */
+ void setSize(int ijk) { mSizex = ijk; mSizey = ijk; mSizez = ijk; seenThis( PARAM_SIZE ); }
+ void setSize(int i,int j, int k) { mSizex = i; mSizey = j; mSizez = k; seenThis( PARAM_SIZE ); }
+
+ /*! set no of animation steps (renderer) */
+ void setAniFrames(int set) { mAniFrames = set; seenThis( PARAM_ANIFRAMES ); }
+ /*! get no of animation steps (renderer) */
+ int getAniFrames( void ) { return mAniFrames; }
+
+ /*! set time of an animation frame (renderer) */
+ void setAniFrameTime(ParamFloat set) { mAniFrameTime = set; seenThis( PARAM_ANIFRAMETIME ); }
+ /*! get time of an animation frame (renderer) */
+ ParamFloat getAniFrameTime( void ) { return mAniFrameTime; }
+
+ /*! set starting time of the animation (renderer) */
+ void setAniStart(ParamFloat set) { mAniStart = set; seenThis( PARAM_ANISTART ); }
+ /*! get starting time of the animation (renderer) */
+ ParamFloat getAniStart( void ) { return mAniStart; }
+
+ /*! set starting time of the animation (renderer) */
+ void setSurfaceTension(ParamFloat set) { mSurfaceTension = set; seenThis( PARAM_SURFACETENSION ); }
+ /*! get starting time of the animation (renderer) */
+ ParamFloat getSurfaceTension( void ) { return mSurfaceTension; }
+
+ /*! set fluid density */
+ void setDensity(ParamFloat set) { mDensity = set; seenThis( PARAM_DENSITY ); }
+ /*! get fluid density */
+ ParamFloat getDensity( void ) { return mDensity; }
+
+ /*! set g star value */
+ void setGStar(ParamFloat set) { mGStar = set; seenThis( PARAM_GSTAR ); }
+ /*! get g star value */
+ ParamFloat getGStar( void ) { return mGStar; }
+ /*! get g star value with fhvol calculations */
+ ParamFloat getCurrentGStar( void );
+ /*! set normalized g star value */
+ void setNormalizedGStar(ParamFloat set) { mNormalizedGStar = set; seenThis( PARAM_NORMALIZEDGSTAR ); }
+ /*! get normalized g star value */
+ ParamFloat getNormalizedGStar( void ) { return mNormalizedGStar; }
+
+ /*! set g star value */
+ void setFluidVolumeHeight(ParamFloat set) { mFluidVolumeHeight = set; seenThis( PARAM_FLUIDVOLHEIGHT ); }
+ /*! get g star value */
+ ParamFloat getFluidVolumeHeight( void ) { return mFluidVolumeHeight; }
+
+ /*! set the size of a single lbm cell */
+ void setDomainSize(ParamFloat set) { mDomainSize = set; seenThis( PARAM_DOMAINSIZE ); }
+ /*! get the size of a single lbm cell */
+ ParamFloat getDomainSize( void ) { return mDomainSize; }
+
+ /*! set the size of a single lbm cell */
+ void setCellSize(ParamFloat set) { mCellSize = set; seenThis( PARAM_CELLSIZE ); }
+ /*! get the size of a single lbm cell */
+ ParamFloat getCellSize( void ) { return mCellSize; }
+
+ /*! set active flag for parametrizer */
+ //void setActive(bool set) { mActive = set; }
+
+ /*! set attr list pointer */
+ void setAttrList(AttributeList *set) { mpAttrs = set; }
+ /*! Returns the attribute list pointer */
+ inline AttributeList *getAttributeList() { return mpAttrs; }
+
+ /*! set maximum allowed speed for maxspeed setup */
+ void setMaxSpeed(ParamFloat set) { mMaxSpeed = set; seenThis( PARAM_MAXSPEED ); }
+ /*! get maximum allowed speed for maxspeed setup */
+ ParamFloat getMaxSpeed( void ) { return mMaxSpeed; }
+
+ /*! set maximum allowed speed for maxspeed setup */
+ void setSimulationMaxSpeed(ParamFloat set) { mSimulationMaxSpeed = set; seenThis( PARAM_SIMMAXSPEED ); }
+ /*! get maximum allowed speed for maxspeed setup */
+ ParamFloat getSimulationMaxSpeed( void ) { return mSimulationMaxSpeed; }
+
+ /*! set maximum allowed omega for time adaptivity */
+ void setTadapMaxOmega(ParamFloat set) { mTadapMaxOmega = set; }
+ /*! get maximum allowed omega for time adaptivity */
+ ParamFloat getTadapMaxOmega( void ) { return mTadapMaxOmega; }
+
+ /*! set maximum allowed speed for time adaptivity */
+ void setTadapMaxSpeed(ParamFloat set) { mTadapMaxSpeed = set; }
+ /*! get maximum allowed speed for time adaptivity */
+ ParamFloat getTadapMaxSpeed( void ) { return mTadapMaxSpeed; }
+
+ /*! set maximum allowed omega for time adaptivity */
+ void setTadapLevels(int set) { mTadapLevels = set; }
+ /*! get maximum allowed omega for time adaptivity */
+ int getTadapLevels( void ) { return mTadapLevels; }
+
+
+ /*! set */
+ // void set(ParamFloat set) { m = set; seenThis( PARAM_ ); }
+ /*! get */
+ // ParamFloat get( void ) { return m; }
+
+
+
+ private:
+
+ /*! type of parameter setup to use */
+ string mSetupType;
+
+ /*! relaxation time [s] */
+ ParamFloat mRelaxTime;
+
+ /*! reynolds number (calculated from domain length and max. speed [dimensionless] */
+ ParamFloat mReynolds;
+
+ /*! kinematic viscosity of the fluid [m^2/s] */
+ ParamFloat mViscosity;
+
+ /*! speed of sound of the fluid [m/s] */
+ ParamFloat mSoundSpeed;
+
+ /*! size of the domain [m] */
+ ParamFloat mDomainSize;
+
+ /*! size of a single cell in the grid [m] */
+ ParamFloat mCellSize;
+
+ /*! time step length [s] */
+ ParamFloat mTimeStep;
+
+ /*! external force as acceleration [m/s^2] */
+ ParamVec mGravity;
+ /*! force converted to lattice units (returned by calc gravity) */
+ ParamVec mLatticeGravity;
+
+ /*! lenth of the simulation [s] */
+ //ParamFloat mTimeLength;
+
+ /*! length of one time step in the simulation */
+ ParamFloat mStepTime;
+ /*! desired step time for rescaling/adaptive timestepping, only regarded if >0.0, reset after usage */
+ ParamFloat mDesiredStepTime;
+ /*! minimal and maximal step times for current setup */
+ ParamFloat mMaxStepTime, mMinStepTime;
+
+ /*! domain resoultion, the same values as in lbmsolver */
+ int mSizex, mSizey, mSizez;
+
+ /*! time scaling factor (auto calc from accel, or set), equals the delta t in LBM */
+ ParamFloat mTimeFactor;
+
+ /*! from renderer - no of animation frames for the animation (same as mpglob mAniFrames) */
+ int mAniFrames;
+
+ /*! for renderer - length of an animation step [s] */
+ ParamFloat mAniFrameTime;
+
+ /*! for renderer - start time of the animation [s] */
+ ParamFloat mAniStart;
+
+ /*! extent of the domain in meters */
+ ParamVec mExtent;
+
+ /*! surface tension, [kg/s^2] */
+ ParamFloat mSurfaceTension;
+
+ /*! fluid density [kg/m^3], default 1.0 g/cm^3 */
+ ParamFloat mDensity;
+
+ /*! max difference due to gravity (for caro setup) */
+ ParamFloat mGStar;
+ /*! set gstar normalized! */
+ ParamFloat mNormalizedGStar;
+ /*! fluid volume/height multiplier for GStar */
+ ParamFloat mFluidVolumeHeight;
+
+ /*! max speed (for maxspeed setup) */
+ ParamFloat mMaxSpeed;
+
+ /*! current max speed of the simulation (for adaptive time steps) */
+ ParamFloat mSimulationMaxSpeed;
+ /*! maximum omega (for adaptive time steps) */
+ ParamFloat mTadapMaxOmega;
+ /*! maximum allowed speed in lattice units e.g. 0.1 (for adaptive time steps, not directly used in parametrizer) */
+ ParamFloat mTadapMaxSpeed;
+ /*! no. of levels for max omega (set by fsgr, not in cfg file) */
+ int mTadapLevels;
+
+
+ /*! values that are seen for this simulation */
+ int mSeenValues;
+
+ /*! values that are calculated from the seen ones for this simulation */
+ int mCalculatedValues;
+
+ /*! is the parametrizer active? */
+ //bool mActive;
+
+ /*! pointer to the attribute list */
+ AttributeList *mpAttrs;
+};
+
+
+#endif
+
diff --git a/intern/elbeem/intern/particletracer.cpp b/intern/elbeem/intern/particletracer.cpp
new file mode 100644
index 00000000000..7b9fb9fd1f4
--- /dev/null
+++ b/intern/elbeem/intern/particletracer.cpp
@@ -0,0 +1,270 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Particle Viewer/Tracer
+ *
+ *****************************************************************************/
+
+#include <stdio.h>
+//#include "../libs/my_gl.h"
+//#include "../libs/my_glu.h"
+
+/* own lib's */
+#include "particletracer.h"
+#include "ntl_matrices.h"
+#include "ntl_ray.h"
+#include "ntl_scene.h"
+
+
+
+/******************************************************************************
+ * Standard constructor
+ *****************************************************************************/
+ParticleTracer::ParticleTracer() :
+ ntlGeometryObject(),
+ mParts(1),
+ mNumParticles(0), mTrailLength(1), mTrailInterval(1),mTrailIntervalCounter(0),
+ mPartSize(0.01), mTrailScale(1.0),
+ mStart(-1.0), mEnd(1.0),
+ mSimStart(-1.0), mSimEnd(1.0),
+ mPartScale(1.0) , mPartHeadDist( 0.5 ), mPartTailDist( -4.5 ), mPartSegments( 4 ),
+ mValueScale(0),
+ mValueCutoffTop(0.0), mValueCutoffBottom(0.0)
+{
+};
+
+/*****************************************************************************/
+//! parse settings from attributes (dont use own list!)
+/*****************************************************************************/
+void ParticleTracer::parseAttrList(AttributeList *att)
+{
+ AttributeList *tempAtt = mpAttrs;
+ mpAttrs = att;
+ mNumParticles = mpAttrs->readInt("particles",mNumParticles, "ParticleTracer","mNumParticles", false);
+ mTrailLength = mpAttrs->readInt("traillength",mTrailLength, "ParticleTracer","mTrailLength", false);
+ mTrailInterval= mpAttrs->readInt("trailinterval",mTrailInterval, "ParticleTracer","mTrailInterval", false);
+
+ mPartScale = mpAttrs->readFloat("part_scale",mPartScale, "ParticleTracer","mPartScale", false);
+ mPartHeadDist = mpAttrs->readFloat("part_headdist",mPartHeadDist, "ParticleTracer","mPartHeadDist", false);
+ mPartTailDist = mpAttrs->readFloat("part_taildist",mPartTailDist, "ParticleTracer","mPartTailDist", false);
+ mPartSegments = mpAttrs->readInt ("part_segments",mPartSegments, "ParticleTracer","mPartSegments", false);
+ mValueScale = mpAttrs->readInt ("part_valscale",mValueScale, "ParticleTracer","mValueScale", false);
+ mValueCutoffTop = mpAttrs->readFloat("part_valcutofftop",mValueCutoffTop, "ParticleTracer","mValueCutoffTop", false);
+ mValueCutoffBottom = mpAttrs->readFloat("part_valcutoffbottom",mValueCutoffBottom, "ParticleTracer","mValueCutoffBottom", false);
+
+ mTrailScale = mpAttrs->readFloat("trail_scale",mTrailScale, "ParticleTracer","mTrailScale", false);
+
+ string matPart;
+ matPart = mpAttrs->readString("material_part", "default", "ParticleTracer","material", false);
+ setMaterialName( matPart );
+ // trail length has to be at least one, if anything should be displayed
+ if((mNumParticles>0)&&(mTrailLength<2)) mTrailLength = 2;
+
+ // restore old list
+ mpAttrs = tempAtt;
+ mParts.resize(mTrailLength*mTrailInterval);
+}
+
+/******************************************************************************
+ * draw the particle array
+ *****************************************************************************/
+void ParticleTracer::draw()
+{
+}
+
+
+/******************************************************************************
+ * set the number of timesteps to trace
+ *****************************************************************************/
+void ParticleTracer::setTimesteps(int steps)
+{
+ steps=0; // remove warning...
+}
+
+
+/******************************************************************************
+ * add a particle at this position
+ *****************************************************************************/
+void ParticleTracer::addParticle(double x, double y, double z)
+{
+ ntlVec3Gfx p(x,y,z);
+ ParticleObject part( p );
+ //mParts[0].push_back( part );
+ // TODO handle other arrays?
+ //part.setActive( false );
+ for(size_t l=0; l<mParts.size(); l++) {
+ // add deactivated particles to other arrays
+ mParts[l].push_back( part );
+ // deactivate further particles
+ if(l>1) {
+ //mParts[l][ mParts.size()-1 ].setActive( false );
+ }
+ }
+}
+
+
+
+/******************************************************************************
+ * save particle positions before adding a new timestep
+ * copy "one index up", newest has to remain unmodified, it will be
+ * advanced after the next smiulation step
+ *****************************************************************************/
+void ParticleTracer::savePreviousPositions()
+{
+ //debugOut(" PARTS SIZE "<<mParts.size() ,10);
+ if(mTrailIntervalCounter==0) {
+ //errMsg("spp"," PARTS SIZE "<<mParts.size() );
+ for(size_t l=mParts.size()-1; l>0; l--) {
+ if( mParts[l].size() != mParts[l-1].size() ) {
+ errorOut("ParticleTracer::savePreviousPositions error: Invalid array sizes ["<<l<<"]="<<mParts[l].size()<<
+ " ["<<(l+1)<<"]="<<mParts[l+1].size() <<" , total "<< mParts.size() );
+ exit(1);
+ }
+
+ for(size_t i=0; i<mParts[l].size(); i++) {
+ mParts[l][i] = mParts[l-1][i];
+ }
+
+ }
+ }
+ mTrailIntervalCounter++;
+ if(mTrailIntervalCounter>=mTrailInterval) mTrailIntervalCounter = 0;
+}
+
+
+
+
+/******************************************************************************
+ * Get triangles for rendering
+ *****************************************************************************/
+void ParticleTracer::getTriangles( vector<ntlTriangle> *triangles,
+ vector<ntlVec3Gfx> *vertices,
+ vector<ntlVec3Gfx> *normals, int objectId )
+{
+ int tris = 0;
+ gfxReal partNormSize = 0.01 * mPartScale;
+ ntlVec3Gfx pScale = ntlVec3Gfx(
+ (mEnd[0]-mStart[0])/(mSimEnd[0]-mSimStart[0]),
+ (mEnd[1]-mStart[1])/(mSimEnd[1]-mSimStart[1]),
+ (mEnd[2]-mStart[2])/(mSimEnd[2]-mSimStart[2])
+ );
+ //errMsg(" PS ", " S "<<pScale );
+ ntlVec3Gfx org = mStart;
+ int segments = mPartSegments;
+
+ int lnewst = mTrailLength-1;
+ int loldst = mTrailLength-2;
+ // trails gehen nicht so richtig mit der
+ // richtung der partikel...
+ //for(int l=0; l<mTrailLength-2; l++) {
+ //int lnewst = l+1;
+ //int loldst = l;
+
+ for(size_t i=0; i<mParts[lnewst].size(); i++) {
+
+ //mParts[0][i].setActive(true);
+
+ if( mParts[lnewst][i].getActive()==false ) continue;
+ if( mParts[loldst][i].getActive()==false ) continue;
+
+ ntlVec3Gfx pnew = mParts[lnewst][i].getPos();
+ ntlVec3Gfx pold = mParts[loldst][i].getPos();
+ ntlVec3Gfx pdir = pnew - pold;
+ gfxReal plen = normalize( pdir );
+ if( plen < 1e-05) pdir = ntlVec3Gfx(-1.0 ,0.0 ,0.0);
+ ntlVec3Gfx p = org + pnew*pScale;
+ gfxReal partsize = 0.0;
+ //errMsg("pp"," "<<l<<" i"<<i<<" new"<<pnew<<" old"<<pold );
+
+ // value length scaling?
+ if(mValueScale==1) {
+ partsize = mPartScale * plen;
+ } else if(mValueScale==2) {
+ // cut off scaling
+ if(plen > mValueCutoffTop) continue;
+ if(plen < mValueCutoffBottom) continue;
+ partsize = mPartScale * plen;
+ } else {
+ partsize = mPartScale; // no length scaling
+ }
+
+ ntlVec3Gfx pstart( mPartHeadDist *partsize, 0.0, 0.0 );
+ ntlVec3Gfx pend ( mPartTailDist *partsize, 0.0, 0.0 );
+ gfxReal phi = 0.0;
+ gfxReal phiD = 2.0*M_PI / (gfxReal)segments;
+
+ ntlMat4Gfx cvmat;
+ cvmat.initId();
+ pdir *= -1.0;
+ ntlVec3Gfx cv1 = pdir;
+ ntlVec3Gfx cv2 = ntlVec3Gfx(pdir[1], -pdir[0], 0.0);
+ ntlVec3Gfx cv3 = cross( cv1, cv2);
+ for(int l=0; l<3; l++) {
+ cvmat.value[l][0] = cv1[l];
+ cvmat.value[l][1] = cv2[l];
+ cvmat.value[l][2] = cv3[l];
+ }
+ pstart = (cvmat * pstart);
+ pend = (cvmat * pend);
+
+ for(int s=0; s<segments; s++) {
+ ntlVec3Gfx p1( 0.0 );
+ ntlVec3Gfx p2( 0.0 );
+
+ gfxReal radscale = partNormSize;
+ radscale = (partsize+partNormSize)*0.5;
+ p1[1] += cos(phi) * radscale;
+ p1[2] += sin(phi) * radscale;
+ p2[1] += cos(phi + phiD) * radscale;
+ p2[2] += sin(phi + phiD) * radscale;
+ ntlVec3Gfx n1 = ntlVec3Gfx( 0.0, cos(phi), sin(phi) );
+ ntlVec3Gfx n2 = ntlVec3Gfx( 0.0, cos(phi + phiD), sin(phi + phiD) );
+ ntlVec3Gfx ns = n1*0.5 + n2*0.5;
+
+ p1 = (cvmat * p1);
+ p2 = (cvmat * p2);
+
+ sceneAddTriangle( p+pstart, p+p1, p+p2,
+ ns,n1,n2, ntlVec3Gfx(0.0), 1 );
+ sceneAddTriangle( p+pend , p+p2, p+p1,
+ ns,n2,n1, ntlVec3Gfx(0.0), 1 );
+
+ phi += phiD;
+ tris += 2;
+ }
+ }
+
+ //} // trail
+ return; // DEBUG
+
+
+ // add trails
+ //double tScale = 0.01 * mPartScale * mTrailScale;
+ double trails = 0.01 * mPartScale * mTrailScale;
+ //for(int l=0; l<mParts.size()-1; l++) {
+ for(int l=0; l<mTrailLength-2; l++) {
+ for(size_t i=0; i<mParts[0].size(); i++) {
+ int tl1 = l*mTrailInterval;
+ int tl2 = (l+1)*mTrailInterval;
+ if( mParts[tl1][i].getActive()==false ) continue;
+ if( mParts[tl2][i].getActive()==false ) continue;
+ ntlVec3Gfx p1 = org+mParts[tl1][i].getPos()*pScale;
+ ntlVec3Gfx p2 = org+mParts[tl2][i].getPos()*pScale;
+ ntlVec3Gfx n = ntlVec3Gfx(0,0,-1);
+ sceneAddTriangle( p1+ntlVec3Gfx(0,trails,0), p1+ntlVec3Gfx(0,-trails,0), p2,
+ n,n,n, ntlVec3Gfx(0.0), 1 );
+ sceneAddTriangle( p2, p1+ntlVec3Gfx(0,-trails,0), p1+ntlVec3Gfx(0,trails,0),
+ n,n,n, ntlVec3Gfx(0.0), 1 );
+ tris += 2;
+ }
+ }
+ debugOut("ParticleTracer::getTriangles "<<mName<<" : Triangulated "<< (mParts[0].size()) <<" particles (triangles: "<<tris<<") ", 10);
+ //debugOut(" s"<<mStart<<" e"<<mEnd<<" ss"<<mSimStart<<" se"<<mSimEnd , 10);
+
+}
+
+
+
+
diff --git a/intern/elbeem/intern/particletracer.h b/intern/elbeem/intern/particletracer.h
new file mode 100644
index 00000000000..71e7ed1a788
--- /dev/null
+++ b/intern/elbeem/intern/particletracer.h
@@ -0,0 +1,165 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Particle Viewer/Tracer
+ *
+ *****************************************************************************/
+#ifndef NTL_PARTICLETRACER_H
+
+#include "ntl_geometryobject.h"
+
+
+//! A single particle
+class ParticleObject
+{
+ public:
+ //! Standard constructor
+ inline ParticleObject(ntlVec3Gfx mp) :
+ mPos(mp), mActive( true ) { };
+ //! Copy constructor
+ inline ParticleObject(const ParticleObject &a) :
+ mPos(a.mPos), mActive(a.mActive) { };
+ //! Destructor
+ inline ~ParticleObject() { /* empty */ };
+
+ //! add vector to position
+ inline void advance(double vx, double vy, double vz) {
+ mPos[0] += vx; mPos[1] += vy; mPos[2] += vz; }
+
+ //! add vector to position
+ inline ntlVec3Gfx getPos() { return mPos; }
+
+ //! get active flag
+ inline bool getActive() { return mActive; }
+ //! set active flag
+ inline void setActive(bool set) { mActive = set; }
+
+ protected:
+
+ /*! the particle position */
+ ntlVec3Gfx mPos;
+
+ /*! particle active? */
+ bool mActive;
+};
+
+
+//! A whole particle array
+class ParticleTracer :
+ public ntlGeometryObject
+{
+ public:
+ //! Standard constructor
+ ParticleTracer();
+ //! Destructor
+ ~ParticleTracer() { /* empty */ };
+
+ //! add a particle at this position
+ void addParticle(double x, double y, double z);
+
+ //! save particle positions before adding a new timestep
+ void savePreviousPositions();
+
+ //! draw the particle array
+ void draw();
+
+ //! parse settings from attributes (dont use own list!)
+ void parseAttrList( AttributeList *att );
+
+
+ // access funcs
+
+ //! set the number of timesteps to trace
+ void setTimesteps(int steps);
+
+ //! set the number of particles
+ inline void setNumParticles(int set) { mNumParticles = set; }
+ //! get the number of particles
+ inline int getNumParticles() { return mNumParticles; }
+
+ //! set the number of timesteps to trace
+ inline void setTrailLength(int set) { mTrailLength = set; mParts.resize(mTrailLength*mTrailInterval); }
+ //! get the number of timesteps to trace
+ inline int getTrailLength() { return mTrailLength; }
+ //! set the number of timesteps between each anim step saving
+ inline void setTrailInterval(int set) { mTrailInterval = set; mParts.resize(mTrailLength*mTrailInterval); }
+
+ //! get the no. of particles in the current array
+ inline int getPartArraySize() { return mParts[0].size(); }
+
+ //! iterate over all newest particles (for advancing positions)
+ inline vector<ParticleObject>::iterator getParticlesBegin() { return mParts[0].begin(); }
+ //! end iterator for newest particles
+ inline vector<ParticleObject>::iterator getParticlesEnd() { return mParts[0].end(); }
+
+ /*! set geometry start (for renderer) */
+ inline void setStart(ntlVec3Gfx set) { mStart = set; }
+ /*! set geometry end (for renderer) */
+ inline void setEnd(ntlVec3Gfx set) { mEnd = set; }
+
+ /*! set simulation domain start */
+ inline void setSimStart(ntlVec3Gfx set) { mSimStart = set; }
+ /*! set simulation domain end */
+ inline void setSimEnd(ntlVec3Gfx set) { mSimEnd = set; }
+
+ //! set the particle scaling factor
+ inline void setPartScale(double set) { mPartScale = set; }
+ //! set the trail scaling factor
+ inline void setTrailScale(double set) { mTrailScale = set; }
+
+
+ // NTL geometry implementation
+
+ /*! Get the triangles from this object */
+ virtual void getTriangles( vector<ntlTriangle> *triangles,
+ vector<ntlVec3Gfx> *vertices,
+ vector<ntlVec3Gfx> *normals, int objectId );
+
+
+ protected:
+
+ /*! the particle array (for multiple timesteps) */
+ vector< vector<ParticleObject> > mParts;
+
+ /*! desired number of particles */
+ int mNumParticles;
+
+ /*! number of particle positions to trace */
+ int mTrailLength;
+
+ /*! number of timesteps to between saving particle positions */
+ int mTrailInterval;
+ int mTrailIntervalCounter;
+
+ /*! size of the particles to display */
+ double mPartSize;
+
+ /*! size of the particle trail */
+ double mTrailScale;
+
+ /*! start and end vectors for the triangulation region to create particles in */
+ ntlVec3Gfx mStart, mEnd;
+
+ /*! start and end vectors of the simulation domain */
+ ntlVec3Gfx mSimStart, mSimEnd;
+
+ /*! scaling param for particles */
+ double mPartScale;
+ /*! head and tail distance for particle shapes */
+ double mPartHeadDist, mPartTailDist;
+ /*! no of segments for particle cone */
+ int mPartSegments;
+ /*! use length/absval of values to scale particles? */
+ int mValueScale;
+ /*! value length maximal cutoff value, for mValueScale==2 */
+ double mValueCutoffTop;
+ /*! value length minimal cutoff value, for mValueScale==2 */
+ double mValueCutoffBottom;
+
+};
+
+#define NTL_PARTICLETRACER_H
+#endif
+
diff --git a/intern/elbeem/intern/simulation_object.cpp b/intern/elbeem/intern/simulation_object.cpp
new file mode 100644
index 00000000000..eabbeac5662
--- /dev/null
+++ b/intern/elbeem/intern/simulation_object.cpp
@@ -0,0 +1,355 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Basic interface for all simulation modules
+ *
+ *****************************************************************************/
+
+#include "simulation_object.h"
+#include "ntl_bsptree.h"
+#include "ntl_scene.h"
+#include "factory_lbm.h"
+#include "lbmfunctions.h"
+
+#ifdef _WIN32
+#else
+#include <sys/time.h>
+#endif
+
+
+
+
+/******************************************************************************
+ * Constructor
+ *****************************************************************************/
+SimulationObject::SimulationObject() :
+ ntlGeometryShader(),
+ mGeoStart(-100.0), mGeoEnd(100.0),
+ mGeoInitId(-1), mpGiTree(NULL), mpGiObjects(NULL),
+ mpGlob(NULL),
+ mPanic( false ),
+ mDebugType( 1 /* =FLUIDDISPNothing*/ ),
+ mSolverType("-"), mStepsPerFrame( 10 ),
+ mpLbm(NULL),
+ mpParam( NULL ),
+ mShowSurface(true), mShowParticles(false),
+ mSelectedCid( NULL ),
+
+ stnOld("opt"),
+ stnFsgr("fsgr")
+{
+ mpParam = new Parametrizer();
+
+ for(int i=0; i<MAX_DEBDISPSET; i++) {
+ mDebDispSet[i].type = (i);
+ mDebDispSet[i].on = false;
+ mDebDispSet[i].scale = 1.0;
+ }
+
+ // reset time
+ mTime = 0.0;
+ mDisplayTime = 0.0;
+}
+
+
+/******************************************************************************
+ * Destructor
+ *****************************************************************************/
+SimulationObject::~SimulationObject()
+{
+ if(mpGiTree != NULL) delete mpGiTree;
+ delete mpLbm;
+ delete mpParam;
+ debMsgStd("SimulationObject",DM_MSG,"El'Beem Done!\n",10);
+}
+
+
+
+/*****************************************************************************/
+/*! init tree for certain geometry init */
+/*****************************************************************************/
+void SimulationObject::initGeoTree(int id) {
+ if(mpGlob == NULL) { errorOut("SimulationObject::initGeoTree error: Requires globals!"); exit(1); }
+ mGeoInitId = id;
+ ntlScene *scene = mpGlob->getScene();
+ mpGiObjects = scene->getObjects();
+
+ if(mpGiTree != NULL) delete mpGiTree;
+ char treeFlag = (1<<(mGeoInitId+4));
+ mpGiTree = new ntlTree( 20, 4, // warning - fixed values for depth & maxtriangles here...
+ scene, treeFlag );
+}
+
+/*****************************************************************************/
+/*! destroy tree etc. when geometry init done */
+/*****************************************************************************/
+void SimulationObject::freeGeoTree() {
+ if(mpGiTree != NULL) delete mpGiTree;
+}
+
+
+
+
+/******************************************************************************
+ * simluation interface: initialize simulation using the given configuration file
+ *****************************************************************************/
+int SimulationObject::initializeLbmSimulation(ntlRenderGlobals *glob)
+{
+ mpGlob = glob;
+ if(!getVisible()) {
+ mpAttrs->setAllUsed();
+ return 0;
+ }
+
+ //mDimension is deprecated
+ mSolverType = mpAttrs->readString("solver", mSolverType, "SimulationObject","mSolverType", false );
+ if(mSolverType == stnFsgr) {
+ mpLbm = createSolverLbmFsgr();
+ } else if(mSolverType == stnOld) {
+#ifdef LBM_INCLUDE_TESTSOLVERS
+ // old solver for gfx demo
+ mpLbm = createSolverOld();
+#endif // LBM_TESTSOLVER
+ } else {
+ errorOut("SimulationObject::initializeLbmSimulation : Invalid solver type - note that mDimension is deprecated, use the 'solver' keyword instead");
+ exit(1);
+ }
+
+
+ /* check lbm pointer */
+ if(mpLbm == NULL) {
+ errorOut("SimulationObject::initializeLbmSimulation : Unable to init dim"<<mSolverType<<" LBM solver! ");
+ exit(1);
+ }
+ debugOut("SimulationObject::initialized "<< mpLbm->getIdString() <<" LBM solver! ", 2);
+
+ // for non-param simulations
+ mpLbm->setParametrizer( mpParam );
+ mpParam->setAttrList( getAttributeList() );
+ mpParam->setSize( mpLbm->getSizeX(), mpLbm->getSizeY(), mpLbm->getSizeZ() );
+ mpParam->parseAttrList();
+
+ mpLbm->setAttrList( getAttributeList() );
+ mpLbm->parseAttrList();
+ mParts.parseAttrList( getAttributeList() );
+ mParts.setName( getName() + "_part" );
+ mParts.initialize( glob );
+
+ // init material settings
+ string matMc("default");
+ matMc = mpAttrs->readString("material_surf", matMc, "SimulationObject","matMc", false );
+ mShowSurface = mpAttrs->readInt("showsurface", mShowSurface, "SimulationObject","mShowSurface", false );
+ mShowParticles = mpAttrs->readInt("showparticles", mShowParticles, "SimulationObject","mShowParticles", false );
+
+ checkBoundingBox( mGeoStart, mGeoEnd, "SimulationObject::initializeSimulation" );
+ mpLbm->setGeoStart( mGeoStart );
+ mpLbm->setGeoEnd( mGeoEnd );
+ mpLbm->setRenderGlobals( mpGlob );
+ mpLbm->setName( getName() + "_lbm" );
+ mpLbm->initialize( NULL, mpGlob->getScene()->getObjects() );
+
+ // print cell type stats
+ const int jmax = sizeof(CellFlagType)*8;
+ int totalCells = 0;
+ int flagCount[jmax];
+ for(int j=0; j<jmax ; j++) flagCount[j] = 0;
+ int diffInits = 0;
+ LbmSolverInterface::CellIdentifier cid = mpLbm->getFirstCell();
+ for(; mpLbm->noEndCell( cid );
+ mpLbm->advanceCell( cid ) ) {
+ int flag = mpLbm->getCellFlag(cid,0);
+ int flag2 = mpLbm->getCellFlag(cid,1);
+ if(flag != flag2) {
+ diffInits++;
+ }
+ for(int j=0; j<jmax ; j++) {
+ if( flag&(1<<j) ) flagCount[j]++;
+ }
+ totalCells++;
+ }
+ mpLbm->deleteCellIterator( &cid );
+
+#if ELBEEM_BLENDER!=1
+ char charNl = '\n';
+ debugOutNnl("SimulationObject::initializeLbmSimulation celltype stats: " <<charNl, 5);
+ debugOutNnl("no. of cells = "<<totalCells<<", "<<charNl ,5);
+ for(int j=0; j<jmax ; j++) {
+ std::ostringstream out;
+ if(flagCount[j]>0) {
+ out<<"\t" << flagCount[j] <<" x "<< convertCellFlagType2String( (CellFlagType)(1<<j) ) <<", " << charNl;
+ debugOutNnl(out.str(), 5);
+ }
+ }
+ // compute dist. of empty/bnd - fluid - if
+ // cfEmpty = (1<<0), cfBnd = (1<< 2), cfFluid = (1<<10), cfInter = (1<<11),
+ {
+ std::ostringstream out;
+ out.precision(2); out.width(4);
+ int totNum = flagCount[0]+flagCount[2]+flagCount[10]+flagCount[11];
+ double ebFrac = (double)(flagCount[0]+flagCount[2]) / totNum;
+ double flFrac = (double)(flagCount[10]) / totNum;
+ double ifFrac = (double)(flagCount[11]) / totNum;
+ double eifFrac = (double)(flagCount[11]+flagCount[26]+flagCount[27]) / totNum;
+ //???
+ out<<"\tFractions: [empty/bnd - fluid - interface - ext. if] = [" << ebFrac<<" - " << flFrac<<" - " << ifFrac<<" - " << eifFrac <<"] "<< charNl;
+
+ if(diffInits > 0) {
+ debugOut("SimulationObject::initializeLbmSimulation celltype Warning: Diffinits="<<diffInits<<" !!!!!!!!!" , 5);
+ }
+ debugOutNnl(out.str(), 5);
+ }
+#endif // ELBEEM_BLENDER==1
+
+ mpLbm->initParticles( &mParts );
+
+ // this has to be inited here - before, the values might be unknown
+ ntlGeometryObject *surf = mpLbm->getSurfaceGeoObj();
+ if(surf) {
+ surf->setName( "final" ); // final surface mesh
+ // warning - this might cause overwriting effects for multiple sims and geom dump...
+ surf->setCastShadows( true );
+ surf->setReceiveShadows( false );
+ surf->searchMaterial( glob->getMaterials() );
+ if(mShowSurface) mObjects.push_back( surf );
+ }
+
+ mParts.setStart( mGeoStart );
+ mParts.setEnd( mGeoEnd );
+ mParts.setCastShadows( false );
+ mParts.setReceiveShadows( false );
+ mParts.searchMaterial( glob->getMaterials() );
+ if(mShowParticles) mObjects.push_back( &mParts );
+
+ // add objects to display for debugging (e.g. levelset particles)
+ vector<ntlGeometryObject *> debugObjs = mpLbm->getDebugObjects();
+ for(size_t i=0;i<debugObjs.size(); i++) {
+ debugObjs[i]->setCastShadows( false );
+ debugObjs[i]->setReceiveShadows( false );
+ debugObjs[i]->searchMaterial( glob->getMaterials() );
+ mObjects.push_back( debugObjs[i] );
+ }
+ return 0;
+}
+
+
+/******************************************************************************
+ * simluation interface: advance simulation another step (whatever delta time that might be)
+ *****************************************************************************/
+void SimulationObject::step( void )
+{
+ mpLbm->step();
+
+ mParts.savePreviousPositions();
+ mpLbm->advanceParticles( &mParts );
+ mTime += mpParam->getStepTime();
+ if(mpLbm->getPanic()) mPanic = true;
+
+ //debMsgStd("SimulationObject::step",DM_MSG," Sim '"<<mName<<"' stepped to "<<mTime<<" (stept="<<(mpParam->getStepTime())<<", framet="<<getFrameTime()<<") ", 10);
+}
+/*! prepare visualization of simulation for e.g. raytracing */
+void SimulationObject::prepareVisualization( void ) {
+ if(mPanic) return;
+ mpLbm->prepareVisualization();
+}
+
+
+/******************************************************************************/
+/* get current start simulation time */
+double SimulationObject::getStartTime( void ) {
+ //return mpParam->calculateAniStart();
+ return mpParam->getAniStart();
+}
+/* get time for a single animation frame */
+double SimulationObject::getFrameTime( void ) {
+ return mpParam->getAniFrameTime();
+}
+/* get time for a single time step */
+double SimulationObject::getStepTime( void ) {
+ return mpParam->getStepTime();
+}
+
+
+/******************************************************************************
+ * return a pointer to the geometry object of this simulation
+ *****************************************************************************/
+//ntlGeometryObject *SimulationObject::getGeometry() { return mpMC; }
+vector<ntlGeometryObject *>::iterator
+SimulationObject::getObjectsBegin()
+{
+ return mObjects.begin();
+}
+vector<ntlGeometryObject *>::iterator
+SimulationObject::getObjectsEnd()
+{
+ return mObjects.end();
+}
+
+
+
+
+
+/******************************************************************************
+ * GUI - display debug info
+ *****************************************************************************/
+
+void SimulationObject::drawDebugDisplay() {
+#ifndef NOGUI
+ //debugOut(" SD: "<<mDebugType<<" v"<<getVisible()<<" don"<< (mDebDispSet[mDebugType].on) , 10);
+ if(!getVisible()) return;
+
+ if( mDebugType > (MAX_DEBDISPSET-1) ){
+ errorOut("SimulationObject::drawDebugDisplay : Invalid debug type!");
+ exit(1);
+ }
+
+ mDebDispSet[ mDebugType ].on = true;
+ //errorOut( mDebugType <<"//"<< mDebDispSet[mDebugType].type );
+ mpLbm->debugDisplay( &mDebDispSet[ mDebugType ] );
+
+ ::lbmMarkedCellDisplay<>( mpLbm );
+#endif
+}
+
+/* GUI - display interactive info */
+void SimulationObject::drawInteractiveDisplay()
+{
+#ifndef NOGUI
+ if(!getVisible()) return;
+ if(mSelectedCid) {
+ // in debugDisplayNode if dispset is on is ignored...
+ ::debugDisplayNode<>( &mDebDispSet[ FLUIDDISPGrid ], mpLbm, mSelectedCid );
+ }
+#endif
+}
+
+
+/*******************************************************************************/
+// GUI - handle mouse movement for selection
+/*******************************************************************************/
+void SimulationObject::setMousePos(int x,int y, ntlVec3Gfx org, ntlVec3Gfx dir)
+{
+ normalize( dir );
+ // assume 2D sim is in XY plane...
+
+ double zplane = (mGeoEnd[2]-mGeoStart[2])*0.5;
+ double zt = (zplane-org[2]) / dir[2];
+ ntlVec3Gfx pos(
+ org[0]+ dir[0] * zt,
+ org[1]+ dir[1] * zt, 0.0);
+
+ mSelectedCid = mpLbm->getCellAt( pos );
+ //errMsg("SMP ", mName<< x<<" "<<y<<" - "<<dir );
+ x = y = 0; // remove warning
+}
+
+
+void SimulationObject::setMouseClick()
+{
+ if(mSelectedCid) {
+ ::debugPrintNodeInfo<>( mpLbm, mSelectedCid, mpLbm->getNodeInfoString() );
+ }
+}
+
+
diff --git a/intern/elbeem/intern/simulation_object.h b/intern/elbeem/intern/simulation_object.h
new file mode 100644
index 00000000000..ec84ab02bd3
--- /dev/null
+++ b/intern/elbeem/intern/simulation_object.h
@@ -0,0 +1,202 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Basic interface for all simulation modules
+ *
+ *****************************************************************************/
+
+#ifndef ELBEEM_SIMINTERFACE
+#define ELBEEM_SIMINTERFACE
+
+
+#define USE_GLUTILITIES
+#include "ntl_geometryshader.h"
+#include "lbmdimensions.h"
+#include "parametrizer.h"
+#include "particletracer.h"
+
+class ntlTree;
+class ntlRenderGlobals;
+class ntlRenderGlobals;
+
+
+//! type fluid geometry init
+// warning : should match typeslbm.h values!
+const int cFgiFlagstart = 16;
+typedef enum {
+ fgiFluid = (1<<(cFgiFlagstart+0)),
+ fgiNoFluid = (1<<(cFgiFlagstart+1)),
+ fgiSlipNo = (1<<(cFgiFlagstart+2)),
+ fgiSlipFree = (1<<(cFgiFlagstart+3)),
+ fgiNoBnd = (1<<(cFgiFlagstart+4)),
+ fgiAcc = (1<<(cFgiFlagstart+5)),
+ fgiNoAcc = (1<<(cFgiFlagstart+6)),
+
+ fgiBndAll = (fgiSlipNo | fgiSlipFree)
+} FgiFlagType;
+
+
+/*! interface for different simluation models to visualize */
+class SimulationObject :
+ public ntlGeometryShader {
+
+ public:
+
+ /*! Constructor */
+ SimulationObject();
+ /*! Destructor */
+ virtual ~SimulationObject();
+
+
+ /*! init tree for certain geometry init */
+ void initGeoTree(int id);
+ /*! destroy tree etc. when geometry init done */
+ void freeGeoTree();
+ /*! get fluid init type at certain position */
+ int geoInitGetPointType(ntlVec3Gfx org, int &OId);
+ /*! check for a certain flag type at position org */
+ bool geoInitCheckPointInside(ntlVec3Gfx org, int flags, int &OId);
+
+ // access functions
+
+ /*! get current (max) simulation time */
+ double getCurrentTime( void ) { return mTime; }
+
+ /*! set time to display */
+ void setDisplayTime(double set) { mDisplayTime = set; }
+
+ /*! set geometry generation start point */
+ virtual void setGeoStart(ntlVec3Gfx set) { mGeoStart = set; }
+ /*! set geometry generation end point */
+ virtual void setGeoEnd(ntlVec3Gfx set) { mGeoEnd = set; }
+
+ /*! set sim panic flag */
+ void setPanic(bool set) { mPanic = set; }
+ /*! get sim panic flag */
+ bool getPanic( void ) { return mPanic; }
+
+ /*! simluation interface: initialize simulation */
+ int initializeLbmSimulation(ntlRenderGlobals *glob);
+
+ /*! Do geo etc. init */
+ virtual int postGeoConstrInit(ntlRenderGlobals *glob) { return initializeLbmSimulation(glob); };
+ virtual int initializeShader() { /* ... */ return true; };
+ /*! simluation interface: draw the simulation with OpenGL */
+ virtual void draw( void ) {};
+ virtual vector<ntlGeometryObject *>::iterator getObjectsBegin();
+ virtual vector<ntlGeometryObject *>::iterator getObjectsEnd();
+
+
+ /*! simluation interface: advance simulation another step (whatever delta time that might be) */
+ virtual void step( void );
+ /*! prepare visualization of simulation for e.g. raytracing */
+ virtual void prepareVisualization( void );
+
+ /*! get current start simulation time */
+ virtual double getStartTime( void );
+ /*! get time for a single animation frame */
+ virtual double getFrameTime( void );
+ /*! get time for a single time step in the simulation */
+ virtual double getStepTime( void );
+
+ /*! GUI - display debug info */
+ virtual void drawDebugDisplay();
+ /*! GUI - display interactive info */
+ virtual void drawInteractiveDisplay();
+ /*! GUI - handle mouse movement for selection */
+ virtual void setMousePos(int x,int y, ntlVec3Gfx org, ntlVec3Gfx dir);
+ virtual void setMouseClick();
+
+ //! access solver
+ LbmSolverInterface *getSolver(){ return mpLbm; }
+
+ protected:
+
+ /*! current time in the simulation */
+ double mTime;
+
+ /*! time to display in the visualizer */
+ double mDisplayTime;
+
+ /*! for display - start and end vectors for geometry */
+ ntlVec3Gfx mGeoStart, mGeoEnd;
+
+ /*! geometry init id */
+ int mGeoInitId;
+ /*! tree object for geomerty initialization */
+ ntlTree *mpGiTree;
+ /*! object vector for geo init */
+ vector<ntlGeometryObject*> *mpGiObjects;
+ /*! remember globals */
+ ntlRenderGlobals *mpGlob;
+
+ /*! simulation panic on/off */
+ bool mPanic;
+
+ /*! debug info to display */
+ int mDebugType;
+
+ //! dimension of the simulation - now given by LBMDIM define globally
+ //! solver type
+ string mSolverType;
+
+ /*! when no parametrizer, use this as no. of steps per frame */
+ int mStepsPerFrame;
+
+ /*! pointer to the lbm solver */
+ LbmSolverInterface *mpLbm;
+
+ /*! marching cubes object */
+ //mCubes *mpMC;
+
+ /*! parametrizer for lbm solver */
+ Parametrizer *mpParam;
+
+ /*! particle tracing object */
+ ParticleTracer mParts;
+
+ /*! show parts of the simulation toggles */
+ bool mShowSurface;
+ bool mShowParticles;
+
+ /*! debug display settings */
+ static const int MAX_DEBDISPSET = 10;
+ fluidDispSettings mDebDispSet[ MAX_DEBDISPSET ];
+
+ /*! pointer to identifier of selected node */
+ CellIdentifierInterface *mSelectedCid;
+
+ public:
+
+ // debug display setting funtions
+
+ /*! set type of info to display */
+ inline void setDebugDisplay(int disp) { mDebugType = disp; }
+
+ /* miscelleanous access functions */
+
+ /*! init parametrizer for anim step length */
+ void initParametrizer(Parametrizer *set) { mpParam = set; }
+ /*! init parametrizer for anim step length */
+ Parametrizer *getParametrizer() { return mpParam; }
+
+ /*! Access marching cubes object */
+ //mCubes *getMCubes( void ) { return mpMC; }
+
+ /*! get bounding box of fluid for GUI */
+ virtual inline ntlVec3Gfx *getBBStart() { return &mGeoStart; }
+ virtual inline ntlVec3Gfx *getBBEnd() { return &mGeoEnd; }
+
+ /*! solver dimension constants */
+ const string stnOld;
+ const string stnFsgr;
+
+};
+
+
+#endif
+
+
+
diff --git a/intern/elbeem/intern/typeslbm.h b/intern/elbeem/intern/typeslbm.h
new file mode 100644
index 00000000000..3a00ffd7251
--- /dev/null
+++ b/intern/elbeem/intern/typeslbm.h
@@ -0,0 +1,260 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Lattice-Boltzmann defines...
+ *
+ *****************************************************************************/
+#ifndef TYPES_LBM_H
+
+/* standard precision for LBM solver */
+typedef double LBM_Float;
+//typedef float LBM_Float;
+
+typedef double LBM2D_Float;
+//typedef float LBM2D_Float; // FLAGS might not work!!!!
+
+
+/******************************************************************************
+ * 2D
+ *****************************************************************************/
+
+
+//! use incompressible LGBK model?
+#define LBM2D_INCOMPBGK 1
+
+
+/*! size of a single set of distribution functions */
+#define LBM2D_DISTFUNCSIZE 9
+/*! size of a single set for a cell (+cell flags, mass, bubble id) */
+#define LBM2D_SETSIZE 12
+/*! floats per LBM cell */
+#define LBM2D_FLOATSPERCELL (LBM2D_SETSIZE +LBM2D_SETSIZE )
+
+
+/*! sphere init full or empty */
+#define LBM2D_FILLED true
+#define LBM2D_EMPTY false
+
+/*! distribution functions directions */
+#define WC 0
+#define WN 1
+#define WS 2
+#define WE 3
+#define WW 4
+#define WNE 5
+#define WNW 6
+#define WSE 7
+#define WSW 8
+#define FLAG2D_BND (9)
+#define FLAG2D_MASS (10)
+#define FLAG2D_BUBBLE (11)
+
+/* Wi factors for collide step */
+#define LBM2D_COLLEN_ZERO (4.0/9.0)
+#define LBM2D_COLLEN_ONE (1.0/9.0)
+#define LBM2D_COLLEN_SQRTWO (1.0/36.0)
+
+
+/* calculate equlibrium function for a single direction at cell i,j
+ * pass 0 for the u_ terms that are not needed
+ */
+#define LBM2D_VELVEC(l, ux,uy) ((ux)*DF2DdvecX[l]+(uy)*DF2DdvecY[l])
+#if LBM2D_INCOMPBGK!=1
+#define LBM2D_COLLIDE_EQ(target, l,Rho, ux,uy) \
+ {\
+ LBM2D_Float tmp = LBM2D_VELVEC(l,ux,uy); \
+ target = ( (DF2Dlength[l]*Rho) *( \
+ + 1.0 - (3.0/2.0*(ux*ux + uy*uy)) \
+ + 3.0 *tmp \
+ + 9.0/2.0 *(tmp*tmp) ) \
+ );\
+ }
+#endif
+
+/* incompressible LBGK model?? */
+#if LBM2D_INCOMPBGK==1
+#define LBM2D_COLLIDE_EQ(target, l,Rho, ux,uy) \
+ {\
+ LBM2D_Float tmp = LBM2D_VELVEC(l,ux,uy); \
+ target = ( (DF2Dlength[l]) *( \
+ + Rho - (3.0/2.0*(ux*ux + uy*uy )) \
+ + 3.0 *tmp \
+ + 9.0/2.0 *(tmp*tmp) ) \
+ );\
+ }
+#endif
+
+/* calculate new distribution function for cell i,j
+ * Now also includes gravity
+ */
+#define LBM2D_COLLIDE(l,omega, Rho, ux,uy ) \
+ {\
+ LBM2D_Float collideTempVar; \
+ LBM2D_COLLIDE_EQ(collideTempVar, l,Rho, (ux), (uy) ); \
+ m[l] = (1.0-omega) * m[l] + \
+ omega* collideTempVar \
+ ; \
+ }\
+
+
+#ifdef LBM2D_IMPORT
+extern char *DF2Dstring[LBM2D_DISTFUNCSIZE];
+extern int DF2Dnorm[LBM2D_DISTFUNCSIZE];
+extern int DF2Dinv[LBM2D_DISTFUNCSIZE];
+extern int DF2DrefX[LBM2D_DISTFUNCSIZE];
+extern int DF2DrefY[LBM2D_DISTFUNCSIZE];
+extern LBM2D_Float DF2Dequil[ LBM2D_DISTFUNCSIZE ];
+extern int DF2DvecX[LBM2D_DISTFUNCSIZE];
+extern int DF2DvecY[LBM2D_DISTFUNCSIZE];
+extern LBM2D_Float DF2DdvecX[LBM2D_DISTFUNCSIZE];
+extern LBM2D_Float DF2DdvecY[LBM2D_DISTFUNCSIZE];
+extern LBM2D_Float DF2Dlength[LBM2D_DISTFUNCSIZE];
+#endif
+
+
+
+/******************************************************************************
+ * 3D
+ *****************************************************************************/
+
+// use incompressible LGBK model?
+#define LBM_INCOMPBGK 1
+
+
+
+/*! size of a single set of distribution functions */
+#define LBM_DISTFUNCSIZE 19
+/*! size of a single set for a cell (+cell flags, mass, bubble id) */
+#define LBM_SETSIZE 22
+/*! floats per LBM cell */
+#define LBM_FLOATSPERCELL (LBM_SETSIZE +LBM_SETSIZE )
+
+
+/*! distribution functions directions */
+#define MC 0
+#define MN 1
+#define MS 2
+#define ME 3
+#define MW 4
+#define MT 5
+#define MB 6
+#define MNE 7
+#define MNW 8
+#define MSE 9
+#define MSW 10
+#define MNT 11
+#define MNB 12
+#define MST 13
+#define MSB 14
+#define MET 15
+#define MEB 16
+#define MWT 17
+#define MWB 18
+#define FLAG_BND (19)
+#define FLAG_MASS (20)
+#define FLAG_BUBBLE (21)
+
+/* Wi factors for collide step */
+#define LBM_COLLEN_ZERO (1.0/3.0)
+#define LBM_COLLEN_ONE (1.0/18.0)
+#define LBM_COLLEN_SQRTWO (1.0/36.0)
+
+
+/* calculate equlibrium function for a single direction at cell i,j,k
+ * pass 0 for the u_ terms that are not needed
+ */
+#define LBM_VELVEC(l, ux,uy,uz) ((ux)*DFdvecX[l]+(uy)*DFdvecY[l]+(uz)*DFdvecZ[l])
+#ifndef LBM_INCOMPBGK
+#define LBM_COLLIDE_EQ(target, l,Rho, ux,uy,uz) \
+ {\
+ LBM_Float tmp = LBM_VELVEC(l,ux,uy,uz); \
+ target = ( (DFlength[l]*Rho) *( \
+ + 1.0 - (3.0/2.0*(ux*ux + uy*uy + uz*uz)) \
+ + 3.0 *tmp \
+ + 9.0/2.0 *(tmp*tmp) ) \
+ );\
+ }
+#endif
+
+/* incompressible LBGK model?? */
+#ifdef LBM_INCOMPBGK
+#define LBM_COLLIDE_EQ(target, l,Rho, ux,uy,uz) \
+ {\
+ LBM_Float tmp = LBM_VELVEC(l,ux,uy,uz); \
+ target = ( (DFlength[l]) *( \
+ + Rho - (3.0/2.0*(ux*ux + uy*uy + uz*uz)) \
+ + 3.0 *tmp \
+ + 9.0/2.0 *(tmp*tmp) ) \
+ );\
+ }
+#endif
+
+/* calculate new distribution function for cell i,j,k
+ * Now also includes gravity
+ */
+#define LBM_COLLIDE(l,omega,Rho, ux,uy,uz ) \
+ {\
+ LBM_Float collideTempVar; \
+ LBM_COLLIDE_EQ(collideTempVar, l,Rho, (ux), (uy), (uz) ); \
+ m[l] = (1.0-omega) * m[l] + \
+ omega* collideTempVar \
+ ; \
+ }\
+
+
+#ifdef LBM3D_IMPORT
+char *DFstring[LBM_DISTFUNCSIZE];
+int DFnorm[LBM_DISTFUNCSIZE];
+int DFinv[LBM_DISTFUNCSIZE];
+int DFrefX[LBM_DISTFUNCSIZE];
+int DFrefY[LBM_DISTFUNCSIZE];
+int DFrefZ[LBM_DISTFUNCSIZE];
+LBM_Float DFequil[ LBM_DISTFUNCSIZE ];
+int DFvecX[LBM_DISTFUNCSIZE];
+int DFvecY[LBM_DISTFUNCSIZE];
+int DFvecZ[LBM_DISTFUNCSIZE];
+LBM_Float DFdvecX[LBM_DISTFUNCSIZE];
+LBM_Float DFdvecY[LBM_DISTFUNCSIZE];
+LBM_Float DFdvecZ[LBM_DISTFUNCSIZE];
+LBM_Float DFlength[LBM_DISTFUNCSIZE];
+#endif
+
+
+/******************************************************************************
+ * BOTH
+ *****************************************************************************/
+
+/*! boundary flags
+ * only 1 should be active for a cell */
+#define BND (1<< 0)
+#define ACCX (1<< 1)
+#define ACCY (1<< 2)
+#define ACCZ (1<< 3)
+#define FREESLIP (1<< 4)
+#define NOSLIP (1<< 5)
+#define PERIODIC (1<< 6)
+#define PARTSLIP (1<< 7)
+/*! surface type, also only 1 should be active (2. flag byte) */
+#define EMPTY (0)
+#define FLUID (1<< 8)
+#define INTER (1<< 9)
+/*! neighbor flags (3. flag byte) */
+#define I_NONBFLUID (1<<16)
+#define I_NONBINTER (1<<17)
+#define I_NONBEMPTY (1<<18)
+#define I_NODELETE (1<<19)
+#define I_NEWCELL (1<<20)
+#define I_NEWINTERFACE (1<<21)
+/*! marker only for debugging, this bit is reset each step */
+#define I_CELLMARKER ((int) (1<<30) )
+#define I_NOTCELLMARKER ((int) (~(1<<30)) )
+
+
+
+
+
+#define TYPES_LBM_H
+#endif
+
diff --git a/intern/elbeem/intern/utilities.cpp b/intern/elbeem/intern/utilities.cpp
new file mode 100644
index 00000000000..c647281fe68
--- /dev/null
+++ b/intern/elbeem/intern/utilities.cpp
@@ -0,0 +1,292 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Global C style utility funcions
+ *
+ *****************************************************************************/
+
+
+#include <iostream>
+#include <sstream>
+#ifdef WIN32
+// for timing
+#include <windows.h>
+#else
+#include <time.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#endif
+
+#include "utilities.h"
+
+#ifndef NOPNG
+#ifdef WIN32
+#include "png.h"
+#else
+#include <png.h>
+#endif
+#endif // NOPNG
+
+//! for interval debugging output
+myTime_t globalIntervalTime = 0;
+//! color output setting for messages (0==off, else on)
+#ifdef WIN32
+int globalColorSetting = 0;
+#else // WIN32
+int globalColorSetting = 1;
+#endif // WIN32
+
+
+//-----------------------------------------------------------------------------
+// helper function that converts a string to integer,
+// and returns an alternative value if the conversion fails
+int convertString2Int(const char *str, int alt)
+{
+ int val;
+ char *endptr;
+ bool success=true;
+
+ val = strtol(str, &endptr, 10);
+ if( (str==endptr) ||
+ ((str!=endptr) && (*endptr != '\0')) ) success = false;
+
+ if(!success) {
+ return alt;
+ }
+ return val;
+}
+
+//-----------------------------------------------------------------------------
+//! helper function that converts a flag field to a readable integer
+std::string convertFlags2String(int flags) {
+ std::ostringstream ret;
+ ret <<"(";
+ int max = sizeof(int)*8;
+ for(int i=0; i<max; i++) {
+ if(flags & (1<<31)) ret <<"1";
+ else ret<<"0";
+ if(i<max-1) {
+ //ret << ",";
+ if((i%8)==7) ret << " ";
+ }
+ flags = flags << 1;
+ }
+ ret <<")";
+ return ret.str();
+}
+
+#ifndef NOPNG
+//-----------------------------------------------------------------------------
+//! write png image
+int writePng(const char *fileName, unsigned char **rowsp, int w, int h)
+{
+ // defaults for elbeem
+ const int colortype = PNG_COLOR_TYPE_RGBA;
+ const int bitdepth = 8;
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ png_bytep *rows = rowsp;
+
+ //FILE *fp = fopen(fileName, "wb");
+ FILE *fp = NULL;
+ char *doing = "open for writing";
+ if (!(fp = fopen(fileName, "wb"))) goto fail;
+
+ if(!png_ptr) {
+ doing = "create png write struct";
+ if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) goto fail;
+ }
+ if(!info_ptr) {
+ doing = "create png info struct";
+ if (!(info_ptr = png_create_info_struct(png_ptr))) goto fail;
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr))) goto fail;
+ doing = "init IO";
+ png_init_io(png_ptr, fp);
+ doing = "write header";
+ png_set_IHDR(png_ptr, info_ptr, w, h, bitdepth, colortype, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+ doing = "write info";
+ png_write_info(png_ptr, info_ptr);
+ doing = "write image";
+ png_write_image(png_ptr, rows);
+ doing = "write end";
+ png_write_end(png_ptr, NULL);
+ doing = "write destroy structs";
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+ fclose( fp );
+ return 0;
+
+fail:
+ errMsg("writePng","Write_png: could not "<<doing<<" !");
+ if(fp) fclose( fp );
+ if(png_ptr || info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr);
+ return -1;
+}
+#endif // NOPNG
+
+
+//-----------------------------------------------------------------------------
+// helper function to determine current time
+myTime_t getTime()
+{
+ myTime_t ret = 0;
+#ifdef WIN32
+ LARGE_INTEGER liTimerFrequency;
+ QueryPerformanceFrequency(&liTimerFrequency);
+ LARGE_INTEGER liLastTime;
+ QueryPerformanceCounter(&liLastTime);
+ ret = (INT)( ((double)liLastTime.QuadPart / liTimerFrequency.QuadPart)*1000 ); // - mFirstTime;
+#else
+ //fprintf(stderr, " Tp s%lu us%lu \n", tv.tv_sec, tv.tv_usec );
+ //clock_t ct = clock();
+ //ret = ct*1000/CLOCKS_PER_SEC;
+ //fprintf(stderr, " Tp s%lu cps%lu us%lu \n", ct,CLOCKS_PER_SEC, ret );
+
+ /*struct tms tt;
+ times(&tt);
+ //ret = tt.tms_utime/(CLOCKS_PER_SEC/1000);
+ ret = tt.tms_utime*10;
+ //fprintf(stderr, " Tp s%lu cps%lu us%lu %d %d \n", tt.tms_cutime,CLOCKS_PER_SEC, ret, sizeof(clock_t), tt.tms_cutime );
+ //fprintf(stderr, " Tp s%d cps%d us%d %d %d \n", tt.tms_utime,CLOCKS_PER_SEC, ret, sizeof(clock_t), clock() );
+ // */
+
+ struct timeval tv;
+ struct timezone tz;
+ tz.tz_minuteswest = 0;
+ tz.tz_dsttime = 0;
+ gettimeofday(&tv,&tz);
+ ret = (tv.tv_sec*1000)+(tv.tv_usec/1000); //-mFirstTime;
+ //fprintf(stderr, " Tp s%lu us%lu \n", tv.tv_sec, tv.tv_usec );
+#endif
+ //cout << " Tret " << ret <<endl;
+ return (myTime_t)ret;
+}
+//-----------------------------------------------------------------------------
+// convert time to readable string
+std::string getTimeString(myTime_t usecs) {
+ std::ostringstream ret;
+ //myTime_t us = usecs % 1000;
+ myTime_t ms = usecs / (60*1000);
+ myTime_t ss = (usecs / 1000) - (ms*60);
+
+ //ret.setf(ios::showpoint|ios::fixed);
+ //ret.precision(5); ret.width(7);
+
+ if(ms>0) {
+ ret << ms<<"m"<< ss<<"s" ;
+ } else {
+ ret << ss<<"s" ;
+ }
+ return ret.str();
+}
+
+//! helper to check if a bounding box was specified in the right way
+bool checkBoundingBox(ntlVec3Gfx s, ntlVec3Gfx e, std::string checker) {
+ if( (s[0]>e[0]) ||
+ (s[1]>e[1]) ||
+ (s[2]>e[2]) ) {
+ errMsg("checkBoundingBox","Check by '"<<checker<<"' for BB "<<s<<":"<<e<<" failed! Aborting...");
+ exit(1);
+ }
+ return 0;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// debug message output
+
+static std::string col_black ( "\033[0;30m");
+static std::string col_dark_gray ( "\033[1;30m");
+static std::string col_bright_gray ( "\033[0;37m");
+static std::string col_red ( "\033[0;31m");
+static std::string col_bright_red ( "\033[1;31m");
+static std::string col_green ( "\033[0;32m");
+static std::string col_bright_green ( "\033[1;32m");
+static std::string col_bright_yellow ( "\033[1;33m");
+static std::string col_yellow ( "\033[0;33m");
+static std::string col_cyan ( "\033[0;36m");
+static std::string col_bright_cyan ( "\033[1;36m");
+static std::string col_purple ( "\033[0;35m");
+static std::string col_bright_purple ( "\033[1;35m");
+static std::string col_neutral ( "\033[0m");
+static std::string col_std = col_bright_gray;
+void messageOutputFunc(std::string from, int id, std::string msg, myTime_t interval) {
+ if(interval>0) {
+ myTime_t currTime = getTime();
+ if((currTime - globalIntervalTime)>interval) {
+ globalIntervalTime = getTime();
+ } else {
+ return;
+ }
+ }
+
+ // colors off?
+ if(globalColorSetting==0) {
+ // only reset once
+ col_std = col_black = col_dark_gray = col_bright_gray =
+ col_red = col_bright_red = col_green =
+ col_bright_green = col_bright_yellow =
+ col_yellow = col_cyan = col_bright_cyan =
+ col_purple = col_bright_purple = col_neutral = "";
+ globalColorSetting=1;
+ }
+
+ std::ostringstream sout;
+ if(id==DM_DIRECT) {
+ sout << msg;
+ } else {
+ sout << col_cyan<< from;
+ switch(id) {
+ case DM_MSG:
+ sout << col_std << " message:";
+ break;
+ case DM_NOTIFY:
+ sout << col_bright_cyan << " note:" << col_std;
+ break;
+ case DM_IMPORTANT:
+ sout << col_yellow << " important:" << col_std;
+ break;
+ case DM_WARNING:
+ sout << col_bright_red << " warning:" << col_std;
+ break;
+ case DM_ERROR:
+ sout << col_red << " error:" << col_red;
+ break;
+ default:
+ // this shouldnt happen...
+ sout << col_red << " --- messageOutputFunc error: invalid id ("<<id<<") --- aborting... \n\n" << col_std;
+ exit(1);
+ break;
+ }
+ sout <<" "<< msg << col_std;
+ }
+#ifdef ELBEEM_BLENDER
+ fprintf(GEN_userstream, "%s",sout.str().c_str() );
+ if(id!=DM_DIRECT) fflush(GEN_userstream);
+#else
+ fprintf(stdout,"%s", sout.str().c_str());
+ if(id!=DM_DIRECT) fflush(stdout);
+#endif
+}
+
+#ifdef DEBUG
+bool debugOutInterTest(myTime_t interval) {
+ myTime_t currTime = getTime();
+ if((currTime - globalIntervalTime)>interval) {
+ globalIntervalTime = getTime();
+ return true;
+ }
+ return false;
+}
+
+#endif
+
+
+
+
diff --git a/intern/elbeem/intern/utilities.h b/intern/elbeem/intern/utilities.h
new file mode 100644
index 00000000000..fa74f3d091c
--- /dev/null
+++ b/intern/elbeem/intern/utilities.h
@@ -0,0 +1,170 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * Copyright 2003,2004 Nils Thuerey
+ *
+ * Global C style utility funcions
+ *
+ *****************************************************************************/
+#ifndef UTILITIES_H
+#include "ntl_vector3dim.h"
+
+typedef unsigned long myTime_t;
+
+//! helper function that converts a string to integer
+int convertString2Int(const char *string, int alt);
+
+//! helper function that converts a flag field to a readable integer
+std::string convertFlags2String(int flags);
+
+//! write png image
+#ifndef NOPNG
+//int writePng(const char *fileName, unsigned char **rows, int w, int h, int colortype, int bitdepth);
+int writePng(const char *fileName, unsigned char **rows, int w, int h);
+//! write opengl buffer to png
+void writeOpenglToPng(const char *fileName);
+#endif// NOPNG
+
+// output streams
+#ifdef ELBEEM_BLENDER
+extern "C" FILE* GEN_errorstream;
+extern "C" FILE* GEN_userstream;
+#endif // ELBEEM_BLENDER
+
+//! get the current system time
+myTime_t getTime();
+//! convert time to readable string
+std::string getTimeString(myTime_t usecs);
+
+//! helper to check if a bounding box was specified in the right way
+bool checkBoundingBox(ntlVec3Gfx s, ntlVec3Gfx e, std::string checker);
+
+// optionally include OpenGL utility functions
+#ifdef USE_GLUTILITIES
+
+void drawCubeWire(ntlVec3Gfx s, ntlVec3Gfx e);
+void drawCubeSolid(ntlVec3Gfx s, ntlVec3Gfx e);
+
+#endif // USE_GLUTILITIES
+
+
+/* debugging outputs */
+//#define DEBUG 10
+
+/* debug output function */
+#define DM_MSG 1
+#define DM_NOTIFY 2
+#define DM_IMPORTANT 3
+#define DM_WARNING 4
+#define DM_ERROR 5
+#define DM_DIRECT 6
+void messageOutputFunc(std::string from, int id, std::string msg, myTime_t interval);
+
+/* debugging messages defines */
+#if LBM_PRECISION==2
+#define MSGSTREAM std::ostringstream msg; msg.precision(15); msg.width(17);
+#else
+#define MSGSTREAM std::ostringstream msg; msg.precision(7); msg.width(9);
+#endif
+#ifdef DEBUG
+# define debMsgDirect(mStr) { std::ostringstream msg; msg << mStr; messageOutputFunc(string(""), DM_DIRECT, msg.str(), 0); }
+# define debMsgStd(from,id,mStr,level) if(DEBUG>=level){ MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, id, msg.str(), 0); }
+# define debMsgNnl(from,id,mStr,level) if(DEBUG>=level){ MSGSTREAM; msg << mStr ; messageOutputFunc(from, id, msg.str(), 0); }
+# define debMsgInter(from,id,mStr,level, interval) if(DEBUG>=level){ MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, id, msg.str(), interval); }
+# define debugOut(mStr,level) if(DEBUG>=level){ debMsgStd("D",DM_MSG,mStr,level); }
+# define debugOutNnl(mStr,level) if(DEBUG>=level){ debMsgNnl("D",DM_MSG,mStr,level); }
+# define debugOutInter(mStr,level, interval) debMsgInter("D",DM_MSG,mStr,level, interval);
+
+#else
+
+# define debMsgDirect(mStr)
+# define debMsgStd(from,id,mStr,level)
+# define debMsgNnl(from,id,mStr,level)
+# define debMsgInter(from,id,mStr,level, interval)
+# define debugOut(mStr,level)
+# define debugOutNnl(mStr,level)
+# define debugOutInter(mStr,level, interval)
+#endif
+
+/* Error output function */
+#define errMsg(from,mStr) { MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, DM_ERROR, msg.str(), 0); }
+#define warnMsg(from,mStr){ MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, DM_WARNING, msg.str(), 0); }
+#define errorOut(mStr) { errMsg("D",mStr); }
+// old... #define ...(mStr) { std::cout << mStr << "\n"; fflush(stdout); }
+
+/*! print some vector from 3 values e.g. for ux,uy,uz */
+#define PRINT_VEC(x,y,z) " ["<<(x)<<","<<(y)<<","<<(z)<<"] "
+
+/*! print some vector from 3 values e.g. for ux,uy,uz */
+#define PRINT_VEC2D(x,y) " ["<<(x)<<","<<(y)<<"] "
+
+/*! print l'th neighbor of i,j,k as a vector, as we need ijk all the time */
+#define PRINT_IJK_NBL PRINT_VEC(i+D::dfVecX[l],j+D::dfVecY[l],k+D::dfVecZ[l])
+
+/*! print i,j,k as a vector, as we need ijk all the time */
+#define PRINT_IJK PRINT_VEC(i,j,k)
+
+/*! print i,j,k as a vector, as we need ijk all the time */
+#define PRINT_IJ PRINT_VEC2D(i,j)
+
+/*! print some vector from 3 values e.g. for ux,uy,uz */
+#define PRINT_NTLVEC(v) " ["<<(v)[0]<<","<<(v)[1]<<","<<(v)[2]<<"] "
+
+/*! print some vector from 3 values e.g. for ux,uy,uz */
+#define PRINT_NTLVEC2D(v) " ["<<(v)[0]<<","<<(v)[1]<<"] "
+
+/*! print a triangle */
+#define PRINT_TRIANGLE(t,mpV) " { "<<PRINT_VEC( (mpV[(t).getPoints()[0]][0]),(mpV[(t).getPoints()[0]][1]),(mpV[(t).getPoints()[0]][2]) )<<\
+ PRINT_VEC( (mpV[(t).getPoints()[1]][0]),(mpV[(t).getPoints()[1]][1]),(mpV[(t).getPoints()[1]][2]) )<<" | "<<\
+ PRINT_VEC( (mpV[(t).getPoints()[2]][0]),(mpV[(t).getPoints()[2]][1]),(mpV[(t).getPoints()[2]][2]) )<<" } "
+
+
+
+/* some useful templated functions
+ * may require some operators for the classes
+ */
+
+/* minimum */
+template < class T >
+inline T
+MIN( T a, T b )
+{ return (a < b) ? a : b ; }
+
+/* maximum */
+template < class T >
+inline T
+MAX( T a, T b )
+{ return (a < b) ? b : a ; }
+
+/* absolute value */
+template < class T >
+inline T
+ABS( T a )
+{ return (0 < a) ? a : -a ; }
+
+/* sign of the value */
+template < class T >
+inline T
+SIGNUM( T a )
+{ return (0 < a) ? 1 : -1 ; }
+
+/* sign, returns -1,0,1 depending on sign/value=0 */
+template < class T >
+inline T
+SIGNUM0( T a )
+{ return (0 < a) ? 1 : ( a < 0 ? -1 : 0 ) ; }
+
+/* round to nearest integer */
+inline int
+ROUND(double d)
+{ return int(d + 0.5); }
+
+/* square function */
+template < class T >
+inline T
+SQUARE( T a )
+{ return a*a; }
+
+
+#define UTILITIES_H
+#endif
diff --git a/source/Makefile b/source/Makefile
index 142aeb1929e..67ec1c82961 100644
--- a/source/Makefile
+++ b/source/Makefile
@@ -218,6 +218,7 @@ endif
PULIB = $(NAN_IKSOLVER)/lib/libiksolver.a
PULIB += $(NAN_MOTO)/lib/libmoto.a
+ PULIB += $(NAN_ELBEEM)/lib/$(DEBUG_DIR)libelbeem.a
PULIB += $(OCGDIR)/blender/readblenfile/$(DEBUG_DIR)libreadblenfile.a
PULIB += $(OCGDIR)/blender/src/$(DEBUG_DIR)libsrcpublisher.a
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 55a09fcd158..0ceb39db401 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -205,5 +205,13 @@ struct Object* modifiers_isDeformedByArmature(struct Object *ob);
ModifierData* modifiers_getVirtualModifierList (struct Object *ob);
+ /* Modifier utility calls, do call through type pointer and return
+ * default values if pointer is optional.
+ */
+struct ModifierData* modifier_new (int type);
+void modifier_free (struct ModifierData *md);
+
+int modifier_dependsOnTime (struct ModifierData *md);
+
#endif
diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript
index 620890ba7c3..d279fc4a7d7 100644
--- a/source/blender/blenkernel/SConscript
+++ b/source/blender/blenkernel/SConscript
@@ -56,6 +56,7 @@ blenkernel_env.Append (CPPPATH = ['.',
'../../../intern/decimation/extern',
'../imbuf',
'../avi',
+ '#/intern/elbeem/extern',
'#/intern/iksolver/extern',
'../blenloader'])
@@ -71,3 +72,4 @@ SConscript(['bad_level_call_stubs/SConscript'])
blenkernel_env.Append (CPPPATH = user_options_dict['OPENGL_INCLUDE'])
blenkernel_env.Append (CPPPATH = user_options_dict['Z_INCLUDE'])
+blenkernel_env.Append (CPPPATH = user_options_dict['SDL_INCLUDE'])
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 5459277c379..5d83bb42753 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -36,6 +36,8 @@
#include <config.h>
#endif
+#include <zlib.h>
+
#include "PIL_time.h"
#include "MEM_guardedalloc.h"
@@ -46,6 +48,8 @@
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
+#include "DNA_object_fluidsim.h" // N_T
+#include "DNA_scene_types.h" // N_T
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
@@ -60,6 +64,7 @@
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_subsurf.h"
+#include "LBM_fluidsim.h"
#include "BKE_deform.h"
#include "BKE_modifier.h"
#include "BKE_key.h"
@@ -531,6 +536,7 @@ static DerivedMesh *getMeshDerivedMesh(Mesh *me, Object *ob, float (*vertCos)[3]
mdm->dm.drawFacesSolid = meshDM_drawFacesSolid;
mdm->dm.drawFacesColored = meshDM_drawFacesColored;
mdm->dm.drawFacesTex = meshDM_drawFacesTex;
+ mdm->dm.drawMappedFaces = meshDM_drawMappedFaces;
mdm->dm.drawMappedEdges = meshDM_drawMappedEdges;
mdm->dm.drawMappedFaces = meshDM_drawMappedFaces;
@@ -1429,7 +1435,6 @@ DerivedMesh *derivedmesh_from_displistmesh(DispListMesh *dlm, float (*vertexCos)
/***/
-typedef float vec3f[3];
DerivedMesh *mesh_create_derived_for_modifier(Object *ob, ModifierData *md)
{
@@ -1468,6 +1473,14 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], DerivedM
if (deform_r) *deform_r = NULL;
*final_r = NULL;
+ // N_T
+ if((G.obedit!=ob) && (ob->fluidsimFlag & OB_FLUIDSIM_ENABLE)) {
+ if(ob->fluidsimSettings->type & OB_FLUIDSIM_DOMAIN) {
+ *final_r = getFluidsimDerivedMesh(ob,useRenderParams, NULL,NULL);
+ if(*final_r) return;
+ }
+ }
+
if (useDeform) {
do_mesh_key(me);
@@ -1936,3 +1949,374 @@ DerivedMesh *editmesh_get_derived_base(void)
{
return getEditMeshDerivedMesh(G.editMesh, NULL);
}
+
+// N_T fluidsim declarations
+typedef struct {
+ MeshDerivedMesh mdm;
+
+ /* release whole mesh? */
+ char freeMesh;
+} FluidsimDerivedMesh;
+
+
+/***/
+// N_T fluidsim interface
+#ifdef WIN32
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#endif
+
+
+static void fluidsimDM_release(DerivedMesh *dm)
+{
+ FluidsimDerivedMesh *fsdm = (FluidsimDerivedMesh*) dm;
+ if(fsdm->freeMesh) {
+ // similar to free_mesh(fsdm->mdm.me) , but no things like unlink...
+ if(fsdm->mdm.me->mvert) MEM_freeN(fsdm->mdm.me->mvert);
+ if(fsdm->mdm.me->medge) MEM_freeN(fsdm->mdm.me->medge);
+ if(fsdm->mdm.me->mface) MEM_freeN(fsdm->mdm.me->mface);
+ MEM_freeN(fsdm->mdm.me);
+ }
+
+ if (fsdm->mdm.freeNors) MEM_freeN(fsdm->mdm.nors);
+ if (fsdm->mdm.freeVerts) MEM_freeN(fsdm->mdm.verts);
+ MEM_freeN(fsdm);
+}
+
+DerivedMesh *getFluidsimDerivedMesh(Object *srcob, int useRenderParams, float *extverts, float *nors) {
+ //fprintf(stderr,"getFluidsimDerivedMesh call (obid '%s', rp %d)\n", srcob->id.name, useRenderParams); // debug
+ int i;
+ Mesh *mesh = NULL; // srcob->ata;
+ FluidsimDerivedMesh *fsdm;
+ MeshDerivedMesh *mdm = NULL;
+ float (*vertCos)[3];
+ int displaymode = 0;
+ int curFrame = G.scene->r.cfra - 1; /* start with 0 */
+ char filename[FILE_MAXFILE],filepath[FILE_MAXFILE+FILE_MAXDIR];
+ char curWd[FILE_MAXDIR];
+
+ if(!useRenderParams) {
+ displaymode = srcob->fluidsimSettings->guiDisplayMode;
+ } else {
+ displaymode = srcob->fluidsimSettings->renderDisplayMode;
+ }
+
+ //fprintf(stderr,"getFluidsimDerivedMesh call (obid '%s', rp %d, dm %d)\n", srcob->id.name, useRenderParams, displaymode); // debug
+ if((displaymode==1) || (G.obedit==srcob)) {
+ mesh = srcob->data;
+ return getMeshDerivedMesh(mesh , srcob, NULL);
+ }
+
+ // init preview frame
+ if(displaymode==2) {
+ // use preview
+ snprintf(filename,FILE_MAXFILE,"%s_surface_preview_%04d.bobj.gz", srcob->fluidsimSettings->surfdataPrefix, curFrame);
+ } else {
+ // load final mesh
+ snprintf(filename,FILE_MAXFILE,"%s_surface_final_%04d.bobj.gz", srcob->fluidsimSettings->surfdataPrefix, curFrame);
+ }
+ BLI_getwdN(curWd);
+ BLI_make_file_string(G.sce, filepath, srcob->fluidsimSettings->surfdataDir, filename);
+
+ //fprintf(stderr,"getFluidsimDerivedMesh call (obid '%s', rp %d, dm %d) %s \n", srcob->id.name, useRenderParams, displaymode, filepath); // debug
+ mesh = readBobjgz(filepath, (Mesh*)(srcob->data) );
+ if(!mesh) {
+ // display org. object upon failure
+ mesh = srcob->data;
+ return getMeshDerivedMesh(mesh , srcob, NULL);
+ }
+ if((mesh)&&(mesh->totvert>0)) {
+ make_edges(mesh);
+ for(i=0;i<mesh->totedge;i++) {
+ // force all edge draw
+ mesh->medge[i].flag |= ME_EDGEDRAW;
+ //fprintf(stderr,"INI %d a%d f%d\n",fsdm->fsmesh->totedge,i, (fsdm->fsmesh->medge[i].flag & ME_EDGEDRAW) );
+ }
+ }
+
+ // WARNING copied from getMeshDerivedMesh
+ fsdm = MEM_callocN(sizeof(*fsdm), "getFluidsimDerivedMesh_fsdm");
+ fsdm->freeMesh = 1;
+ mdm = &fsdm->mdm;
+ vertCos = NULL;
+
+ mdm->dm.getMinMax = meshDM_getMinMax;
+ mdm->dm.convertToDispListMesh = meshDM_convertToDispListMesh;
+ mdm->dm.getNumVerts = meshDM_getNumVerts;
+ mdm->dm.getNumFaces = meshDM_getNumFaces;
+ mdm->dm.getVertCos = meshDM_getVertCos;
+ mdm->dm.getVertCo = meshDM_getVertCo;
+ mdm->dm.getVertNo = meshDM_getVertNo;
+ mdm->dm.drawVerts = meshDM_drawVerts;
+ mdm->dm.drawUVEdges = meshDM_drawUVEdges;
+ mdm->dm.drawEdges = meshDM_drawEdges;
+ mdm->dm.drawLooseEdges = meshDM_drawLooseEdges;
+ mdm->dm.drawFacesSolid = meshDM_drawFacesSolid;
+ mdm->dm.drawFacesColored = meshDM_drawFacesColored;
+ mdm->dm.drawFacesTex = meshDM_drawFacesTex;
+ mdm->dm.drawMappedFaces = meshDM_drawMappedFaces;
+ mdm->dm.drawMappedEdges = meshDM_drawMappedEdges;
+ mdm->dm.drawMappedFaces = meshDM_drawMappedFaces;
+
+ // use own release function
+ mdm->dm.release = fluidsimDM_release;
+
+ mdm->ob = srcob;
+ mdm->me = mesh;
+ mdm->verts = mesh->mvert;
+ mdm->nors = NULL;
+ mdm->freeNors = 0;
+ mdm->freeVerts = 0;
+
+ //fprintf(stderr,"fsdm loc %f,%f,%f; size %f,%f,%f; rot %f,%f,%f \n",
+ //mesh->loc[0], mesh->loc[1], mesh->loc[2],
+ //mesh->size[0], mesh->size[1], mesh->size[2],
+ //mesh->rot[0], mesh->rot[1], mesh->rot[2]);
+
+ if (vertCos) {
+ int i;
+
+ mdm->verts = MEM_mallocN(sizeof(*mdm->verts)*mdm->me->totvert, "deformedVerts");
+ for (i=0; i<mdm->me->totvert; i++) {
+ mdm->verts[i].co[0] = vertCos[i][0];
+ mdm->verts[i].co[1] = vertCos[i][1];
+ mdm->verts[i].co[2] = vertCos[i][2];
+ }
+ mesh_calc_normals(mdm->verts, mdm->me->totvert, mdm->me->mface, mdm->me->totface, &mdm->nors);
+ mdm->freeNors = 1;
+ mdm->freeVerts = 1;
+ } else {
+ // XXX this is kinda ... see getMeshDerivedMesh
+ mesh_calc_normals(mdm->verts, mdm->me->totvert, mdm->me->mface, mdm->me->totface, &mdm->nors);
+ mdm->freeNors = 1;
+ }
+
+ return (DerivedMesh*) mdm;
+}
+
+
+/* ***************************** bobj file handling ***************************** */
+
+/* write .bobj.gz file for a mesh object */
+
+void writeBobjgz(char *filename, struct Object *ob)
+{
+ int wri,i,j;
+ float wrf;
+ gzFile gzf;
+ DispListMesh *dlm = NULL;
+ DerivedMesh *dm;
+ float vec[3];
+ float rotmat[3][3];
+ MFace *mface = NULL;
+
+ if(!ob->data || (ob->type!=OB_MESH)) {
+ fprintf(stderr,"Writing GZ_BOBJ Invalid object %s ...\n", ob->id.name);
+ return;
+ }
+ if((ob->size[0]<0.0) || (ob->size[0]<0.0) || (ob->size[0]<0.0) ) {
+ fprintf(stderr,"\nfluidSim::writeBobjgz:: Warning object %s has negative scaling - check triangle ordering...?\n\n", ob->id.name);
+ }
+
+ fprintf(stderr,"Writing GZ_BOBJ '%s' ... ",filename);
+ gzf = gzopen(filename, "wb9");
+ if (!gzf) {
+ fprintf(stderr,"writeBobjgz::error - Unable to open file for writing '%s'\n", filename);
+ return;
+ }
+
+ dm = mesh_create_derived_render(ob);
+ dlm = dm->convertToDispListMesh(dm, 1);
+ mface = dlm->mface;
+
+ if(sizeof(wri)!=4) { fprintf(stderr,"Writing GZ_BOBJ, Invalid int size %d...\n", wri); return; } // paranoia check
+ wri = dlm->totvert;
+ gzwrite(gzf, &wri, sizeof(wri));
+ for(i=0; i<wri;i++) {
+ VECCOPY(vec, dlm->mvert[i].co); /* get transformed point */
+ Mat4MulVecfl(ob->obmat, vec);
+ //fprintf(stderr,"VTEST %d = %f,%f,%f\n",i,vec[0],vec[1],vec[2]); // DEBUG
+ for(j=0; j<3; j++) {
+ wrf = vec[j];
+ gzwrite(gzf, &wrf, sizeof( wrf ));
+ }
+ }
+
+ // should be the same as Vertices.size
+ wri = dlm->totvert;
+ gzwrite(gzf, &wri, sizeof(wri));
+ EulToMat3(ob->rot, rotmat);
+ for(i=0; i<wri;i++) {
+ VECCOPY(vec, dlm->mvert[i].no);
+ // FIXME divide? mv->no[0]= (short)(no[0]*32767.0);
+ Mat3MulVecfl(rotmat, vec);
+ Normalise(vec);
+ //fprintf(stderr, "N %s normrot %d %f %f %f\n",ob->id.name, i,vec[0],vec[1],vec[2]); // DEBUG
+ for(j=0; j<3; j++) {
+ wrf = vec[j]; //dlm->normals[i][j];
+ gzwrite(gzf, &wrf, sizeof( wrf ));
+ }
+ }
+
+
+ /* compute no. of triangles */
+ wri = 0;
+ for(i=0; i<dlm->totface; i++) {
+ wri++;
+ if(mface[i].v4) { wri++; }
+ }
+ gzwrite(gzf, &wri, sizeof(wri));
+ for(i=0; i<dlm->totface; i++) {
+
+ int face[4];
+ face[0] = mface[i].v1;
+ face[1] = mface[i].v2;
+ face[2] = mface[i].v3;
+ face[3] = mface[i].v4;
+ //fprintf(stderr,"F %s %d = %d,%d,%d,%d \n",ob->id.name, i, face[0],face[1],face[2],face[3] );
+
+ gzwrite(gzf, &(face[0]), sizeof( face[0] ));
+ gzwrite(gzf, &(face[1]), sizeof( face[1] ));
+ gzwrite(gzf, &(face[2]), sizeof( face[2] ));
+ if(face[3]) {
+ gzwrite(gzf, &(face[0]), sizeof( face[0] ));
+ gzwrite(gzf, &(face[2]), sizeof( face[2] ));
+ gzwrite(gzf, &(face[3]), sizeof( face[3] ));
+ }
+ }
+
+ gzclose( gzf );
+ if(dlm) displistmesh_free(dlm);
+ dm->release(dm);
+
+ //fprintf(stderr,"done. #Vertices: %d, #Normals: %d, #Triangles: %d\n", dlm->vertices.size(), dlm->normals.size(), dlm->faces.size() );
+}
+
+/* security macro for readgin bobjs */
+#define CHECK_GOTBYTES(b,s) \
+ if((b)!=4) { \
+ if(newmesh->mvert) MEM_freeN(newmesh->mvert); \
+ if(newmesh->mface) MEM_freeN(newmesh->mface); \
+ if(newmesh) MEM_freeN(newmesh); \
+ return NULL; \
+ }
+/* read .bobj.gz file into a fluidsimDerivedMesh struct */
+Mesh* readBobjgz(char *filename, Mesh *orgmesh) //, fluidsimDerivedMesh *fsdm)
+{
+ int wri,i,j;
+ float wrf;
+ gzFile gzf;
+ Mesh *newmesh;
+ const int debugOutput = 0;
+ // init data from old mesh (materials,flags)
+ MFace *origMFace = &((MFace*) orgmesh->mface)[0];
+ int mat_nr = origMFace->mat_nr;
+ int flag = origMFace->flag;
+ MFace *fsface = NULL;
+ int gotBytes;
+
+ if(!orgmesh) return NULL;
+
+ // similar to copy_mesh
+ newmesh = MEM_dupallocN(orgmesh);
+ newmesh->mat= orgmesh->mat; //MEM_dupallocN(orgmesh->mat); // use original?
+
+ newmesh->mvert= NULL;
+ newmesh->medge= NULL;
+ newmesh->mface= NULL;
+ newmesh->tface= NULL;
+ newmesh->dface= NULL;
+
+ newmesh->dvert = NULL; //MEM_mallocN (sizeof (MDeformVert)*orgmesh->totvert, "MDeformVert");
+
+ newmesh->mcol= NULL; //MEM_dupallocN(orgmesh->mcol);
+ newmesh->msticky= NULL; //MEM_dupallocN(orgmesh->msticky);
+ newmesh->texcomesh= NULL;
+
+ newmesh->key= NULL; //copy_key(orgmesh->key);
+ newmesh->totface = 0;
+ newmesh->totvert = 0;
+ newmesh->totedge = 0;
+ newmesh->medge = NULL; //? MEM_mallocN(sizeof(MEdge)*fsdm->fstotedge, "fluidsimDerivedMesh_edges");
+
+
+ if(debugOutput) fprintf(stderr,"Reading '%s' GZ_BOBJ... ",filename);
+ gzf = gzopen(filename, "rb");
+ if (!gzf) {
+ //fprintf(stderr,"readBobjgz::error - Unable to open file for reading '%s'\n", filename); // DEBUG
+ MEM_freeN(newmesh);
+ return NULL;
+ }
+
+ //if(sizeof(wri)!=4) { fprintf(stderr,"Reading GZ_BOBJ, Invalid int size %d...\n", wri); return NULL; } // paranoia check
+
+ gotBytes = gzread(gzf, &wri, sizeof(wri));
+ CHECK_GOTBYTES(gotBytes, "numverts");
+ newmesh->totvert = wri;
+ newmesh->mvert = MEM_mallocN(sizeof(MVert)*newmesh->totvert, "fluidsimDerivedMesh_bobjvertices");
+ if(debugOutput) fprintf(stderr,"#vertices %d ", newmesh->totvert); //DEBUG
+ for(i=0; i<newmesh->totvert;i++) {
+ for(j=0; j<3; j++) {
+ gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
+ CHECK_GOTBYTES(gotBytes, "vert");
+ newmesh->mvert[i].co[j] = wrf;
+ }
+ //fprintf(stderr,"VTEST %d = %f,%f,%f\n",i,newmesh->mvert[i].co[0],newmesh->mvert[i].co[1],newmesh->mvert[i].co[2]); // DEBUG
+ }
+
+ // should be the same as Vertices.size
+ gotBytes = gzread(gzf, &wri, sizeof(wri));
+ CHECK_GOTBYTES(gotBytes, "numnorms");
+ if(wri != newmesh->totvert) {
+ // complain #vertices has to be equal to #normals, reset&abort
+ MEM_freeN(newmesh->mvert);
+ MEM_freeN(newmesh);
+ fprintf(stderr,"Reading GZ_BOBJ, #normals=%d, #vertices=%d, aborting...\n", wri,newmesh->totvert );
+ return NULL;
+ }
+ for(i=0; i<newmesh->totvert;i++) {
+ for(j=0; j<3; j++) {
+ gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
+ CHECK_GOTBYTES(gotBytes, "norm");
+ newmesh->mvert[i].no[j] = wrf*32767.0;
+ }
+ }
+
+
+ /* compute no. of triangles */
+ gotBytes = gzread(gzf, &wri, sizeof(wri));
+ CHECK_GOTBYTES(gotBytes, "numfaces");
+ newmesh->totface = wri;
+ newmesh->mface = MEM_mallocN(sizeof(MFace)*newmesh->totface, "fluidsimDerivedMesh_bobjfaces");
+ if(debugOutput) fprintf(stderr,"#faces %d ", newmesh->totface); // DEBUG
+ fsface = newmesh->mface;
+ for(i=0; i<newmesh->totface; i++) {
+ int face[4];
+
+ gotBytes = gzread(gzf, &(face[0]), sizeof( face[0] ));
+ CHECK_GOTBYTES(gotBytes, "f1");
+ gotBytes = gzread(gzf, &(face[1]), sizeof( face[1] ));
+ CHECK_GOTBYTES(gotBytes, "f2");
+ gotBytes = gzread(gzf, &(face[2]), sizeof( face[2] ));
+ CHECK_GOTBYTES(gotBytes, "f3");
+ face[3] = 0;
+
+ fsface[i].v1 = face[0];
+ fsface[i].v2 = face[1];
+ fsface[i].v3 = face[2];
+ fsface[i].v4 = face[3];
+ //fprintf(stderr,"F %s %d = %d,%d,%d,%d \n",newmesh->ob->id.name, i, face[0],face[1],face[2],face[3] );
+ }
+
+ gzclose( gzf );
+
+ for(i=0;i<newmesh->totface;i++) {
+ fsface[i].mat_nr = mat_nr;
+ fsface[i].flag = flag;
+ }
+
+// if(debugOutput) fprintf(stderr," done\n");
+ return newmesh;
+}
+
diff --git a/source/blender/blenkernel/intern/Makefile b/source/blender/blenkernel/intern/Makefile
index 250ddae1fd9..9207023f9a5 100644
--- a/source/blender/blenkernel/intern/Makefile
+++ b/source/blender/blenkernel/intern/Makefile
@@ -69,6 +69,7 @@ CPPFLAGS += -I../../render/extern/include
CPPFLAGS += -I$(NAN_IKSOLVER)/include
CPPFLAGS += -I$(NAN_DECIMATION)/include
+CPPFLAGS += -I$(NAN_ELBEEM)/include
# path to zlib
CPPFLAGS += -I$(NAN_ZLIB)/include
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index d3e2d8c3ea8..58d72b89394 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -51,6 +51,7 @@
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
+#include "DNA_object_fluidsim.h"
#include "DNA_oops_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -1437,6 +1438,16 @@ void DAG_scene_update_flags(Scene *sce, unsigned int lay)
case OB_MESH:
me= ob->data;
if(me->key) ob->recalc |= OB_RECALC_DATA;
+ else if(ob->effect.first) {
+ Effect *eff= ob->effect.first;
+ if(eff->type==EFF_WAVE) ob->recalc |= OB_RECALC_DATA;
+ }
+ if((ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) && (ob->fluidsimSettings)) {
+ // fluidsimSettings might not be initialized during load...
+ if(ob->fluidsimSettings->type & OB_FLUIDSIM_DOMAIN) {
+ ob->recalc |= OB_RECALC_DATA; // NT
+ }
+ }
break;
case OB_CURVE:
case OB_SURF:
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index a1b03b18eb7..7d84e7830ec 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -216,6 +216,7 @@ void free_object(Object *ob)
if(ob->pd) MEM_freeN(ob->pd);
if(ob->soft) sbFree(ob->soft);
+ if(ob->fluidsimSettings) MEM_freeN(ob->fluidsimSettings); /* NT */
}
static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Object **obpoin)
@@ -730,6 +731,10 @@ Object *add_object(int type)
ob->anisotropicFriction[1] = 1.0f;
ob->anisotropicFriction[2] = 1.0f;
ob->gameflag= OB_PROP;
+
+ /* NT fluid sim defaults */
+ ob->fluidsimFlag = 0;
+ ob->fluidsimSettings = NULL;
ob->data= add_obdata_from_type(type);
@@ -832,6 +837,10 @@ Object *copy_object(Object *ob)
if(ob->pd) obn->pd= MEM_dupallocN(ob->pd);
obn->soft= copy_softbody(ob->soft);
+
+ /* NT copy fluid sim setting memory */
+ if(ob->fluidsimSettings) ob->fluidsimSettings = MEM_dupallocN(ob->fluidsimSettings);
+ else ob->fluidsimSettings = NULL;
ob->derivedDeform = NULL;
ob->derivedFinal = NULL;
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 96e10a71479..d11bb9ed563 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -85,6 +85,7 @@
#include "DNA_nla_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
+#include "DNA_object_fluidsim.h" // NT
#include "DNA_oops_types.h"
#include "DNA_object_force.h"
#include "DNA_packedFile_types.h"
@@ -2385,6 +2386,11 @@ static void direct_link_object(FileData *fd, Object *ob)
}
}
}
+ ob->fluidsimSettings= newdataadr(fd, ob->fluidsimSettings); /* NT */
+ if(ob->fluidsimSettings) {
+ // not much to do for now... fprintf(stderr, "FLUIDSIMT newdataadr\n");
+ ob->fluidsimSettings->orgMesh = NULL;
+ }
link_list(fd, &ob->prop);
prop= ob->prop.first;
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index c54363e692a..bce6dceb384 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -712,6 +712,7 @@ static void write_objects(WriteData *wd, ListBase *idbase)
}
}
}
+ writestruct(wd, DATA, "FluidsimSettings", 1, ob->fluidsimSettings); // NT
write_modifiers(wd, &ob->modifiers);
}
diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h
index 011c13eb0db..96080e187b1 100644
--- a/source/blender/include/butspace.h
+++ b/source/blender/include/butspace.h
@@ -234,6 +234,10 @@ void test_idbutton_cb(void *namev, void *arg2_unused);
/* this has MAX_EFFECT settings! Next free define is 1450... */
#define B_SELEFFECT 1430
+/* Fluidsim button defines */
+#define B_FLUIDSIM_BAKE 1450
+#define B_FLUIDSIM_SELDIR 1451
+
/* *********************** */
#define B_WORLDBUTS 1600
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 036a2bdc9cb..6bb18fe1df9 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -53,6 +53,7 @@ struct Material;
struct bConstraintChannel;
struct PartDeflect;
struct SoftBody;
+struct FluidsimSettings;
struct DerivedMesh;
typedef struct bDeformGroup {
@@ -190,6 +191,10 @@ typedef struct Object {
LBuf port;
float pad3, smoothresh; /* smoothresh is phong interpolation ray_shadow correction in render */
+
+ short fluidsimFlag; /* NT toggle fluidsim participation on/off */
+ short dnapadFluidsimDummy1, dnapadFluidsimDummy2, dnapadFluidsimDummy3; /* 8byte align */
+ struct FluidsimSettings *fluidsimSettings; /* if fluidsim enabled, store additional settings */
struct DerivedMesh *derivedDeform, *derivedFinal;
} Object;
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 3db54336060..2354b93dcbb 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -97,6 +97,7 @@ char *includefiles[] = {
"DNA_lattice_types.h",
"DNA_object_types.h",
"DNA_object_force.h",
+ "DNA_object_fluidsim.h",
"DNA_world_types.h",
"DNA_radio_types.h",
"DNA_scene_types.h",
@@ -1104,6 +1105,7 @@ int main(int argc, char ** argv)
#include "DNA_lattice_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
+#include "DNA_object_fluidsim.h",
#include "DNA_world_types.h"
#include "DNA_radio_types.h"
#include "DNA_scene_types.h"
diff --git a/source/blender/src/Makefile b/source/blender/src/Makefile
index e694880b1dd..f0728897d47 100644
--- a/source/blender/src/Makefile
+++ b/source/blender/src/Makefile
@@ -59,6 +59,7 @@ endif
CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
CPPFLAGS += -I$(NAN_GHOST)/include
CPPFLAGS += -I$(NAN_BMFONT)/include
+CPPFLAGS += -I$(NAN_ELBEEM)/include
CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include $(NAN_SDLCFLAGS)
# External interfaces of modules:
diff --git a/source/blender/src/SConscript b/source/blender/src/SConscript
index 84bdd178b67..7c745b251da 100644
--- a/source/blender/src/SConscript
+++ b/source/blender/src/SConscript
@@ -23,7 +23,7 @@ source_files = ['B.blend.c',
'cmovie.tga.c',
'cursors.c',
'drawaction.c',
- 'drawarmature.c',
+ 'drawarmature.c',
'drawdeps.c',
'drawimage.c',
'drawimasel.c',
@@ -71,6 +71,7 @@ source_files = ['B.blend.c',
'editview.c',
'eventdebug.c',
'filesel.c',
+ 'fluidsim.c',
'ghostwinlay.c',
'glutil.c',
'headerbuttons.c',
@@ -150,6 +151,7 @@ src_env.Append (CPPPATH = ['#/intern/guardedalloc',
'../readstreamglue',
'../img',
'../quicktime',
+ '#/intern/elbeem/extern',
'#/intern/ghost',
'#/intern/opennl/extern'])
diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c
index d1455afc879..1b4dfda3975 100644
--- a/source/blender/src/buttons_object.c
+++ b/source/blender/src/buttons_object.c
@@ -1,5 +1,5 @@
/**
- * $Id:
+ * $Id$
*
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
*
@@ -50,6 +50,7 @@
#include "BKE_main.h"
#include "BKE_library.h"
#include "BKE_softbody.h"
+#include "BKE_utildefines.h"
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
@@ -97,6 +98,7 @@
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
+#include "DNA_object_fluidsim.h"
#include "DNA_radio_types.h"
#include "DNA_screen_types.h"
#include "DNA_sound_types.h"
@@ -126,6 +128,7 @@
#include "BKE_texture.h"
#include "BKE_utildefines.h"
#include "BKE_DerivedMesh.h"
+#include "LBM_fluidsim.h"
#include "BIF_editconstraint.h"
#include "BSE_editipo.h"
@@ -1182,6 +1185,57 @@ static void softbody_bake(Object *ob)
}
+// NT store processed path & file prefix for fluidsim bake directory
+void fluidsimFilesel(char *selection)
+{
+ Object *ob = OBACT;
+ char srcDir[FILE_MAXDIR], srcFile[FILE_MAXFILE];
+ char prefix[FILE_MAXFILE];
+ char *srch, *srchSub, *srchExt, *lastFound;
+ int isElbeemSurf = 0;
+
+ strcpy(srcDir, selection);
+ BLI_splitdirstring(srcDir, srcFile);
+
+ // make prefix
+ strcpy(prefix, srcFile);
+ // check if this is a previously generated surface mesh file
+ srch = strstr(prefix, "_surface_");
+ if(srch) {
+ srchSub = strstr(prefix,"_preview_");
+ if(!srchSub) srchSub = strstr(prefix,"_final_");
+ srchExt = strstr(prefix,".gz.bobj");
+ if(!srchExt) srchExt = strstr(prefix,".bobj");
+ if(srchSub && srchExt) {
+ *srch = '\0';
+ isElbeemSurf = 1;
+ }
+ }
+ if(!isElbeemSurf) {
+ // try to remove suffix
+ lastFound = NULL;
+ srch = strchr(prefix, '.'); // search last . from extension
+ while(srch) {
+ lastFound = srch;
+ if(srch) {
+ srch++;
+ srch = strchr(srch, '.');
+ }
+ }
+ if(lastFound) {
+ *lastFound = '\0';
+ }
+ }
+
+ // TODO check srcDir for file path from sce?
+
+
+ strcpy(ob->fluidsimSettings->surfdataDir, srcDir);
+ strcpy(ob->fluidsimSettings->surfdataPrefix, prefix);
+ //fprintf(stderr,"fluidsimFilesel: Using surfdata path '%s', prefix '%s' \n", ob->fluidsimSettings->surfdataDir,ob->fluidsimSettings->surfdataPrefix); // DEBUG
+
+}
+
void do_object_panels(unsigned short event)
{
Object *ob;
@@ -1261,6 +1315,22 @@ void do_object_panels(unsigned short event)
allqueue(REDRAWBUTSOBJECT, 0);
allqueue(REDRAWVIEW3D, 0);
break;
+
+ case B_FLUIDSIM_BAKE:
+ ob= OBACT;
+ /* write config files (currently no simulation) */
+ fluidsimBake(ob);
+ break;
+ case B_FLUIDSIM_SELDIR: {
+ char str[FILE_MAXDIR+FILE_MAXFILE];
+ ScrArea *sa = closest_bigger_area();
+ strcpy(str,"//");
+ ob= OBACT;
+ /* chosse dir for surface files */
+ areawinset(sa->win);
+ activate_fileselect(FILE_SPECIAL, "Select Directory", str, fluidsimFilesel);
+ }
+ break;
default:
if(event>=B_SELEFFECT && event<B_SELEFFECT+MAX_EFFECT) {
@@ -1800,6 +1870,119 @@ static void object_panel_effects(Object *ob)
}
}
+/* NT - Panel for fluidsim settings */
+static void object_panel_fluidsim(Object *ob)
+{
+ uiBlock *block;
+ int yline = 160;
+ const int lineHeight = 20;
+ const int objHeight = 20;
+
+ block= uiNewBlock(&curarea->uiblocks, "object_fluidsim", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Constraints", "Object");
+ if(uiNewPanel(curarea, block, "Fluidsim", "Object", 640, 0, 318, 204)==0) return;
+
+ uiDefButBitS(block, TOG, OB_FLUIDSIM_ENABLE, REDRAWBUTSOBJECT, "Enable", 0,yline, 75,objHeight,
+ &ob->fluidsimFlag, 0, 0, 0, 0, "Sets object to participate in fluid simulation");
+
+ if(ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) {
+ FluidsimSettings *fss= ob->fluidsimSettings;
+
+ if(fss==NULL) {
+ fss = ob->fluidsimSettings = fluidsimSettingsNew(ob); // sbNew();
+ }
+
+ if(ob->type==OB_MESH) {
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, REDRAWBUTSOBJECT ,"Domain", 90, yline, 70,objHeight, &fss->type, 15.0, OB_FLUIDSIM_DOMAIN, 0.0, 0.0, "Bounding box of this object represents the computational domain of the fluid simulation.");
+ uiDefButS(block, ROW, REDRAWBUTSOBJECT ,"Fluid", 160, yline, 70,objHeight, &fss->type, 15.0, OB_FLUIDSIM_FLUID, 0.0, 0.0, "Object represents a volume of fluid in the simulation.");
+ uiDefButS(block, ROW, REDRAWBUTSOBJECT ,"Obstacle", 230, yline, 70,objHeight, &fss->type, 15.0, OB_FLUIDSIM_OBSTACLE, 0.0, 0.0, "Object is a fixed obstacle.");
+ yline -= lineHeight;
+ yline -= 5;
+
+ /* display specific settings for each type */
+ if(fss->type == OB_FLUIDSIM_DOMAIN) {
+ const int maxRes = 200;
+
+ uiDefButS(block, NUM, B_DIFF, "Resolution:", 0, yline,150,objHeight, &fss->resolutionxyz, 1, maxRes, 10, 0, "Domain resolution in X,Y and Z direction");
+ uiDefButS(block, NUM, B_DIFF, "Preview-Res.:", 150, yline,150,objHeight, &fss->previewresxyz, 1, 100, 10, 0, "Resolution of the preview meshes to generate, also in X,Y and Z direction");
+ yline -= lineHeight;
+ uiDefButF(block, NUM, B_DIFF, "Real-size:", 0, yline,150,objHeight, &fss->realsize, 0.0, 1.0, 10, 0, "Size of the simulation domain in meters.");
+ yline -= lineHeight;
+
+ uiDefButF(block, NUM, B_DIFF, "GravX:", 0, yline, 100,objHeight, &fss->gravx, -1000.1, 1000.1, 10, 0, "Gravity in X direction");
+ uiDefButF(block, NUM, B_DIFF, "GravY:", 100, yline, 100,objHeight, &fss->gravy, -1000.1, 1000.1, 10, 0, "Gravity in Y direction");
+ uiDefButF(block, NUM, B_DIFF, "GravZ:", 200, yline, 100,objHeight, &fss->gravz, -1000.1, 1000.1, 10, 0, "Gravity in Z direction");
+ yline -= lineHeight;
+ uiDefButF(block, NUM, B_DIFF, "Start time:", 0, yline,150,objHeight, &fss->animStart, 0.0, 100.0, 10, 0, "Simulation time of the first blender frame.");
+ uiDefButF(block, NUM, B_DIFF, "End time:", 150, yline,150,objHeight, &fss->animEnd , 0.0, 100.0, 10, 0, "Simulation time of the last blender frame.");
+ yline -= lineHeight;
+
+ /* "advanced" settings */
+ yline -= 5;
+
+ /* could also be char? */
+ uiDefButS(block, MENU, REDRAWVIEW3D, "Viscosity%t|Manual %x1|Water %x2|Oil %x3|Honey %x4",
+ 0,yline,100,objHeight, &fss->viscosityMode, 0, 0, 0, 0, "Set viscosity of the fluid to a preset value, or use manual input.");
+ if(fss->viscosityMode==1) {
+ uiDefButF(block, NUM, B_DIFF, "Value:", 100, yline, 100,objHeight, &fss->viscosityValue, 0.0, 1.0, 10, 0, "Viscosity setting, value that is multiplied by 10 to the power of (exponent*-1).");
+ uiDefButS(block, NUM, B_DIFF, "Neg-Exp.:", 200, yline, 100,objHeight, &fss->viscosityExponent, 0, 10, 10, 0, "Negative exponent for the viscosity value (to simplify entering small values e.g. 5*10^-6.");
+ } else {
+ // display preset values
+ uiDefBut(block, LABEL, 0, fluidsimViscosityPresetString[fss->viscosityMode], 100,yline,200,objHeight, NULL, 0.0, 0, 0, 0, "");
+ }
+ yline -= lineHeight;
+
+ uiDefBut(block, LABEL, 0, "Gui:", 0,yline,50,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefButS(block, MENU, REDRAWVIEW3D, "GuiDisplayMode%t|Geometry %x1|Preview %x2|Final %x3",
+ 50,yline,100,objHeight, &fss->guiDisplayMode, 0, 0, 0, 0, "How to display the fluid mesh in the blender gui.");
+ uiDefBut(block, LABEL, 0, "Rend:", 150,yline,50,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefButS(block, MENU, REDRAWVIEW3D, "RenderDisplayMode%t|Geometry %x1|Preview %x2|Final %x3",
+ 200,yline,100,objHeight, &fss->renderDisplayMode, 0, 0, 0, 0, "How to display the fluid mesh for rendering.");
+ yline -= lineHeight;
+
+ uiDefBut(block, BUT, B_FLUIDSIM_SELDIR, "Select Output Directory", 0, yline,100,objHeight, NULL, 0.0, 0.0, 10, 0, "Select Directory (and/or filenames) to store baked fluid simulation files in");
+ uiDefBut(block, LABEL, 0, fss->surfdataDir, 100,yline,100,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, fss->surfdataPrefix, 200,yline,100,objHeight, NULL, 0.0, 0, 0, 0, "");
+ yline -= lineHeight;
+
+ uiDefBut(block, BUT, B_FLUIDSIM_BAKE, "BAKE", 0, yline,300,objHeight, NULL, 0.0, 0.0, 10, 0, "Perform simulation and output and surface&preview meshes for each frame.");
+ }
+ else if(fss->type == OB_FLUIDSIM_FLUID) {
+ yline -= lineHeight + 5;
+ uiDefBut(block, LABEL, 0, "Initial velocity:", 0,yline,300,objHeight, NULL, 0.0, 0, 0, 0, "");
+ yline -= lineHeight;
+ uiDefButF(block, NUM, B_DIFF, "X:", 0, yline, 100,objHeight, &fss->iniVelx, -1000.1, 1000.1, 10, 0, "Initial fluid velocity in X direction");
+ uiDefButF(block, NUM, B_DIFF, "Y:", 100, yline, 100,objHeight, &fss->iniVely, -1000.1, 1000.1, 10, 0, "Initial fluid velocity in Y direction");
+ uiDefButF(block, NUM, B_DIFF, "Z:", 200, yline, 100,objHeight, &fss->iniVelz, -1000.1, 1000.1, 10, 0, "Initial fluid velocity in Z direction");
+ yline -= lineHeight;
+ }
+ else if(fss->type == OB_FLUIDSIM_OBSTACLE) {
+ yline -= lineHeight + 5;
+ uiDefBut(block, LABEL, 0, "No additional settings as of now...", 0,yline,300,objHeight, NULL, 0.0, 0, 0, 0, "");
+ yline -= lineHeight;
+ }
+ else {
+ yline -= lineHeight + 5;
+ /* not yet set */
+ uiDefBut(block, LABEL, 0, "Select object type for simulation", 0,yline,300,objHeight, NULL, 0.0, 0, 0, 0, "");
+ yline -= lineHeight;
+ }
+
+ } else {
+ yline -= lineHeight + 5;
+ uiDefBut(block, LABEL, 0, "Sorry - only meshes supported", 0,yline,300,objHeight, NULL, 0.0, 0, 0, 0, "");
+ yline -= lineHeight;
+ }
+ } else {
+ yline -= lineHeight + 5;
+ uiDefBut(block, LABEL, 0, "Object not enabled for fluid simulation...", 0,yline,300,objHeight, NULL, 0.0, 0, 0, 0, "");
+ yline -= lineHeight;
+ }
+ uiBlockEndAlign(block);
+}
+
void object_panels()
{
Object *ob;
@@ -1817,6 +2000,7 @@ void object_panels()
}
object_panel_deflectors(ob);
object_softbodies(ob);
+ object_panel_fluidsim(ob);
uiClearButLock();
}
diff --git a/source/nan_definitions.mk b/source/nan_definitions.mk
index a8795ecee48..a861a80509c 100644
--- a/source/nan_definitions.mk
+++ b/source/nan_definitions.mk
@@ -85,6 +85,7 @@ endif
export NAN_TEST_VERBOSITY ?= 1
export NAN_BMFONT ?= $(LCGDIR)/bmfont
export NAN_OPENNL ?= $(LCGDIR)/opennl
+ export NAN_ELBEEM ?= $(LCGDIR)/elbeem
export NAN_SUPERLU ?= $(LCGDIR)/superlu
ifeq ($(FREE_WINDOWS), true)
export NAN_FTGL ?= $(LCGDIR)/gcc/ftgl
diff --git a/tools/scons/bs/bs_libs.py b/tools/scons/bs/bs_libs.py
index 83cf6f1c243..b62879478ef 100644
--- a/tools/scons/bs/bs_libs.py
+++ b/tools/scons/bs/bs_libs.py
@@ -62,7 +62,8 @@ def blender_libs(env):
'blender_blenkernel',
'blender_LOD',
'blender_IK',
- 'blender_ONL'])
+ 'blender_ONL',
+ 'blender_elbeem' ])
def ketsji_libs(env):
"""