diff --git a/CMakeLists.txt b/CMakeLists.txt
index d94779c..78def0d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -22,3 +22,4 @@ set(LIBRARY_OUTPUT_PATH "${PROJECT_BINARY_DIR}/bin")
add_subdirectory(extern)
add_subdirectory(glviz)
+add_subdirectory(surface_splatting)
diff --git a/COPYING.GPL b/COPYING.GPL
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/COPYING.GPL
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. 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
+them 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 prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. 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.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey 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;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU 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 that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ 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.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+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.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ 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
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 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, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program 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, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/surface_splatting/CMakeLists.txt b/surface_splatting/CMakeLists.txt
new file mode 100644
index 0000000..3b3a4c6
--- /dev/null
+++ b/surface_splatting/CMakeLists.txt
@@ -0,0 +1,41 @@
+# Use static anttweakbar.
+add_definitions(-DTW_NO_LIB_PRAGMA -DTW_STATIC)
+
+# Use static GLEW.
+add_definitions(-DGLEW_STATIC)
+
+# Use static freeglut.
+add_definitions(-DFREEGLUT_LIB_PRAGMAS=0 -DFREEGLUT_STATIC)
+
+file(TO_NATIVE_PATH "${PROJECT_SOURCE_DIR}/resources/" GLVIZ_RESOURCES_DIR)
+configure_file(config.hpp.in "${CMAKE_CURRENT_BINARY_DIR}/config.hpp")
+
+file(GLOB OPENGL_SHADERS shader/*)
+shader_wrap_cpp(SOURCES_OPENGL_SHADERS "${OPENGL_SHADERS}")
+
+add_executable(surface_splatting
+ main.cpp
+ framebuffer.hpp
+ framebuffer.cpp
+ program_finalization.hpp
+ program_finalization.cpp
+ program_attribute.hpp
+ program_attribute.cpp
+ splat_renderer.cpp
+ splat_renderer.hpp
+ ${OPENGL_SHADERS}
+ ${SOURCES_OPENGL_SHADERS}
+)
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${glviz_INCLUDE_DIRS}
+)
+
+add_dependencies(surface_splatting
+ glviz
+)
+
+target_link_libraries(surface_splatting
+ ${glviz_LIBRARIES}
+)
diff --git a/surface_splatting/config.hpp.in b/surface_splatting/config.hpp.in
new file mode 100644
index 0000000..3184f54
--- /dev/null
+++ b/surface_splatting/config.hpp.in
@@ -0,0 +1 @@
+const char* path_resources = R"(${GLVIZ_RESOURCES_DIR})";
diff --git a/surface_splatting/framebuffer.cpp b/surface_splatting/framebuffer.cpp
new file mode 100644
index 0000000..ffca015
--- /dev/null
+++ b/surface_splatting/framebuffer.cpp
@@ -0,0 +1,480 @@
+// This file is part of Surface Splatting.
+//
+// Copyright (C) 2010, 2015 by Sebastian Lipponer.
+//
+// Surface Splatting is free software: you can redistribute it and / or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Surface Splatting is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Surface Splatting. If not, see .
+
+#include "framebuffer.hpp"
+
+#include
+#include
+#include
+
+struct Framebuffer::Impl
+{
+ virtual void framebuffer_texture_2d(GLenum target,
+ GLenum attachment, GLuint texture, GLint level) = 0;
+ virtual void renderbuffer_storage(GLenum target,
+ GLenum internalformat, GLsizei width, GLsizei height) = 0;
+ virtual void allocate_depth_texture(GLuint texture,
+ GLsizei width, GLsizei height) = 0;
+ virtual void allocate_rgba_texture(GLuint texture,
+ GLsizei width, GLsizei height) = 0;
+ virtual void resize_rgba_texture(GLuint texture,
+ GLsizei width, GLsizei height) = 0;
+ virtual void resize_depth_texture(GLuint texture,
+ GLsizei width, GLsizei height) = 0;
+ virtual bool multisample() const = 0;
+};
+
+struct Framebuffer::Default : public Framebuffer::Impl
+{
+ void framebuffer_texture_2d(GLenum target,
+ GLenum attachment, GLuint texture, GLint level)
+ {
+ glFramebufferTexture2D(target, attachment,
+ GL_TEXTURE_2D, texture, level);
+ }
+
+ void renderbuffer_storage(GLenum target,
+ GLenum internalformat, GLsizei width, GLsizei height)
+ {
+ glRenderbufferStorage(target, internalformat,
+ width, height);
+ }
+
+ void allocate_depth_texture(GLuint texture,
+ GLsizei width, GLsizei height)
+ {
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F,
+ width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+ void allocate_rgba_texture(GLuint texture,
+ GLsizei width, GLsizei height)
+ {
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F,
+ width, height, 0, GL_RGBA, GL_FLOAT, nullptr);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+ void resize_rgba_texture(GLuint texture, GLsizei width, GLsizei height)
+ {
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F,
+ width, height, 0, GL_RGBA, GL_FLOAT, nullptr);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+ void resize_depth_texture(GLuint texture, GLsizei width, GLsizei height)
+ {
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F,
+ width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+ bool multisample() const
+ {
+ return false;
+ }
+};
+
+struct Framebuffer::Multisample : public Framebuffer::Impl
+{
+ void framebuffer_texture_2d(GLenum target,
+ GLenum attachment, GLuint texture, GLint level)
+ {
+ glFramebufferTexture2D(target, attachment,
+ GL_TEXTURE_2D_MULTISAMPLE, texture, level);
+ }
+
+ void renderbuffer_storage(GLenum target,
+ GLenum internalformat, GLsizei width, GLsizei height)
+ {
+ glRenderbufferStorageMultisample(target, 4,
+ internalformat, width, height);
+ }
+
+ void allocate_depth_texture(GLuint texture,
+ GLsizei width, GLsizei height)
+ {
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture);
+ glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4,
+ GL_DEPTH_COMPONENT32F, width, height, GL_TRUE);
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
+ }
+
+ void allocate_rgba_texture(GLuint texture,
+ GLsizei width, GLsizei height)
+ {
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture);
+ glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA32F,
+ width, height, GL_TRUE);
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
+ }
+
+ void resize_rgba_texture(GLuint texture, GLsizei width, GLsizei height)
+ {
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture);
+ GLint internal_format;
+ glGetTexLevelParameteriv(GL_TEXTURE_2D_MULTISAMPLE, 0,
+ GL_TEXTURE_INTERNAL_FORMAT, &internal_format);
+
+ glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4,
+ internal_format, width, height, GL_TRUE);
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
+ }
+
+ void resize_depth_texture(GLuint texture, GLsizei width, GLsizei height)
+ {
+ resize_rgba_texture(texture, width, height);
+ }
+
+ bool multisample() const
+ {
+ return true;
+ }
+};
+
+Framebuffer::Framebuffer()
+ : m_fbo(0), m_color(0), m_normal(0), m_depth(0),
+ m_pimpl(new Default())
+{
+ // Create framebuffer object.
+ glGenFramebuffers(1, &m_fbo);
+
+ // Initialize.
+ bind();
+ initialize();
+ unbind();
+}
+
+Framebuffer::~Framebuffer()
+{
+ bind();
+ remove_and_delete_attachments();
+ unbind();
+
+ glDeleteFramebuffers(1, &m_fbo);
+}
+
+GLuint
+Framebuffer::color_texture()
+{
+ return m_color;
+}
+
+void
+Framebuffer::enable_depth_texture()
+{
+ bind();
+
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ GL_RENDERBUFFER, 0);
+ glDeleteRenderbuffers(1, &m_depth);
+
+ GLint viewport[4];
+ glGetIntegerv(GL_VIEWPORT, viewport);
+
+ glGenTextures(1, &m_depth);
+ m_pimpl->allocate_depth_texture(m_depth, viewport[2], viewport[3]);
+ m_pimpl->framebuffer_texture_2d(GL_FRAMEBUFFER,
+ GL_DEPTH_ATTACHMENT, m_depth, 0);
+
+ unbind();
+}
+
+void
+Framebuffer::disable_depth_texture()
+{
+ bind();
+
+ m_pimpl->framebuffer_texture_2d(GL_FRAMEBUFFER,
+ GL_DEPTH_ATTACHMENT, 0, 0);
+ glDeleteTextures(1, &m_depth);
+
+ GLint viewport[4];
+ glGetIntegerv(GL_VIEWPORT, viewport);
+
+ glGenRenderbuffers(1, &m_depth);
+ glBindRenderbuffer(GL_RENDERBUFFER, m_depth);
+ m_pimpl->renderbuffer_storage(GL_RENDERBUFFER,
+ GL_DEPTH_COMPONENT32F, viewport[2], viewport[3]);
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ GL_RENDERBUFFER, m_depth);
+
+ unbind();
+}
+
+GLuint
+Framebuffer::depth_texture()
+{
+ return m_depth;
+}
+
+void
+Framebuffer::attach_normal_texture()
+{
+ bind();
+
+ GLint viewport[4];
+ glGetIntegerv(GL_VIEWPORT, viewport);
+
+ glGenTextures(1, &m_normal);
+ m_pimpl->allocate_rgba_texture(m_normal, viewport[2], viewport[3]);
+ m_pimpl->framebuffer_texture_2d(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT1, m_normal, 0);
+
+ GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
+ glDrawBuffers(2, buffers);
+
+ unbind();
+}
+
+void
+Framebuffer::detach_normal_texture()
+{
+ bind();
+
+ m_pimpl->framebuffer_texture_2d(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT1, 0, 0);
+ glDeleteTextures(1, &m_normal);
+
+ GLenum buffers[] = { GL_COLOR_ATTACHMENT0 };
+ glDrawBuffers(1, buffers);
+
+ unbind();
+}
+
+GLuint
+Framebuffer::normal_texture()
+{
+ return m_normal;
+}
+
+void
+Framebuffer::set_multisample(bool enable)
+{
+ if (m_pimpl->multisample() != enable)
+ {
+ bind();
+
+ GLint type;
+ glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT1, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &type);
+
+ remove_and_delete_attachments();
+
+ if (m_pimpl->multisample())
+ {
+ m_pimpl = std::unique_ptr(
+ new Framebuffer::Default());
+ }
+ else
+ {
+ m_pimpl = std::unique_ptr(
+ new Framebuffer::Multisample());
+ }
+
+ initialize();
+ if (type == GL_TEXTURE)
+ {
+ attach_normal_texture();
+ enable_depth_texture();
+ }
+
+#ifndef NDEBUG
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE)
+ {
+ std::cerr << __FILE__ << "(" << __LINE__ << "): "
+ << GLviz::get_gl_framebuffer_status_string(status) << std::endl;
+ }
+
+ GLenum gl_error = glGetError();
+ if (GL_NO_ERROR != gl_error)
+ {
+ std::cerr << __FILE__ << "(" << __LINE__ << "): "
+ << GLviz::get_gl_error_string(gl_error) << std::endl;
+ }
+#endif
+ unbind();
+ }
+}
+
+void
+Framebuffer::bind()
+{
+ glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
+}
+
+void
+Framebuffer::unbind()
+{
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+void
+Framebuffer::reshape(GLint width, GLint height)
+{
+ bind();
+
+ GLenum attachment[2] = {
+ GL_COLOR_ATTACHMENT0,
+ GL_COLOR_ATTACHMENT1
+ };
+
+ for (unsigned int i(0); i < 2; ++i)
+ {
+ GLint type, name;
+ glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, attachment[i],
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &type);
+ glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, attachment[i],
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &name);
+
+ if (type == GL_TEXTURE)
+ {
+ m_pimpl->resize_rgba_texture(name, width, height);
+ }
+ }
+
+ {
+ GLint type, name;
+ glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
+ GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
+ &type);
+ glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
+ GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
+ &name);
+
+ switch (type)
+ {
+ case GL_TEXTURE:
+ m_pimpl->resize_depth_texture(name, width, height);
+ break;
+
+ case GL_RENDERBUFFER:
+ glBindRenderbuffer(GL_RENDERBUFFER, name);
+ m_pimpl->renderbuffer_storage(GL_RENDERBUFFER,
+ GL_DEPTH_COMPONENT, width, height);
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+ break;
+
+ case GL_NONE:
+ default:
+ break;
+ }
+ }
+
+#ifndef NDEBUG
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE)
+ {
+ std::cerr << __FILE__ << "(" << __LINE__ << "): "
+ << GLviz::get_gl_framebuffer_status_string(status) << std::endl;
+ }
+
+ GLenum gl_error = glGetError();
+ if (GL_NO_ERROR != gl_error)
+ {
+ std::cerr << __FILE__ << "(" << __LINE__ << "): "
+ << GLviz::get_gl_error_string(gl_error) << std::endl;
+ }
+#endif
+
+ unbind();
+}
+
+void
+Framebuffer::initialize()
+{
+ GLint viewport[4];
+ glGetIntegerv(GL_VIEWPORT, viewport);
+
+ // Attach color texture to framebuffer object.
+ glGenTextures(1, &m_color);
+ m_pimpl->allocate_rgba_texture(m_color, viewport[2], viewport[3]);
+ m_pimpl->framebuffer_texture_2d(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ m_color, 0);
+
+ // Attach renderbuffer object to framebuffer object.
+ glGenRenderbuffers(1, &m_depth);
+ glBindRenderbuffer(GL_RENDERBUFFER, m_depth);
+ m_pimpl->renderbuffer_storage(GL_RENDERBUFFER,
+ GL_DEPTH_COMPONENT32F, viewport[2], viewport[3]);
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ GL_RENDERBUFFER, m_depth);
+
+ GLenum buffers[] = { GL_COLOR_ATTACHMENT0 };
+ glDrawBuffers(1, buffers);
+
+#ifndef NDEBUG
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE)
+ {
+ std::cerr << __FILE__ << "(" << __LINE__ << "): "
+ << GLviz::get_gl_framebuffer_status_string(status) << std::endl;
+ }
+#endif
+}
+
+void
+Framebuffer::remove_and_delete_attachments()
+{
+ GLenum attachment[3] = {
+ GL_COLOR_ATTACHMENT0,
+ GL_COLOR_ATTACHMENT1,
+ GL_DEPTH_ATTACHMENT
+ };
+
+ for (unsigned int i(0); i < 3; ++i)
+ {
+ GLint type, name;
+ glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
+ attachment[i], GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &type);
+ glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
+ attachment[i], GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &name);
+
+ switch (type)
+ {
+ case GL_TEXTURE:
+ m_pimpl->framebuffer_texture_2d(
+ GL_FRAMEBUFFER, attachment[i], 0, 0);
+ glDeleteTextures(1, reinterpret_cast(&name));
+ break;
+
+ case GL_RENDERBUFFER:
+ glFramebufferRenderbuffer(
+ GL_FRAMEBUFFER, attachment[i], GL_RENDERBUFFER, 0);
+ glDeleteRenderbuffers(1, reinterpret_cast(&name));
+ break;
+
+ case GL_NONE:
+ default:
+ break;
+ }
+ }
+}
\ No newline at end of file
diff --git a/surface_splatting/framebuffer.hpp b/surface_splatting/framebuffer.hpp
new file mode 100644
index 0000000..2c47887
--- /dev/null
+++ b/surface_splatting/framebuffer.hpp
@@ -0,0 +1,61 @@
+// This file is part of Surface Splatting.
+//
+// Copyright (C) 2010, 2015 by Sebastian Lipponer.
+//
+// Surface Splatting is free software: you can redistribute it and / or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Surface Splatting is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Surface Splatting. If not, see .
+
+#ifndef FRAMEBUFFER_HPP
+#define FRAMEBUFFER_HPP
+
+#include
+#include
+
+class Framebuffer
+{
+
+public:
+ Framebuffer();
+ ~Framebuffer();
+
+ GLuint color_texture();
+
+ void enable_depth_texture();
+ void disable_depth_texture();
+ GLuint depth_texture();
+
+ void attach_normal_texture();
+ void detach_normal_texture();
+ GLuint normal_texture();
+
+ void set_multisample(bool enable = true);
+
+ void bind();
+ void unbind();
+ void reshape(GLint width, GLint height);
+
+private:
+ void initialize();
+ void remove_and_delete_attachments();
+
+ GLuint m_fbo;
+ GLuint m_color, m_normal, m_depth;
+
+ struct Impl;
+ struct Default;
+ struct Multisample;
+
+ std::unique_ptr m_pimpl;
+};
+
+#endif // FRAMEBUFFER_HPP
diff --git a/surface_splatting/main.cpp b/surface_splatting/main.cpp
new file mode 100644
index 0000000..a30ae6c
--- /dev/null
+++ b/surface_splatting/main.cpp
@@ -0,0 +1,638 @@
+// This file is part of Surface Splatting.
+//
+// Copyright (C) 2010, 2015 by Sebastian Lipponer.
+//
+// Surface Splatting is free software: you can redistribute it and / or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Surface Splatting is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Surface Splatting. If not, see .
+
+#include
+
+#include "splat_renderer.hpp"
+
+#include "config.hpp"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace Eigen;
+
+namespace
+{
+
+GLviz::Camera camera;
+unsigned int g_model(1);
+std::unique_ptr viz;
+
+std::vector m_ref_vertices;
+std::vector m_ref_normals;
+
+std::vector m_vertices;
+std::vector > m_faces;
+std::vector m_normals;
+
+std::vector m_surfels;
+
+void load_triangle_mesh(std::string const& filename);
+
+void
+displayFunc()
+{
+ viz->render_frame(m_surfels);
+}
+
+void
+reshapeFunc(int width, int height)
+{
+ const float aspect = static_cast(width) /
+ static_cast(height);
+
+ glViewport(0, 0, width, height);
+ camera.set_perspective(60.0f, aspect, 0.005f, 5.0f);
+
+ viz->reshape(width, height);
+}
+
+void
+closeFunc()
+{
+ viz = nullptr;
+}
+
+void
+load_triangle_mesh(std::string const& filename)
+{
+ std::cout << "\nRead " << filename << "." << std::endl;
+ std::ifstream input(filename);
+
+ if (input.good())
+ {
+ input.close();
+ GLviz::load_raw(filename, m_vertices, m_faces);
+ }
+ else
+ {
+ input.close();
+
+ std::ostringstream fqfn;
+ fqfn << path_resources;
+ fqfn << filename;
+ GLviz::load_raw(fqfn.str(), m_vertices, m_faces);
+ }
+
+ std::cout << " #vertices " << m_vertices.size() << std::endl;
+ std::cout << " #faces " << m_faces.size() << std::endl;
+
+ GLviz::set_vertex_normals_from_triangle_mesh(
+ m_vertices, m_faces, m_normals);
+
+ m_ref_vertices = m_vertices;
+ m_ref_normals = m_normals;
+}
+
+void
+steiner_circumellipse(float const* v0_ptr, float const* v1_ptr,
+ float const* v2_ptr, float* p0_ptr, float* t1_ptr, float* t2_ptr)
+{
+ Matrix2f Q;
+ Vector3f d0, d1, d2;
+ {
+ Map v[3] = { v0_ptr, v1_ptr, v2_ptr };
+
+ d0 = v[1] - v[0];
+ d0.normalize();
+
+ d1 = v[2] - v[0];
+ d1 = d1 - d0 * d0.dot(d1);
+ d1.normalize();
+
+ d2 = (1.0f / 3.0f) * (v[0] + v[1] + v[2]);
+
+ Vector2f p[3];
+ for (unsigned int j(0); j < 3; ++j)
+ {
+ p[j] = Vector2f(
+ d0.dot(v[j] - d2),
+ d1.dot(v[j] - d2)
+ );
+ }
+
+ Matrix3f A;
+ for (unsigned int j(0); j < 3; ++j)
+ {
+ A.row(j) = Vector3f(
+ p[j].x() * p[j].x(),
+ 2.0f * p[j].x() * p[j].y(),
+ p[j].y() * p[j].y()
+ );
+ }
+
+ FullPivLU lu(A);
+ Vector3f res = lu.solve(Vector3f::Ones());
+
+ Q(0, 0) = res(0);
+ Q(1, 1) = res(2);
+ Q(0, 1) = Q(1, 0) = res(1);
+ }
+
+ Map p0(p0_ptr), t1(t1_ptr), t2(t2_ptr);
+ {
+ SelfAdjointEigenSolver es;
+ es.compute(Q);
+
+ Vector2f const& l = es.eigenvalues();
+ Vector2f const& e0 = es.eigenvectors().col(0);
+ Vector2f const& e1 = es.eigenvectors().col(1);
+
+ p0 = d2;
+ t1 = (1.0f / std::sqrt(l.x())) * (d0 * e0.x() + d1 * e0.y());
+ t2 = (1.0f / std::sqrt(l.y())) * (d0 * e1.x() + d1 * e1.y());
+ }
+}
+
+void
+load_plane(unsigned int n)
+{
+ const float d = 1.0f / static_cast(2 * n);
+
+ Surfel s(Vector3f::Zero(),
+ 2.0f * d * Vector3f::UnitX(),
+ 2.0f * d * Vector3f::UnitY(),
+ Vector3f::Zero(),
+ 0);
+
+ m_surfels.resize(4 * n * n);
+ unsigned int m(0);
+
+ for (unsigned int i(0); i <= 2 * n; ++i)
+ {
+ for (unsigned int j(0); j <= 2 * n; ++j)
+ {
+ unsigned int k(i * (2 * n + 1) + j);
+
+ if (k % 2 == 1)
+ {
+ s.c = Vector3f(
+ -1.0f + 2.0f * d * static_cast(j),
+ -1.0f + 2.0f * d * static_cast(i),
+ 0.0f);
+ s.rgba = (((j / 2) % 2) == ((i / 2) % 2)) ? 0u : ~0u;
+ m_surfels[m] = s;
+
+ // Clip border surfels.
+ if (j == 2 * n)
+ {
+ m_surfels[m].p = Vector3f(-1.0f, 0.0f, 0.0f);
+ m_surfels[m].rgba = ~s.rgba;
+ }
+ else if (i == 2 * n)
+ {
+ m_surfels[m].p = Vector3f(0.0f, -1.0f, 0.0f);
+ m_surfels[m].rgba = ~s.rgba;
+ }
+ else if (j == 0)
+ {
+ m_surfels[m].p = Vector3f(1.0f, 0.0f, 0.0f);
+ }
+ else if (i == 0)
+ {
+ m_surfels[m].p = Vector3f(0.0f, 1.0f, 0.0f);
+ }
+ else
+ {
+ // Duplicate and clip inner surfels.
+ if (j % 2 == 0)
+ {
+ m_surfels[m].p = Vector3f(1.0, 0.0f, 0.0f);
+
+ m_surfels[++m] = s;
+ m_surfels[m].p = Vector3f(-1.0, 0.0f, 0.0f);
+ m_surfels[m].rgba = ~s.rgba;
+ }
+
+ if (i % 2 == 0)
+ {
+ m_surfels[m].p = Vector3f(0.0, 1.0f, 0.0f);
+
+ m_surfels[++m] = s;
+ m_surfels[m].p = Vector3f(0.0, -1.0f, 0.0f);
+ m_surfels[m].rgba = ~s.rgba;
+ }
+ }
+
+ ++m;
+ }
+ }
+ }
+}
+
+void
+load_cube()
+{
+ Surfel cube[24];
+ unsigned int color = 0;
+
+ // Front.
+ cube[0].c = Vector3f(-0.5f, 0.0f, 0.5f);
+ cube[0].u = 0.5f * Vector3f::UnitX();
+ cube[0].v = 0.5f * Vector3f::UnitY();
+ cube[0].p = Vector3f(1.0f, 0.0f, 0.0f);
+ cube[0].rgba = color;
+
+ cube[1] = cube[0];
+ cube[1].c = Vector3f(0.5f, 0.0f, 0.5f);
+ cube[1].p = Vector3f(-1.0f, 0.0f, 0.0f);
+
+ cube[2] = cube[0];
+ cube[2].c = Vector3f(0.0f, 0.5f, 0.5f);
+ cube[2].p = Vector3f(0.0f, -1.0f, 0.0f);
+
+ cube[3] = cube[0];
+ cube[3].c = Vector3f(0.0f, -0.5f, 0.5f);
+ cube[3].p = Vector3f(0.0f, 1.0f, 0.0f);
+
+ // Back.
+ cube[4].c = Vector3f(-0.5f, 0.0f, -0.5f);
+ cube[4].u = 0.5f * Vector3f::UnitX();
+ cube[4].v = -0.5f * Vector3f::UnitY();
+ cube[4].p = Vector3f(1.0f, 0.0f, 0.0f);
+ cube[4].rgba = color;
+
+ cube[5] = cube[4];
+ cube[5].c = Vector3f(0.5f, 0.0f, -0.5f);
+ cube[5].p = Vector3f(-1.0f, 0.0f, 0.0f);
+
+ cube[6] = cube[4];
+ cube[6].c = Vector3f(0.0f, 0.5f, -0.5f);
+ cube[6].p = Vector3f(0.0f, 1.0f, 0.0f);
+
+ cube[7] = cube[4];
+ cube[7].c = Vector3f(0.0f, -0.5f, -0.5f);
+ cube[7].p = Vector3f(0.0f, -1.0f, 0.0f);
+
+ // Top.
+ cube[8].c = Vector3f(-0.5f, 0.5f, 0.0f);
+ cube[8].u = 0.5f * Vector3f::UnitX();
+ cube[8].v = -0.5f * Vector3f::UnitZ();
+ cube[8].p = Vector3f(1.0f, 0.0f, 0.0f);
+ cube[8].rgba = color;
+
+ cube[9] = cube[8];
+ cube[9].c = Vector3f(0.5f, 0.5f, 0.0f);
+ cube[9].p = Vector3f(-1.0f, 0.0f, 0.0f);
+
+ cube[10] = cube[8];
+ cube[10].c = Vector3f(0.0f, 0.5f, 0.5f);
+ cube[10].p = Vector3f(0.0f, 1.0f, 0.0f);
+
+ cube[11] = cube[8];
+ cube[11].c = Vector3f(0.0f, 0.5f, -0.5f);
+ cube[11].p = Vector3f(0.0f, -1.0f, 0.0f);
+
+ // Bottom.
+ cube[12].c = Vector3f(-0.5f, -0.5f, 0.0f);
+ cube[12].u = 0.5f * Vector3f::UnitX();
+ cube[12].v = 0.5f * Vector3f::UnitZ();
+ cube[12].p = Vector3f(1.0f, 0.0f, 0.0f);
+ cube[12].rgba = color;
+
+ cube[13] = cube[12];
+ cube[13].c = Vector3f(0.5f, -0.5f, 0.0f);
+ cube[13].p = Vector3f(-1.0f, 0.0f, 0.0f);
+
+ cube[14] = cube[12];
+ cube[14].c = Vector3f(0.0f, -0.5f, 0.5f);
+ cube[14].p = Vector3f(0.0f, -1.0f, 0.0f);
+
+ cube[15] = cube[12];
+ cube[15].c = Vector3f(0.0f, -0.5f, -0.5f);
+ cube[15].p = Vector3f(0.0f, 1.0f, 0.0f);
+
+ // Left.
+ cube[16].c = Vector3f(-0.5f, -0.5f, 0.0f);
+ cube[16].u = 0.5f * Vector3f::UnitY();
+ cube[16].v = -0.5f * Vector3f::UnitZ();
+ cube[16].p = Vector3f(1.0f, 0.0f, 0.0f);
+ cube[16].rgba = color;
+
+ cube[17] = cube[16];
+ cube[17].c = Vector3f(-0.5f, 0.5f, 0.0f);
+ cube[17].p = Vector3f(-1.0f, 0.0f, 0.0f);
+
+ cube[18] = cube[16];
+ cube[18].c = Vector3f(-0.5f, 0.0f, 0.5f);
+ cube[18].p = Vector3f(0.0f, 1.0f, 0.0f);
+
+ cube[19] = cube[16];
+ cube[19].c = Vector3f(-0.5f, 0.0f, -0.5f);
+ cube[19].p = Vector3f(0.0f, -1.0f, 0.0f);
+
+ // Right.
+ cube[20].c = Vector3f(0.5f, -0.5f, 0.0f);
+ cube[20].u = 0.5f * Vector3f::UnitY();
+ cube[20].v = 0.5f * Vector3f::UnitZ();
+ cube[20].p = Vector3f(1.0f, 0.0f, 0.0f);
+ cube[20].rgba = color;
+
+ cube[21] = cube[20];
+ cube[21].c = Vector3f(0.5f, 0.5f, 0.0f);
+ cube[21].p = Vector3f(-1.0f, 0.0f, 0.0f);
+
+ cube[22] = cube[20];
+ cube[22].c = Vector3f(0.5f, 0.0f, 0.5f);
+ cube[22].p = Vector3f(0.0f, -1.0f, 0.0f);
+
+ cube[23] = cube[20];
+ cube[23].c = Vector3f(0.5f, 0.0f, -0.5f);
+ cube[23].p = Vector3f(0.0f, 1.0f, 0.0f);
+
+ m_surfels = std::vector(cube, cube + 24);
+}
+
+void
+hsv2rgb(float h, float s, float v, float& r, float& g, float& b)
+{
+ float h_i = std::floor(h / 60.0f);
+ float f = h / 60.0f - h_i;
+
+ float p = v * (1.0f - s);
+ float q = v * (1.0f - s * f);
+ float t = v * (1.0f - s * (1.0f - f));
+
+ switch (static_cast(h_i))
+ {
+ case 1:
+ r = q; g = v; b = p;
+ break;
+ case 2:
+ r = p; g = v; b = t;
+ break;
+ case 3:
+ r = p; g = q; b = v;
+ break;
+ case 4:
+ r = t; g = p; b = v;
+ break;
+ case 5:
+ r = v; g = p; b = q;
+ break;
+ default:
+ r = v; g = t; b = p;
+ }
+}
+
+void
+load_dragon()
+{
+ m_surfels.resize(m_faces.size());
+
+ for (unsigned int i(0); i < static_cast(
+ m_faces.size()); ++i)
+ {
+ std::array face = m_faces[i];
+ Vector3f v[3] = {
+ m_vertices[face[0]],
+ m_vertices[face[1]],
+ m_vertices[face[2]]
+ };
+
+ Vector3f p0, t1, t2;
+ steiner_circumellipse(
+ v[0].data(), v[1].data(), v[2].data(),
+ p0.data(), t1.data(), t2.data()
+ );
+
+ Vector3f n_s = t1.cross(t2);
+ Vector3f n_t = (v[1] - v[0]).cross(v[2] - v[0]);
+
+ if (n_t.dot(n_s) < 0.0f)
+ {
+ t1.swap(t2);
+ }
+
+ m_surfels[i].c = p0;
+ m_surfels[i].u = t1;
+ m_surfels[i].v = t2;
+ m_surfels[i].p = Vector3f::Zero();
+
+ float h = std::min((std::abs(p0.x()) / 0.45f) * 360.0f, 360.0f);
+ float r, g, b;
+ hsv2rgb(h, 1.0f, 1.0f, r, g, b);
+ m_surfels[i].rgba = static_cast(r * 255.0f)
+ | (static_cast(g * 255.0f) << 8)
+ | (static_cast(b * 255.0f) << 16);
+ }
+}
+
+void
+get_model(void* value, void* data)
+{
+ *static_cast(value) = g_model;
+}
+
+void
+set_model(void const* value, void* data)
+{
+ g_model = *static_cast(value);
+
+ switch (g_model)
+ {
+ case 1:
+ load_plane(200);
+ break;
+ case 2:
+ load_cube();
+ break;
+ default:
+ load_dragon();
+ }
+}
+
+void
+set_soft_zbuffer(void const* value, void* data)
+{
+ viz->set_soft_zbuffer(*static_cast(value));
+
+ if (viz->soft_zbuffer())
+ TwDefine(" TweakBar/'EWA filter' readonly=false ");
+ else
+ TwDefine(" TweakBar/'EWA filter' readonly=true ");
+}
+void get_soft_zbuffer(void* value, void* data)
+{ *static_cast(value) = viz->soft_zbuffer(); }
+
+void set_soft_zbuffer_epsilon(void const* value, void* data)
+{ viz->set_soft_zbuffer_epsilon(*static_cast(value)); }
+void get_soft_zbuffer_epsilon(void* value, void* data)
+{ *static_cast(value) = viz->soft_zbuffer_epsilon(); }
+
+void get_pointsize_method(void* value, void* data)
+{ *static_cast(value) = viz->pointsize_method(); }
+void set_pointsize_method(void const* value, void* data)
+{ viz->set_pointsize_method(*static_cast(value)); }
+
+void set_ewa_filter(void const* enable, void* data)
+{ viz->set_ewa_filter(*static_cast(enable)); }
+void get_ewa_filter(void* value, void* data)
+{ *static_cast(value) = viz->ewa_filter(); }
+
+void set_ewa_radius(void const* value, void* data)
+{ viz->set_ewa_radius(*static_cast(value)); }
+void get_ewa_radius(void* value, void* data)
+{ *static_cast(value) = viz->ewa_radius(); }
+
+void set_multisample(void const* enable, void* data)
+{ viz->set_multisample(*static_cast(enable)); }
+void get_multisample(void* value, void* data)
+{ *static_cast(value) = viz->multisample(); }
+
+void set_backface_culling(void const* enable, void* data)
+{ viz->set_backface_culling(*static_cast(enable)); }
+void get_backface_culling(void* value, void* data)
+{ *static_cast(value) = viz->backface_culling(); }
+
+void get_smooth(void* value, void* data)
+{ *static_cast(value) = viz->smooth(); }
+void set_smooth(void const* value, void* data)
+{ viz->set_smooth(*static_cast(value)); }
+
+void get_color_material(void* value, void* data)
+{ *static_cast(value) = viz->color_material() ? 1 : 0; }
+void set_color_material(void const* value, void* data)
+{ viz->set_color_material(*static_cast(value) == 1); }
+
+void get_material_color(void* value, void* data)
+{ Map color(static_cast(value));
+ color = Map(viz->material_color()); }
+void set_material_color(void const* value, void* data)
+{ viz->set_material_color(static_cast(value)); }
+
+void get_material_shininess(void* value, void* data)
+{ *static_cast(value) = viz->material_shininess(); }
+void set_material_shininess(void const* value, void* data)
+{ viz->set_material_shininess(*static_cast(value)); }
+
+void get_radius_scale(void* value, void* data)
+{ *static_cast(value) = viz->radius_scale(); }
+void set_radius_scale(void const* value, void* data)
+{ viz->set_radius_scale(*static_cast(value)); }
+
+}
+
+int
+main(int argc, char* argv[])
+{
+ GLviz::init(argc, argv);
+
+ camera.translate(Eigen::Vector3f(0.0f, 0.0f, -2.0f));
+ viz = std::unique_ptr(new SplatRenderer(camera));
+
+ try
+ {
+ load_triangle_mesh("stanford_dragon_v40k_f80k.raw");
+ }
+ catch(std::runtime_error const& e)
+ {
+ std::cerr << e.what() << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+
+ set_model(&g_model, nullptr);
+
+ // Setup AntTweakBar.
+ {
+ TwBar* bar = GLviz::twbar();
+
+ TwType models = TwDefineEnumFromString("models",
+ "Dragon,Plane,Cube");
+ TwAddVarCB(bar, "Model", models, &set_model,
+ &get_model, nullptr, " group=Scene ");
+
+ TwAddSeparator(bar, nullptr, " group=Scene ");
+
+ TwType shading_type = TwDefineEnumFromString("shading_type",
+ "Flat,Phong");
+ TwAddVarCB(bar, "Shading", shading_type, &set_smooth,
+ &get_smooth, nullptr, " key=5 group='Surface Splatting' ");
+
+ TwAddSeparator(bar, nullptr, " group='Surface Splatting' ");
+
+ TwType color_src = TwDefineEnumFromString("color_src",
+ "Surfel,Material");
+ TwAddVarCB(bar, "Color", color_src, &set_color_material,
+ &get_color_material, nullptr,
+ " key='c' group='Surface Splatting' ");
+
+ TwAddVarCB(bar, "Material Color", TW_TYPE_COLOR3F,
+ &set_material_color, &get_material_color, nullptr,
+ " help='Material Color' group='Surface Splatting' ");
+
+ TwAddVarCB(bar, "Material Shininess", TW_TYPE_FLOAT,
+ &set_material_shininess, &get_material_shininess, nullptr,
+ " min=1e-12 max=1000 help='Material Shininess' \
+ group='Surface Splatting' ");
+
+ TwAddSeparator(bar, nullptr, " group='Surface Splatting' ");
+
+ TwAddVarCB(bar, "Soft z-buffer", TW_TYPE_BOOLCPP,
+ &set_soft_zbuffer, &get_soft_zbuffer, nullptr,
+ " key=z group='Surface Splatting' ");
+
+ TwAddVarCB(bar, "EWA filter", TW_TYPE_BOOLCPP,
+ &set_ewa_filter, &get_ewa_filter, nullptr,
+ " key=u help='EWA filter' group='Surface Splatting' ");
+
+ TwAddVarCB(bar, "EWA radius", TW_TYPE_FLOAT,
+ &set_ewa_radius, &get_ewa_radius, nullptr,
+ " min=0.1 max=4.0 step=1e-3 group='Surface Splatting' ");
+
+ TwAddVarCB(bar, "Soft z-buffer epsilon", TW_TYPE_FLOAT,
+ &set_soft_zbuffer_epsilon, &get_soft_zbuffer_epsilon, nullptr,
+ " min=0 max=1.0 step=1e-6 group='Surface Splatting' ");
+
+ TwType point_size = TwDefineEnumFromString("Point size",
+ "PBP,BHZK05,WHA+07,ZRB+04");
+ TwAddVarCB(bar, "Point size", point_size, &set_pointsize_method,
+ &get_pointsize_method, nullptr,
+ " key='t' group='Surface Splatting' ");
+
+ TwAddSeparator(bar, NULL, " group='Surface Splatting' ");
+
+ TwAddVarCB(bar, "Multisample 4x", TW_TYPE_BOOLCPP,
+ &set_multisample, &get_multisample, nullptr,
+ " help='Multisample 4x' group='Surface Splatting' ");
+
+ TwAddVarCB(bar, "Backface culling", TW_TYPE_BOOLCPP,
+ &set_backface_culling, &get_backface_culling, nullptr,
+ " group='Surface Splatting' ");
+
+ TwAddVarCB(bar, "Radius scale", TW_TYPE_FLOAT,
+ &set_radius_scale, &get_radius_scale, nullptr,
+ " min=1e-6 max=2.0 step=1e-3 group='Surface Splatting' ");
+ }
+
+ TwDefine(" TweakBar size='300 400' valueswidth='100' \
+ color='100 100 100' refresh=0.01 ");
+
+ GLviz::display_callback(displayFunc);
+ GLviz::reshape_callback(reshapeFunc);
+ GLviz::close_callback(closeFunc);
+
+ return GLviz::exec(camera);
+}
diff --git a/surface_splatting/program_attribute.cpp b/surface_splatting/program_attribute.cpp
new file mode 100644
index 0000000..04a48ee
--- /dev/null
+++ b/surface_splatting/program_attribute.cpp
@@ -0,0 +1,168 @@
+// This file is part of Surface Splatting.
+//
+// Copyright (C) 2010, 2015 by Sebastian Lipponer.
+//
+// Surface Splatting is free software: you can redistribute it and / or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Surface Splatting is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Surface Splatting. If not, see .
+
+#include "program_attribute.hpp"
+
+#include
+#include
+
+extern unsigned char const attribute_vs_glsl[];
+extern unsigned char const attribute_fs_glsl[];
+extern unsigned char const lighting_glsl[];
+
+ProgramAttribute::ProgramAttribute()
+ : m_ewa_filter(false), m_backface_culling(false),
+ m_visibility_pass(true), m_smooth(false), m_color_material(false),
+ m_pointsize_method(0)
+{
+ initialize_shader_obj();
+ initialize_program_obj();
+}
+
+void
+ProgramAttribute::set_ewa_filter(bool enable)
+{
+ if (m_ewa_filter != enable)
+ {
+ m_ewa_filter = enable;
+ initialize_program_obj();
+ }
+}
+
+void
+ProgramAttribute::set_pointsize_method(unsigned int pointsize_method)
+{
+ if (m_pointsize_method != pointsize_method)
+ {
+ m_pointsize_method = pointsize_method;
+ initialize_program_obj();
+ }
+}
+
+void
+ProgramAttribute::set_backface_culling(bool enable)
+{
+ if (m_backface_culling != enable)
+ {
+ m_backface_culling = enable;
+ initialize_program_obj();
+ }
+}
+
+void
+ProgramAttribute::set_visibility_pass(bool enable)
+{
+ if (m_visibility_pass != enable)
+ {
+ m_visibility_pass = enable;
+ initialize_program_obj();
+ }
+}
+
+void
+ProgramAttribute::set_smooth(bool enable)
+{
+ if (m_smooth != enable)
+ {
+ m_smooth = enable;
+ initialize_program_obj();
+ }
+}
+
+void
+ProgramAttribute::set_color_material(bool enable)
+{
+ if (m_color_material != enable)
+ {
+ m_color_material = enable;
+ initialize_program_obj();
+ }
+}
+
+void
+ProgramAttribute::initialize_shader_obj()
+{
+ m_attribute_vs_obj.load_from_cstr(
+ reinterpret_cast(attribute_vs_glsl));
+ m_lighting_vs_obj.load_from_cstr(
+ reinterpret_cast(lighting_glsl));
+
+ m_attribute_fs_obj.load_from_cstr(
+ reinterpret_cast(attribute_fs_glsl));
+}
+
+void
+ProgramAttribute::initialize_program_obj()
+{
+ try
+ {
+ detach_all();
+
+ attach_shader(m_attribute_vs_obj);
+ attach_shader(m_attribute_fs_obj);
+ attach_shader(m_lighting_vs_obj);
+
+ std::map defines;
+
+ defines.insert(std::make_pair("EWA_FILTER",
+ m_ewa_filter ? 1 : 0));
+ defines.insert(std::make_pair("POINTSIZE_METHOD",
+ static_cast(m_pointsize_method)));
+ defines.insert(std::make_pair("BACKFACE_CULLING",
+ m_backface_culling ? 1 : 0));
+ defines.insert(std::make_pair("VISIBILITY_PASS",
+ m_visibility_pass ? 1 : 0));
+ defines.insert(std::make_pair("SMOOTH",
+ m_smooth ? 1 : 0));
+ defines.insert(std::make_pair("COLOR_MATERIAL",
+ m_color_material ? 1 : 0));
+
+ m_attribute_vs_obj.compile(defines);
+ m_attribute_fs_obj.compile(defines);
+ m_lighting_vs_obj.compile(defines);
+ }
+ catch (shader_compilation_error const& e)
+ {
+ std::cerr << "Error: A shader failed to compile." << std::endl
+ << e.what() << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+
+ try
+ {
+ link();
+ }
+ catch (shader_link_error const& e)
+ {
+ std::cerr << "Error: A program failed to link." << std::endl
+ << e.what() << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+
+ try
+ {
+ set_uniform_block_binding("Camera", 0);
+ set_uniform_block_binding("Raycast", 1);
+ set_uniform_block_binding("Frustum", 2);
+ set_uniform_block_binding("Parameter", 3);
+ }
+ catch (uniform_not_found_error const& e)
+ {
+ std::cerr << "Warning: Failed to set a uniform variable." << std::endl
+ << e.what() << std::endl;
+ }
+}
diff --git a/surface_splatting/program_attribute.hpp b/surface_splatting/program_attribute.hpp
new file mode 100644
index 0000000..f6b5499
--- /dev/null
+++ b/surface_splatting/program_attribute.hpp
@@ -0,0 +1,49 @@
+// This file is part of Surface Splatting.
+//
+// Copyright (C) 2010, 2015 by Sebastian Lipponer.
+//
+// Surface Splatting is free software: you can redistribute it and / or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Surface Splatting is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Surface Splatting. If not, see .
+
+#ifndef PROGRAM_RENDER_HPP
+#define PROGRAM_RENDER_HPP
+
+#include
+
+class ProgramAttribute : public glProgram
+{
+
+public:
+ ProgramAttribute();
+
+ void set_ewa_filter(bool enable = true);
+ void set_pointsize_method(unsigned int pointsize_method);
+ void set_backface_culling(bool enable = true);
+ void set_visibility_pass(bool enable = true);
+ void set_smooth(bool enable = true);
+ void set_color_material(bool enable = true);
+
+private:
+ void initialize_shader_obj();
+ void initialize_program_obj();
+
+private:
+ glVertexShader m_attribute_vs_obj, m_lighting_vs_obj;
+ glFragmentShader m_attribute_fs_obj;
+
+ bool m_ewa_filter, m_backface_culling,
+ m_visibility_pass, m_smooth, m_color_material;
+ unsigned int m_pointsize_method;
+};
+
+#endif // PROGRAM_RENDER_HPP
diff --git a/surface_splatting/program_finalization.cpp b/surface_splatting/program_finalization.cpp
new file mode 100644
index 0000000..7a9bd30
--- /dev/null
+++ b/surface_splatting/program_finalization.cpp
@@ -0,0 +1,112 @@
+// This file is part of Surface Splatting.
+//
+// Copyright (C) 2010, 2015 by Sebastian Lipponer.
+//
+// Surface Splatting is free software: you can redistribute it and / or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Surface Splatting is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Surface Splatting. If not, see .
+
+#include "program_finalization.hpp"
+
+#include
+#include
+
+extern unsigned char const finalization_vs_glsl[];
+extern unsigned char const finalization_fs_glsl[];
+extern unsigned char const lighting_glsl[];
+
+ProgramFinalization::ProgramFinalization()
+ : m_smooth(false), m_multisampling(false)
+{
+ initialize_shader_obj();
+ initialize_program_obj();
+}
+
+void
+ProgramFinalization::set_multisampling(bool enable)
+{
+ if (m_multisampling != enable)
+ {
+ m_multisampling = enable;
+ initialize_program_obj();
+ }
+}
+
+void
+ProgramFinalization::set_smooth(bool enable)
+{
+ if (m_smooth != enable)
+ {
+ m_smooth = enable;
+ initialize_program_obj();
+ }
+}
+
+void
+ProgramFinalization::initialize_shader_obj()
+{
+ m_finalization_vs_obj.load_from_cstr(
+ reinterpret_cast(finalization_vs_glsl));
+ m_finalization_fs_obj.load_from_cstr(
+ reinterpret_cast(finalization_fs_glsl));
+ m_lighting_fs_obj.load_from_cstr(
+ reinterpret_cast(lighting_glsl));
+
+ attach_shader(m_finalization_vs_obj);
+ attach_shader(m_finalization_fs_obj);
+ attach_shader(m_lighting_fs_obj);
+}
+
+void
+ProgramFinalization::initialize_program_obj()
+{
+ try
+ {
+ std::map defines;
+ defines.insert(std::make_pair("SMOOTH", m_smooth ? 1 : 0));
+ defines.insert(std::make_pair("MULTISAMPLING",
+ m_multisampling ? 1 : 0));
+
+ m_finalization_vs_obj.compile(defines);
+ m_finalization_fs_obj.compile(defines);
+ m_lighting_fs_obj.compile(defines);
+ }
+ catch (shader_compilation_error const& e)
+ {
+ std::cerr << "Error: A shader failed to compile." << std::endl
+ << e.what() << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+
+ try
+ {
+ link();
+ }
+ catch (shader_link_error const& e)
+ {
+ std::cerr << "Error: A program failed to link." << std::endl
+ << e.what() << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+
+ try
+ {
+ set_uniform_block_binding("Camera", 0);
+ set_uniform_block_binding("Raycast", 1);
+ set_uniform_block_binding("Parameter", 3);
+ }
+ catch (uniform_not_found_error const& e)
+ {
+ std::cerr << "Warning: Failed to set a uniform variable." << std::endl
+ << e.what() << std::endl;
+ }
+}
diff --git a/surface_splatting/program_finalization.hpp b/surface_splatting/program_finalization.hpp
new file mode 100644
index 0000000..34f59d5
--- /dev/null
+++ b/surface_splatting/program_finalization.hpp
@@ -0,0 +1,43 @@
+// This file is part of Surface Splatting.
+//
+// Copyright (C) 2010, 2015 by Sebastian Lipponer.
+//
+// Surface Splatting is free software: you can redistribute it and / or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Surface Splatting is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Surface Splatting. If not, see .
+
+#ifndef PROGRAM_FINALIZATION_HPP
+#define PROGRAM_FINALIZATION_HPP
+
+#include
+
+class ProgramFinalization : public glProgram
+{
+
+public:
+ ProgramFinalization();
+
+ void set_multisampling(bool enable);
+ void set_smooth(bool enable);
+
+private:
+ void initialize_shader_obj();
+ void initialize_program_obj();
+
+private:
+ glVertexShader m_finalization_vs_obj;
+ glFragmentShader m_finalization_fs_obj, m_lighting_fs_obj;
+
+ bool m_smooth, m_multisampling;
+};
+
+#endif // PROGRAM_FINALIZATION_HPP
diff --git a/surface_splatting/shader/attribute_fs.glsl b/surface_splatting/shader/attribute_fs.glsl
new file mode 100644
index 0000000..25ec9c5
--- /dev/null
+++ b/surface_splatting/shader/attribute_fs.glsl
@@ -0,0 +1,137 @@
+// This file is part of Surface Splatting.
+//
+// Copyright (C) 2010, 2015 by Sebastian Lipponer.
+//
+// Surface Splatting is free software: you can redistribute it and / or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Surface Splatting is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Surface Splatting. If not, see .
+
+#version 330
+
+#define VISIBILITY_PASS 0
+#define SMOOTH 0
+#define EWA_FILTER 0
+
+layout(std140, column_major) uniform Camera
+{
+ mat4 modelview_matrix;
+ mat4 projection_matrix;
+};
+
+layout(std140, column_major) uniform Raycast
+{
+ mat4 projection_matrix_inv;
+ vec4 viewport;
+};
+
+layout(std140) uniform Parameter
+{
+ vec3 material_color;
+ float material_shininess;
+ float radius_scale;
+ float ewa_radius;
+ float epsilon;
+};
+
+uniform sampler1D filter_kernel;
+
+in block
+{
+ flat in vec3 c_eye;
+ flat in vec3 u_eye;
+ flat in vec3 v_eye;
+ flat in vec3 p;
+ flat in vec3 n_eye;
+
+ #if !VISIBILITY_PASS
+ #if EWA_FILTER
+ flat in vec2 c_scr;
+ #endif
+ flat in vec3 color;
+ #endif
+}
+In;
+
+#define FRAG_COLOR 0
+layout(location = FRAG_COLOR) out vec4 frag_color;
+
+#if !VISIBILITY_PASS
+ #if SMOOTH
+ #define FRAG_NORMAL 1
+ layout(location = FRAG_NORMAL) out vec4 frag_normal;
+ #endif
+#endif
+
+void main()
+{
+ vec4 p_ndc = vec4(2.0 * (gl_FragCoord.xy - viewport.xy)
+ / (viewport.zw) - 1.0, -1.0, 1.0);
+ vec4 p_eye = projection_matrix_inv * p_ndc;
+ vec3 qn = p_eye.xyz / p_eye.w;
+
+ vec3 q = qn * dot(In.c_eye, In.n_eye) / dot(qn, In.n_eye);
+ vec3 d = q - In.c_eye;
+
+ vec2 u = vec2(dot(In.u_eye, d) / dot(In.u_eye, In.u_eye),
+ dot(In.v_eye, d) / dot(In.v_eye, In.v_eye));
+
+ if (dot(vec3(u, 1.0), In.p) < 0)
+ {
+ discard;
+ }
+
+ float w3d = length(u);
+ float zval = q.z;
+
+ #if !VISIBILITY_PASS && EWA_FILTER
+ float w2d = distance(gl_FragCoord.xy, In.c_scr) / ewa_radius;
+ float dist = min(w2d, w3d);
+
+ // Avoid visual artifacts due to wrong z-values for fragments
+ // being part of the low-pass filter, but outside of the
+ // reconstruction filter.
+ if (w3d > 1.0)
+ {
+ zval = In.c_eye.z;
+ }
+ #else
+ float dist = w3d;
+ #endif
+
+ if (dist > 1.0)
+ {
+ discard;
+ }
+
+ #if !VISIBILITY_PASS
+ #if EWA_FILTER
+ float alpha = texture(filter_kernel, dist).r;
+ #else
+ float alpha = 1.0;
+ #endif
+
+ frag_color = vec4(In.color, alpha);
+
+ #if SMOOTH
+ frag_normal = vec4(In.n_eye, alpha);
+ #endif
+ #endif
+
+ #if VISIBILITY_PASS
+ zval -= epsilon;
+ #endif
+
+ float depth = -projection_matrix[3][2] * (1.0 / zval) -
+ projection_matrix[2][2];
+
+ gl_FragDepth = (depth + 1.0) / 2.0;
+}
diff --git a/surface_splatting/shader/attribute_vs.glsl b/surface_splatting/shader/attribute_vs.glsl
new file mode 100644
index 0000000..0acbed5
--- /dev/null
+++ b/surface_splatting/shader/attribute_vs.glsl
@@ -0,0 +1,392 @@
+// This file is part of Surface Splatting.
+//
+// Copyright (C) 2010, 2015 by Sebastian Lipponer.
+//
+// Surface Splatting is free software: you can redistribute it and / or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Surface Splatting is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Surface Splatting. If not, see .
+
+#version 330
+
+#define VISIBILITY_PASS 0
+#define BACKFACE_CULLING 0
+#define SMOOTH 0
+#define COLOR_MATERIAL 0
+#define EWA_FILTER 0
+#define POINTSIZE_METHOD 0
+
+layout(std140, column_major) uniform Camera
+{
+ mat4 modelview_matrix;
+ mat4 projection_matrix;
+};
+
+layout(std140, column_major) uniform Raycast
+{
+ mat4 projection_matrix_inv;
+ vec4 viewport;
+};
+
+layout(std140) uniform Frustum
+{
+ vec4 frustum_plane[6];
+};
+
+layout(std140) uniform Parameter
+{
+ vec3 material_color;
+ float material_shininess;
+ float radius_scale;
+ float ewa_radius;
+ float epsilon;
+};
+
+#define ATTR_CENTER 0
+layout(location = ATTR_CENTER) in vec3 c;
+
+#define ATTR_T1 1
+layout(location = ATTR_T1) in vec3 u;
+
+#define ATTR_T2 2
+layout(location = ATTR_T2) in vec3 v;
+
+#define ATTR_PLANE 3
+layout(location = ATTR_PLANE) in vec3 p;
+
+#define ATTR_COLOR 4
+layout(location = ATTR_COLOR) in vec4 rgba;
+
+out block
+{
+ flat out vec3 c_eye;
+ flat out vec3 u_eye;
+ flat out vec3 v_eye;
+ flat out vec3 p;
+ flat out vec3 n_eye;
+
+ #if !VISIBILITY_PASS
+ #if EWA_FILTER
+ flat out vec2 c_scr;
+ #endif
+ flat out vec3 color;
+ #endif
+}
+Out;
+
+#if !VISIBILITY_PASS
+ vec3 lighting(vec3 n_eye, vec3 v_eye, vec3 color, float shininess);
+#endif
+
+void
+intersect(in vec4 v1, in vec4 v2, in int p,
+ out int n_pts, out vec4[2] pts)
+{
+ int i = p / 2;
+ float j = float(-1 + 2 * (p % 2));
+
+ float b1 = v1.w + float(j) * v1[i];
+ float b2 = v2.w + float(j) * v2[i];
+
+ bool tb1 = b1 > 0.0;
+ bool tb2 = b2 > 0.0;
+
+ n_pts = 0;
+
+ if (tb1 && tb2)
+ {
+ pts[0] = v2;
+ n_pts = 1;
+ }
+ else
+ if (tb1 && !tb2)
+ {
+ float a = b1 / (b1 - b2);
+ pts[0] = (1.0 - a) * v1 + a * v2;
+ n_pts = 1;
+ }
+ else
+ if (!tb1 && tb2)
+ {
+ float a = b1 / (b1 - b2);
+ pts[0] = (1.0 - a) * v1 + a * v2;
+ pts[1] = v2;
+ n_pts = 2;
+ }
+}
+
+void clip_polygon(in vec4 p0[4], out int n_pts, out vec4 p1[8])
+{
+ vec4 p[8];
+ int n = 4;
+
+ p[0] = p0[0];
+ p[1] = p0[1];
+ p[2] = p0[2];
+ p[3] = p0[3];
+
+ for (int i = 0; i < 6; ++i)
+ {
+ int k = 0;
+
+ for (int j = 0; j < n; ++j)
+ {
+ int n_pts;
+ vec4 pts[2];
+
+ intersect(p[j], p[(j + 1) % n], i, n_pts, pts);
+
+ if (n_pts == 1)
+ {
+ p1[k++] = pts[0];
+ }
+ else
+ if (n_pts == 2)
+ {
+ p1[k++] = pts[0];
+ p1[k++] = pts[1];
+ }
+ }
+
+ for (int j = 0; j < k; ++j)
+ {
+ p[j] = p1[j];
+ }
+
+ n = k;
+ }
+
+ n_pts = n;
+}
+
+void
+conic_Q(in vec3 u, in vec3 v, in vec3 c,
+ out mat3 Q1)
+{
+ mat3 Q0 = mat3(vec3(1.0, 0.0, 0.0),
+ vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, -1.0));
+
+ mat3 Sinv = transpose(mat3(cross(v, c),
+ cross(u, c), cross(u, v)));
+ Sinv[0][1] = -Sinv[0][1];
+ Sinv[1][1] = -Sinv[1][1];
+ Sinv[2][1] = -Sinv[2][1];
+
+ mat3 Pinv = mat3(
+ vec3(projection_matrix_inv[0]),
+ vec3(projection_matrix_inv[1]),
+ vec3(projection_matrix_inv[2]));
+ Pinv[2][2] = -1.0;
+
+ mat3 Minv = Sinv * Pinv;
+ Q1 = transpose(Minv) * Q0 * Minv;
+}
+
+void
+pointsprite(in vec3 c, in vec3 u, in vec3 v,
+ out vec4 p_scr, out vec2 w)
+{
+#if POINTSIZE_METHOD == 0
+
+ // This method obtains the position and bounds of a splat by
+ // clipping and perspectively projecting a bounding polygon.
+ mat4 M = projection_matrix * mat4(
+ vec4(u, 0.0), vec4(v, 0.0), vec4(c, 0.0),
+ vec4(0.0, 0.0, 0.0, 1.0));
+
+ vec4 p0[4];
+ p0[0] = M * vec4(1.0);
+ p0[1] = M * vec4(1.0, -1.0, 1.0, 1.0);
+ p0[2] = M * vec4(-1.0, -1.0, 1.0, 1.0);
+ p0[3] = M * vec4(-1.0, 1.0, 1.0, 1.0);
+
+ int n_pts;
+ vec4 p1[8];
+
+ clip_polygon(p0, n_pts, p1);
+
+ if (n_pts == 0)
+ {
+ p_scr = vec4(1.0, 0.0, 0.0, 0.0);
+ w = vec2(0.0);
+ }
+ else
+ {
+ vec2 p_min = vec2(1.0);
+ vec2 p_max = vec2(-1.0);
+
+ for (int i = 0; i < n_pts; ++i)
+ {
+ vec2 p1i = p1[i].xy / p1[i].w;
+ p_min = min(p_min, p1i);
+ p_max = max(p_max, p1i);
+ }
+
+ w = 0.5 * (p_max - p_min);
+
+ p_scr.xy = p_min + w;
+ p_scr.z = 0.0;
+ p_scr.w = 1.0;
+ }
+
+#elif POINTSIZE_METHOD == 1
+
+ // BHZK05.
+ p_scr = projection_matrix * vec4(c, 1.0);
+
+ float p11 = projection_matrix[1][1];
+ float r = max(length(u), length(v));
+
+ w = vec2(0.0, r * p11 / abs(c.z));
+
+#elif POINTSIZE_METHOD == 2
+
+ // WHA+07.
+ float r = max(length(u), length(v));
+ vec3 pl = vec3(
+ dot(frustum_plane[0], vec4(c, 1.0)),
+ dot(frustum_plane[2], vec4(c, 1.0)),
+ dot(frustum_plane[4], vec4(c, 1.0)));
+ vec3 pr = vec3(
+ dot(frustum_plane[1], vec4(c, 1.0)),
+ dot(frustum_plane[3], vec4(c, 1.0)),
+ dot(frustum_plane[5], vec4(c, 1.0)));
+
+ bool t_lr = (pl.x + r) > 0.0 && (pr.x + r) > 0.0;
+ bool t_bt = (pl.y + r) > 0.0 && (pr.y + r) > 0.0;
+ bool t_nf = (pl.z + r) > 0.0 && (pr.z + r) > 0.0;
+
+ if (t_lr && t_bt && t_nf)
+ {
+ mat4x3 T = transpose(projection_matrix * mat3x4(
+ vec4(u, 0.0), vec4(v, 0.0), vec4(c, 1.0)
+ ));
+
+ float d = dot(vec3(1.0, 1.0, -1.0), T[3] * T[3]);
+ vec3 f = (1.0 / d) * vec3(1.0, 1.0, -1.0);
+
+ vec3 p = vec3(dot(f, T[0] * T[3]),
+ dot(f, T[1] * T[3]), dot(f, T[2] * T[3]));
+
+ vec3 h0 = p * p - vec3(dot(f, T[0] * T[0]),
+ dot(f, T[1] * T[1]), dot(f, T[2] * T[2]));
+ vec3 h = sqrt(max(vec3(0.0), h0)) + vec3(0.0, 0.0, 1e-2);
+
+ w = h.xy;
+ p_scr = vec4(p.xy, 0.0, 1.0);
+ }
+ else
+ {
+ p_scr = vec4(1.0, 0.0, 0.0, 0.0);
+ w = vec2(0.0);
+ }
+
+#elif POINTSIZE_METHOD == 3
+
+ // ZRB+04.
+ mat3 Q;
+ conic_Q(u, v, c, Q);
+
+ float Qa = Q[0][0]; float Qb = Q[1][0];
+ float Qc = Q[1][1]; float Qd = Q[2][0];
+ float Qe = Q[2][1]; float Qf = -Q[2][2];
+
+ float delta = Qa * Qc - Qb * Qb;
+
+ if (delta > 0.0)
+ {
+ vec2 p = (Qb * vec2(Qe, Qd) - vec2(Qc * Qd, Qa * Qe)) / delta;
+ float bb = Qf - dot(vec2(Qd, Qe), p);
+
+ mat3 Q2 = mat3(
+ vec3(Qa, Qb, 0.0),
+ vec3(Qb, Qc, 0.0),
+ vec3(0.0, 0.0, -bb)) / bb;
+
+ float delta2 = Q2[0][0] * Q2[1][1] - Q2[0][1] * Q2[0][1];
+ vec2 h = sqrt(vec2(Q2[1][1], Q2[0][0]) / delta2);
+
+ // Put an upper bound on the point size since the
+ // centralized conics method is numerically unstable.
+ w = clamp(h, 0.0, 0.1);
+ p_scr = vec4(p, 0.0, 1.0);
+ }
+ else
+ {
+ p_scr = vec4(1.0, 0.0, 0.0, 0.0);
+ w = vec2(0.0);
+ }
+#endif
+}
+
+void main()
+{
+ vec4 c_eye = modelview_matrix * vec4(c, 1.0);
+ vec3 u_eye = radius_scale * mat3(modelview_matrix) * u;
+ vec3 v_eye = radius_scale * mat3(modelview_matrix) * v;
+ vec3 n_eye = normalize(cross(u_eye, v_eye));
+
+ vec4 p_scr;
+ vec2 w;
+ pointsprite(c_eye.xyz, u_eye, v_eye, p_scr, w);
+
+#if !VISIBILITY_PASS
+ #if SMOOTH
+ #if COLOR_MATERIAL
+ Out.color = material_color;
+ #else
+ Out.color = vec3(rgba);
+ #endif
+ #else
+ #if COLOR_MATERIAL
+ Out.color = lighting(n_eye, vec3(c_eye), material_color,
+ material_shininess);
+ #else
+ Out.color = lighting(n_eye, vec3(c_eye), vec3(rgba),
+ material_shininess);
+ #endif
+ #endif
+#endif
+
+#if BACKFACE_CULLING
+ // Backface culling
+ if (dot(n_eye, -vec3(c_eye)) > 0.0)
+ {
+#endif
+ // Pointsprite position.
+ gl_Position = p_scr;
+
+ Out.c_eye = vec3(c_eye);
+ Out.u_eye = u_eye;
+ Out.v_eye = v_eye;
+ Out.p = p;
+ Out.n_eye = n_eye;
+
+ // Pointsprite size. One additional pixel
+ // avoids artifacts.
+ float point_size = max(w[0] * viewport.z,
+ w[1] * viewport.w) + 1.0;
+
+#if !VISIBILITY_PASS && EWA_FILTER
+ Out.c_scr = vec2((p_scr.xy + 1.0) * viewport.zw * 0.5);
+ gl_PointSize = max(2.0, point_size);
+#else
+ gl_PointSize = point_size;
+#endif
+
+#if BACKFACE_CULLING
+ }
+ else
+ {
+ gl_Position = vec4(1.0, 0.0, 0.0, 0.0);
+ }
+#endif
+}
diff --git a/surface_splatting/shader/finalization_fs.glsl b/surface_splatting/shader/finalization_fs.glsl
new file mode 100644
index 0000000..c8805e1
--- /dev/null
+++ b/surface_splatting/shader/finalization_fs.glsl
@@ -0,0 +1,127 @@
+// This file is part of Surface Splatting.
+//
+// Copyright (C) 2010, 2015 by Sebastian Lipponer.
+//
+// Surface Splatting is free software: you can redistribute it and / or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Surface Splatting is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Surface Splatting. If not, see .
+
+#version 330
+
+#define MULTISAMPLING 0
+#define SMOOTH 0
+
+layout(std140, column_major) uniform Camera
+{
+ mat4 modelview_matrix;
+ mat4 projection_matrix;
+};
+
+layout(std140, column_major) uniform Raycast
+{
+ mat4 projection_matrix_inv;
+ vec4 viewport;
+};
+
+layout(std140) uniform Parameter
+{
+ vec3 material_color;
+ float material_shininess;
+ float radius_scale;
+ float ewa_radius;
+ float epsilon;
+};
+
+#if MULTISAMPLING
+ uniform sampler2DMS color_texture;
+#else
+ uniform sampler2D color_texture;
+#endif
+
+#if SMOOTH
+ #if MULTISAMPLING
+ uniform sampler2DMS normal_texture;
+ uniform sampler2DMS depth_texture;
+ #else
+ uniform sampler2D normal_texture;
+ uniform sampler2D depth_texture;
+ #endif
+
+ vec3 lighting(vec3 n_eye, vec3 v_eye, vec3 color, float shininess);
+#endif
+
+in block
+{
+ vec2 texture_uv;
+}
+In;
+
+#define FRAG_COLOR 0
+layout(location = FRAG_COLOR) out vec4 frag_color;
+
+void main()
+{
+ vec4 res = vec4(0.0);
+#if MULTISAMPLING
+ ivec2 itexture_uv = ivec2(textureSize(color_texture) * In.texture_uv);
+
+ for (int i = 0; i < 4; ++i)
+#endif
+ {
+ #if MULTISAMPLING
+ vec4 pixel = texelFetch(color_texture, itexture_uv, i);
+
+ #if SMOOTH
+ vec3 normal = normalize(
+ texelFetch(normal_texture, ivec2(itexture_uv), i).xyz
+ );
+ float depth = texelFetch(depth_texture, ivec2(itexture_uv), i).r;
+ #endif
+ #else
+ vec4 pixel = texture(color_texture, In.texture_uv);
+
+ #if SMOOTH
+ vec3 normal = normalize(texture(normal_texture, In.texture_uv).xyz);
+ float depth = texture(depth_texture, In.texture_uv).r;
+ #endif
+ #endif
+
+ if (pixel.a > 0.0)
+ {
+ #if SMOOTH
+ vec4 p_ndc = vec4(
+ 2.0 * (gl_FragCoord.xy - viewport.xy) / (viewport.zw) - 1.0,
+ (2.0 * depth - gl_DepthRange.near - gl_DepthRange.far)
+ / gl_DepthRange.diff, 1.0
+ );
+
+ vec4 v_eye = projection_matrix_inv * p_ndc;
+ v_eye = v_eye / v_eye.w;
+
+ res += vec4(lighting(normal, v_eye.xyz,
+ pixel.rgb / pixel.a, material_shininess), 1.0);
+ #else
+ res += vec4(pixel.rgb / pixel.a, 1.0f);
+ #endif
+ }
+ else
+ {
+ res += vec4(1.0);
+ }
+ }
+
+ #if MULTISAMPLING
+ frag_color = sqrt(res / 4.0);
+ #else
+ frag_color = sqrt(res);
+ #endif
+}
diff --git a/surface_splatting/shader/finalization_vs.glsl b/surface_splatting/shader/finalization_vs.glsl
new file mode 100644
index 0000000..a578197
--- /dev/null
+++ b/surface_splatting/shader/finalization_vs.glsl
@@ -0,0 +1,37 @@
+// This file is part of Surface Splatting.
+//
+// Copyright (C) 2010, 2015 by Sebastian Lipponer.
+//
+// Surface Splatting is free software: you can redistribute it and / or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Surface Splatting is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Surface Splatting. If not, see .
+
+#version 330
+
+#define ATTR_POSITION 0
+layout(location = ATTR_POSITION) in vec3 position;
+
+#define ATTR_TEXTURE_UV 1
+layout(location = ATTR_TEXTURE_UV)
+ in vec2 texture_uv;
+
+out block
+{
+ vec2 texture_uv;
+}
+Out;
+
+void main()
+{
+ gl_Position = vec4(position, 1.0);
+ Out.texture_uv = texture_uv;
+}
diff --git a/surface_splatting/shader/lighting.glsl b/surface_splatting/shader/lighting.glsl
new file mode 100644
index 0000000..bbfcae3
--- /dev/null
+++ b/surface_splatting/shader/lighting.glsl
@@ -0,0 +1,38 @@
+// This file is part of Surface Splatting.
+//
+// Copyright (C) 2010, 2015 by Sebastian Lipponer.
+//
+// Surface Splatting is free software: you can redistribute it and / or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Surface Splatting is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Surface Splatting. If not, see .
+
+#version 330
+
+vec3 lighting(vec3 normal_eye, vec3 v_eye, vec3 color, float shininess)
+{
+ const vec3 light_eye = vec3(0.0, 0.0, 1.0);
+
+ float dif = max(dot(light_eye, normal_eye), 0.0);
+ vec3 refl_eye = reflect(light_eye, normal_eye);
+
+ vec3 view_eye = normalize(v_eye);
+ float spe = pow(clamp(dot(refl_eye, view_eye), 0.0, 1.0),
+ shininess);
+ float rim = pow(1.0 + dot(normal_eye, view_eye), 3.0);
+
+ vec3 res = 0.15 * color;
+ res += 0.6 * dif * color;
+ res += 0.1 * spe * vec3(1.0);
+ res += 0.1 * rim * vec3(1.0);
+
+ return res;
+}
diff --git a/surface_splatting/splat_renderer.cpp b/surface_splatting/splat_renderer.cpp
new file mode 100644
index 0000000..1217e4e
--- /dev/null
+++ b/surface_splatting/splat_renderer.cpp
@@ -0,0 +1,642 @@
+// This file is part of Surface Splatting.
+//
+// Copyright (C) 2010, 2015 by Sebastian Lipponer.
+//
+// Surface Splatting is free software: you can redistribute it and / or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Surface Splatting is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Surface Splatting. If not, see .
+
+#include "splat_renderer.hpp"
+
+#include
+
+#include
+#include
+
+using namespace Eigen;
+
+UniformBufferRaycast::UniformBufferRaycast()
+ : glUniformBuffer(sizeof(Matrix4f) + sizeof(Vector4f))
+{
+}
+
+void
+UniformBufferRaycast::set_buffer_data(Matrix4f const&
+ projection_matrix_inv, GLint const* viewport)
+{
+ float viewportf[4] = {
+ static_cast(viewport[0]),
+ static_cast(viewport[1]),
+ static_cast(viewport[2]),
+ static_cast(viewport[3])
+ };
+
+ bind();
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(Matrix4f),
+ projection_matrix_inv.data());
+ glBufferSubData(GL_UNIFORM_BUFFER, sizeof(Matrix4f),
+ 4 * sizeof(float), viewportf);
+ unbind();
+}
+
+UniformBufferFrustum::UniformBufferFrustum()
+ : glUniformBuffer(6 * sizeof(Vector4f))
+{
+}
+
+void
+UniformBufferFrustum::set_buffer_data(Vector4f const* frustum_plane)
+{
+ bind();
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, 6 * sizeof(Vector4f),
+ static_cast(frustum_plane));
+ unbind();
+}
+
+UniformBufferParameter::UniformBufferParameter()
+ : glUniformBuffer(8 * sizeof(float))
+{
+}
+
+void
+UniformBufferParameter::set_buffer_data(Vector3f const& color, float shininess,
+ float radius_scale, float ewa_radius, float epsilon)
+{
+ bind();
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, 3 * sizeof(float), color.data());
+ glBufferSubData(GL_UNIFORM_BUFFER, 12, sizeof(float), &shininess);
+ glBufferSubData(GL_UNIFORM_BUFFER, 16, sizeof(float), &radius_scale);
+ glBufferSubData(GL_UNIFORM_BUFFER, 20, sizeof(float), &ewa_radius);
+ glBufferSubData(GL_UNIFORM_BUFFER, 24, sizeof(float), &epsilon);
+ unbind();
+}
+
+
+SplatRenderer::SplatRenderer(GLviz::Camera const& camera)
+ : m_camera(camera), m_soft_zbuffer(true), m_smooth(false),
+ m_color_material(true), m_ewa_filter(false), m_multisample(false),
+ m_pointsize_method(0), m_backface_culling(false),
+ m_color(Vector3f(0.0, 0.25f, 1.0f)), m_epsilon(5.0f * 1e-3f),
+ m_shininess(8.0f), m_radius_scale(1.0f), m_ewa_radius(1.0f)
+{
+ m_uniform_camera.bind_buffer_base(0);
+ m_uniform_raycast.bind_buffer_base(1);
+ m_uniform_frustum.bind_buffer_base(2);
+ m_uniform_parameter.bind_buffer_base(3);
+
+ setup_program_objects();
+ setup_filter_kernel();
+ setup_screen_size_quad();
+ setup_vertex_array_buffer_object();
+}
+
+SplatRenderer::~SplatRenderer()
+{
+ glDeleteVertexArrays(1, &m_vao);
+ glDeleteBuffers(1, &m_vbo);
+
+ glDeleteBuffers(1, &m_rect_vertices_vbo);
+ glDeleteBuffers(1, &m_rect_texture_uv_vbo);
+ glDeleteVertexArrays(1, &m_rect_vao);
+
+ glDeleteTextures(1, &m_filter_kernel);
+}
+
+void
+SplatRenderer::setup_program_objects()
+{
+ m_visibility.set_visibility_pass();
+ m_visibility.set_pointsize_method(m_pointsize_method);
+ m_visibility.set_backface_culling(m_backface_culling);
+
+ m_attribute.set_visibility_pass(false);
+ m_attribute.set_pointsize_method(m_pointsize_method);
+ m_attribute.set_backface_culling(m_backface_culling);
+ m_attribute.set_color_material(m_color_material);
+ m_attribute.set_ewa_filter(m_ewa_filter);
+ m_attribute.set_smooth(m_smooth);
+
+ m_finalization.set_multisampling(m_multisample);
+ m_finalization.set_smooth(m_smooth);
+}
+
+inline void
+SplatRenderer::setup_filter_kernel()
+{
+ const float sigma2 = 0.316228f; // Sqrt(0.1).
+
+ GLfloat yi[256];
+ for (unsigned int i = 0; i < 256; ++i)
+ {
+ float x = static_cast(i) / 255.0f;
+ float const w = x * x / (2.0f * sigma2);
+ yi[i] = std::exp(-w);
+ }
+
+ glGenTextures(1, &m_filter_kernel);
+ glBindTexture(GL_TEXTURE_1D, m_filter_kernel);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage1D(GL_TEXTURE_1D, 0, GL_R32F, 256, 0, GL_RED, GL_FLOAT, yi);
+}
+
+inline void
+SplatRenderer::setup_screen_size_quad()
+{
+ float rect_vertices[12] = {
+ 1.0f, 1.0f, 0.0f,
+ 1.0f, -1.0f, 0.0f,
+ -1.0f, 1.0f, 0.0f,
+ -1.0f, -1.0f, 0.0f
+ };
+
+ float rect_texture_uv[8] = {
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 0.0f, 0.0f
+ };
+
+ glGenBuffers(1, &m_rect_vertices_vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, m_rect_vertices_vbo);
+ glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), rect_vertices,
+ GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glGenBuffers(1, &m_rect_texture_uv_vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, m_rect_texture_uv_vbo);
+ glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(float), rect_texture_uv,
+ GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glGenVertexArrays(1, &m_rect_vao);
+ glBindVertexArray(m_rect_vao);
+
+ glBindBuffer(GL_ARRAY_BUFFER, m_rect_vertices_vbo);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
+ 3 * sizeof(float), reinterpret_cast(0));
+
+ glBindBuffer(GL_ARRAY_BUFFER, m_rect_texture_uv_vbo);
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE,
+ 2 * sizeof(float), reinterpret_cast(0));
+
+ glBindVertexArray(0);
+}
+
+void
+SplatRenderer::setup_vertex_array_buffer_object()
+{
+ glGenBuffers(1, &m_vbo);
+
+ glGenVertexArrays(1, &m_vao);
+ glBindVertexArray(m_vao);
+
+ glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
+
+ // Center c.
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
+ sizeof(Surfel), reinterpret_cast(0));
+
+ // Tagent vector u.
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
+ sizeof(Surfel), reinterpret_cast(12));
+
+ // Tangent vector v.
+ glEnableVertexAttribArray(2);
+ glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE,
+ sizeof(Surfel), reinterpret_cast(24));
+
+ // Clipping plane p.
+ glEnableVertexAttribArray(3);
+ glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE,
+ sizeof(Surfel), reinterpret_cast(36));
+
+ // Color rgba.
+ glEnableVertexAttribArray(4);
+ glVertexAttribPointer(4, 4, GL_UNSIGNED_BYTE, GL_TRUE,
+ sizeof(Surfel), reinterpret_cast(48));
+
+ glBindVertexArray(0);
+}
+
+bool
+SplatRenderer::smooth() const
+{
+ return m_smooth;
+}
+
+void
+SplatRenderer::set_smooth(bool enable)
+{
+ if (m_smooth != enable)
+ {
+ m_smooth = enable;
+
+ m_attribute.set_smooth(enable);
+ m_finalization.set_smooth(enable);
+
+ if (m_smooth)
+ {
+ m_fbo.enable_depth_texture();
+ m_fbo.attach_normal_texture();
+ }
+ else
+ {
+ m_fbo.disable_depth_texture();
+ m_fbo.detach_normal_texture();
+ }
+ }
+}
+
+bool
+SplatRenderer::color_material() const
+{
+ return m_color_material;
+}
+
+void
+SplatRenderer::set_color_material(bool enable)
+{
+ if (m_color_material != enable)
+ {
+ m_color_material = enable;
+ m_attribute.set_color_material(enable);
+ }
+}
+
+bool
+SplatRenderer::backface_culling() const
+{
+ return m_backface_culling;
+}
+
+void
+SplatRenderer::set_backface_culling(bool enable)
+{
+ if (m_backface_culling != enable)
+ {
+ m_backface_culling = enable;
+ m_visibility.set_backface_culling(enable);
+ m_attribute.set_backface_culling(enable);
+ }
+}
+
+bool
+SplatRenderer::soft_zbuffer() const
+{
+ return m_soft_zbuffer;
+}
+
+void
+SplatRenderer::set_soft_zbuffer(bool enable)
+{
+ if (m_soft_zbuffer != enable)
+ {
+ if (!enable)
+ {
+ m_ewa_filter = false;
+ m_attribute.set_ewa_filter(false);
+ }
+
+ m_soft_zbuffer = enable;
+ }
+}
+
+float
+SplatRenderer::soft_zbuffer_epsilon() const
+{
+ return m_epsilon;
+}
+
+void
+SplatRenderer::set_soft_zbuffer_epsilon(float epsilon)
+{
+ m_epsilon = epsilon;
+}
+
+unsigned int
+SplatRenderer::pointsize_method() const
+{
+ return m_pointsize_method;
+}
+
+void
+SplatRenderer::set_pointsize_method(unsigned int pointsize_method)
+{
+ if (m_pointsize_method != pointsize_method)
+ {
+ m_pointsize_method = pointsize_method;
+ m_visibility.set_pointsize_method(pointsize_method);
+ m_attribute.set_pointsize_method(pointsize_method);
+ }
+}
+
+bool
+SplatRenderer::ewa_filter() const
+{
+ return m_ewa_filter;
+}
+
+void
+SplatRenderer::set_ewa_filter(bool enable)
+{
+ if (m_soft_zbuffer && m_ewa_filter != enable)
+ {
+ m_ewa_filter = enable;
+ m_attribute.set_ewa_filter(enable);
+ }
+}
+
+bool
+SplatRenderer::multisample() const
+{
+ return m_multisample;
+}
+
+void
+SplatRenderer::set_multisample(bool enable)
+{
+ if (m_multisample != enable)
+ {
+ m_multisample = enable;
+ m_finalization.set_multisampling(enable);
+ m_fbo.set_multisample(enable);
+ }
+}
+
+float const*
+SplatRenderer::material_color() const
+{
+ return m_color.data();
+}
+
+void
+SplatRenderer::set_material_color(float const* color_ptr)
+{
+ Map color(color_ptr);
+ m_color = color;
+}
+
+float
+SplatRenderer::material_shininess() const
+{
+ return m_shininess;
+}
+
+void
+SplatRenderer::set_material_shininess(float shininess)
+{
+ m_shininess = shininess;
+}
+
+float
+SplatRenderer::radius_scale() const
+{
+ return m_radius_scale;
+}
+
+void
+SplatRenderer::set_radius_scale(float radius_scale)
+{
+ m_radius_scale = radius_scale;
+}
+
+float
+SplatRenderer::ewa_radius() const
+{
+ return m_ewa_radius;
+}
+
+void
+SplatRenderer::set_ewa_radius(float ewa_radius)
+{
+ m_ewa_radius = ewa_radius;
+}
+
+void
+SplatRenderer::reshape(int width, int height)
+{
+ m_fbo.reshape(width, height);
+}
+
+void
+SplatRenderer::setup_uniforms(glProgram& program)
+{
+ m_uniform_camera.set_buffer_data(m_camera);
+
+ GLint viewport[4];
+ glGetIntegerv(GL_VIEWPORT, viewport);
+ GLviz::Frustum view_frustum = m_camera.get_frustum();
+
+ m_uniform_raycast.set_buffer_data(
+ m_camera.get_projection_matrix().inverse(),
+ viewport);
+
+ Vector4f frustum_plane[6];
+
+ Matrix4f const& projection_matrix = m_camera.get_projection_matrix();
+ for (unsigned int i(0); i < 6; ++i)
+ {
+ frustum_plane[i] = projection_matrix.row(3) + (-1.0f + 2.0f
+ * static_cast(i % 2)) * projection_matrix.row(i / 2);
+ }
+
+ for (unsigned int i(0); i < 6; ++i)
+ {
+ frustum_plane[i] = (1.0f / frustum_plane[i].block<3, 1>(
+ 0, 0).norm()) * frustum_plane[i];
+ }
+
+ m_uniform_frustum.set_buffer_data(frustum_plane);
+
+ m_uniform_parameter.set_buffer_data(
+ m_color, m_shininess, m_radius_scale, m_ewa_radius, m_epsilon
+ );
+}
+
+void
+SplatRenderer::render_pass(bool depth_only)
+{
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_PROGRAM_POINT_SIZE);
+
+ if (!depth_only && m_soft_zbuffer)
+ {
+ glEnable(GL_BLEND);
+ glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE);
+ }
+
+ glProgram &program = depth_only ? m_visibility : m_attribute;
+
+ program.use();
+
+ if (depth_only)
+ {
+ glDepthMask(GL_TRUE);
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+ }
+ else
+ {
+ if (m_soft_zbuffer)
+ glDepthMask(GL_FALSE);
+ else
+ glDepthMask(GL_TRUE);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ }
+
+ setup_uniforms(program);
+
+ if (!depth_only && m_soft_zbuffer && m_ewa_filter)
+ {
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_1D, m_filter_kernel);
+
+ program.set_uniform_1i("filter_kernel", 1);
+ }
+
+ glBindVertexArray(m_vao);
+ glDrawArrays(GL_POINTS, 0, m_num_pts);
+ glBindVertexArray(0);
+
+ program.unuse();
+
+ glDisable(GL_PROGRAM_POINT_SIZE);
+ glDisable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST);
+}
+
+void
+SplatRenderer::begin_frame()
+{
+ m_fbo.bind();
+
+ glDepthMask(GL_TRUE);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClearDepth(1.0);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+void
+SplatRenderer::end_frame()
+{
+ m_fbo.unbind();
+
+ if (m_multisample)
+ {
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_fbo.color_texture());
+
+ if (m_smooth)
+ {
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_fbo.normal_texture());
+
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_fbo.depth_texture());
+ }
+ }
+ else
+ {
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, m_fbo.color_texture());
+
+ if (m_smooth)
+ {
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, m_fbo.normal_texture());
+
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, m_fbo.depth_texture());
+ }
+ }
+
+ m_finalization.use();
+
+ try
+ {
+ setup_uniforms(m_finalization);
+ m_finalization.set_uniform_1i("color_texture", 0);
+
+ if (m_smooth)
+ {
+ m_finalization.set_uniform_1i("normal_texture", 1);
+ m_finalization.set_uniform_1i("depth_texture", 2);
+ }
+ }
+ catch (uniform_not_found_error const& e)
+ {
+ std::cerr << "Warning: Failed to set a uniform variable." << std::endl
+ << e.what() << std::endl;
+ }
+
+ glBindVertexArray(m_rect_vao);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ glBindVertexArray(0);
+}
+
+void
+SplatRenderer::render_frame(std::vector const& visible_geometry)
+{
+ begin_frame();
+
+ m_num_pts = static_cast(visible_geometry.size());
+
+ if (m_num_pts > 0)
+ {
+ glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
+ glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STATIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(Surfel) * m_num_pts,
+ &visible_geometry.front(), GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ if (m_multisample)
+ {
+ glEnable(GL_MULTISAMPLE);
+ glEnable(GL_SAMPLE_SHADING);
+ glMinSampleShading(4.0);
+ }
+
+ if (m_soft_zbuffer)
+ {
+ render_pass(true);
+ }
+
+ render_pass(false);
+
+ if (m_multisample)
+ {
+ glDisable(GL_MULTISAMPLE);
+ glDisable(GL_SAMPLE_SHADING);
+ }
+ }
+
+ end_frame();
+
+#ifndef NDEBUG
+ GLenum gl_error = glGetError();
+ if (GL_NO_ERROR != gl_error)
+ {
+ std::cerr << __FILE__ << "(" << __LINE__ << "): "
+ << GLviz::get_gl_error_string(gl_error) << std::endl;
+ }
+#endif
+}
diff --git a/surface_splatting/splat_renderer.hpp b/surface_splatting/splat_renderer.hpp
new file mode 100644
index 0000000..e147c8d
--- /dev/null
+++ b/surface_splatting/splat_renderer.hpp
@@ -0,0 +1,161 @@
+// This file is part of Surface Splatting.
+//
+// Copyright (C) 2010, 2015 by Sebastian Lipponer.
+//
+// Surface Splatting is free software: you can redistribute it and / or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Surface Splatting is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Surface Splatting. If not, see .
+
+#ifndef SPLATRENDER_HPP
+#define SPLATRENDER_HPP
+
+#include "program_attribute.hpp"
+#include "program_finalization.hpp"
+
+#include
+
+#include "framebuffer.hpp"
+
+#include
+#include
+#include
+
+struct Surfel
+{
+ Surfel() { }
+
+ Surfel(Eigen::Vector3f c_, Eigen::Vector3f u_, Eigen::Vector3f v_,
+ Eigen::Vector3f p_, unsigned int rgba_)
+ : c(c_), u(u_), v(v_), p(p_), rgba(rgba_) { }
+
+ Eigen::Vector3f c, // Position of the ellipse center point.
+ u, v, // Ellipse major and minor axis.
+ p; // Clipping plane.
+
+ unsigned int rgba; // Color.
+};
+
+class UniformBufferRaycast : public GLviz::glUniformBuffer
+{
+
+public:
+ UniformBufferRaycast();
+
+ void set_buffer_data(Eigen::Matrix4f const& projection_matrix_inv,
+ GLint const* viewport);
+};
+
+class UniformBufferFrustum : public GLviz::glUniformBuffer
+{
+
+public:
+ UniformBufferFrustum();
+
+ void set_buffer_data(Eigen::Vector4f const* frustum_plane);
+};
+
+class UniformBufferParameter : public GLviz::glUniformBuffer
+{
+
+public:
+ UniformBufferParameter();
+
+ void set_buffer_data(Eigen::Vector3f const& color, float shininess,
+ float radius_scale, float ewa_radius, float epsilon);
+};
+
+class SplatRenderer
+{
+
+public:
+ SplatRenderer(GLviz::Camera const& camera);
+ virtual ~SplatRenderer();
+
+ void render_frame(std::vector const& visible_geometry);
+
+ bool smooth() const;
+ void set_smooth(bool enable = true);
+
+ bool color_material() const;
+ void set_color_material(bool enable = true);
+
+ bool backface_culling() const;
+ void set_backface_culling(bool enable = true);
+
+ bool soft_zbuffer() const;
+ void set_soft_zbuffer(bool enable = true);
+
+ float soft_zbuffer_epsilon() const;
+ void set_soft_zbuffer_epsilon(float epsilon);
+
+ unsigned int pointsize_method() const;
+ void set_pointsize_method(unsigned int pointsize_method);
+
+ bool ewa_filter() const;
+ void set_ewa_filter(bool enable = true);
+
+ bool multisample() const;
+ void set_multisample(bool enable = true);
+
+ float const* material_color() const;
+ void set_material_color(float const* color_ptr);
+ float material_shininess() const;
+ void set_material_shininess(float shininess);
+
+ float radius_scale() const;
+ void set_radius_scale(float radius_scale);
+
+ float ewa_radius() const;
+ void set_ewa_radius(float ewa_radius);
+
+ void reshape(int width, int height);
+
+private:
+ void setup_program_objects();
+ void setup_filter_kernel();
+ void setup_screen_size_quad();
+ void setup_vertex_array_buffer_object();
+
+ void setup_uniforms(glProgram& program);
+
+ void begin_frame();
+ void end_frame();
+ void render_pass(bool depth_only = false);
+
+private:
+ GLviz::Camera const& m_camera;
+
+ GLuint m_rect_vertices_vbo, m_rect_texture_uv_vbo,
+ m_rect_vao, m_filter_kernel;
+
+ GLuint m_vbo, m_vao;
+ unsigned int m_num_pts;
+
+ ProgramAttribute m_visibility, m_attribute;
+ ProgramFinalization m_finalization;
+
+ Framebuffer m_fbo;
+
+ bool m_soft_zbuffer, m_backface_culling, m_smooth,
+ m_color_material, m_ewa_filter, m_multisample;
+ unsigned int m_pointsize_method;
+ Eigen::Vector3f m_color;
+ float m_epsilon, m_shininess, m_radius_scale,
+ m_ewa_radius;
+
+ GLviz::UniformBufferCamera m_uniform_camera;
+ UniformBufferRaycast m_uniform_raycast;
+ UniformBufferFrustum m_uniform_frustum;
+ UniformBufferParameter m_uniform_parameter;
+};
+
+#endif // SPLATRENDER_HPP