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
This commit is contained in:
Jean-Luc Peurière 2005-09-18 13:27:12 +00:00
parent 9e3468bde2
commit e2d577de9e
83 changed files with 27913 additions and 5 deletions

@ -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 \

@ -9,6 +9,7 @@ SConscript(['SoundSystem/SConscript',
'memutil/SConscript/',
'decimation/SConscript',
'iksolver/SConscript',
'elbeem/SConscript',
'opennl/SConscript'])
NEW_CSG='false'

360
intern/elbeem/COPYING Normal file

@ -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.

@ -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

58
intern/elbeem/Makefile Normal file

@ -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/

56
intern/elbeem/SConscript Normal file

@ -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)

68
intern/elbeem/extern/LBM_fluidsim.h vendored Normal file

@ -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

@ -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

@ -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

@ -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;
}
}
}

@ -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

@ -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;
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -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;

@ -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 ";

@ -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;
}

@ -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

@ -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;

File diff suppressed because it is too large Load Diff

@ -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

@ -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

File diff suppressed because it is too large Load Diff

@ -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

@ -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]");
}

@ -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

@ -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}
};

@ -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;
}

@ -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

@ -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;
}

@ -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

@ -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
}

@ -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

@ -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

@ -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
}

@ -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

@ -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);
}

@ -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

@ -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

@ -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 );
}
}

@ -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

@ -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"

@ -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

@ -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;
}

@ -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

@ -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

@ -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

@ -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();
}

@ -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

@ -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;
}

@ -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

@ -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

@ -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

@ -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);
}

@ -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

@ -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

File diff suppressed because it is too large Load Diff

@ -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;
}

@ -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

@ -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);
}

@ -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

@ -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() );
}
}

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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'])

@ -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;
}

@ -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

@ -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:

@ -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;

@ -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;

@ -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);
}

@ -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

@ -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;

@ -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"

@ -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:

@ -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'])

@ -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();
}

@ -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

@ -62,7 +62,8 @@ def blender_libs(env):
'blender_blenkernel',
'blender_LOD',
'blender_IK',
'blender_ONL'])
'blender_ONL',
'blender_elbeem' ])
def ketsji_libs(env):
"""