diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..18ca1b1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/app/assets
\ No newline at end of file
diff --git a/1-build_assets.bat b/1-build_assets.bat
new file mode 100644
index 0000000..753486e
--- /dev/null
+++ b/1-build_assets.bat
@@ -0,0 +1,2 @@
+app\bin\harfang\assetc\assetc.exe app\resources app\assets
+pause
\ No newline at end of file
diff --git a/2-run.bat b/2-run.bat
new file mode 100644
index 0000000..1085022
--- /dev/null
+++ b/2-run.bat
@@ -0,0 +1,3 @@
+cd app
+bin\lua.exe main.lua
+pause
\ No newline at end of file
diff --git a/3-run - python.bat b/3-run - python.bat
new file mode 100644
index 0000000..a02116b
--- /dev/null
+++ b/3-run - python.bat
@@ -0,0 +1,3 @@
+cd app
+python main.py
+pause
\ No newline at end of file
diff --git a/4-run - python vr.bat b/4-run - python vr.bat
new file mode 100644
index 0000000..8bf4854
--- /dev/null
+++ b/4-run - python vr.bat
@@ -0,0 +1,3 @@
+cd app
+python main.py --vr
+pause
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f288702
--- /dev/null
+++ b/LICENSE
@@ -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/app/__pycache__/car.cpython-310.pyc b/app/__pycache__/car.cpython-310.pyc
new file mode 100644
index 0000000..39a0483
Binary files /dev/null and b/app/__pycache__/car.cpython-310.pyc differ
diff --git a/app/__pycache__/car_camera.cpython-310.pyc b/app/__pycache__/car_camera.cpython-310.pyc
new file mode 100644
index 0000000..4d50fff
Binary files /dev/null and b/app/__pycache__/car_camera.cpython-310.pyc differ
diff --git a/app/__pycache__/car_lights.cpython-310.pyc b/app/__pycache__/car_lights.cpython-310.pyc
new file mode 100644
index 0000000..4e6cc43
Binary files /dev/null and b/app/__pycache__/car_lights.cpython-310.pyc differ
diff --git a/app/__pycache__/gui.cpython-310.pyc b/app/__pycache__/gui.cpython-310.pyc
new file mode 100644
index 0000000..7d17913
Binary files /dev/null and b/app/__pycache__/gui.cpython-310.pyc differ
diff --git a/app/__pycache__/utils.cpython-310.pyc b/app/__pycache__/utils.cpython-310.pyc
new file mode 100644
index 0000000..0bcda89
Binary files /dev/null and b/app/__pycache__/utils.cpython-310.pyc differ
diff --git a/app/bin/glfw3.dll b/app/bin/glfw3.dll
new file mode 100644
index 0000000..313dfdb
Binary files /dev/null and b/app/bin/glfw3.dll differ
diff --git a/app/bin/harfang.dll b/app/bin/harfang.dll
new file mode 100644
index 0000000..3ac44ca
Binary files /dev/null and b/app/bin/harfang.dll differ
diff --git a/app/bin/harfang/assetc/assetc.exe b/app/bin/harfang/assetc/assetc.exe
new file mode 100644
index 0000000..d4325d1
Binary files /dev/null and b/app/bin/harfang/assetc/assetc.exe differ
diff --git a/app/bin/harfang/assetc/glfw3.dll b/app/bin/harfang/assetc/glfw3.dll
new file mode 100644
index 0000000..3850ea3
Binary files /dev/null and b/app/bin/harfang/assetc/glfw3.dll differ
diff --git a/app/bin/harfang/assetc/lua54.dll b/app/bin/harfang/assetc/lua54.dll
new file mode 100644
index 0000000..567aeb9
Binary files /dev/null and b/app/bin/harfang/assetc/lua54.dll differ
diff --git a/app/bin/harfang/assetc/openvr_api.dll b/app/bin/harfang/assetc/openvr_api.dll
new file mode 100644
index 0000000..a4ad764
Binary files /dev/null and b/app/bin/harfang/assetc/openvr_api.dll differ
diff --git a/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/bulletc.exe b/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/bulletc.exe
new file mode 100644
index 0000000..2c0b08b
Binary files /dev/null and b/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/bulletc.exe differ
diff --git a/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/cmft.exe b/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/cmft.exe
new file mode 100644
index 0000000..af1ffd4
Binary files /dev/null and b/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/cmft.exe differ
diff --git a/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/luac.exe b/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/luac.exe
new file mode 100644
index 0000000..47a2b6e
Binary files /dev/null and b/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/luac.exe differ
diff --git a/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/recastc.exe b/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/recastc.exe
new file mode 100644
index 0000000..5b7ce27
Binary files /dev/null and b/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/recastc.exe differ
diff --git a/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/shaderc.exe b/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/shaderc.exe
new file mode 100644
index 0000000..5598a6a
Binary files /dev/null and b/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/shaderc.exe differ
diff --git a/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/texconv.exe b/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/texconv.exe
new file mode 100644
index 0000000..75718a4
Binary files /dev/null and b/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/texconv.exe differ
diff --git a/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/texturec.exe b/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/texturec.exe
new file mode 100644
index 0000000..338ad3a
Binary files /dev/null and b/app/bin/harfang/assetc/toolchains/host-windows-x64-target-windows-x64/texturec.exe differ
diff --git a/app/bin/harfang/bin.lua b/app/bin/harfang/bin.lua
new file mode 100644
index 0000000..0cee5c3
--- /dev/null
+++ b/app/bin/harfang/bin.lua
@@ -0,0 +1,30 @@
+hg = require("harfang")
+
+local bin = {}
+local path_sep = package.config:sub(1, 1)
+local here = hg.CutFileName(debug.getinfo(1,'S').source)
+if here:find('@', 1, true) == 1 then
+ here = here:sub(2,-1)
+end
+
+-- [todo] check against a list (like python) ?
+setmetatable(bin,
+ {
+ __index = function(t, name)
+ t[name] = function(...)
+ local path = table.concat({here, name, name}, path_sep)
+ if not hg.Exists(path) then
+ path = path .. '.exe'
+ if not hg.Exists(path) then
+ path = nil
+ end
+ end
+ assert(path, "Unknown tool " .. name)
+ return os.execute(table.concat({path, ...}, ' '))
+ end
+ return rawget(t, name)
+ end
+ }
+)
+
+return bin
diff --git a/app/bin/lua.exe b/app/bin/lua.exe
new file mode 100644
index 0000000..7d6cc03
Binary files /dev/null and b/app/bin/lua.exe differ
diff --git a/app/bin/lua54.dll b/app/bin/lua54.dll
new file mode 100644
index 0000000..fdea500
Binary files /dev/null and b/app/bin/lua54.dll differ
diff --git a/app/bin/openvr_api.dll b/app/bin/openvr_api.dll
new file mode 100644
index 0000000..a4ad764
Binary files /dev/null and b/app/bin/openvr_api.dll differ
diff --git a/app/car.lua b/app/car.lua
new file mode 100644
index 0000000..8f3f682
--- /dev/null
+++ b/app/car.lua
@@ -0,0 +1,223 @@
+hg = require("harfang")
+
+function CreateRCCar(name, instance_node_name, scene, scene_physics, resources, start_position, start_rotation)
+ local o = {}
+ o.start_position = start_position or hg.Vec3(0, 0, 0)
+ o.start_rotation = start_rotation or hg.Vec3(0, 0, 0)
+ o.name = name
+
+ -- Instance_node is not affected by physics.
+ o.instance_node = scene:GetNode(instance_node_name)
+ if not o.instance_node:IsValid() then
+ print("ERROR - Instance node not found !")
+ return
+ end
+ o.instance_node:GetTransform():SetPos(hg.Vec3(0, 0, 0))
+ o.scene_view = o.instance_node:GetInstanceSceneView()
+ o.nodes = o.scene_view:GetNodes(scene)
+ o.chassis_node = o.scene_view:GetNode(scene, "car_body")
+ if not o.chassis_node:IsValid() then
+ print("ERROR - Parent node not found !")
+ return
+ end
+ o.chassis_node:GetTransform():SetPos(o.start_position)
+ o.chassis_node:GetTransform():SetRot(o.start_rotation)
+ o.thrust = o.scene_view:GetNode(scene, "thrust")
+ if not o.thrust:IsValid() then
+ print("ERROR - Thrust node not found !")
+ return
+ end
+ o.wheels = {}
+ for n = 0, 3 do
+ wheel = o.scene_view:GetNode(scene, "wheel_" .. n)
+ if not wheel:IsValid() then
+ print("ERROR - Wheel_"..n.." node not found !")
+ return
+ end
+ table.insert(o.wheels, wheel)
+ end
+
+ o.ray_dir = nil
+ obj = o.wheels[1]:GetObject()
+ f,bounds = obj:GetMinMax(resources)
+ o.wheels_ray = bounds.mx.y
+ o.ray_max_dist = o.wheels_ray + 0.2
+
+ o.wheels_rot_speed = {0, 0, 0, 0}
+ o.ground_hits = {false, false, false, false}
+ o.ground_impacts = {nil, nil, nil, nil}
+
+ -- Constants
+
+ o.mass = 1000
+ o.spring_friction = 2500
+ o.tires_reaction = 25
+ o.tires_adhesion = 1500
+ o.front_angle_max = 45
+ o.thrust_power = 400000 -- Acceleration
+ o.brakes_power = 1000000
+ o.turn_speed = 150
+
+ -- Variables
+
+ o.front_angle = 0
+
+ -- Setup physics
+
+ o.chassis_rigid = scene:CreateRigidBody()
+ o.chassis_rigid:SetType(hg.RBT_Dynamic)
+ o.chassis_node:SetRigidBody(o.chassis_rigid)
+ colbox = scene:CreateCollision()
+ colbox:SetType(hg.CT_Cube)
+ colbox:SetSize(hg.Vec3(1, 0.5, 3))
+ colbox:SetMass(o.mass)
+ colbox:SetLocalTransform(hg.TransformationMat4(hg.Vec3(0, 0, 0), hg.Deg3(0, 0, 0)))
+ o.chassis_node:SetCollision(1,colbox)
+ o.chassis_rigid:SetAngularDamping(0)
+ o.chassis_rigid:SetLinearDamping(0)
+ scene_physics:NodeCreatePhysicsFromAssets(o.chassis_node)
+
+
+ -- Get wheels rays
+
+ o.local_rays = {}
+ for _, wheel in pairs(o.wheels) do
+ table.insert(o.local_rays, wheel:GetTransform():GetPos())
+ end
+
+ return o
+end
+
+function RCCarReset(rccar, scene_physics)
+ scene_physics:NodeResetWorld(rccar.chassis_node, hg.TransformationMat4(rccar.start_position, rccar.start_rotation))
+end
+
+function RCCarTurn(rccar, angle, steering_wheel)
+ rccar.front_angle = math.max(math.min(rccar.front_angle + angle, rccar.front_angle_max), -rccar.front_angle_max)
+ rccar.thrust:GetTransform():SetRot(hg.Deg3(0, rccar.front_angle, 0))
+ steering_wheel_rot = steering_wheel:GetTransform():GetRot()
+ steering_wheel:GetTransform():SetRot(hg.Deg3(steering_wheel_rot.x, 180 - rccar.front_angle * 2, steering_wheel_rot.z))
+end
+
+function RCCarAccelerate(rccar, value, scene_physics)
+ f = 0
+ for i = 1, 2 do
+ if rccar.ground_hits[i] then
+ f = f + 0.5
+ end
+ end
+ pos = hg.GetT(rccar.thrust:GetTransform():GetWorld())
+ dir = hg.GetZ(rccar.thrust:GetTransform():GetWorld())
+ scene_physics:NodeAddImpulse(rccar.chassis_node, dir * f * value * (1/60), pos)
+end
+
+function RCCarBrake(rccar, value, scene_physics)
+ f = 0
+ for i = 1, 4 do
+ if rccar.ground_hits[i] then
+ f = f + 0.25
+ end
+ end
+ v = scene_physics:NodeGetLinearVelocity(rccar.chassis_node)
+ value = value * math.min(hg.Len(v), 1)
+ pos = hg.GetT(rccar.thrust:GetTransform():GetWorld())
+ scene_physics:NodeAddImpulse(rccar.chassis_node,hg.Normalize(v) * (1 / 60) * f * -value, pos)
+end
+
+function RCCarUpdate(rccar, scene, scene_physics, dts)
+ scene_physics:NodeWake(rccar.chassis_node)
+ rccar.ray_dir = hg.Reverse(hg.GetY(rccar.chassis_node:GetTransform():GetWorld()))
+
+ for i = 1, 4 do
+ RCCarUpdateWheel(rccar, scene, scene_physics, i, dts)
+ end
+end
+
+function RCCarUpdateWheel(rccar, scene, scene_physics, id, dts)
+
+ wheel = rccar.wheels[id]
+ mat = rccar.chassis_node:GetTransform():GetWorld() -- Ray position in World space
+ ray_pos = mat * rccar.local_rays[id]
+
+ hit = scene_physics:RaycastFirstHit(scene,ray_pos, rccar.ray_dir * rccar.ray_max_dist + ray_pos)
+ rccar.ground_hits[id] = false
+
+ if hit.t > 0 and hit.t < rccar.ray_max_dist then
+ rccar.ground_impacts[id] = hit
+ hit_distance = hg.Len(rccar.ground_impacts[id].P - ray_pos)
+ if hit_distance <= rccar.ray_max_dist then
+ rccar.ground_hits[id] = true
+ end
+ end
+
+ if rccar.ground_hits[id] then
+
+ v = hg.Reverse(scene_physics:NodeGetPointVelocity(rccar.chassis_node, ray_pos))
+
+ -- Spring bounce
+
+ v_dot_ground_n = hg.Dot(rccar.ground_impacts[id].N, v)
+ if v_dot_ground_n > 0 then
+ v_bounce = rccar.ground_impacts[id].N * v_dot_ground_n
+ scene_physics:NodeAddImpulse(rccar.chassis_node,v_bounce * rccar.spring_friction * dts, ray_pos)
+ end
+
+ -- Tire/Ground reaction
+
+ wheel_reaction = math.sqrt(rccar.ray_max_dist - hit_distance) * rccar.tires_reaction
+ scene_physics:NodeAddForce(rccar.chassis_node, rccar.ground_impacts[id].N * wheel_reaction * rccar.mass / 4, ray_pos)
+
+ -- Wheel lateral friction
+
+ x_axis = hg.GetX(wheel:GetTransform():GetWorld())
+ proj = hg.Dot(x_axis, v)
+ v_lat = x_axis * proj
+ scene_physics:NodeAddImpulse(rccar.chassis_node, v_lat * rccar.tires_adhesion * dts, ray_pos)
+
+ -- Adjust wheel on the ground
+
+ wheel_p = wheel:GetTransform():GetPos()
+ wheel_p.y = rccar.local_rays[id].y - hit_distance + rccar.wheels_ray
+ wheel:GetTransform():SetPos(wheel_p)
+
+ -- Wheel rotation
+
+ z_axis = hg.Normalize(hg.Cross(x_axis, rccar.ray_dir))
+ vlin = hg.Dot(z_axis, v) -- Linear speed (along Z axis)
+ rccar.wheels_rot_speed[id] = (vlin / rccar.wheels_ray)
+ else
+ rccar.wheels_rot_speed[id] = rccar.wheels_rot_speed[id] * 0.95 -- Wheel slow-down
+ end
+
+ rot = wheel:GetTransform():GetRot()
+ rot.x = rot.x + rccar.wheels_rot_speed[id] * dts
+ if id == 1 or id == 2 then
+ rot.y = hg.Deg(rccar.front_angle)
+ end
+ wheel:GetTransform():SetRot(rot)
+end
+
+function RCCarGetParentNode(rccar)
+ return rccar.chassis_node
+end
+
+function RCCarControl(rccar, scene_physics, kb, dts, steering_wheel)
+ if kb:Down(hg.K_Up) then
+ RCCarAccelerate(rccar, rccar.thrust_power * dts, scene_physics)
+ end
+ if kb:Down(hg.K_Down) then
+ RCCarAccelerate(rccar, -rccar.thrust_power * dts, scene_physics)
+ end
+ if kb:Down(hg.K_Space) then
+ RCCarBrake(rccar, rccar.brakes_power * dts, scene_physics)
+ end
+ if kb:Down(hg.K_Left) then
+ RCCarTurn(rccar, -rccar.turn_speed * dts, steering_wheel)
+ end
+ if kb:Down(hg.K_Right) then
+ RCCarTurn(rccar, rccar.turn_speed * dts, steering_wheel)
+ end
+ if kb:Pressed(hg.K_Backspace) then
+ RCCarReset(rccar, scene_physics)
+ end
+end
\ No newline at end of file
diff --git a/app/car.py b/app/car.py
new file mode 100644
index 0000000..dbaec4c
--- /dev/null
+++ b/app/car.py
@@ -0,0 +1,252 @@
+import harfang as hg
+from math import sqrt
+from utils import range_adjust, metersPerSecondToKMH
+
+def CreateRCCar(name, instance_node_name, scene, scene_physics, resources, start_position, start_rotation):
+ o = {}
+ o['start_position'] = start_position
+ o['start_rotation'] = start_rotation
+ o['name'] = name
+
+ # Instance_node is not affected by physics.
+ o['instance_node'] = scene.GetNode(instance_node_name)
+ if not o['instance_node'].IsValid():
+ print("ERROR - Instance node not found !")
+ return
+
+ o['instance_node'].GetTransform().SetPos(hg.Vec3(0, 0, 0))
+ o['scene_view'] = o['instance_node'].GetInstanceSceneView()
+ o['nodes'] = o['scene_view'].GetNodes(scene)
+ o['chassis_node'] = o['scene_view'].GetNode(scene, "car_body")
+ if not o['chassis_node'].IsValid():
+ print("ERROR - Parent node not found !")
+ return
+
+ o['chassis_node'].GetTransform().SetPos(o['start_position'])
+ o['chassis_node'].GetTransform().SetRot(o['start_rotation'])
+ o['thrust'] = o['scene_view'].GetNode(scene, "thrust")
+ if not o['thrust'].IsValid():
+ print("ERROR - Thrust node not found !")
+ return
+
+ o['wheels'] = []
+ for n in range(4):
+ wheel = o['scene_view'].GetNode(scene, "wheel_" + str(n))
+ if not wheel.IsValid():
+ print("ERROR - Wheel_" + str(n) + " node not found !")
+ return
+ o['wheels'].append(wheel)
+
+ o['ray_dir'] = None
+ obj = o['wheels'][1].GetObject()
+ f, bounds = obj.GetMinMax(resources)
+ o['wheels_ray'] = bounds.mx.y
+ o['ray_max_dist'] = o['wheels_ray'] + 0.2
+
+ o['wheels_rot_speed'] = [0, 0, 0, 0]
+ o['ground_hits'] = [False, False, False, False]
+ o['ground_impacts'] = [None, None, None, None]
+
+ # Constants
+
+ o['mass'] = 1000
+ o['spring_friction'] = 2500
+ o['tires_reaction'] = 25
+ o['tires_adhesion'] = 1500
+ o['front_angle_max'] = 45
+ o['thrust_power'] = 400000 # Acceleration
+ o['brakes_power'] = 1000000
+ o['turn_speed'] = 150
+ o['max_speed'] = 1300
+
+ # Variables
+
+ o['front_angle'] = 0
+
+ # Setup physics
+
+ # o['chassis_rigid'] = scene.CreateRigidBody()
+ # o['chassis_rigid'].SetType(hg.RBT_Dynamic)
+ # o['chassis_node'].SetRigidBody(o['chassis_rigid'])
+ # colbox = scene.CreateCollision()
+ # colbox.SetType(hg.CT_Cube)
+ # colbox.SetSize(hg.Vec3(1, 0.5, 3))
+ # colbox.SetMass(o['mass'])
+ # colbox.SetLocalTransform(hg.TransformationMat4(
+ # hg.Vec3(0, 0, 0), hg.Deg3(0, 0, 0)))
+ # o['chassis_node'].SetCollision(1, colbox)
+ # o['chassis_rigid'].SetAngularDamping(0)
+ # o['chassis_rigid'].SetLinearDamping(0)
+ # scene_physics.NodeCreatePhysicsFromAssets(o['chassis_node'])
+
+ # Get wheels rays
+
+ o['local_rays'] = []
+ for wheel in o['wheels']:
+ o['local_rays'].append(wheel.GetTransform().GetPos())
+
+ return o
+
+
+def RCCarReset(rccar, scene_physics):
+ scene_physics.NodeResetWorld(rccar['chassis_node'], hg.TransformationMat4(
+ rccar['start_position'], rccar['start_rotation']))
+
+
+def RCCarSteering(rccar, angle, steering_wheel):
+ if angle > 0.01:
+ rccar['front_angle'] = range_adjust(angle, 0.3, 1, 0, rccar['front_angle_max'])
+ rccar['thrust'].GetTransform().SetRot(
+ hg.Deg3(0, rccar['front_angle'], 0))
+ steering_wheel_rot = steering_wheel.GetTransform().GetRot()
+ steering_wheel.GetTransform().SetRot(hg.Deg3(steering_wheel_rot.x, 180 -
+ rccar['front_angle'] * 3, steering_wheel_rot.z))
+ elif angle < -0.01:
+ rccar['front_angle'] = range_adjust(angle, -0.3, -1, 0, -rccar['front_angle_max'])
+ rccar['thrust'].GetTransform().SetRot(
+ hg.Deg3(0, rccar['front_angle'], 0))
+ steering_wheel_rot = steering_wheel.GetTransform().GetRot()
+ steering_wheel.GetTransform().SetRot(hg.Deg3(steering_wheel_rot.x, 180 -
+ rccar['front_angle'] * 3, steering_wheel_rot.z))
+
+
+def RCCarAccelerate(rccar, value, scene_physics):
+ f = 0
+ for i in range(2):
+ if rccar['ground_hits'][i]:
+ f = f + 0.5
+
+ pos = hg.GetT(rccar['thrust'].GetTransform().GetWorld())
+ dir = hg.GetZ(rccar['thrust'].GetTransform().GetWorld())
+ v = scene_physics.NodeGetLinearVelocity(rccar['chassis_node'])
+ v_kmh = metersPerSecondToKMH(hg.Len(v))
+ if v_kmh > (0.9 * rccar['max_speed']):
+ adjusted_accel = range_adjust(v_kmh, 0.9 * rccar['max_speed'], rccar['max_speed'], 1, 0)
+ scene_physics.NodeAddImpulse(
+ rccar['chassis_node'], dir * f * value * (1/60) * adjusted_accel, pos)
+ else:
+ scene_physics.NodeAddImpulse(
+ rccar['chassis_node'], dir * f * value * (1/60), pos)
+
+
+def RCCarBrake(rccar, value, scene_physics):
+ f = 0
+ for i in range(4):
+ if rccar['ground_hits'][i]:
+ f = f + 0.25
+
+ v = scene_physics.NodeGetLinearVelocity(rccar['chassis_node'])
+ value = value * min(hg.Len(v), 1)
+ pos = hg.GetT(rccar['thrust'].GetTransform().GetWorld())
+ scene_physics.NodeAddImpulse(
+ rccar['chassis_node'], hg.Normalize(v) * (1 / 60) * f * -value, pos)
+
+
+def RCCarUpdate(rccar, scene, scene_physics, dts):
+ scene_physics.NodeWake(rccar['chassis_node'])
+ rccar['ray_dir'] = hg.Reverse(
+ hg.GetY(rccar['chassis_node'].GetTransform().GetWorld()))
+
+ for i in range(4):
+ RCCarUpdateWheel(rccar, scene, scene_physics, i, dts)
+
+ car_velocity = scene_physics.NodeGetLinearVelocity(rccar['chassis_node'])
+ car_world = rccar['chassis_node'].GetTransform().GetWorld()
+ car_pos = hg.GetT(car_world)
+ car_lines = [[car_pos + hg.GetX(car_world) * 2, car_pos - hg.GetX(car_world) * 2, hg.Color.Red], [car_pos + hg.GetY(car_world) * 2, car_pos - hg.GetY(car_world) * 2, hg.Color.Green], [car_pos + hg.GetZ(car_world) * 2, car_pos - hg.GetZ(car_world) * 2, hg.Color.Blue]]
+
+ return car_velocity, car_pos, car_lines
+
+
+def RCCarUpdateWheel(rccar, scene, scene_physics, id, dts):
+
+ wheel = rccar['wheels'][id]
+ mat = rccar['chassis_node'].GetTransform(
+ ).GetWorld() # Ray position in World space
+ ray_pos = mat * rccar['local_rays'][id]
+
+ hit = scene_physics.RaycastFirstHit(
+ scene, ray_pos, rccar['ray_dir'] * rccar['ray_max_dist'] + ray_pos)
+ rccar['ground_hits'][id] = False
+
+ if hit.t > 0 and hit.t < rccar['ray_max_dist']:
+ rccar['ground_impacts'][id] = hit
+ hit_distance = hg.Len(rccar['ground_impacts'][id].P - ray_pos)
+ if hit_distance <= rccar['ray_max_dist']:
+ rccar['ground_hits'][id] = True
+
+ if rccar['ground_hits'][id]:
+
+ v = hg.Reverse(scene_physics.NodeGetPointVelocity(
+ rccar['chassis_node'], ray_pos))
+
+ # Spring bounce
+
+ v_dot_ground_n = hg.Dot(rccar['ground_impacts'][id].N, v)
+ if v_dot_ground_n > 0:
+ v_bounce = rccar['ground_impacts'][id].N * v_dot_ground_n
+ scene_physics.NodeAddImpulse(
+ rccar['chassis_node'], v_bounce * rccar['spring_friction'] * dts, ray_pos)
+
+ # Tire/Ground reaction
+
+ wheel_reaction = sqrt(
+ rccar['ray_max_dist'] - hit_distance) * rccar['tires_reaction']
+ scene_physics.NodeAddForce(
+ rccar['chassis_node'], rccar['ground_impacts'][id].N * wheel_reaction * rccar['mass'] / 4, ray_pos)
+
+ # Wheel lateral friction
+
+ x_axis = hg.GetX(wheel.GetTransform().GetWorld())
+ proj = hg.Dot(x_axis, v)
+ v_lat = x_axis * proj
+ scene_physics.NodeAddImpulse(
+ rccar['chassis_node'], v_lat * rccar['tires_adhesion'] * dts, ray_pos)
+
+ # Adjust wheel on the ground
+
+ wheel_p = wheel.GetTransform().GetPos()
+ wheel_p.y = rccar['local_rays'][id].y - \
+ hit_distance + rccar['wheels_ray']
+ wheel.GetTransform().SetPos(wheel_p)
+
+ # Wheel rotation
+
+ z_axis = hg.Normalize(hg.Cross(x_axis, rccar['ray_dir']))
+ vlin = hg.Dot(z_axis, v) # Linear speed (along Z axis)
+ rccar['wheels_rot_speed'][id] = (vlin / rccar['wheels_ray'])
+ else:
+ rccar['wheels_rot_speed'][id] = rccar['wheels_rot_speed'][id] * \
+ 0.95 # Wheel slow-down
+
+ rot = wheel.GetTransform().GetRot()
+ rot.x = rot.x + rccar['wheels_rot_speed'][id] * dts
+ if id == 0 or id == 1:
+ rot.y = hg.Deg(rccar['front_angle'])
+
+ wheel.GetTransform().SetRot(rot)
+
+
+def RCCarGetParentNode(rccar):
+ return rccar['chassis_node']
+
+
+def RCCarControl(rccar, scene_physics, kb, dts, steering_wheel, joystick):
+ brake = reverse = False
+ if joystick.Down(7) or kb.Down(hg.K_Up):
+ RCCarAccelerate(rccar, rccar['thrust_power'] * dts, scene_physics)
+
+ if kb.Down(hg.K_Down):
+ RCCarAccelerate(rccar, -rccar['thrust_power'] * dts, scene_physics)
+ reverse = True
+
+ if joystick.Down(6) or kb.Down(hg.K_Space):
+ RCCarBrake(rccar, rccar['brakes_power'] * dts, scene_physics)
+ brake = True
+
+ RCCarSteering(rccar, joystick.Axes(0), steering_wheel)
+
+ if kb.Pressed(hg.K_Backspace):
+ RCCarReset(rccar, scene_physics)
+
+ return brake, reverse
diff --git a/app/car_camera.py b/app/car_camera.py
new file mode 100644
index 0000000..47d4abc
--- /dev/null
+++ b/app/car_camera.py
@@ -0,0 +1,49 @@
+import harfang as hg
+from utils import *
+
+def CarCameraCreate(instance_node_name, scene):
+ o = {}
+ o['instance_node'] = scene.GetNode(instance_node_name)
+ if not o['instance_node'].IsValid():
+ print("!CarCameraCreate(): Instance node '" + instance_node_name + "' not found!")
+ return
+
+ o['scene_view'] = o['instance_node'].GetInstanceSceneView()
+ o['nodes'] = o['scene_view'].GetNodes(scene)
+ o['root_node'] = o['scene_view'].GetNode(scene, "car_body")
+ if not o['root_node'].IsValid():
+ print("!CarCameraCreate(): Parent node not found !")
+ return
+
+ o['camera_list'] = []
+ for camera_name in {"camera_interior", "camera_exterior_rear"}:
+ _n = o['scene_view'].GetNode(scene, camera_name)
+ _f = hg.Normalize(hg.GetZ(_n.GetTransform().GetWorld()))
+ _p = _n.GetTransform().GetPos()
+ # table.insert(o.camera_list, {node = _n, trs = _n:GetTransform(), vec_front = _f, pos = _p})
+ o['camera_list'].append({'node' : _n, 'trs' : _n.GetTransform(), 'vec_front' : _f, 'pos' : _p})
+
+ o['current_camera'] = 0
+
+ return o
+
+def CarCameraUpdate(o, scene, kb, dt, car_velocity, render_mode):
+ updated = False
+ if kb.Pressed(hg.K_C):
+ o['current_camera'] = o['current_camera'] + 1
+ if o['current_camera'] == len(o['camera_list']):
+ o['current_camera'] = 0
+ scene.SetCurrentCamera(o['camera_list'][o['current_camera']]['node'])
+ updated = True
+
+
+ # simulate head inertia
+ if render_mode == "normal":
+ _p = o['camera_list'][o['current_camera']]['pos']
+ _f = clamp(Map(hg.Len(car_velocity), -20.0, 20.0, 0.0, 1.0), 0.0, 1.0)
+ _f = EaseInOutQuick(_f)
+ _f = Map(_f, 0.0, 1.0, -0.1, 0.1)
+ _p = _p + o['camera_list'][o['current_camera']]['vec_front'] * _f
+ o['camera_list'][o['current_camera']]['trs'].SetPos(_p)
+ # return current camera node
+ return o['camera_list'][o['current_camera']]['node'], updated
diff --git a/app/car_lights.py b/app/car_lights.py
new file mode 100644
index 0000000..d942173
--- /dev/null
+++ b/app/car_lights.py
@@ -0,0 +1,36 @@
+def CarLightsCreate(instance_node_name, scene):
+ o = {}
+ o['instance_node'] = scene.GetNode(instance_node_name)
+ if not o['instance_node'].IsValid():
+ print("!CarLightsCreate(): Instance node '" + instance_node_name + "' not found!")
+ return
+
+ # carlights
+ # carlight_reverse, carlight_head_light, carlight_day_light, carlight_brake, carlight_backLight, carlight_turn_left, carlight_turn_right
+
+ scene_view = o['instance_node'].GetInstanceSceneView()
+ root_node = scene_view.GetNode(scene, "carlights")
+ if not root_node.IsValid():
+ print("!CarLightsCreate(): Carlights node not found !")
+ return
+
+ o['car_view'] = root_node.GetInstanceSceneView()
+ o['carlight_list'] = {}
+ for carlight_name in {"reverse", "head_light", "day_light", "brake", "backLight", "turn_left", "turn_right"}:
+ _n = o['car_view'].GetNode(scene, "carlight_" + carlight_name)
+ o['carlight_list']["carlight_" + carlight_name] = {'node' : _n, 'enabled' : False}
+ _n.Disable()
+ return o
+
+def CarLightsSetBrake(o, state):
+ o['carlight_list']['carlight_brake']['enabled'] = state
+
+def CarLightsSetReverse(o, state):
+ o['carlight_list']['carlight_reverse']['enabled'] = state
+
+def CarLightsUpdate(o, scene, dt):
+ for carlight_name in o['carlight_list']:
+ if o['carlight_list'][carlight_name]['enabled']:
+ o['carlight_list'][carlight_name]['node'].Enable()
+ else:
+ o['carlight_list'][carlight_name]['node'].Disable()
\ No newline at end of file
diff --git a/app/gui.py b/app/gui.py
new file mode 100644
index 0000000..7a846e1
--- /dev/null
+++ b/app/gui.py
@@ -0,0 +1,23 @@
+import harfang as hg
+from utils import metersPerSecondToKMH
+
+def draw_gui(res_x, res_y, dt, dts, car_vel, vid, debug_physic, car_pos, debug_car):
+ hg.ImGuiBeginFrame(res_x, res_y, dt, hg.ReadMouse(), hg.ReadKeyboard())
+ hg.ImGuiBegin("Debug", True, hg.ImGuiWindowFlags_NoMove | hg.ImGuiWindowFlags_NoResize)
+ hg.ImGuiSetWindowSize("Debug", hg.Vec2(350, 150), hg.ImGuiCond_Once)
+ hg.ImGuiText("dt = " + str(round(dts, 4)))
+ hg.ImGuiText("speed = " + str(round(metersPerSecondToKMH(hg.Len(car_vel)))) + " km/h")
+ hg.ImGuiText("car position = Vec3(" + str(round(car_pos.x, 4)) + ", " + str(round(car_pos.y, 4)) + ", " + str(round(car_pos.z, 4)) + ")")
+ was_clicked, debug_physic = hg.ImGuiCheckbox('Physic Debug', debug_physic)
+ was_clicked, debug_car = hg.ImGuiCheckbox('Car Debug', debug_car)
+
+ hg.ImGuiEnd()
+ hg.ImGuiEndFrame(vid)
+
+ return debug_physic, debug_car
+
+def draw_line(pos_a, pos_b, line_color, vid, vtx_line_layout, line_shader):
+ vtx = hg.Vertices(vtx_line_layout, 2)
+ vtx.Begin(0).SetPos(pos_a).SetColor0(line_color).End()
+ vtx.Begin(1).SetPos(pos_b).SetColor0(line_color).End()
+ hg.DrawLines(vid, vtx, line_shader)
diff --git a/app/main.lua b/app/main.lua
new file mode 100644
index 0000000..ebd77c6
--- /dev/null
+++ b/app/main.lua
@@ -0,0 +1,115 @@
+-- HARFANG® 3D - www.harfang3d.com - Raycast Car demo sample
+
+hg = require("harfang")
+rcar = require("car")
+
+-- HARFANG3D inits
+
+hg.InputInit()
+hg.WindowSystemInit()
+
+res_x, res_y = 1280, 720
+win = hg.RenderInit('Raycast car', res_x, res_y, hg.RF_VSync | hg.RF_MSAA4X)
+
+pipeline = hg.CreateForwardPipeline()
+res = hg.PipelineResources()
+
+hg.AddAssetsFolder("assets")
+
+-- Display physics debug lines
+
+vtx_lines = hg.VertexLayout()
+vtx_lines:Begin()
+vtx_lines:Add(hg.A_Position, 3, hg.AT_Float)
+vtx_lines:Add(hg.A_Color0, 3, hg.AT_Float)
+vtx_lines:End()
+lines_program = hg.LoadProgramFromAssets("shaders/pos_rgb")
+
+-- Load scene
+
+scene = hg.Scene()
+hg.LoadSceneFromAssets("main.scn", scene, res, hg.GetForwardPipelineInfo())
+-- cam = scene:GetNode("CameraInterior")
+cam = scene:GetNode("Camera")
+scene:SetCurrentCamera(cam)
+steering_wheel = scene:GetNode("steering_wheel")
+
+-- Ground
+
+vs_decl= hg.VertexLayoutPosFloatNormUInt8()
+cube_mdl = hg.CreateCubeModel(vs_decl, 10, 10, 10)
+cube_ref = res:AddModel('cube', cube_mdl)
+ground_mdl = hg.CreateCubeModel(vs_decl, 100, 0.01, 100)
+ground_ref = res:AddModel('ground', ground_mdl)
+prg_ref = hg.LoadPipelineProgramRefFromAssets('core/shader/pbr.hps', res, hg.GetForwardPipelineInfo())
+
+function create_material(ubc, orm)
+ mat = hg.Material()
+ hg.SetMaterialProgram(mat, prg_ref)
+ hg.SetMaterialValue(mat, "uBaseOpacityColor", ubc)
+ hg.SetMaterialValue(mat, "uOcclusionRoughnessMetalnessColor", orm)
+ return mat
+end
+
+mat_ground = create_material(hg.Vec4(22/255, 42/255, 42/255, 1),hg.Vec4(1, 1, 0, 1))
+
+cube_node = hg.CreatePhysicCube(scene, hg.Vec3(10,10,10), hg.TransformationMat4(hg.Vec3(0, -2.5, -10),hg.Deg3(30, 0, 10)), cube_ref, {mat_ground}, 0)
+ground_node = hg.CreatePhysicCube(scene, hg.Vec3(100, 0.01, 100), hg.TranslationMat4(hg.Vec3(0, -0.005, 0)), ground_ref, {mat_ground}, 0)
+
+cube_node:GetRigidBody():SetType(hg.RBT_Kinematic)
+ground_node:GetRigidBody():SetType(hg.RBT_Kinematic)
+
+-- Scene physics
+
+clocks = hg.SceneClocks()
+physics = hg.SceneBullet3Physics()
+car = CreateRCCar("Kubolid", "car", scene, physics, res, hg.Vec3(0, 1.5, 0))
+physics:SceneCreatePhysicsFromAssets(scene)
+
+-- Inputs
+
+keyboard = hg.Keyboard()
+mouse = hg.Mouse()
+hg.ResetClock()
+
+-- Main loop
+
+while not keyboard:Pressed(hg.K_Escape) do
+
+ keyboard:Update()
+ mouse:Update()
+
+ dt = hg.TickClock()
+ dts = hg.time_to_sec_f(dt)
+
+ -- Car updates
+
+ RCCarControl(car, physics, keyboard, dts, steering_wheel)
+ RCCarUpdate(car, scene, physics, dts)
+
+ -- Scene updates
+
+ hg.SceneUpdateSystems(scene, clocks, dt, physics, hg.time_from_sec_f(1/60), 3)
+ vid, passId = hg.SubmitSceneToPipeline(0, scene, hg.IntRect(0, 0, res_x, res_y), true, pipeline, res)
+
+ -- Debug physics
+
+ hg.SetViewClear(vid, 0, 0, 1.0, 0)
+ hg.SetViewRect(vid, 0, 0, res_x, res_y)
+ cam_mat = cam:GetTransform():GetWorld()
+ view_matrix = hg.InverseFast(cam_mat)
+ c = cam:GetCamera()
+ projection_matrix = hg.ComputePerspectiveProjectionMatrix(c:GetZNear(), c:GetZFar(), hg.FovToZoomFactor(c:GetFov()), hg.Vec2(res_x / res_y, 1))
+ hg.SetViewTransform(vid, view_matrix, projection_matrix)
+ rs = hg.ComputeRenderState(hg.BM_Opaque, hg.DT_Disabled, hg.FC_Disabled)
+ physics:RenderCollision(vid, vtx_lines, lines_program, rs, 0)
+
+ -- EoF
+
+ hg.Frame()
+ hg.UpdateWindow(win)
+
+end
+
+hg.RenderShutdown()
+hg.DestroyWindow(win)
diff --git a/app/main.py b/app/main.py
new file mode 100644
index 0000000..6487319
--- /dev/null
+++ b/app/main.py
@@ -0,0 +1,260 @@
+# HARFANG® 3D - www.harfang3d.com - Raycast Car demo sample
+import harfang as hg
+from car import *
+from car_camera import *
+from car_lights import *
+from gui import *
+import sys
+
+render_mode = "normal"
+if len(sys.argv) > 1:
+ render_mode = "vr" if sys.argv[1] == "--vr" else "normal"
+
+# HARFANG3D inits
+
+hg.InputInit()
+hg.WindowSystemInit()
+
+
+
+
+res_x, res_y = 1900, 1000
+win = hg.RenderInit('Raycast car', res_x, res_y, hg.RF_VSync | hg.RF_MSAA4X)
+
+pipeline = hg.CreateForwardPipeline()
+res = hg.PipelineResources()
+
+render_data = hg.SceneForwardPipelineRenderData() # this object is used by the low-level scene rendering API to share view-independent data with both eyes
+
+# OpenVR initialization
+if render_mode == "vr":
+ if not hg.OpenVRInit():
+ sys.exit()
+
+vr_left_fb = hg.OpenVRCreateEyeFrameBuffer(hg.OVRAA_MSAA4x)
+vr_right_fb = hg.OpenVRCreateEyeFrameBuffer(hg.OVRAA_MSAA4x)
+
+hg.AddAssetsFolder("assets")
+
+# ImGUI
+
+if render_mode == "normal":
+ imgui_prg = hg.LoadProgramFromAssets('core/shader/imgui')
+ imgui_img_prg = hg.LoadProgramFromAssets('core/shader/imgui_image')
+
+ hg.ImGuiInit(10, imgui_prg, imgui_img_prg)
+
+# Display physics debug lines
+
+vtx_lines = hg.VertexLayout()
+vtx_lines.Begin()
+vtx_lines.Add(hg.A_Position, 3, hg.AT_Float)
+vtx_lines.Add(hg.A_Color0, 3, hg.AT_Float)
+vtx_lines.End()
+vtx_line_layout = hg.VertexLayoutPosFloatColorUInt8()
+lines_program = hg.LoadProgramFromAssets("shaders/pos_rgb")
+
+# Load scene
+
+scene = hg.Scene()
+hg.LoadSceneFromAssets("main.scn", scene, res, hg.GetForwardPipelineInfo())
+
+# Ground
+
+vs_decl= hg.VertexLayoutPosFloatNormUInt8()
+cube_mdl = hg.CreateCubeModel(vs_decl, 10, 10, 10)
+cube_ref = res.AddModel('cube', cube_mdl)
+ground_mdl = hg.CreateCubeModel(vs_decl, 150, 0.01, 150)
+ground_ref = res.AddModel('ground', ground_mdl)
+prg_ref = hg.LoadPipelineProgramRefFromAssets('core/shader/pbr.hps', res, hg.GetForwardPipelineInfo())
+
+def create_material(ubc, orm):
+ mat = hg.Material()
+ hg.SetMaterialProgram(mat, prg_ref)
+ hg.SetMaterialValue(mat, "uBaseOpacityColor", ubc)
+ hg.SetMaterialValue(mat, "uOcclusionRoughnessMetalnessColor", orm)
+ return mat
+
+
+mat_ground = create_material(hg.Vec4(22/255, 42/255, 42/255, 1),hg.Vec4(1, 1, 0, 1))
+
+# cube_node = hg.CreatePhysicCube(scene, hg.Vec3(10,10,10), hg.TransformationMat4(hg.Vec3(0, -2.5, -10),hg.Deg3(30, 0, 10)), cube_ref, [mat_ground], 0)
+# ground_node = hg.CreatePhysicCube(scene, hg.Vec3(150, 0.01, 150), hg.TranslationMat4(hg.Vec3(0, -0.005, 50)), ground_ref, [mat_ground], 0)
+
+# cube_node.GetRigidBody().SetType(hg.RBT_Kinematic)
+# ground_node.GetRigidBody().SetType(hg.RBT_Kinematic)
+
+# Scene physics
+
+clocks = hg.SceneClocks()
+physics = hg.SceneBullet3Physics()
+car = CreateRCCar("Generic Car", "car", scene, physics, res, hg.Vec3(-10, 1.5, 0), hg.Vec3(0, 0, 0))
+carlights = CarLightsCreate("car", scene)
+physics.SceneCreatePhysicsFromAssets(scene)
+
+# Setup 2D rendering to display eyes textures
+quad_layout = hg.VertexLayout()
+quad_layout.Begin().Add(hg.A_Position, 3, hg.AT_Float).Add(hg.A_TexCoord0, 3, hg.AT_Float).End()
+
+quad_model = hg.CreatePlaneModel(quad_layout, 1, 1, 1, 1)
+quad_render_state = hg.ComputeRenderState(hg.BM_Alpha, hg.DT_Disabled, hg.FC_Disabled)
+
+eye_t_size = res_x / 2.5
+eye_t_x = (res_x - 2 * eye_t_size) / 6 + eye_t_size / 2
+quad_matrix = hg.TransformationMat4(hg.Vec3(0, 0, 0), hg.Vec3(hg.Deg(90), hg.Deg(0), hg.Deg(0)), hg.Vec3(eye_t_size, 1, eye_t_size))
+
+tex0_program = hg.LoadProgramFromAssets("shaders/sprite")
+
+quad_uniform_set_value_list = hg.UniformSetValueList()
+quad_uniform_set_value_list.clear()
+quad_uniform_set_value_list.push_back(hg.MakeUniformSetValue("color", hg.Vec4(1, 1, 1, 1)))
+
+quad_uniform_set_texture_list = hg.UniformSetTextureList()
+
+
+# Car camera
+
+car_camera = CarCameraCreate("car", scene)
+steering_wheel = scene.GetNode("steering_wheel")
+default_camera = scene.GetNode("Camera")
+# Inputs
+
+keyboard = hg.Keyboard()
+mouse = hg.Mouse()
+joystick = hg.Joystick()
+hg.ResetClock()
+
+# Main loop
+
+vr_state = None
+initial_head_matrix = hg.TransformationMat4(hg.Vec3(0, 0, 0), hg.Vec3(0, 0, 0))
+vr_calibrated = False
+physics_debug = False
+car_debug = False
+
+highway_turn_node = scene.GetNode("block_highway_turn_in")
+mesh_col = scene.CreateCollision()
+mesh_col.SetType(hg.CT_Mesh)
+mesh_col.SetCollisionResource("road_blocks/block_highway_turn_in/block_highway_turn_in_42.physics_bullet")
+mesh_col.SetMass(0)
+highway_turn_node.SetCollision(0, mesh_col)
+# create rigid body
+rb = scene.CreateRigidBody()
+rb.SetType(hg.RBT_Static)
+rb.SetFriction(0.498)
+rb.SetRollingFriction(0)
+highway_turn_node.SetRigidBody(rb)
+physics.NodeCreatePhysicsFromAssets(highway_turn_node)
+
+while not keyboard.Pressed(hg.K_Escape):
+
+ keyboard.Update()
+ mouse.Update()
+ joystick.Update()
+
+ # for i in range(joystick.ButtonsCount()):
+ # if joystick.Down(i):
+ # print(i)
+
+ # for i in range(joystick.AxesCount()):
+ # print(joystick.Axes(i))
+
+ dt = hg.TickClock()
+ dts = hg.time_to_sec_f(dt)
+
+
+ # Car updates
+ brake, reverse = RCCarControl(car, physics, keyboard, dts, steering_wheel, joystick)
+ car_vel, car_pos, car_lines = RCCarUpdate(car, scene, physics, dts)
+ CarLightsSetBrake(carlights, brake)
+ CarLightsSetReverse(carlights, reverse)
+ CarLightsUpdate(carlights, scene, dt)
+ current_camera_node, camera_update = CarCameraUpdate(car_camera, scene, keyboard, dt, car_vel, render_mode)
+
+ # Scene updates
+ vid = 0 # keep track of the next free view id
+ passId = hg.SceneForwardPipelinePassViewId()
+ hg.SceneUpdateSystems(scene, clocks, dt, physics, hg.time_from_sec_f(1/60), 3)
+ if render_mode == "normal":
+ vid, passId = hg.SubmitSceneToPipeline(0, scene, hg.IntRect(0, 0, res_x, res_y), True, pipeline, res)
+
+ if physics_debug:
+ # Debug physics
+ hg.SetViewClear(vid, 0, 0, 1.0, 0)
+ hg.SetViewRect(vid, 0, 0, res_x, res_y)
+ cam_mat = scene.GetCurrentCamera().GetTransform().GetWorld()
+ view_matrix = hg.InverseFast(cam_mat)
+ c = scene.GetCurrentCamera().GetCamera()
+ projection_matrix = hg.ComputePerspectiveProjectionMatrix(c.GetZNear(), c.GetZFar(), hg.FovToZoomFactor(c.GetFov()), hg.Vec2(res_x / res_y, 1))
+ hg.SetViewTransform(vid, view_matrix, projection_matrix)
+ rs = hg.ComputeRenderState(hg.BM_Opaque, hg.DT_Disabled, hg.FC_Disabled)
+ physics.RenderCollision(vid, vtx_lines, lines_program, rs, 0)
+
+ if car_debug:
+ opaque_view_id = hg.GetSceneForwardPipelinePassViewId(passId, hg.SFPP_Opaque)
+ for line in car_lines:
+ draw_line(line[0], line[1], line[2], opaque_view_id, vtx_line_layout, lines_program)
+
+
+ # EoF
+ if render_mode == "vr":
+ main_camera_matrix = scene.GetCurrentCamera().GetTransform().GetWorld()
+ if vr_state and not vr_calibrated and not camera_update:
+ mat_head = hg.InverseFast(vr_state.body) * vr_state.head
+ rot = hg.GetR(mat_head)
+ rot.x = 0
+ rot.z = 0
+ initial_head_matrix = hg.TransformationMat4(hg.GetT(mat_head), rot)
+ head_pos = vr_state.head
+ vr_calibrated = True
+ if camera_update:
+ vr_calibrated = False
+
+ actor_body_mtx = main_camera_matrix * hg.InverseFast(initial_head_matrix)
+
+ vr_state = hg.OpenVRGetState(actor_body_mtx, 0.1, 1000)
+
+ left, right = hg.OpenVRStateToViewState(vr_state)
+
+ vid = 0 # keep track of the next free view id
+ passId = hg.SceneForwardPipelinePassViewId()
+
+ # Prepare view-independent render data once
+ vid, passId = hg.PrepareSceneForwardPipelineCommonRenderData(vid, scene, render_data, pipeline, res, passId)
+ vr_eye_rect = hg.IntRect(0, 0, vr_state.width, vr_state.height)
+
+ # Prepare the left eye render data then draw to its framebuffer
+ vid, passId = hg.PrepareSceneForwardPipelineViewDependentRenderData(vid, left, scene, render_data, pipeline, res, passId)
+ vid, passId = hg.SubmitSceneToForwardPipeline(vid, scene, vr_eye_rect, left, pipeline, render_data, res, vr_left_fb.GetHandle())
+
+ # Prepare the right eye render data then draw to its framebuffer
+ vid, passId = hg.PrepareSceneForwardPipelineViewDependentRenderData(vid, right, scene, render_data, pipeline, res, passId)
+ vid, passId = hg.SubmitSceneToForwardPipeline(vid, scene, vr_eye_rect, right, pipeline, render_data, res, vr_right_fb.GetHandle())
+
+ # Display the VR eyes texture to the backbuffer
+ hg.SetViewRect(vid, 0, 0, res_x, res_y)
+ vs = hg.ComputeOrthographicViewState(hg.TranslationMat4(hg.Vec3(0, 0, 0)), res_y, 0.1, 100, hg.ComputeAspectRatioX(res_x, res_y))
+ hg.SetViewTransform(vid, vs.view, vs.proj)
+
+ quad_uniform_set_texture_list.clear()
+ quad_uniform_set_texture_list.push_back(hg.MakeUniformSetTexture("s_tex", hg.OpenVRGetColorTexture(vr_left_fb), 0))
+ hg.SetT(quad_matrix, hg.Vec3(eye_t_x, 0, 1))
+ hg.DrawModel(vid, quad_model, tex0_program, quad_uniform_set_value_list, quad_uniform_set_texture_list, quad_matrix, quad_render_state)
+
+ quad_uniform_set_texture_list.clear()
+ quad_uniform_set_texture_list.push_back(hg.MakeUniformSetTexture("s_tex", hg.OpenVRGetColorTexture(vr_right_fb), 0))
+ hg.SetT(quad_matrix, hg.Vec3(-eye_t_x, 0, 1))
+ hg.DrawModel(vid, quad_model, tex0_program, quad_uniform_set_value_list, quad_uniform_set_texture_list, quad_matrix, quad_render_state)
+
+
+ hg.OpenVRSubmitFrame(vr_left_fb, vr_right_fb)
+
+ if render_mode == "normal":
+ vid += 1
+ physics_debug, car_debug = draw_gui(res_x, res_y, dt, dts, car_vel, vid, physics_debug, car_pos, car_debug)
+
+ hg.Frame()
+ hg.UpdateWindow(win)
+
+hg.RenderShutdown()
+hg.DestroyWindow(win)
diff --git a/app/resources/_meta/assimp_importer_cfg.txt b/app/resources/_meta/assimp_importer_cfg.txt
new file mode 100644
index 0000000..c564cd3
--- /dev/null
+++ b/app/resources/_meta/assimp_importer_cfg.txt
@@ -0,0 +1,19 @@
+"anim_policy":"1"
+"anim_simplify_rotation_tolerance":"0.100000"
+"anim_simplify_scale_tolerance":"0.001000"
+"anim_simplify_translation_tolerance":"0.001000"
+"assimp_file_path":""
+"finalizer_script":""
+"geometry_policy":"1"
+"import_animations":"1"
+"material_policy":"1"
+"max_smoothing_angle":"70.000000"
+"merge_meshes":"0"
+"output_folder":""
+"profile":"1"
+"recalculate_normals":"0"
+"recalculate_tangents":"0"
+"scene_policy":"1"
+"scene_scale":"1.000000"
+"texture_policy":"1"
+"use_finalizer_script":"0"
diff --git a/app/resources/_meta/fbx_importer_cfg.txt b/app/resources/_meta/fbx_importer_cfg.txt
new file mode 100644
index 0000000..4a8119e
--- /dev/null
+++ b/app/resources/_meta/fbx_importer_cfg.txt
@@ -0,0 +1,23 @@
+"anim_policy":"1"
+"anim_simplify_color_tolerance":"0.001000"
+"anim_simplify_rotation_tolerance":"0.100000"
+"anim_simplify_scale_tolerance":"0.001000"
+"anim_simplify_translation_tolerance":"0.001000"
+"detect_geometry_instances":"1"
+"fbx_file_path":""
+"finalizer_script":""
+"fix_geometry_orientation":"0"
+"frames_per_second":"24"
+"geometry_policy":"1"
+"geometry_scale":"1.000000"
+"import_animations":"1"
+"material_policy":"1"
+"max_smoothing_angle":"45.000000"
+"output_folder":""
+"profile":"1"
+"recalculate_normals":"0"
+"recalculate_tangents":"0"
+"scale":"1.000000"
+"scene_policy":"1"
+"texture_policy":"1"
+"use_finalizer_script":"0"
diff --git a/app/resources/_meta/gltf_importer_cfg.txt b/app/resources/_meta/gltf_importer_cfg.txt
new file mode 100644
index 0000000..3a36b03
--- /dev/null
+++ b/app/resources/_meta/gltf_importer_cfg.txt
@@ -0,0 +1,15 @@
+"anim_policy":"1"
+"detect_geometry_instances":"1"
+"finalizer_script":""
+"geometry_policy":"1"
+"geometry_scale":"1.000000"
+"gltf_file_path":""
+"material_policy":"1"
+"max_smoothing_angle":"70.000000"
+"output_folder":""
+"recalculate_normals":"0"
+"recalculate_tangents":"0"
+"scale":"1.000000"
+"scene_policy":"1"
+"texture_policy":"1"
+"use_finalizer_script":"0"
diff --git a/app/resources/common_maps/bit15m3v_02.dds b/app/resources/common_maps/bit15m3v_02.dds
new file mode 100644
index 0000000..fdccf96
Binary files /dev/null and b/app/resources/common_maps/bit15m3v_02.dds differ
diff --git a/app/resources/common_maps/bit40m3v_02.dds b/app/resources/common_maps/bit40m3v_02.dds
new file mode 100644
index 0000000..f965e92
Binary files /dev/null and b/app/resources/common_maps/bit40m3v_02.dds differ
diff --git a/app/resources/common_maps/concrete_generic_albedo.png b/app/resources/common_maps/concrete_generic_albedo.png
new file mode 100644
index 0000000..50de4b5
Binary files /dev/null and b/app/resources/common_maps/concrete_generic_albedo.png differ
diff --git a/app/resources/common_maps/diffuse_cement_dirty_03.png b/app/resources/common_maps/diffuse_cement_dirty_03.png
new file mode 100644
index 0000000..f41b1ec
Binary files /dev/null and b/app/resources/common_maps/diffuse_cement_dirty_03.png differ
diff --git a/app/resources/common_maps/diffuse_middle_wall.png b/app/resources/common_maps/diffuse_middle_wall.png
new file mode 100644
index 0000000..df1205f
Binary files /dev/null and b/app/resources/common_maps/diffuse_middle_wall.png differ
diff --git a/app/resources/common_maps/diffuse_road_sides.png b/app/resources/common_maps/diffuse_road_sides.png
new file mode 100644
index 0000000..79477c2
Binary files /dev/null and b/app/resources/common_maps/diffuse_road_sides.png differ
diff --git a/app/resources/common_maps/diffuse_tille_rambardes_02.tga b/app/resources/common_maps/diffuse_tille_rambardes_02.tga
new file mode 100644
index 0000000..ccea15e
Binary files /dev/null and b/app/resources/common_maps/diffuse_tille_rambardes_02.tga differ
diff --git a/app/resources/common_maps/spec_3ways_01.png b/app/resources/common_maps/spec_3ways_01.png
new file mode 100644
index 0000000..383f6e8
Binary files /dev/null and b/app/resources/common_maps/spec_3ways_01.png differ
diff --git a/app/resources/common_maps/spec_cement_dirty_03.png b/app/resources/common_maps/spec_cement_dirty_03.png
new file mode 100644
index 0000000..a51233b
Binary files /dev/null and b/app/resources/common_maps/spec_cement_dirty_03.png differ
diff --git a/app/resources/common_maps/spec_metal_red.png b/app/resources/common_maps/spec_metal_red.png
new file mode 100644
index 0000000..25b7f71
Binary files /dev/null and b/app/resources/common_maps/spec_metal_red.png differ
diff --git a/app/resources/common_maps/spec_road_sides.png b/app/resources/common_maps/spec_road_sides.png
new file mode 100644
index 0000000..c535a83
Binary files /dev/null and b/app/resources/common_maps/spec_road_sides.png differ
diff --git a/app/resources/core/noise/64/HDR_L_0.png b/app/resources/core/noise/64/HDR_L_0.png
new file mode 100644
index 0000000..5730c03
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_0.png differ
diff --git a/app/resources/core/noise/64/HDR_L_1.png b/app/resources/core/noise/64/HDR_L_1.png
new file mode 100644
index 0000000..596dfa0
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_1.png differ
diff --git a/app/resources/core/noise/64/HDR_L_10.png b/app/resources/core/noise/64/HDR_L_10.png
new file mode 100644
index 0000000..5a75021
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_10.png differ
diff --git a/app/resources/core/noise/64/HDR_L_11.png b/app/resources/core/noise/64/HDR_L_11.png
new file mode 100644
index 0000000..569d80a
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_11.png differ
diff --git a/app/resources/core/noise/64/HDR_L_12.png b/app/resources/core/noise/64/HDR_L_12.png
new file mode 100644
index 0000000..fe2131a
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_12.png differ
diff --git a/app/resources/core/noise/64/HDR_L_13.png b/app/resources/core/noise/64/HDR_L_13.png
new file mode 100644
index 0000000..9dc38ff
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_13.png differ
diff --git a/app/resources/core/noise/64/HDR_L_14.png b/app/resources/core/noise/64/HDR_L_14.png
new file mode 100644
index 0000000..f7fbbec
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_14.png differ
diff --git a/app/resources/core/noise/64/HDR_L_15.png b/app/resources/core/noise/64/HDR_L_15.png
new file mode 100644
index 0000000..090b15f
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_15.png differ
diff --git a/app/resources/core/noise/64/HDR_L_16.png b/app/resources/core/noise/64/HDR_L_16.png
new file mode 100644
index 0000000..eaa6d81
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_16.png differ
diff --git a/app/resources/core/noise/64/HDR_L_17.png b/app/resources/core/noise/64/HDR_L_17.png
new file mode 100644
index 0000000..ddf9b29
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_17.png differ
diff --git a/app/resources/core/noise/64/HDR_L_18.png b/app/resources/core/noise/64/HDR_L_18.png
new file mode 100644
index 0000000..5f7fc88
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_18.png differ
diff --git a/app/resources/core/noise/64/HDR_L_19.png b/app/resources/core/noise/64/HDR_L_19.png
new file mode 100644
index 0000000..21ce206
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_19.png differ
diff --git a/app/resources/core/noise/64/HDR_L_2.png b/app/resources/core/noise/64/HDR_L_2.png
new file mode 100644
index 0000000..6cdf639
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_2.png differ
diff --git a/app/resources/core/noise/64/HDR_L_20.png b/app/resources/core/noise/64/HDR_L_20.png
new file mode 100644
index 0000000..c316125
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_20.png differ
diff --git a/app/resources/core/noise/64/HDR_L_21.png b/app/resources/core/noise/64/HDR_L_21.png
new file mode 100644
index 0000000..b29b803
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_21.png differ
diff --git a/app/resources/core/noise/64/HDR_L_22.png b/app/resources/core/noise/64/HDR_L_22.png
new file mode 100644
index 0000000..abe7edb
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_22.png differ
diff --git a/app/resources/core/noise/64/HDR_L_23.png b/app/resources/core/noise/64/HDR_L_23.png
new file mode 100644
index 0000000..7c42d17
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_23.png differ
diff --git a/app/resources/core/noise/64/HDR_L_24.png b/app/resources/core/noise/64/HDR_L_24.png
new file mode 100644
index 0000000..242ac47
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_24.png differ
diff --git a/app/resources/core/noise/64/HDR_L_25.png b/app/resources/core/noise/64/HDR_L_25.png
new file mode 100644
index 0000000..61bc628
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_25.png differ
diff --git a/app/resources/core/noise/64/HDR_L_26.png b/app/resources/core/noise/64/HDR_L_26.png
new file mode 100644
index 0000000..a64222d
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_26.png differ
diff --git a/app/resources/core/noise/64/HDR_L_27.png b/app/resources/core/noise/64/HDR_L_27.png
new file mode 100644
index 0000000..5d70c25
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_27.png differ
diff --git a/app/resources/core/noise/64/HDR_L_28.png b/app/resources/core/noise/64/HDR_L_28.png
new file mode 100644
index 0000000..ca84abb
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_28.png differ
diff --git a/app/resources/core/noise/64/HDR_L_29.png b/app/resources/core/noise/64/HDR_L_29.png
new file mode 100644
index 0000000..8181e94
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_29.png differ
diff --git a/app/resources/core/noise/64/HDR_L_3.png b/app/resources/core/noise/64/HDR_L_3.png
new file mode 100644
index 0000000..b9e476f
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_3.png differ
diff --git a/app/resources/core/noise/64/HDR_L_30.png b/app/resources/core/noise/64/HDR_L_30.png
new file mode 100644
index 0000000..8d78550
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_30.png differ
diff --git a/app/resources/core/noise/64/HDR_L_31.png b/app/resources/core/noise/64/HDR_L_31.png
new file mode 100644
index 0000000..92c8f4f
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_31.png differ
diff --git a/app/resources/core/noise/64/HDR_L_32.png b/app/resources/core/noise/64/HDR_L_32.png
new file mode 100644
index 0000000..342b0fd
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_32.png differ
diff --git a/app/resources/core/noise/64/HDR_L_33.png b/app/resources/core/noise/64/HDR_L_33.png
new file mode 100644
index 0000000..7b556cc
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_33.png differ
diff --git a/app/resources/core/noise/64/HDR_L_34.png b/app/resources/core/noise/64/HDR_L_34.png
new file mode 100644
index 0000000..93a6a79
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_34.png differ
diff --git a/app/resources/core/noise/64/HDR_L_35.png b/app/resources/core/noise/64/HDR_L_35.png
new file mode 100644
index 0000000..22c1272
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_35.png differ
diff --git a/app/resources/core/noise/64/HDR_L_36.png b/app/resources/core/noise/64/HDR_L_36.png
new file mode 100644
index 0000000..3a09ecf
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_36.png differ
diff --git a/app/resources/core/noise/64/HDR_L_37.png b/app/resources/core/noise/64/HDR_L_37.png
new file mode 100644
index 0000000..64ec78f
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_37.png differ
diff --git a/app/resources/core/noise/64/HDR_L_38.png b/app/resources/core/noise/64/HDR_L_38.png
new file mode 100644
index 0000000..ad2162f
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_38.png differ
diff --git a/app/resources/core/noise/64/HDR_L_39.png b/app/resources/core/noise/64/HDR_L_39.png
new file mode 100644
index 0000000..a06b071
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_39.png differ
diff --git a/app/resources/core/noise/64/HDR_L_4.png b/app/resources/core/noise/64/HDR_L_4.png
new file mode 100644
index 0000000..8679a35
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_4.png differ
diff --git a/app/resources/core/noise/64/HDR_L_40.png b/app/resources/core/noise/64/HDR_L_40.png
new file mode 100644
index 0000000..c7d7bff
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_40.png differ
diff --git a/app/resources/core/noise/64/HDR_L_41.png b/app/resources/core/noise/64/HDR_L_41.png
new file mode 100644
index 0000000..847557d
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_41.png differ
diff --git a/app/resources/core/noise/64/HDR_L_42.png b/app/resources/core/noise/64/HDR_L_42.png
new file mode 100644
index 0000000..76d3961
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_42.png differ
diff --git a/app/resources/core/noise/64/HDR_L_43.png b/app/resources/core/noise/64/HDR_L_43.png
new file mode 100644
index 0000000..5c77c5a
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_43.png differ
diff --git a/app/resources/core/noise/64/HDR_L_44.png b/app/resources/core/noise/64/HDR_L_44.png
new file mode 100644
index 0000000..1e21207
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_44.png differ
diff --git a/app/resources/core/noise/64/HDR_L_45.png b/app/resources/core/noise/64/HDR_L_45.png
new file mode 100644
index 0000000..de2becc
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_45.png differ
diff --git a/app/resources/core/noise/64/HDR_L_46.png b/app/resources/core/noise/64/HDR_L_46.png
new file mode 100644
index 0000000..c208869
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_46.png differ
diff --git a/app/resources/core/noise/64/HDR_L_47.png b/app/resources/core/noise/64/HDR_L_47.png
new file mode 100644
index 0000000..1f52d77
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_47.png differ
diff --git a/app/resources/core/noise/64/HDR_L_48.png b/app/resources/core/noise/64/HDR_L_48.png
new file mode 100644
index 0000000..7a4ab95
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_48.png differ
diff --git a/app/resources/core/noise/64/HDR_L_49.png b/app/resources/core/noise/64/HDR_L_49.png
new file mode 100644
index 0000000..01ffaca
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_49.png differ
diff --git a/app/resources/core/noise/64/HDR_L_5.png b/app/resources/core/noise/64/HDR_L_5.png
new file mode 100644
index 0000000..39f965a
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_5.png differ
diff --git a/app/resources/core/noise/64/HDR_L_50.png b/app/resources/core/noise/64/HDR_L_50.png
new file mode 100644
index 0000000..328dc08
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_50.png differ
diff --git a/app/resources/core/noise/64/HDR_L_51.png b/app/resources/core/noise/64/HDR_L_51.png
new file mode 100644
index 0000000..c12cd2c
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_51.png differ
diff --git a/app/resources/core/noise/64/HDR_L_52.png b/app/resources/core/noise/64/HDR_L_52.png
new file mode 100644
index 0000000..f76cb27
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_52.png differ
diff --git a/app/resources/core/noise/64/HDR_L_53.png b/app/resources/core/noise/64/HDR_L_53.png
new file mode 100644
index 0000000..732322c
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_53.png differ
diff --git a/app/resources/core/noise/64/HDR_L_54.png b/app/resources/core/noise/64/HDR_L_54.png
new file mode 100644
index 0000000..5286ea6
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_54.png differ
diff --git a/app/resources/core/noise/64/HDR_L_55.png b/app/resources/core/noise/64/HDR_L_55.png
new file mode 100644
index 0000000..824a36e
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_55.png differ
diff --git a/app/resources/core/noise/64/HDR_L_56.png b/app/resources/core/noise/64/HDR_L_56.png
new file mode 100644
index 0000000..ef102d0
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_56.png differ
diff --git a/app/resources/core/noise/64/HDR_L_57.png b/app/resources/core/noise/64/HDR_L_57.png
new file mode 100644
index 0000000..356faa3
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_57.png differ
diff --git a/app/resources/core/noise/64/HDR_L_58.png b/app/resources/core/noise/64/HDR_L_58.png
new file mode 100644
index 0000000..d832e1a
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_58.png differ
diff --git a/app/resources/core/noise/64/HDR_L_59.png b/app/resources/core/noise/64/HDR_L_59.png
new file mode 100644
index 0000000..84941d0
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_59.png differ
diff --git a/app/resources/core/noise/64/HDR_L_6.png b/app/resources/core/noise/64/HDR_L_6.png
new file mode 100644
index 0000000..101d253
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_6.png differ
diff --git a/app/resources/core/noise/64/HDR_L_60.png b/app/resources/core/noise/64/HDR_L_60.png
new file mode 100644
index 0000000..5b27a7d
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_60.png differ
diff --git a/app/resources/core/noise/64/HDR_L_61.png b/app/resources/core/noise/64/HDR_L_61.png
new file mode 100644
index 0000000..e0b4e5c
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_61.png differ
diff --git a/app/resources/core/noise/64/HDR_L_62.png b/app/resources/core/noise/64/HDR_L_62.png
new file mode 100644
index 0000000..a16223a
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_62.png differ
diff --git a/app/resources/core/noise/64/HDR_L_63.png b/app/resources/core/noise/64/HDR_L_63.png
new file mode 100644
index 0000000..ee50763
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_63.png differ
diff --git a/app/resources/core/noise/64/HDR_L_7.png b/app/resources/core/noise/64/HDR_L_7.png
new file mode 100644
index 0000000..509f4f9
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_7.png differ
diff --git a/app/resources/core/noise/64/HDR_L_8.png b/app/resources/core/noise/64/HDR_L_8.png
new file mode 100644
index 0000000..6559f34
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_8.png differ
diff --git a/app/resources/core/noise/64/HDR_L_9.png b/app/resources/core/noise/64/HDR_L_9.png
new file mode 100644
index 0000000..8b803e1
Binary files /dev/null and b/app/resources/core/noise/64/HDR_L_9.png differ
diff --git a/app/resources/core/noise/HDR_L_0.png b/app/resources/core/noise/HDR_L_0.png
new file mode 100644
index 0000000..5730c03
Binary files /dev/null and b/app/resources/core/noise/HDR_L_0.png differ
diff --git a/app/resources/core/noise/HDR_L_1.png b/app/resources/core/noise/HDR_L_1.png
new file mode 100644
index 0000000..509f4f9
Binary files /dev/null and b/app/resources/core/noise/HDR_L_1.png differ
diff --git a/app/resources/core/noise/HDR_L_2.png b/app/resources/core/noise/HDR_L_2.png
new file mode 100644
index 0000000..090b15f
Binary files /dev/null and b/app/resources/core/noise/HDR_L_2.png differ
diff --git a/app/resources/core/noise/HDR_L_3.png b/app/resources/core/noise/HDR_L_3.png
new file mode 100644
index 0000000..7c42d17
Binary files /dev/null and b/app/resources/core/noise/HDR_L_3.png differ
diff --git a/app/resources/core/noise/HDR_L_4.png b/app/resources/core/noise/HDR_L_4.png
new file mode 100644
index 0000000..92c8f4f
Binary files /dev/null and b/app/resources/core/noise/HDR_L_4.png differ
diff --git a/app/resources/core/noise/HDR_L_5.png b/app/resources/core/noise/HDR_L_5.png
new file mode 100644
index 0000000..a06b071
Binary files /dev/null and b/app/resources/core/noise/HDR_L_5.png differ
diff --git a/app/resources/core/noise/HDR_L_6.png b/app/resources/core/noise/HDR_L_6.png
new file mode 100644
index 0000000..1f52d77
Binary files /dev/null and b/app/resources/core/noise/HDR_L_6.png differ
diff --git a/app/resources/core/noise/HDR_L_7.png b/app/resources/core/noise/HDR_L_7.png
new file mode 100644
index 0000000..824a36e
Binary files /dev/null and b/app/resources/core/noise/HDR_L_7.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_0.png b/app/resources/core/noise/LDR_RGBA_0.png
new file mode 100644
index 0000000..5c1fc26
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_0.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_1.png b/app/resources/core/noise/LDR_RGBA_1.png
new file mode 100644
index 0000000..f41e4ed
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_1.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_10.png b/app/resources/core/noise/LDR_RGBA_10.png
new file mode 100644
index 0000000..6a0b810
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_10.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_11.png b/app/resources/core/noise/LDR_RGBA_11.png
new file mode 100644
index 0000000..77a4179
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_11.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_12.png b/app/resources/core/noise/LDR_RGBA_12.png
new file mode 100644
index 0000000..e27b5ae
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_12.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_13.png b/app/resources/core/noise/LDR_RGBA_13.png
new file mode 100644
index 0000000..0144bae
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_13.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_14.png b/app/resources/core/noise/LDR_RGBA_14.png
new file mode 100644
index 0000000..b4f4f82
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_14.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_15.png b/app/resources/core/noise/LDR_RGBA_15.png
new file mode 100644
index 0000000..2cc165d
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_15.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_16.png b/app/resources/core/noise/LDR_RGBA_16.png
new file mode 100644
index 0000000..14b3619
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_16.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_17.png b/app/resources/core/noise/LDR_RGBA_17.png
new file mode 100644
index 0000000..942a3ec
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_17.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_18.png b/app/resources/core/noise/LDR_RGBA_18.png
new file mode 100644
index 0000000..d79b876
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_18.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_19.png b/app/resources/core/noise/LDR_RGBA_19.png
new file mode 100644
index 0000000..db28dcc
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_19.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_2.png b/app/resources/core/noise/LDR_RGBA_2.png
new file mode 100644
index 0000000..cb40652
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_2.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_20.png b/app/resources/core/noise/LDR_RGBA_20.png
new file mode 100644
index 0000000..81cf178
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_20.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_21.png b/app/resources/core/noise/LDR_RGBA_21.png
new file mode 100644
index 0000000..7642668
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_21.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_22.png b/app/resources/core/noise/LDR_RGBA_22.png
new file mode 100644
index 0000000..c2b4441
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_22.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_23.png b/app/resources/core/noise/LDR_RGBA_23.png
new file mode 100644
index 0000000..3859d12
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_23.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_24.png b/app/resources/core/noise/LDR_RGBA_24.png
new file mode 100644
index 0000000..f7becb1
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_24.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_25.png b/app/resources/core/noise/LDR_RGBA_25.png
new file mode 100644
index 0000000..776ab64
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_25.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_26.png b/app/resources/core/noise/LDR_RGBA_26.png
new file mode 100644
index 0000000..ca75692
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_26.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_27.png b/app/resources/core/noise/LDR_RGBA_27.png
new file mode 100644
index 0000000..1715769
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_27.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_28.png b/app/resources/core/noise/LDR_RGBA_28.png
new file mode 100644
index 0000000..c112d65
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_28.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_29.png b/app/resources/core/noise/LDR_RGBA_29.png
new file mode 100644
index 0000000..eb4ebec
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_29.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_3.png b/app/resources/core/noise/LDR_RGBA_3.png
new file mode 100644
index 0000000..6f2f2f4
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_3.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_30.png b/app/resources/core/noise/LDR_RGBA_30.png
new file mode 100644
index 0000000..5e13aef
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_30.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_31.png b/app/resources/core/noise/LDR_RGBA_31.png
new file mode 100644
index 0000000..a352c03
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_31.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_32.png b/app/resources/core/noise/LDR_RGBA_32.png
new file mode 100644
index 0000000..7243fc9
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_32.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_33.png b/app/resources/core/noise/LDR_RGBA_33.png
new file mode 100644
index 0000000..57be782
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_33.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_34.png b/app/resources/core/noise/LDR_RGBA_34.png
new file mode 100644
index 0000000..da1f938
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_34.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_35.png b/app/resources/core/noise/LDR_RGBA_35.png
new file mode 100644
index 0000000..33b6603
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_35.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_36.png b/app/resources/core/noise/LDR_RGBA_36.png
new file mode 100644
index 0000000..bdb81ce
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_36.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_37.png b/app/resources/core/noise/LDR_RGBA_37.png
new file mode 100644
index 0000000..32ae4fd
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_37.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_38.png b/app/resources/core/noise/LDR_RGBA_38.png
new file mode 100644
index 0000000..3b79e9c
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_38.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_39.png b/app/resources/core/noise/LDR_RGBA_39.png
new file mode 100644
index 0000000..20d643f
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_39.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_4.png b/app/resources/core/noise/LDR_RGBA_4.png
new file mode 100644
index 0000000..1d5b4d5
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_4.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_40.png b/app/resources/core/noise/LDR_RGBA_40.png
new file mode 100644
index 0000000..7e69870
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_40.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_41.png b/app/resources/core/noise/LDR_RGBA_41.png
new file mode 100644
index 0000000..dc49437
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_41.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_42.png b/app/resources/core/noise/LDR_RGBA_42.png
new file mode 100644
index 0000000..54c8e64
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_42.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_43.png b/app/resources/core/noise/LDR_RGBA_43.png
new file mode 100644
index 0000000..c087fce
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_43.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_44.png b/app/resources/core/noise/LDR_RGBA_44.png
new file mode 100644
index 0000000..7d8f46f
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_44.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_45.png b/app/resources/core/noise/LDR_RGBA_45.png
new file mode 100644
index 0000000..1f15197
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_45.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_46.png b/app/resources/core/noise/LDR_RGBA_46.png
new file mode 100644
index 0000000..1a6806c
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_46.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_47.png b/app/resources/core/noise/LDR_RGBA_47.png
new file mode 100644
index 0000000..077da76
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_47.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_48.png b/app/resources/core/noise/LDR_RGBA_48.png
new file mode 100644
index 0000000..394631f
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_48.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_49.png b/app/resources/core/noise/LDR_RGBA_49.png
new file mode 100644
index 0000000..cc6e590
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_49.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_5.png b/app/resources/core/noise/LDR_RGBA_5.png
new file mode 100644
index 0000000..4f146d3
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_5.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_50.png b/app/resources/core/noise/LDR_RGBA_50.png
new file mode 100644
index 0000000..e10123f
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_50.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_51.png b/app/resources/core/noise/LDR_RGBA_51.png
new file mode 100644
index 0000000..870ca6b
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_51.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_52.png b/app/resources/core/noise/LDR_RGBA_52.png
new file mode 100644
index 0000000..38f1ff7
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_52.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_53.png b/app/resources/core/noise/LDR_RGBA_53.png
new file mode 100644
index 0000000..7bac6dd
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_53.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_54.png b/app/resources/core/noise/LDR_RGBA_54.png
new file mode 100644
index 0000000..207ca5e
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_54.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_55.png b/app/resources/core/noise/LDR_RGBA_55.png
new file mode 100644
index 0000000..e53c3ba
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_55.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_56.png b/app/resources/core/noise/LDR_RGBA_56.png
new file mode 100644
index 0000000..0d8edd7
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_56.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_57.png b/app/resources/core/noise/LDR_RGBA_57.png
new file mode 100644
index 0000000..0501a9a
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_57.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_58.png b/app/resources/core/noise/LDR_RGBA_58.png
new file mode 100644
index 0000000..77946d6
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_58.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_59.png b/app/resources/core/noise/LDR_RGBA_59.png
new file mode 100644
index 0000000..655444e
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_59.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_6.png b/app/resources/core/noise/LDR_RGBA_6.png
new file mode 100644
index 0000000..87517bb
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_6.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_60.png b/app/resources/core/noise/LDR_RGBA_60.png
new file mode 100644
index 0000000..d58be6d
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_60.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_61.png b/app/resources/core/noise/LDR_RGBA_61.png
new file mode 100644
index 0000000..9e886b1
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_61.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_62.png b/app/resources/core/noise/LDR_RGBA_62.png
new file mode 100644
index 0000000..6e2b59b
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_62.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_63.png b/app/resources/core/noise/LDR_RGBA_63.png
new file mode 100644
index 0000000..5e556e6
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_63.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_7.png b/app/resources/core/noise/LDR_RGBA_7.png
new file mode 100644
index 0000000..edf90a8
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_7.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_8.png b/app/resources/core/noise/LDR_RGBA_8.png
new file mode 100644
index 0000000..f320d3f
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_8.png differ
diff --git a/app/resources/core/noise/LDR_RGBA_9.png b/app/resources/core/noise/LDR_RGBA_9.png
new file mode 100644
index 0000000..758aed0
Binary files /dev/null and b/app/resources/core/noise/LDR_RGBA_9.png differ
diff --git a/app/resources/core/pbr/brdf.dds b/app/resources/core/pbr/brdf.dds
new file mode 100644
index 0000000..2adabfa
Binary files /dev/null and b/app/resources/core/pbr/brdf.dds differ
diff --git a/app/resources/core/pbr/probe.hdr b/app/resources/core/pbr/probe.hdr
new file mode 100644
index 0000000..24f0cec
Binary files /dev/null and b/app/resources/core/pbr/probe.hdr differ
diff --git a/app/resources/core/pbr/probe.hdr.meta b/app/resources/core/pbr/probe.hdr.meta
new file mode 100644
index 0000000..0528fa0
--- /dev/null
+++ b/app/resources/core/pbr/probe.hdr.meta
@@ -0,0 +1,9 @@
+{
+ "profiles": {
+ "default": {
+ "generate-probe": true,
+ "max-probe-size": 256,
+ "radiance-edge-fixup": true
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/resources/core/shader/a_trous_fs.sc b/app/resources/core/shader/a_trous_fs.sc
new file mode 100644
index 0000000..ed154ad
--- /dev/null
+++ b/app/resources/core/shader/a_trous_fs.sc
@@ -0,0 +1,69 @@
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+SAMPLER2D(u_color, 0);
+SAMPLER2D(u_attr0, 1);
+
+uniform vec4 u_dir;
+uniform vec4 u_sigma; // x: pos, y: normal, z: depth, w: depth weight cutoff
+
+void main() {
+ const float epsilon = 1.e-6;
+
+ ivec2 p0 = ivec2(gl_FragCoord.xy);
+ ivec2 offset = ivec2(u_dir.xy);
+
+ vec4 c0 = texelFetch(u_color, p0, 0);
+ vec4 v0 = texelFetch(u_attr0, p0, 0);
+
+ float w = 3.0 / 8.0;
+ vec4 c = w * c0;
+
+ float falloff = 1.0 / (sqrt(2.0) * u_sigma.x);
+
+ int i;
+ float ws;
+
+ ws = 1.0 / 4.0;
+ for(i=1; i<=2; i++) {
+ ivec2 p1;
+ vec4 v1;
+ float wn, dz, wz, wp, w1, d;
+
+ ivec2 delta = offset * i;
+ float d2 = dot(vec2(delta), vec2(delta));
+ wp = exp(-d2 * falloff);
+
+ // right
+ p1 = p0 + delta;
+ v1 = texelFetch(u_attr0, p1, 0);
+
+ dz = abs(v1.w - v0.w);
+ wz = exp(-dz / u_sigma.z);
+ wz *= step(u_sigma.w, wz);
+
+ wn = pow(max(0.0, dot(v1.xyz, v0.xyz)), u_sigma.y);
+ w1 = ws * wn * wz * wp;
+
+ w += w1;
+ c += w1 * texelFetch(u_color, p1, 0);
+
+ // left
+ p1 = p0 - delta;
+ v1 = texelFetch(u_attr0, p1, 0);
+
+ dz = abs(v1.w - v0.w);
+ wz = exp(-dz / u_sigma.z);
+ wz *= step(u_sigma.w, wz);
+
+ wn = pow(max(0.0, dot(v1.xyz, v0.xyz)), u_sigma.y);
+ w1 = ws * wn * wz * wp;
+
+ w += w1;
+ c += w1 * texelFetch(u_color, p1, 0);
+
+ ws *= ws;
+ }
+
+ gl_FragColor = c / w;
+}
\ No newline at end of file
diff --git a/app/resources/core/shader/a_trous_varying.def b/app/resources/core/shader/a_trous_varying.def
new file mode 100644
index 0000000..76522d5
--- /dev/null
+++ b/app/resources/core/shader/a_trous_varying.def
@@ -0,0 +1 @@
+vec3 a_position : POSITION;
diff --git a/app/resources/core/shader/a_trous_vs.sc b/app/resources/core/shader/a_trous_vs.sc
new file mode 100644
index 0000000..ef6ecd0
--- /dev/null
+++ b/app/resources/core/shader/a_trous_vs.sc
@@ -0,0 +1,8 @@
+$input a_position
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main() {
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+}
diff --git a/app/resources/core/shader/aaa_downsample_fs.sc b/app/resources/core/shader/aaa_downsample_fs.sc
new file mode 100644
index 0000000..72b4144
--- /dev/null
+++ b/app/resources/core/shader/aaa_downsample_fs.sc
@@ -0,0 +1,71 @@
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+SAMPLER2D(u_color, 0);
+SAMPLER2D(u_attr0, 1);
+SAMPLER2D(u_depth, 2);
+
+void main() {
+ ivec2 pos = ivec2(gl_FragCoord.xy) * 2;
+
+ vec4 v0 = texelFetchOffset(u_attr0, pos, 0, ivec2(0,0));
+ vec4 v1 = texelFetchOffset(u_attr0, pos, 0, ivec2(1,0));
+ vec4 v2 = texelFetchOffset(u_attr0, pos, 0, ivec2(0,1));
+ vec4 v3 = texelFetchOffset(u_attr0, pos, 0, ivec2(1,1));
+
+ vec4 c0 = texelFetchOffset(u_color, pos, 0, ivec2(0,0));
+ vec4 c1 = texelFetchOffset(u_color, pos, 0, ivec2(1,0));
+ vec4 c2 = texelFetchOffset(u_color, pos, 0, ivec2(0,1));
+ vec4 c3 = texelFetchOffset(u_color, pos, 0, ivec2(1,1));
+
+ vec4 z0 = texelFetchOffset(u_depth, pos, 0, ivec2(0,0));
+ vec4 z1 = texelFetchOffset(u_depth, pos, 0, ivec2(1,0));
+ vec4 z2 = texelFetchOffset(u_depth, pos, 0, ivec2(0,1));
+ vec4 z3 = texelFetchOffset(u_depth, pos, 0, ivec2(1,1));
+
+ vec2 tmp = floor(mod(gl_FragCoord.xy, 2.0));
+#if AAA_DOWNSAMPLE_CHECKERBOARD
+ float checkerboard = tmp.x + tmp.y - 2.0*tmp.x*tmp.y;
+
+ vec4 v_min = (v0.w < v1.w) ? v0 : v1;
+ vec4 c_min = (v0.w < v1.w) ? c0 : c1;
+ vec4 z_min = (v0.w < v1.w) ? z0 : z1;
+ vec4 v_max = (v0.w > v1.w) ? v0 : v1;
+ vec4 c_max = (v0.w > v1.w) ? c0 : c1;
+ vec4 z_max = (v0.w > v1.w) ? z0 : z1;
+
+ v_min = (v_min.w < v2.w) ? v_min : v2;
+ c_min = (v_min.w < v2.w) ? c_min : c2;
+ z_min = (v_min.w < v2.w) ? z_min : z2;
+ v_max = (v_max.w > v2.w) ? v_max : v2;
+ c_max = (v_max.w > v2.w) ? c_max : c2;
+ z_max = (v_max.w > v2.w) ? z_max : z2;
+
+ v_min = (v_min.w < v3.w) ? v_min : v3; // mix(v_min, v3, step(v_min.w, v3.w));
+ c_min = (v_min.w < v3.w) ? c_min : c3;
+ z_min = (v_min.w < v3.w) ? z_min : z3;
+ v_max = (v_max.w > v3.w) ? v_max : v3; // mix(v_max, v3, step(v3.w, v_max.w));
+ c_max = (v_max.w > v3.w) ? c_max : c3;
+ z_max = (v_max.w > v3.w) ? z_max : z3;
+
+ gl_FragData[0] = mix(c_min, c_max, checkerboard);
+ gl_FragData[1] = mix(v_min, v_max, checkerboard);
+ gl_FragData[2] = mix(z_min, z_max, checkerboard);
+#else
+ vec4 v_min = (v0.w < v1.w) ? v0 : v1;
+ vec4 c_min = (v0.w < v1.w) ? c0 : c1;
+ vec4 z_min = (v0.w < v1.w) ? z0 : z1;
+
+ v_min = (v_min.w < v2.w) ? v_min : v2;
+ c_min = (v_min.w < v2.w) ? c_min : c2;
+ z_min = (v_min.w < v2.w) ? z_min : z2;
+
+ v_min = (v_min.w < v3.w) ? v_min : v3;
+ c_min = (v_min.w < v3.w) ? c_min : c3;
+ z_min = (v_min.w < v3.w) ? z_min : z3;
+
+ gl_FragData[0] = c_min;
+ gl_FragData[1] = v_min;
+ gl_FragData[2] = z_min;
+#endif
+}
\ No newline at end of file
diff --git a/app/resources/core/shader/aaa_downsample_varying.def b/app/resources/core/shader/aaa_downsample_varying.def
new file mode 100644
index 0000000..76522d5
--- /dev/null
+++ b/app/resources/core/shader/aaa_downsample_varying.def
@@ -0,0 +1 @@
+vec3 a_position : POSITION;
diff --git a/app/resources/core/shader/aaa_downsample_vs.sc b/app/resources/core/shader/aaa_downsample_vs.sc
new file mode 100644
index 0000000..ef6ecd0
--- /dev/null
+++ b/app/resources/core/shader/aaa_downsample_vs.sc
@@ -0,0 +1,8 @@
+$input a_position
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main() {
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+}
diff --git a/app/resources/core/shader/aaa_upsample_fs.sc b/app/resources/core/shader/aaa_upsample_fs.sc
new file mode 100644
index 0000000..2567d83
--- /dev/null
+++ b/app/resources/core/shader/aaa_upsample_fs.sc
@@ -0,0 +1,95 @@
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+SAMPLER2D(u_input, 0);
+SAMPLER2D(u_attr_lo, 1);
+SAMPLER2D(u_attr_hi, 2);
+
+float gaussian(float v, float sigma) {
+ return exp(-(v*v)/(2.0*sigma*sigma));
+}
+
+void main() {
+ vec2 ratio = round(textureSize(u_attr_hi, 0).xy / textureSize(u_attr_lo, 0).xy);
+ vec2 pixel = gl_FragCoord.xy / ratio;
+ vec2 tmp = floor(pixel-vec2_splat(0.5)) + vec2_splat(0.5);
+ ivec2 coord = ivec2(tmp);
+ vec2 f = pixel - tmp;
+
+ vec4 in00 = texelFetch(u_input, coord, 0);
+ vec4 in01 = texelFetchOffset(u_input, coord, 0, ivec2(0,1));
+ vec4 in10 = texelFetchOffset(u_input, coord, 0, ivec2(1,0));
+ vec4 in11 = texelFetchOffset(u_input, coord, 0, ivec2(1,1));
+
+ vec4 attr = texelFetch(u_attr_hi, ivec2(gl_FragCoord.xy), 0);
+
+ vec4 attr00 = texelFetch(u_attr_lo, coord, 0);
+ vec4 attr01 = texelFetchOffset(u_attr_lo, coord, 0, ivec2(0,1));
+ vec4 attr10 = texelFetchOffset(u_attr_lo, coord, 0, ivec2(1,0));
+ vec4 attr11 = texelFetchOffset(u_attr_lo, coord, 0, ivec2(1,1));
+
+ // bilinear weights
+ vec4 w_b = vec4(
+ (1.0-f.x) * (1.0-f.y),
+ (1.0-f.x) * f.y,
+ f.x * (1.0-f.y),
+ f.x * f.y
+ );
+
+ // depth weights
+ // [todo] use screen space gradient => gaussian(dz, sigma_z * abs(dot(gradient, vec2(i,j))) + epsilon) ?
+ // [todo] gradient => prewitt ?
+ float sigma_z = 0.02;
+ vec4 d_z = vec4(
+ abs(attr.w - attr00.w),
+ abs(attr.w - attr01.w),
+ abs(attr.w - attr10.w),
+ abs(attr.w - attr11.w)
+ );
+ vec4 w_z = vec4(
+ gaussian(d_z.x, sigma_z),
+ gaussian(d_z.y, sigma_z),
+ gaussian(d_z.z, sigma_z),
+ gaussian(d_z.w, sigma_z)
+ );
+
+ // normal weights
+ float sigma_n = 16.0;
+ vec4 w_n = vec4(
+ pow(max(0.0, dot(attr.xyz, attr00.xyz)), sigma_n),
+ pow(max(0.0, dot(attr.xyz, attr01.xyz)), sigma_n),
+ pow(max(0.0, dot(attr.xyz, attr10.xyz)), sigma_n),
+ pow(max(0.0, dot(attr.xyz, attr11.xyz)), sigma_n)
+ );
+
+ // [todo] luminance variance weights?
+
+ vec4 w = w_b * w_z * w_n;
+ float w_sum = max(1e-6, w.x + w.y + w.z + w.w);
+ vec4 sum = w.x*in00 + w.y*in01 + w.z*in10 + w.w*in11;
+
+ if(abs(w_sum) > 1.e-6) {
+ gl_FragColor = sum / w_sum;
+ } else {
+ // switch to depth aware sampling when the weight is too small.
+ if (all(greaterThan(w_z, vec4_splat(0.5)))) {
+ gl_FragColor = mix(mix(in00, in10, f.x), mix(in10, in11, f.x), f.y);
+ } else {
+ vec4 data = in00;
+ float d_z_min = d_z.x;
+ if (d_z.y < d_z_min) {
+ d_z_min = d_z.y;
+ data = in01;
+ }
+ if (d_z.z < d_z_min) {
+ d_z_min = d_z.z;
+ data = in10;
+ }
+ if (d_z.w < d_z_min) {
+ d_z_min = d_z.w;
+ data = in11;
+ }
+ gl_FragColor = data;
+ }
+ }
+}
diff --git a/app/resources/core/shader/aaa_upsample_varying.def b/app/resources/core/shader/aaa_upsample_varying.def
new file mode 100644
index 0000000..32f30d1
--- /dev/null
+++ b/app/resources/core/shader/aaa_upsample_varying.def
@@ -0,0 +1 @@
+vec3 a_position : POSITION;
\ No newline at end of file
diff --git a/app/resources/core/shader/aaa_upsample_vs.sc b/app/resources/core/shader/aaa_upsample_vs.sc
new file mode 100644
index 0000000..ef6ecd0
--- /dev/null
+++ b/app/resources/core/shader/aaa_upsample_vs.sc
@@ -0,0 +1,8 @@
+$input a_position
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main() {
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+}
diff --git a/app/resources/core/shader/aaa_utils.sh b/app/resources/core/shader/aaa_utils.sh
new file mode 100644
index 0000000..d0585d4
--- /dev/null
+++ b/app/resources/core/shader/aaa_utils.sh
@@ -0,0 +1,39 @@
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#ifndef AAA_UTILS_SH_HEADER_GUARD
+#define AAA_UTILS_SH_HEADER_GUARD
+
+# if !defined(uv_ratio)
+# define uv_ratio vec2_splat(uAAAParams[0].x)
+# endif
+
+vec2 NDCToViewRect(vec2 xy) { return ((xy * 0.5 + 0.5) * u_viewRect.zw + u_viewRect.xy); }
+
+vec2 GetVelocityVector(in vec2 uv) {
+#if BGFX_SHADER_LANGUAGE_GLSL
+ const vec2 offset = vec2(0.5, 0.5);
+#else
+ const vec2 offset = vec2(0.5,-0.5);
+#endif
+ return texture2D(u_attr1, uv).xy * offset / (uResolution.xy / u_viewRect.zw);
+}
+
+vec2 GetAttributeTexCoord(vec2 coord, vec2 size) {
+#if BGFX_SHADER_LANGUAGE_GLSL
+ vec2 uv = vec2(coord.x, 1.0 - coord.y) * u_viewRect.zw / size;
+ uv.y = 1.0 - uv.y;
+ return uv;
+#else
+ return coord * u_viewRect.zw / size;
+#endif
+}
+
+vec3 GetRayOrigin(mat4 projection, vec3 viewRay, float depth) {
+#if BGFX_SHADER_LANGUAGE_GLSL
+ float z = (depth - projection[3].z) / projection[2].z;
+#else
+ float z = (depth - projection[2].w) / projection[2].z;
+#endif
+ return viewRay * z;
+}
+
+#endif // AAA_UTILS_SH_HEADER_GUARD
diff --git a/app/resources/core/shader/bgfx_compute.sh b/app/resources/core/shader/bgfx_compute.sh
new file mode 100644
index 0000000..a67103e
--- /dev/null
+++ b/app/resources/core/shader/bgfx_compute.sh
@@ -0,0 +1,357 @@
+/*
+ * Copyright 2011-2021 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
+ */
+
+#ifndef BGFX_COMPUTE_H_HEADER_GUARD
+#define BGFX_COMPUTE_H_HEADER_GUARD
+
+#include "bgfx_shader.sh"
+
+#ifndef __cplusplus
+
+#if BGFX_SHADER_LANGUAGE_METAL || BGFX_SHADER_LANGUAGE_SPIRV
+# define ANNOTATION(_format) [[spv::format_ ## _format]]
+#else
+# define ANNOTATION(_format)
+#endif
+
+#if BGFX_SHADER_LANGUAGE_GLSL
+
+#define SHARED shared
+
+#define __IMAGE_XX(_name, _format, _reg, _image, _access) \
+ layout(_format, binding=_reg) _access uniform highp _image _name
+
+#define readwrite
+#define IMAGE2D_RO( _name, _format, _reg) __IMAGE_XX(_name, _format, _reg, image2D, readonly)
+#define UIMAGE2D_RO(_name, _format, _reg) __IMAGE_XX(_name, _format, _reg, uimage2D, readonly)
+#define IMAGE2D_WR( _name, _format, _reg) __IMAGE_XX(_name, _format, _reg, image2D, writeonly)
+#define UIMAGE2D_WR(_name, _format, _reg) __IMAGE_XX(_name, _format, _reg, uimage2D, writeonly)
+#define IMAGE2D_RW( _name, _format, _reg) __IMAGE_XX(_name, _format, _reg, image2D, readwrite)
+#define UIMAGE2D_RW(_name, _format, _reg) __IMAGE_XX(_name, _format, _reg, uimage2D, readwrite)
+
+#define IMAGE2D_ARRAY_RO( _name, _format, _reg) __IMAGE_XX(_name, _format, _reg, image2DArray, readonly)
+#define UIMAGE2D_ARRAY_RO(_name, _format, _reg) __IMAGE_XX(_name, _format, _reg, uimage2DArray, readonly)
+#define IMAGE2D_ARRAY_WR( _name, _format, _reg) __IMAGE_XX(_name, _format, _reg, image2DArray, writeonly)
+#define UIMAGE2D_ARRAY_WR(_name, _format, _reg) __IMAGE_XX(_name, _format, _reg, uimage2DArray, writeonly)
+#define IMAGE2D_ARRAY_RW( _name, _format, _reg) __IMAGE_XX(_name, _format, _reg, image2DArray, readwrite)
+#define UIMAGE2D_ARRAY_RW(_name, _format, _reg) __IMAGE_XX(_name, _format, _reg, uimage2DArray, readwrite)
+
+#define IMAGE3D_RO( _name, _format, _reg) __IMAGE_XX(_name, _format, _reg, image3D, readonly)
+#define UIMAGE3D_RO(_name, _format, _reg) __IMAGE_XX(_name, _format, _reg, uimage3D, readonly)
+#define IMAGE3D_WR( _name, _format, _reg) __IMAGE_XX(_name, _format, _reg, image3D, writeonly)
+#define UIMAGE3D_WR(_name, _format, _reg) __IMAGE_XX(_name, _format, _reg, uimage3D, writeonly)
+#define IMAGE3D_RW( _name, _format, _reg) __IMAGE_XX(_name, _format, _reg, image3D, readwrite)
+#define UIMAGE3D_RW(_name, _format, _reg) __IMAGE_XX(_name, _format, _reg, uimage3D, readwrite)
+
+#define __BUFFER_XX(_name, _type, _reg, _access) \
+ layout(std430, binding=_reg) _access buffer _name ## Buffer \
+ { \
+ _type _name[]; \
+ }
+
+#define BUFFER_RO(_name, _type, _reg) __BUFFER_XX(_name, _type, _reg, readonly)
+#define BUFFER_RW(_name, _type, _reg) __BUFFER_XX(_name, _type, _reg, readwrite)
+#define BUFFER_WR(_name, _type, _reg) __BUFFER_XX(_name, _type, _reg, writeonly)
+
+#define NUM_THREADS(_x, _y, _z) layout (local_size_x = _x, local_size_y = _y, local_size_z = _z) in;
+
+#define atomicFetchAndAdd(_mem, _data, _original) _original = atomicAdd(_mem, _data)
+#define atomicFetchAndAnd(_mem, _data, _original) _original = atomicAnd(_mem, _data)
+#define atomicFetchAndMax(_mem, _data, _original) _original = atomicMax(_mem, _data)
+#define atomicFetchAndMin(_mem, _data, _original) _original = atomicMin(_mem, _data)
+#define atomicFetchAndOr(_mem, _data, _original) _original = atomicOr(_mem, _data)
+#define atomicFetchAndXor(_mem, _data, _original) _original = atomicXor(_mem, _data)
+#define atomicFetchAndExchange(_mem, _data, _original) _original = atomicExchange(_mem, _data)
+#define atomicFetchCompareExchange(_mem, _compare, _data, _original) _original = atomicCompSwap(_mem,_compare, _data)
+
+#else
+
+#define SHARED groupshared
+
+#define r32ui uint
+#define rg32ui uint2
+#define rgba32ui uint4
+#define r32f float
+#define rg32f float2
+#define r16f float
+#define rg16f float2
+#define rgba16f float4
+#if BGFX_SHADER_LANGUAGE_HLSL
+# define rgba8 unorm float4
+# define rg8 unorm float2
+# define r8 unorm float
+#else
+# define rgba8 float4
+# define rg8 float2
+# define r8 float
+#endif // BGFX_SHADER_LANGUAGE_HLSL
+#define rgba32f float4
+
+#define IMAGE2D_RO( _name, _format, _reg) \
+ Texture2D<_format> _name ## Texture : REGISTER(t, _reg); \
+ static BgfxROImage2D_ ## _format _name = { _name ## Texture }
+
+#define UIMAGE2D_RO(_name, _format, _reg) IMAGE2D_RO(_name, _format, _reg)
+
+#define IMAGE2D_RW( _name, _format, _reg) \
+ ANNOTATION(_format) RWTexture2D<_format> _name ## Texture : REGISTER(u, _reg); \
+ static BgfxRWImage2D_ ## _format _name = { _name ## Texture }
+
+#define IMAGE2D_WR( _name, _format, _reg) IMAGE2D_RW(_name, _format, _reg)
+#define UIMAGE2D_WR(_name, _format, _reg) IMAGE2D_RW(_name, _format, _reg)
+#define UIMAGE2D_RW(_name, _format, _reg) IMAGE2D_RW(_name, _format, _reg)
+
+#define IMAGE2D_ARRAY_RO(_name, _format, _reg) \
+ Texture2DArray<_format> _name ## Texture : REGISTER(t, _reg); \
+ static BgfxROImage2DArray_ ## _format _name = { _name ## Texture }
+
+#define UIMAGE2D_ARRAY_RO(_name, _format, _reg) IMAGE2D_ARRAY_RO(_name, _format, _reg)
+
+#define IMAGE2D_ARRAY_RW(_name, _format, _reg) \
+ ANNOTATION(_format) RWTexture2DArray<_format> _name ## Texture : REGISTER(u, _reg); \
+ static BgfxRWImage2DArray_ ## _format _name = { _name ## Texture }
+
+#define UIMAGE2D_ARRAY_RW(_name, _format, _reg) IMAGE2D_ARRAY_RW(_name, _format, _reg)
+#define IMAGE2D_ARRAY_WR( _name, _format, _reg) IMAGE2D_ARRAY_RW(_name, _format, _reg)
+#define UIMAGE2D_ARRAY_WR(_name, _format, _reg) IMAGE2D_ARRAY_RW(_name, _format, _reg)
+
+#define IMAGE3D_RO( _name, _format, _reg) \
+ Texture3D<_format> _name ## Texture : REGISTER(t, _reg); \
+ static BgfxROImage3D_ ## _format _name = { _name ## Texture }
+
+#define UIMAGE3D_RO(_name, _format, _reg) IMAGE3D_RO(_name, _format, _reg)
+
+#define IMAGE3D_RW( _name, _format, _reg) \
+ ANNOTATION(_format) RWTexture3D<_format> _name ## Texture : REGISTER(u, _reg); \
+ static BgfxRWImage3D_ ## _format _name = { _name ## Texture }
+
+#define UIMAGE3D_RW(_name, _format, _reg) IMAGE3D_RW(_name, _format, _reg)
+#define IMAGE3D_WR( _name, _format, _reg) IMAGE3D_RW(_name, _format, _reg)
+#define UIMAGE3D_WR(_name, _format, _reg) IMAGE3D_RW(_name, _format, _reg)
+
+#if BGFX_SHADER_LANGUAGE_METAL || BGFX_SHADER_LANGUAGE_SPIRV
+#define BUFFER_RO(_name, _struct, _reg) StructuredBuffer<_struct> _name : REGISTER(t, _reg)
+#define BUFFER_RW(_name, _struct, _reg) RWStructuredBuffer <_struct> _name : REGISTER(u, _reg)
+#define BUFFER_WR(_name, _struct, _reg) BUFFER_RW(_name, _struct, _reg)
+#else
+#define BUFFER_RO(_name, _struct, _reg) Buffer<_struct> _name : REGISTER(t, _reg)
+#define BUFFER_RW(_name, _struct, _reg) RWBuffer<_struct> _name : REGISTER(u, _reg)
+#define BUFFER_WR(_name, _struct, _reg) BUFFER_RW(_name, _struct, _reg)
+#endif
+
+#define NUM_THREADS(_x, _y, _z) [numthreads(_x, _y, _z)]
+
+#define __IMAGE_IMPL_S(_format, _storeComponents, _type, _loadComponents) \
+ \
+ struct BgfxROImage2D_ ## _format \
+ { \
+ Texture2D<_format> m_texture; \
+ }; \
+ \
+ struct BgfxRWImage2D_ ## _format \
+ { \
+ ANNOTATION(_format) RWTexture2D<_format> m_texture; \
+ }; \
+ \
+ struct BgfxROImage2DArray_ ## _format \
+ { \
+ Texture2DArray<_format> m_texture; \
+ }; \
+ \
+ struct BgfxRWImage2DArray_ ## _format \
+ { \
+ ANNOTATION(_format) RWTexture2DArray<_format> m_texture; \
+ }; \
+ \
+ struct BgfxROImage3D_ ## _format \
+ { \
+ Texture3D<_format> m_texture; \
+ }; \
+ \
+ struct BgfxRWImage3D_ ## _format \
+ { \
+ ANNOTATION(_format) RWTexture3D<_format> m_texture; \
+ }; \
+
+#define __IMAGE_IMPL_A(_format, _storeComponents, _type, _loadComponents) \
+ __IMAGE_IMPL_S(_format, _storeComponents, _type, _loadComponents) \
+ \
+ _type imageLoad(BgfxROImage2D_ ## _format _image, ivec2 _uv) \
+ { \
+ return _image.m_texture[_uv]._loadComponents; \
+ } \
+ \
+ ivec2 imageSize(BgfxROImage2D_ ## _format _image) \
+ { \
+ uvec2 result; \
+ _image.m_texture.GetDimensions(result.x, result.y); \
+ return ivec2(result); \
+ } \
+ \
+ _type imageLoad(BgfxRWImage2D_ ## _format _image, ivec2 _uv) \
+ { \
+ return _image.m_texture[_uv]._loadComponents; \
+ } \
+ \
+ ivec2 imageSize(BgfxRWImage2D_ ## _format _image) \
+ { \
+ uvec2 result; \
+ _image.m_texture.GetDimensions(result.x, result.y); \
+ return ivec2(result); \
+ } \
+ \
+ void imageStore(BgfxRWImage2D_ ## _format _image, ivec2 _uv, _type _value) \
+ { \
+ _image.m_texture[_uv] = _value._storeComponents; \
+ } \
+ \
+ _type imageLoad(BgfxROImage2DArray_ ## _format _image, ivec3 _uvw) \
+ { \
+ return _image.m_texture[_uvw]._loadComponents; \
+ } \
+ \
+ ivec3 imageSize(BgfxROImage2DArray_ ## _format _image) \
+ { \
+ uvec3 result; \
+ _image.m_texture.GetDimensions(result.x, result.y, result.z); \
+ return ivec3(result); \
+ } \
+ \
+ _type imageLoad(BgfxRWImage2DArray_ ## _format _image, ivec3 _uvw) \
+ { \
+ return _image.m_texture[_uvw]._loadComponents; \
+ } \
+ \
+ void imageStore(BgfxRWImage2DArray_ ## _format _image, ivec3 _uvw, _type _value) \
+ { \
+ _image.m_texture[_uvw] = _value._storeComponents; \
+ } \
+ \
+ ivec3 imageSize(BgfxRWImage2DArray_ ## _format _image) \
+ { \
+ uvec3 result; \
+ _image.m_texture.GetDimensions(result.x, result.y, result.z); \
+ return ivec3(result); \
+ } \
+ \
+ _type imageLoad(BgfxROImage3D_ ## _format _image, ivec3 _uvw) \
+ { \
+ return _image.m_texture[_uvw]._loadComponents; \
+ } \
+ \
+ ivec3 imageSize(BgfxROImage3D_ ## _format _image) \
+ { \
+ uvec3 result; \
+ _image.m_texture.GetDimensions(result.x, result.y, result.z); \
+ return ivec3(result); \
+ } \
+ \
+ _type imageLoad(BgfxRWImage3D_ ## _format _image, ivec3 _uvw) \
+ { \
+ return _image.m_texture[_uvw]._loadComponents; \
+ } \
+ \
+ ivec3 imageSize(BgfxRWImage3D_ ## _format _image) \
+ { \
+ uvec3 result; \
+ _image.m_texture.GetDimensions(result.x, result.y, result.z); \
+ return ivec3(result); \
+ } \
+ \
+ void imageStore(BgfxRWImage3D_ ## _format _image, ivec3 _uvw, _type _value) \
+ { \
+ _image.m_texture[_uvw] = _value._storeComponents; \
+ }
+
+#define __IMAGE_IMPL_ATOMIC(_format, _storeComponents, _type, _loadComponents) \
+ \
+ void imageAtomicAdd(BgfxRWImage2D_ ## _format _image, ivec2 _uv, _type _value) \
+ { \
+ InterlockedAdd(_image.m_texture[_uv], _value._storeComponents); \
+ } \
+
+
+__IMAGE_IMPL_A(rgba8, xyzw, vec4, xyzw)
+__IMAGE_IMPL_A(rg8, xy, vec4, xyyy)
+__IMAGE_IMPL_A(r8, x, vec4, xxxx)
+__IMAGE_IMPL_A(rg16f, xy, vec4, xyyy)
+#if BGFX_SHADER_LANGUAGE_HLSL
+__IMAGE_IMPL_S(rgba16f, xyzw, vec4, xyzw)
+__IMAGE_IMPL_S(r16f, x, vec4, xxxx)
+__IMAGE_IMPL_S(rg32f, xy, vec4, xyyy)
+#else
+__IMAGE_IMPL_A(rgba16f, xyzw, vec4, xyzw)
+__IMAGE_IMPL_A(r16f, x, vec4, xxxx)
+__IMAGE_IMPL_A(rg32f, xy, vec4, xyyy)
+#endif // BGFX_SHADER_LANGUAGE_HLSL
+__IMAGE_IMPL_A(r32f, x, vec4, xxxx)
+__IMAGE_IMPL_A(rgba32f, xyzw, vec4, xyzw)
+__IMAGE_IMPL_A(r32ui, x, uvec4, xxxx)
+__IMAGE_IMPL_A(rg32ui, xy, uvec4, xyyy)
+__IMAGE_IMPL_A(rgba32ui, xyzw, uvec4, xyzw)
+
+__IMAGE_IMPL_ATOMIC(r32ui, x, uvec4, xxxx)
+
+#define atomicAdd(_mem, _data) InterlockedAdd(_mem, _data)
+#define atomicAnd(_mem, _data) InterlockedAnd(_mem, _data)
+#define atomicMax(_mem, _data) InterlockedMax(_mem, _data)
+#define atomicMin(_mem, _data) InterlockedMin(_mem, _data)
+#define atomicOr(_mem, _data) InterlockedOr(_mem, _data)
+#define atomicXor(_mem, _data) InterlockedXor(_mem, _data)
+#define atomicFetchAndAdd(_mem, _data, _original) InterlockedAdd(_mem, _data, _original)
+#define atomicFetchAndAnd(_mem, _data, _original) InterlockedAnd(_mem, _data, _original)
+#define atomicFetchAndMax(_mem, _data, _original) InterlockedMax(_mem, _data, _original)
+#define atomicFetchAndMin(_mem, _data, _original) InterlockedMin(_mem, _data, _original)
+#define atomicFetchAndOr(_mem, _data, _original) InterlockedOr(_mem, _data, _original)
+#define atomicFetchAndXor(_mem, _data, _original) InterlockedXor(_mem, _data, _original)
+#define atomicFetchAndExchange(_mem, _data, _original) InterlockedExchange(_mem, _data, _original)
+#define atomicFetchCompareExchange(_mem, _compare, _data, _original) InterlockedCompareExchange(_mem,_compare, _data, _original)
+
+// InterlockedCompareStore
+
+#define barrier() GroupMemoryBarrierWithGroupSync()
+#define memoryBarrier() GroupMemoryBarrierWithGroupSync()
+#define memoryBarrierAtomicCounter() GroupMemoryBarrierWithGroupSync()
+#define memoryBarrierBuffer() AllMemoryBarrierWithGroupSync()
+#define memoryBarrierImage() GroupMemoryBarrierWithGroupSync()
+#define memoryBarrierShared() GroupMemoryBarrierWithGroupSync()
+#define groupMemoryBarrier() GroupMemoryBarrierWithGroupSync()
+
+#endif // BGFX_SHADER_LANGUAGE_GLSL
+
+#define dispatchIndirect( \
+ _buffer \
+ , _offset \
+ , _numX \
+ , _numY \
+ , _numZ \
+ ) \
+ _buffer[(_offset)*2+0] = uvec4(_numX, _numY, _numZ, 0u)
+
+#define drawIndirect( \
+ _buffer \
+ , _offset \
+ , _numVertices \
+ , _numInstances \
+ , _startVertex \
+ , _startInstance \
+ ) \
+ _buffer[(_offset)*2+0] = uvec4(_numVertices, _numInstances, _startVertex, _startInstance)
+
+#define drawIndexedIndirect( \
+ _buffer \
+ , _offset \
+ , _numIndices \
+ , _numInstances \
+ , _startIndex \
+ , _startVertex \
+ , _startInstance \
+ ) \
+ _buffer[(_offset)*2+0] = uvec4(_numIndices, _numInstances, _startIndex, _startVertex); \
+ _buffer[(_offset)*2+1] = uvec4(_startInstance, 0u, 0u, 0u)
+
+#endif // __cplusplus
+
+#endif // BGFX_COMPUTE_H_HEADER_GUARD
diff --git a/app/resources/core/shader/bgfx_shader.sh b/app/resources/core/shader/bgfx_shader.sh
new file mode 100644
index 0000000..f11bcd2
--- /dev/null
+++ b/app/resources/core/shader/bgfx_shader.sh
@@ -0,0 +1,645 @@
+/*
+ * Copyright 2011-2021 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
+ */
+
+#ifndef BGFX_SHADER_H_HEADER_GUARD
+#define BGFX_SHADER_H_HEADER_GUARD
+
+#if !defined(BGFX_CONFIG_MAX_BONES)
+# define BGFX_CONFIG_MAX_BONES 32
+#endif // !defined(BGFX_CONFIG_MAX_BONES)
+
+#ifndef __cplusplus
+
+#if BGFX_SHADER_LANGUAGE_HLSL > 300
+# define BRANCH [branch]
+# define LOOP [loop]
+# define UNROLL [unroll]
+#else
+# define BRANCH
+# define LOOP
+# define UNROLL
+#endif // BGFX_SHADER_LANGUAGE_HLSL > 300
+
+#if BGFX_SHADER_LANGUAGE_HLSL > 300 && BGFX_SHADER_TYPE_FRAGMENT
+# define EARLY_DEPTH_STENCIL [earlydepthstencil]
+#else
+# define EARLY_DEPTH_STENCIL
+#endif // BGFX_SHADER_LANGUAGE_HLSL > 300 && BGFX_SHADER_TYPE_FRAGMENT
+
+#if BGFX_SHADER_LANGUAGE_GLSL
+# define ARRAY_BEGIN(_type, _name, _count) _type _name[_count] = _type[](
+# define ARRAY_END() )
+#else
+# define ARRAY_BEGIN(_type, _name, _count) _type _name[_count] = {
+# define ARRAY_END() }
+#endif // BGFX_SHADER_LANGUAGE_GLSL
+
+#if BGFX_SHADER_LANGUAGE_HLSL \
+ || BGFX_SHADER_LANGUAGE_PSSL \
+ || BGFX_SHADER_LANGUAGE_SPIRV \
+ || BGFX_SHADER_LANGUAGE_METAL
+# define CONST(_x) static const _x
+# define dFdx(_x) ddx(_x)
+# define dFdy(_y) ddy(-_y)
+# define inversesqrt(_x) rsqrt(_x)
+# define fract(_x) frac(_x)
+
+# define bvec2 bool2
+# define bvec3 bool3
+# define bvec4 bool4
+
+// To be able to patch the uav registers on the DXBC SPDB Chunk (D3D11 renderer) the whitespaces around
+// '_type[_reg]' are necessary. This only affects shaders with debug info (i.e., those that have the SPDB Chunk).
+# if BGFX_SHADER_LANGUAGE_HLSL > 400
+# define REGISTER(_type, _reg) register( _type[_reg] )
+# else
+# define REGISTER(_type, _reg) register(_type ## _reg)
+# endif // BGFX_SHADER_LANGUAGE_HLSL
+
+# if BGFX_SHADER_LANGUAGE_HLSL > 300 || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL
+# if BGFX_SHADER_LANGUAGE_HLSL > 400 || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL
+# define dFdxCoarse(_x) ddx_coarse(_x)
+# define dFdxFine(_x) ddx_fine(_x)
+# define dFdyCoarse(_y) ddy_coarse(-_y)
+# define dFdyFine(_y) ddy_fine(-_y)
+# endif // BGFX_SHADER_LANGUAGE_HLSL > 400
+
+# if BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL
+float intBitsToFloat(int _x) { return asfloat(_x); }
+vec2 intBitsToFloat(uint2 _x) { return asfloat(_x); }
+vec3 intBitsToFloat(uint3 _x) { return asfloat(_x); }
+vec4 intBitsToFloat(uint4 _x) { return asfloat(_x); }
+# endif // BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL
+
+float uintBitsToFloat(uint _x) { return asfloat(_x); }
+vec2 uintBitsToFloat(uint2 _x) { return asfloat(_x); }
+vec3 uintBitsToFloat(uint3 _x) { return asfloat(_x); }
+vec4 uintBitsToFloat(uint4 _x) { return asfloat(_x); }
+
+uint floatBitsToUint(float _x) { return asuint(_x); }
+uvec2 floatBitsToUint(vec2 _x) { return asuint(_x); }
+uvec3 floatBitsToUint(vec3 _x) { return asuint(_x); }
+uvec4 floatBitsToUint(vec4 _x) { return asuint(_x); }
+
+int floatBitsToInt(float _x) { return asint(_x); }
+ivec2 floatBitsToInt(vec2 _x) { return asint(_x); }
+ivec3 floatBitsToInt(vec3 _x) { return asint(_x); }
+ivec4 floatBitsToInt(vec4 _x) { return asint(_x); }
+
+uint bitfieldReverse(uint _x) { return reversebits(_x); }
+uint2 bitfieldReverse(uint2 _x) { return reversebits(_x); }
+uint3 bitfieldReverse(uint3 _x) { return reversebits(_x); }
+uint4 bitfieldReverse(uint4 _x) { return reversebits(_x); }
+
+# if !BGFX_SHADER_LANGUAGE_SPIRV
+uint packHalf2x16(vec2 _x)
+{
+ return (f32tof16(_x.y)<<16) | f32tof16(_x.x);
+}
+
+vec2 unpackHalf2x16(uint _x)
+{
+ return vec2(f16tof32(_x & 0xffff), f16tof32(_x >> 16) );
+}
+# endif // !BGFX_SHADER_LANGUAGE_SPIRV
+
+struct BgfxSampler2D
+{
+ SamplerState m_sampler;
+ Texture2D m_texture;
+};
+
+struct BgfxISampler2D
+{
+ Texture2D m_texture;
+};
+
+struct BgfxUSampler2D
+{
+ Texture2D m_texture;
+};
+
+struct BgfxSampler2DArray
+{
+ SamplerState m_sampler;
+ Texture2DArray m_texture;
+};
+
+struct BgfxSampler2DShadow
+{
+ SamplerComparisonState m_sampler;
+ Texture2D m_texture;
+};
+
+struct BgfxSampler2DArrayShadow
+{
+ SamplerComparisonState m_sampler;
+ Texture2DArray m_texture;
+};
+
+struct BgfxSampler3D
+{
+ SamplerState m_sampler;
+ Texture3D m_texture;
+};
+
+struct BgfxISampler3D
+{
+ Texture3D m_texture;
+};
+
+struct BgfxUSampler3D
+{
+ Texture3D m_texture;
+};
+
+struct BgfxSamplerCube
+{
+ SamplerState m_sampler;
+ TextureCube m_texture;
+};
+
+struct BgfxSamplerCubeShadow
+{
+ SamplerComparisonState m_sampler;
+ TextureCube m_texture;
+};
+
+struct BgfxSampler2DMS
+{
+ Texture2DMS m_texture;
+};
+
+vec4 bgfxTexture2D(BgfxSampler2D _sampler, vec2 _coord)
+{
+ return _sampler.m_texture.Sample(_sampler.m_sampler, _coord);
+}
+
+vec4 bgfxTexture2DBias(BgfxSampler2D _sampler, vec2 _coord, float _bias)
+{
+ return _sampler.m_texture.SampleBias(_sampler.m_sampler, _coord, _bias);
+}
+
+vec4 bgfxTexture2DLod(BgfxSampler2D _sampler, vec2 _coord, float _level)
+{
+ return _sampler.m_texture.SampleLevel(_sampler.m_sampler, _coord, _level);
+}
+
+vec4 bgfxTexture2DLodOffset(BgfxSampler2D _sampler, vec2 _coord, float _level, ivec2 _offset)
+{
+ return _sampler.m_texture.SampleLevel(_sampler.m_sampler, _coord, _level, _offset);
+}
+
+vec4 bgfxTexture2DProj(BgfxSampler2D _sampler, vec3 _coord)
+{
+ vec2 coord = _coord.xy * rcp(_coord.z);
+ return _sampler.m_texture.Sample(_sampler.m_sampler, coord);
+}
+
+vec4 bgfxTexture2DProj(BgfxSampler2D _sampler, vec4 _coord)
+{
+ vec2 coord = _coord.xy * rcp(_coord.w);
+ return _sampler.m_texture.Sample(_sampler.m_sampler, coord);
+}
+
+vec4 bgfxTexture2DGrad(BgfxSampler2D _sampler, vec2 _coord, vec2 _dPdx, vec2 _dPdy)
+{
+ return _sampler.m_texture.SampleGrad(_sampler.m_sampler, _coord, _dPdx, _dPdy);
+}
+
+vec4 bgfxTexture2DArray(BgfxSampler2DArray _sampler, vec3 _coord)
+{
+ return _sampler.m_texture.Sample(_sampler.m_sampler, _coord);
+}
+
+vec4 bgfxTexture2DArrayLod(BgfxSampler2DArray _sampler, vec3 _coord, float _lod)
+{
+ return _sampler.m_texture.SampleLevel(_sampler.m_sampler, _coord, _lod);
+}
+
+vec4 bgfxTexture2DArrayLodOffset(BgfxSampler2DArray _sampler, vec3 _coord, float _level, ivec2 _offset)
+{
+ return _sampler.m_texture.SampleLevel(_sampler.m_sampler, _coord, _level, _offset);
+}
+
+float bgfxShadow2D(BgfxSampler2DShadow _sampler, vec3 _coord)
+{
+ return _sampler.m_texture.SampleCmpLevelZero(_sampler.m_sampler, _coord.xy, _coord.z);
+}
+
+float bgfxShadow2DProj(BgfxSampler2DShadow _sampler, vec4 _coord)
+{
+ vec3 coord = _coord.xyz * rcp(_coord.w);
+ return _sampler.m_texture.SampleCmpLevelZero(_sampler.m_sampler, coord.xy, coord.z);
+}
+
+vec4 bgfxShadow2DArray(BgfxSampler2DArrayShadow _sampler, vec4 _coord)
+{
+ return _sampler.m_texture.SampleCmpLevelZero(_sampler.m_sampler, _coord.xyz, _coord.w);
+}
+
+vec4 bgfxTexture3D(BgfxSampler3D _sampler, vec3 _coord)
+{
+ return _sampler.m_texture.Sample(_sampler.m_sampler, _coord);
+}
+
+vec4 bgfxTexture3DLod(BgfxSampler3D _sampler, vec3 _coord, float _level)
+{
+ return _sampler.m_texture.SampleLevel(_sampler.m_sampler, _coord, _level);
+}
+
+ivec4 bgfxTexture3D(BgfxISampler3D _sampler, vec3 _coord)
+{
+ uvec3 size;
+ _sampler.m_texture.GetDimensions(size.x, size.y, size.z);
+ return _sampler.m_texture.Load(ivec4(_coord * size, 0) );
+}
+
+uvec4 bgfxTexture3D(BgfxUSampler3D _sampler, vec3 _coord)
+{
+ uvec3 size;
+ _sampler.m_texture.GetDimensions(size.x, size.y, size.z);
+ return _sampler.m_texture.Load(ivec4(_coord * size, 0) );
+}
+
+vec4 bgfxTextureCube(BgfxSamplerCube _sampler, vec3 _coord)
+{
+ return _sampler.m_texture.Sample(_sampler.m_sampler, _coord);
+}
+
+vec4 bgfxTextureCubeBias(BgfxSamplerCube _sampler, vec3 _coord, float _bias)
+{
+ return _sampler.m_texture.SampleBias(_sampler.m_sampler, _coord, _bias);
+}
+
+vec4 bgfxTextureCubeLod(BgfxSamplerCube _sampler, vec3 _coord, float _level)
+{
+ return _sampler.m_texture.SampleLevel(_sampler.m_sampler, _coord, _level);
+}
+
+float bgfxShadowCube(BgfxSamplerCubeShadow _sampler, vec4 _coord)
+{
+ return _sampler.m_texture.SampleCmpLevelZero(_sampler.m_sampler, _coord.xyz, _coord.w);
+}
+
+vec4 bgfxTexelFetch(BgfxSampler2D _sampler, ivec2 _coord, int _lod)
+{
+ return _sampler.m_texture.Load(ivec3(_coord, _lod) );
+}
+
+vec4 bgfxTexelFetchOffset(BgfxSampler2D _sampler, ivec2 _coord, int _lod, ivec2 _offset)
+{
+ return _sampler.m_texture.Load(ivec3(_coord, _lod), _offset );
+}
+
+vec2 bgfxTextureSize(BgfxSampler2D _sampler, int _lod)
+{
+ vec2 result;
+ _sampler.m_texture.GetDimensions(result.x, result.y);
+ return result;
+}
+
+vec4 bgfxTextureGather(BgfxSampler2D _sampler, vec2 _coord)
+{
+ return _sampler.m_texture.GatherRed(_sampler.m_sampler, _coord );
+}
+vec4 bgfxTextureGatherOffset(BgfxSampler2D _sampler, vec2 _coord, ivec2 _offset)
+{
+ return _sampler.m_texture.GatherRed(_sampler.m_sampler, _coord, _offset );
+}
+vec4 bgfxTextureGather(BgfxSampler2DArray _sampler, vec3 _coord)
+{
+ return _sampler.m_texture.GatherRed(_sampler.m_sampler, _coord );
+}
+
+ivec4 bgfxTexelFetch(BgfxISampler2D _sampler, ivec2 _coord, int _lod)
+{
+ return _sampler.m_texture.Load(ivec3(_coord, _lod) );
+}
+
+uvec4 bgfxTexelFetch(BgfxUSampler2D _sampler, ivec2 _coord, int _lod)
+{
+ return _sampler.m_texture.Load(ivec3(_coord, _lod) );
+}
+
+vec4 bgfxTexelFetch(BgfxSampler2DMS _sampler, ivec2 _coord, int _sampleIdx)
+{
+ return _sampler.m_texture.Load(_coord, _sampleIdx);
+}
+
+vec4 bgfxTexelFetch(BgfxSampler2DArray _sampler, ivec3 _coord, int _lod)
+{
+ return _sampler.m_texture.Load(ivec4(_coord, _lod) );
+}
+
+vec4 bgfxTexelFetch(BgfxSampler3D _sampler, ivec3 _coord, int _lod)
+{
+ return _sampler.m_texture.Load(ivec4(_coord, _lod) );
+}
+
+vec3 bgfxTextureSize(BgfxSampler3D _sampler, int _lod)
+{
+ vec3 result;
+ _sampler.m_texture.GetDimensions(result.x, result.y, result.z);
+ return result;
+}
+
+# define SAMPLER2D(_name, _reg) \
+ uniform SamplerState _name ## Sampler : REGISTER(s, _reg); \
+ uniform Texture2D _name ## Texture : REGISTER(t, _reg); \
+ static BgfxSampler2D _name = { _name ## Sampler, _name ## Texture }
+# define ISAMPLER2D(_name, _reg) \
+ uniform Texture2D _name ## Texture : REGISTER(t, _reg); \
+ static BgfxISampler2D _name = { _name ## Texture }
+# define USAMPLER2D(_name, _reg) \
+ uniform Texture2D _name ## Texture : REGISTER(t, _reg); \
+ static BgfxUSampler2D _name = { _name ## Texture }
+# define sampler2D BgfxSampler2D
+# define texture2D(_sampler, _coord) bgfxTexture2D(_sampler, _coord)
+# define texture2DBias(_sampler, _coord, _bias) bgfxTexture2DBias(_sampler, _coord, _bias)
+# define texture2DLod(_sampler, _coord, _level) bgfxTexture2DLod(_sampler, _coord, _level)
+# define texture2DLodOffset(_sampler, _coord, _level, _offset) bgfxTexture2DLodOffset(_sampler, _coord, _level, _offset)
+# define texture2DProj(_sampler, _coord) bgfxTexture2DProj(_sampler, _coord)
+# define texture2DGrad(_sampler, _coord, _dPdx, _dPdy) bgfxTexture2DGrad(_sampler, _coord, _dPdx, _dPdy)
+
+# define SAMPLER2DARRAY(_name, _reg) \
+ uniform SamplerState _name ## Sampler : REGISTER(s, _reg); \
+ uniform Texture2DArray _name ## Texture : REGISTER(t, _reg); \
+ static BgfxSampler2DArray _name = { _name ## Sampler, _name ## Texture }
+# define sampler2DArray BgfxSampler2DArray
+# define texture2DArray(_sampler, _coord) bgfxTexture2DArray(_sampler, _coord)
+# define texture2DArrayLod(_sampler, _coord, _lod) bgfxTexture2DArrayLod(_sampler, _coord, _lod)
+# define texture2DArrayLodOffset(_sampler, _coord, _level, _offset) bgfxTexture2DArrayLodOffset(_sampler, _coord, _level, _offset)
+
+# define SAMPLER2DMS(_name, _reg) \
+ uniform Texture2DMS _name ## Texture : REGISTER(t, _reg); \
+ static BgfxSampler2DMS _name = { _name ## Texture }
+# define sampler2DMS BgfxSampler2DMS
+
+# define SAMPLER2DSHADOW(_name, _reg) \
+ uniform SamplerComparisonState _name ## SamplerComparison : REGISTER(s, _reg); \
+ uniform Texture2D _name ## Texture : REGISTER(t, _reg); \
+ static BgfxSampler2DShadow _name = { _name ## SamplerComparison, _name ## Texture }
+# define sampler2DShadow BgfxSampler2DShadow
+# define shadow2D(_sampler, _coord) bgfxShadow2D(_sampler, _coord)
+# define shadow2DProj(_sampler, _coord) bgfxShadow2DProj(_sampler, _coord)
+
+# define SAMPLER2DARRAYSHADOW(_name, _reg) \
+ uniform SamplerComparisonState _name ## SamplerComparison : REGISTER(s, _reg); \
+ uniform Texture2DArray _name ## Texture : REGISTER(t, _reg); \
+ static BgfxSampler2DArrayShadow _name = { _name ## SamplerComparison, _name ## Texture }
+# define sampler2DArrayShadow BgfxSampler2DArrayShadow
+# define shadow2DArray(_sampler, _coord) bgfxShadow2DArray(_sampler, _coord)
+
+# define SAMPLER3D(_name, _reg) \
+ uniform SamplerState _name ## Sampler : REGISTER(s, _reg); \
+ uniform Texture3D _name ## Texture : REGISTER(t, _reg); \
+ static BgfxSampler3D _name = { _name ## Sampler, _name ## Texture }
+# define ISAMPLER3D(_name, _reg) \
+ uniform Texture3D _name ## Texture : REGISTER(t, _reg); \
+ static BgfxISampler3D _name = { _name ## Texture }
+# define USAMPLER3D(_name, _reg) \
+ uniform Texture3D _name ## Texture : REGISTER(t, _reg); \
+ static BgfxUSampler3D _name = { _name ## Texture }
+# define sampler3D BgfxSampler3D
+# define texture3D(_sampler, _coord) bgfxTexture3D(_sampler, _coord)
+# define texture3DLod(_sampler, _coord, _level) bgfxTexture3DLod(_sampler, _coord, _level)
+
+# define SAMPLERCUBE(_name, _reg) \
+ uniform SamplerState _name ## Sampler : REGISTER(s, _reg); \
+ uniform TextureCube _name ## Texture : REGISTER(t, _reg); \
+ static BgfxSamplerCube _name = { _name ## Sampler, _name ## Texture }
+# define samplerCube BgfxSamplerCube
+# define textureCube(_sampler, _coord) bgfxTextureCube(_sampler, _coord)
+# define textureCubeBias(_sampler, _coord, _bias) bgfxTextureCubeBias(_sampler, _coord, _bias)
+# define textureCubeLod(_sampler, _coord, _level) bgfxTextureCubeLod(_sampler, _coord, _level)
+
+# define SAMPLERCUBESHADOW(_name, _reg) \
+ uniform SamplerComparisonState _name ## SamplerComparison : REGISTER(s, _reg); \
+ uniform TextureCube _name ## Texture : REGISTER(t, _reg); \
+ static BgfxSamplerCubeShadow _name = { _name ## SamplerComparison, _name ## Texture }
+# define samplerCubeShadow BgfxSamplerCubeShadow
+# define shadowCube(_sampler, _coord) bgfxShadowCube(_sampler, _coord)
+
+# define texelFetch(_sampler, _coord, _lod) bgfxTexelFetch(_sampler, _coord, _lod)
+# define texelFetchOffset(_sampler, _coord, _lod, _offset) bgfxTexelFetchOffset(_sampler, _coord, _lod, _offset)
+# define textureSize(_sampler, _lod) bgfxTextureSize(_sampler, _lod)
+# define textureGather(_sampler, _coord) bgfxTextureGather(_sampler, _coord)
+# define textureGatherOffset(_sampler, _coord, _offset) bgfxTextureGatherOffset(_sampler, _coord, _offset)
+# else
+
+# define sampler2DShadow sampler2D
+
+vec4 bgfxTexture2DProj(sampler2D _sampler, vec3 _coord)
+{
+ return tex2Dproj(_sampler, vec4(_coord.xy, 0.0, _coord.z) );
+}
+
+vec4 bgfxTexture2DProj(sampler2D _sampler, vec4 _coord)
+{
+ return tex2Dproj(_sampler, _coord);
+}
+
+float bgfxShadow2D(sampler2DShadow _sampler, vec3 _coord)
+{
+#if 0
+ float occluder = tex2D(_sampler, _coord.xy).x;
+ return step(_coord.z, occluder);
+#else
+ return tex2Dproj(_sampler, vec4(_coord.xy, _coord.z, 1.0) ).x;
+#endif // 0
+}
+
+float bgfxShadow2DProj(sampler2DShadow _sampler, vec4 _coord)
+{
+#if 0
+ vec3 coord = _coord.xyz * rcp(_coord.w);
+ float occluder = tex2D(_sampler, coord.xy).x;
+ return step(coord.z, occluder);
+#else
+ return tex2Dproj(_sampler, _coord).x;
+#endif // 0
+}
+
+# define SAMPLER2D(_name, _reg) uniform sampler2D _name : REGISTER(s, _reg)
+# define SAMPLER2DMS(_name, _reg) uniform sampler2DMS _name : REGISTER(s, _reg)
+# define texture2D(_sampler, _coord) tex2D(_sampler, _coord)
+# define texture2DProj(_sampler, _coord) bgfxTexture2DProj(_sampler, _coord)
+
+# define SAMPLER2DARRAY(_name, _reg) SAMPLER2D(_name, _reg)
+# define texture2DArray(_sampler, _coord) texture2D(_sampler, (_coord).xy)
+# define texture2DArrayLod(_sampler, _coord, _lod) texture2DLod(_sampler, _coord, _lod)
+
+# define SAMPLER2DSHADOW(_name, _reg) uniform sampler2DShadow _name : REGISTER(s, _reg)
+# define shadow2D(_sampler, _coord) bgfxShadow2D(_sampler, _coord)
+# define shadow2DProj(_sampler, _coord) bgfxShadow2DProj(_sampler, _coord)
+
+# define SAMPLER3D(_name, _reg) uniform sampler3D _name : REGISTER(s, _reg)
+# define texture3D(_sampler, _coord) tex3D(_sampler, _coord)
+
+# define SAMPLERCUBE(_name, _reg) uniform samplerCUBE _name : REGISTER(s, _reg)
+# define textureCube(_sampler, _coord) texCUBE(_sampler, _coord)
+
+# define texture2DLod(_sampler, _coord, _level) tex2Dlod(_sampler, vec4( (_coord).xy, 0.0, _level) )
+# define texture2DGrad(_sampler, _coord, _dPdx, _dPdy) tex2Dgrad(_sampler, _coord, _dPdx, _dPdy)
+# define texture3DLod(_sampler, _coord, _level) tex3Dlod(_sampler, vec4( (_coord).xyz, _level) )
+# define textureCubeLod(_sampler, _coord, _level) texCUBElod(_sampler, vec4( (_coord).xyz, _level) )
+
+# endif // BGFX_SHADER_LANGUAGE_HLSL > 300
+
+vec3 instMul(vec3 _vec, mat3 _mtx) { return mul(_mtx, _vec); }
+vec3 instMul(mat3 _mtx, vec3 _vec) { return mul(_vec, _mtx); }
+vec4 instMul(vec4 _vec, mat4 _mtx) { return mul(_mtx, _vec); }
+vec4 instMul(mat4 _mtx, vec4 _vec) { return mul(_vec, _mtx); }
+
+bvec2 lessThan(vec2 _a, vec2 _b) { return _a < _b; }
+bvec3 lessThan(vec3 _a, vec3 _b) { return _a < _b; }
+bvec4 lessThan(vec4 _a, vec4 _b) { return _a < _b; }
+
+bvec2 lessThanEqual(vec2 _a, vec2 _b) { return _a <= _b; }
+bvec3 lessThanEqual(vec3 _a, vec3 _b) { return _a <= _b; }
+bvec4 lessThanEqual(vec4 _a, vec4 _b) { return _a <= _b; }
+
+bvec2 greaterThan(vec2 _a, vec2 _b) { return _a > _b; }
+bvec3 greaterThan(vec3 _a, vec3 _b) { return _a > _b; }
+bvec4 greaterThan(vec4 _a, vec4 _b) { return _a > _b; }
+
+bvec2 greaterThanEqual(vec2 _a, vec2 _b) { return _a >= _b; }
+bvec3 greaterThanEqual(vec3 _a, vec3 _b) { return _a >= _b; }
+bvec4 greaterThanEqual(vec4 _a, vec4 _b) { return _a >= _b; }
+
+bvec2 notEqual(vec2 _a, vec2 _b) { return _a != _b; }
+bvec3 notEqual(vec3 _a, vec3 _b) { return _a != _b; }
+bvec4 notEqual(vec4 _a, vec4 _b) { return _a != _b; }
+
+bvec2 equal(vec2 _a, vec2 _b) { return _a == _b; }
+bvec3 equal(vec3 _a, vec3 _b) { return _a == _b; }
+bvec4 equal(vec4 _a, vec4 _b) { return _a == _b; }
+
+float mix(float _a, float _b, float _t) { return lerp(_a, _b, _t); }
+vec2 mix(vec2 _a, vec2 _b, vec2 _t) { return lerp(_a, _b, _t); }
+vec3 mix(vec3 _a, vec3 _b, vec3 _t) { return lerp(_a, _b, _t); }
+vec4 mix(vec4 _a, vec4 _b, vec4 _t) { return lerp(_a, _b, _t); }
+
+float mod(float _a, float _b) { return _a - _b * floor(_a / _b); }
+vec2 mod(vec2 _a, vec2 _b) { return _a - _b * floor(_a / _b); }
+vec3 mod(vec3 _a, vec3 _b) { return _a - _b * floor(_a / _b); }
+vec4 mod(vec4 _a, vec4 _b) { return _a - _b * floor(_a / _b); }
+
+#else
+# define CONST(_x) const _x
+# define atan2(_x, _y) atan(_x, _y)
+# define mul(_a, _b) ( (_a) * (_b) )
+# define saturate(_x) clamp(_x, 0.0, 1.0)
+# define SAMPLER2D(_name, _reg) uniform sampler2D _name
+# define SAMPLER2DMS(_name, _reg) uniform sampler2DMS _name
+# define SAMPLER3D(_name, _reg) uniform sampler3D _name
+# define SAMPLERCUBE(_name, _reg) uniform samplerCube _name
+# define SAMPLER2DSHADOW(_name, _reg) uniform sampler2DShadow _name
+
+# define SAMPLER2DARRAY(_name, _reg) uniform sampler2DArray _name
+# define SAMPLER2DMSARRAY(_name, _reg) uniform sampler2DMSArray _name
+# define SAMPLERCUBEARRAY(_name, _reg) uniform samplerCubeArray _name
+# define SAMPLER2DARRAYSHADOW(_name, _reg) uniform sampler2DArrayShadow _name
+
+# define ISAMPLER2D(_name, _reg) uniform isampler2D _name
+# define USAMPLER2D(_name, _reg) uniform usampler2D _name
+# define ISAMPLER3D(_name, _reg) uniform isampler3D _name
+# define USAMPLER3D(_name, _reg) uniform usampler3D _name
+
+# define texture2DBias(_sampler, _coord, _bias) texture2D(_sampler, _coord, _bias)
+# define textureCubeBias(_sampler, _coord, _bias) textureCube(_sampler, _coord, _bias)
+
+# if BGFX_SHADER_LANGUAGE_GLSL >= 130
+# define texture2D(_sampler, _coord) texture(_sampler, _coord)
+# define texture2DArray(_sampler, _coord) texture(_sampler, _coord)
+# define texture3D(_sampler, _coord) texture(_sampler, _coord)
+# define texture2DLod(_sampler, _coord, _lod) textureLod(_sampler, _coord, _lod)
+# define texture2DLodOffset(_sampler, _coord, _lod, _offset) textureLodOffset(_sampler, _coord, _lod, _offset)
+# endif // BGFX_SHADER_LANGUAGE_GLSL >= 130
+
+vec3 instMul(vec3 _vec, mat3 _mtx) { return mul(_vec, _mtx); }
+vec3 instMul(mat3 _mtx, vec3 _vec) { return mul(_mtx, _vec); }
+vec4 instMul(vec4 _vec, mat4 _mtx) { return mul(_vec, _mtx); }
+vec4 instMul(mat4 _mtx, vec4 _vec) { return mul(_mtx, _vec); }
+
+float rcp(float _a) { return 1.0/_a; }
+vec2 rcp(vec2 _a) { return vec2(1.0)/_a; }
+vec3 rcp(vec3 _a) { return vec3(1.0)/_a; }
+vec4 rcp(vec4 _a) { return vec4(1.0)/_a; }
+#endif // BGFX_SHADER_LANGUAGE_*
+
+vec2 vec2_splat(float _x) { return vec2(_x, _x); }
+vec3 vec3_splat(float _x) { return vec3(_x, _x, _x); }
+vec4 vec4_splat(float _x) { return vec4(_x, _x, _x, _x); }
+
+#if BGFX_SHADER_LANGUAGE_GLSL >= 130 || BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL
+uvec2 uvec2_splat(uint _x) { return uvec2(_x, _x); }
+uvec3 uvec3_splat(uint _x) { return uvec3(_x, _x, _x); }
+uvec4 uvec4_splat(uint _x) { return uvec4(_x, _x, _x, _x); }
+#endif // BGFX_SHADER_LANGUAGE_GLSL >= 130 || BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL
+
+mat4 mtxFromRows(vec4 _0, vec4 _1, vec4 _2, vec4 _3)
+{
+#if BGFX_SHADER_LANGUAGE_GLSL
+ return transpose(mat4(_0, _1, _2, _3) );
+#else
+ return mat4(_0, _1, _2, _3);
+#endif // BGFX_SHADER_LANGUAGE_GLSL
+}
+mat4 mtxFromCols(vec4 _0, vec4 _1, vec4 _2, vec4 _3)
+{
+#if BGFX_SHADER_LANGUAGE_GLSL
+ return mat4(_0, _1, _2, _3);
+#else
+ return transpose(mat4(_0, _1, _2, _3) );
+#endif // BGFX_SHADER_LANGUAGE_GLSL
+}
+mat3 mtxFromRows(vec3 _0, vec3 _1, vec3 _2)
+{
+#if BGFX_SHADER_LANGUAGE_GLSL
+ return transpose(mat3(_0, _1, _2) );
+#else
+ return mat3(_0, _1, _2);
+#endif // BGFX_SHADER_LANGUAGE_GLSL
+}
+mat3 mtxFromCols(vec3 _0, vec3 _1, vec3 _2)
+{
+#if BGFX_SHADER_LANGUAGE_GLSL
+ return mat3(_0, _1, _2);
+#else
+ return transpose(mat3(_0, _1, _2) );
+#endif // BGFX_SHADER_LANGUAGE_GLSL
+}
+
+#if BGFX_SHADER_LANGUAGE_GLSL
+#define mtxFromRows3(_0, _1, _2) transpose(mat3(_0, _1, _2) )
+#define mtxFromRows4(_0, _1, _2, _3) transpose(mat4(_0, _1, _2, _3) )
+#define mtxFromCols3(_0, _1, _2) mat3(_0, _1, _2)
+#define mtxFromCols4(_0, _1, _2, _3) mat4(_0, _1, _2, _3)
+#else
+#define mtxFromRows3(_0, _1, _2) mat3(_0, _1, _2)
+#define mtxFromRows4(_0, _1, _2, _3) mat4(_0, _1, _2, _3)
+#define mtxFromCols3(_0, _1, _2) transpose(mat3(_0, _1, _2) )
+#define mtxFromCols4(_0, _1, _2, _3) transpose(mat4(_0, _1, _2, _3) )
+#endif // BGFX_SHADER_LANGUAGE_GLSL
+
+uniform vec4 u_viewRect;
+uniform vec4 u_viewTexel;
+uniform mat4 u_view;
+uniform mat4 u_invView;
+uniform mat4 u_proj;
+uniform mat4 u_invProj;
+uniform mat4 u_viewProj;
+uniform mat4 u_invViewProj;
+uniform mat4 u_model[BGFX_CONFIG_MAX_BONES];
+uniform mat4 u_modelView;
+uniform mat4 u_modelViewProj;
+uniform vec4 u_alphaRef4;
+#define u_alphaRef u_alphaRef4.x
+
+#endif // __cplusplus
+
+#endif // BGFX_SHADER_H_HEADER_GUARD
diff --git a/app/resources/core/shader/bloom_combine_fs.sc b/app/resources/core/shader/bloom_combine_fs.sc
new file mode 100644
index 0000000..d6abacb
--- /dev/null
+++ b/app/resources/core/shader/bloom_combine_fs.sc
@@ -0,0 +1,16 @@
+$input v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+SAMPLER2D(u_source, 0);
+SAMPLER2D(u_input, 1);
+
+void main() {
+ vec2 uv = gl_FragCoord.xy / uResolution.xy;
+
+ vec3 color = texture2D(u_source, uv).rgb;
+ color += texture2D(u_input, uv).rgb;
+
+ gl_FragColor = vec4(color, 1.);
+}
diff --git a/app/resources/core/shader/bloom_combine_varying.def b/app/resources/core/shader/bloom_combine_varying.def
new file mode 100644
index 0000000..b7b69d9
--- /dev/null
+++ b/app/resources/core/shader/bloom_combine_varying.def
@@ -0,0 +1,4 @@
+vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0);
+
+vec3 a_position : POSITION;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/app/resources/core/shader/bloom_combine_vs.sc b/app/resources/core/shader/bloom_combine_vs.sc
new file mode 100644
index 0000000..a8521fe
--- /dev/null
+++ b/app/resources/core/shader/bloom_combine_vs.sc
@@ -0,0 +1,10 @@
+$input a_position, a_texcoord0
+$output v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main() {
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0., 1.));
+ v_texcoord0 = a_texcoord0;
+}
diff --git a/app/resources/core/shader/bloom_downsample_fs.sc b/app/resources/core/shader/bloom_downsample_fs.sc
new file mode 100644
index 0000000..f418d95
--- /dev/null
+++ b/app/resources/core/shader/bloom_downsample_fs.sc
@@ -0,0 +1,47 @@
+$input v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+SAMPLER2D(u_source, 0);
+uniform vec4 u_source_rect;
+
+vec2 compute_texel(vec2 uv, vec2 center, vec4 bounds) {
+ vec4 w = vec4(step(bounds.xy, uv), step(uv, bounds.zw));
+ return mix(center, uv, vec2(w.x*w.z, w.y*w.w));
+}
+
+void main() {
+ vec2 uv = v_texcoord0.xy;
+ vec4 offset = vec4(-1., 1., 1., 0.) / uResolution.xxyy;
+
+ vec2 center = (floor(v_texcoord0.xy * uResolution.xy) + vec2_splat(0.5)) / uResolution.xy;
+ vec4 bounds = (floor(u_source_rect.xyzw) + vec4(1.,1.,-1.,-1.)) / uResolution.xyxy;
+
+ vec4 s0 = texture2D(u_source, compute_texel(uv - offset.yz, center, bounds)); // -1,-1
+ vec4 s1 = texture2D(u_source, compute_texel(uv - offset.wz, center, bounds)); // 0,-1
+ vec4 s2 = texture2D(u_source, compute_texel(uv - offset.xz, center, bounds)); // 1,-1
+
+ vec4 s3 = texture2D(u_source, compute_texel(uv + offset.xw, center, bounds)); // -1, 0
+ vec4 s4 = texture2D(u_source, compute_texel(uv, center, bounds)); // 0, 0
+ vec4 s5 = texture2D(u_source, compute_texel(uv + offset.yw, center, bounds)); // 1, 0
+
+ vec4 s6 = texture2D(u_source, compute_texel(uv + offset.xz, center, bounds)); // -1, 1
+ vec4 s7 = texture2D(u_source, compute_texel(uv + offset.wz, center, bounds)); // 0, 1
+ vec4 s8 = texture2D(u_source, compute_texel(uv + offset.yz, center, bounds)); // 1, 1
+
+ offset = 0.5 * offset;
+
+ vec4 t0 = texture2D(u_source, compute_texel(uv - offset.yz, center, bounds)); // -1,-1
+ vec4 t1 = texture2D(u_source, compute_texel(uv - offset.xz, center, bounds)); // 1,-1
+ vec4 t2 = texture2D(u_source, compute_texel(uv + offset.xz, center, bounds)); // -1, 1
+ vec4 t3 = texture2D(u_source, compute_texel(uv + offset.yz, center, bounds)); // 1, 1
+
+ vec4 v0 = s0 + s1 + s3 + s4;
+ vec4 v1 = s1 + s2 + s4 + s5;
+ vec4 v2 = s3 + s4 + s6 + s7;
+ vec4 v3 = s4 + s5 + s7 + s8;
+ vec4 v4 = t0 + t1 + t2 + t3;
+
+ gl_FragColor = (((v0 + v1 + v2 + v3) / 4.) + v4) / 8.;
+}
diff --git a/app/resources/core/shader/bloom_downsample_varying.def b/app/resources/core/shader/bloom_downsample_varying.def
new file mode 100644
index 0000000..b7b69d9
--- /dev/null
+++ b/app/resources/core/shader/bloom_downsample_varying.def
@@ -0,0 +1,4 @@
+vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0);
+
+vec3 a_position : POSITION;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/app/resources/core/shader/bloom_downsample_vs.sc b/app/resources/core/shader/bloom_downsample_vs.sc
new file mode 100644
index 0000000..47acae3
--- /dev/null
+++ b/app/resources/core/shader/bloom_downsample_vs.sc
@@ -0,0 +1,16 @@
+$input a_position, a_texcoord0
+$output v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+uniform vec4 u_source_rect;
+
+void main() {
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_GLSL
+ v_texcoord0 = mix(vec2(u_source_rect.x, uResolution.y - u_source_rect.w), vec2(u_source_rect.z, uResolution.y - u_source_rect.y), a_texcoord0) / uResolution.xy;
+#else
+ v_texcoord0 = mix(u_source_rect.xy, u_source_rect.zw, a_texcoord0.xy) / uResolution.xy; // interpolate source rect as UV over primitive
+#endif
+}
diff --git a/app/resources/core/shader/bloom_threshold_fs.sc b/app/resources/core/shader/bloom_threshold_fs.sc
new file mode 100644
index 0000000..88731d7
--- /dev/null
+++ b/app/resources/core/shader/bloom_threshold_fs.sc
@@ -0,0 +1,19 @@
+$input v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+uniform vec4 u_params;
+SAMPLER2D(u_source, 0);
+
+void main() {
+ float threshold = u_params.x;
+ float knee = u_params.y;
+
+ vec4 color = texture2D(u_source, gl_FragCoord.xy / uResolution.xy);
+ float lum = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
+ float r = clamp(lum - threshold + knee, 0, 2. * knee);
+ r = (r * r) / (4. * knee);
+
+ gl_FragColor = color * max(r , lum - threshold) / max(lum, 0.00001);
+}
diff --git a/app/resources/core/shader/bloom_threshold_varying.def b/app/resources/core/shader/bloom_threshold_varying.def
new file mode 100644
index 0000000..b7b69d9
--- /dev/null
+++ b/app/resources/core/shader/bloom_threshold_varying.def
@@ -0,0 +1,4 @@
+vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0);
+
+vec3 a_position : POSITION;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/app/resources/core/shader/bloom_threshold_vs.sc b/app/resources/core/shader/bloom_threshold_vs.sc
new file mode 100644
index 0000000..7519a3d
--- /dev/null
+++ b/app/resources/core/shader/bloom_threshold_vs.sc
@@ -0,0 +1,10 @@
+$input a_position, a_texcoord0
+$output v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main() {
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0) );
+ v_texcoord0 = a_texcoord0;
+}
diff --git a/app/resources/core/shader/bloom_upsample_fs.sc b/app/resources/core/shader/bloom_upsample_fs.sc
new file mode 100644
index 0000000..d121004
--- /dev/null
+++ b/app/resources/core/shader/bloom_upsample_fs.sc
@@ -0,0 +1,35 @@
+$input v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+SAMPLER2D(u_source, 0);
+uniform vec4 u_source_rect;
+uniform vec4 u_params;
+
+vec2 compute_texel(vec2 uv, vec2 center, vec4 bounds) {
+ vec4 w = vec4(step(bounds.xy, uv), step(uv, bounds.zw));
+ return mix(center, uv, vec2(w.x*w.z, w.y*w.w));
+}
+
+void main() {
+ vec2 uv = v_texcoord0.xy;
+ vec4 offset = vec4(-1., 1., 1., 0.) / uResolution.xxyy;
+
+ vec2 center = (floor(v_texcoord0.xy * uResolution.xy) + vec2_splat(0.5)) / uResolution.xy;
+ vec4 bounds = (floor(u_source_rect.xyzw) + vec4(1.,1.,-1.,-1.)) / uResolution.xyxy;
+
+ vec4 t0 = texture2D(u_source, compute_texel(uv - offset.yz, center, bounds)); // -1,-1
+ vec4 t1 = texture2D(u_source, compute_texel(uv - offset.wz, center, bounds)); // 0,-1
+ vec4 t2 = texture2D(u_source, compute_texel(uv - offset.xz, center, bounds)); // 1,-1
+
+ vec4 t3 = texture2D(u_source, compute_texel(uv + offset.xw, center, bounds)); // -1, 0
+ vec4 t4 = texture2D(u_source, compute_texel(uv, center, bounds));
+ vec4 t5 = texture2D(u_source, compute_texel(uv + offset.yw, center, bounds)); // 1, 0
+
+ vec4 t6 = texture2D(u_source, compute_texel(uv + offset.xz, center, bounds)); // -1, 1
+ vec4 t7 = texture2D(u_source, compute_texel(uv + offset.wz, center, bounds)); // 0, 1
+ vec4 t8 = texture2D(u_source, compute_texel(uv + offset.yz, center, bounds)); // 1, 1
+
+ gl_FragColor = u_params.z * (t0 + t2 + t6 + t8 + 2. * (t1 + t3 + t5 + t7) + 4. * t4) / 16.;
+}
diff --git a/app/resources/core/shader/bloom_upsample_varying.def b/app/resources/core/shader/bloom_upsample_varying.def
new file mode 100644
index 0000000..b7b69d9
--- /dev/null
+++ b/app/resources/core/shader/bloom_upsample_varying.def
@@ -0,0 +1,4 @@
+vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0);
+
+vec3 a_position : POSITION;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/app/resources/core/shader/bloom_upsample_vs.sc b/app/resources/core/shader/bloom_upsample_vs.sc
new file mode 100644
index 0000000..df637d9
--- /dev/null
+++ b/app/resources/core/shader/bloom_upsample_vs.sc
@@ -0,0 +1,16 @@
+$input a_position, a_texcoord0
+$output v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+uniform vec4 u_source_rect;
+
+void main() {
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0., 1.));
+#if BGFX_SHADER_LANGUAGE_GLSL
+ v_texcoord0 = mix(vec2(u_source_rect.x, uResolution.y - u_source_rect.w), vec2(u_source_rect.z, uResolution.y - u_source_rect.y), a_texcoord0) / uResolution.xy;
+#else
+ v_texcoord0 = mix(u_source_rect.xy, u_source_rect.zw, a_texcoord0.xy) / uResolution.xy; // interpolate source rect as UV over primitive
+#endif
+}
diff --git a/app/resources/core/shader/compositing_fs.sc b/app/resources/core/shader/compositing_fs.sc
new file mode 100644
index 0000000..c22ffcf
--- /dev/null
+++ b/app/resources/core/shader/compositing_fs.sc
@@ -0,0 +1,106 @@
+$input v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+SAMPLER2D(u_copyColor, 0);
+SAMPLER2D(u_copyDepth, 1);
+
+/*
+ tone-mapping operators implementation taken from https://www.shadertoy.com/view/lslGzl
+*/
+
+vec3 LinearToneMapping(vec3 color, float exposure) { // 1.
+ color = clamp(exposure * color, 0., 1.);
+ return color;
+}
+
+vec3 SimpleReinhardToneMapping(vec3 color, float exposure) { // 1.5
+ color *= exposure / (1. + color / exposure);
+ return color;
+}
+
+vec3 LumaBasedReinhardToneMapping(vec3 color) {
+ float luma = dot(color, vec3(0.2126, 0.7152, 0.0722));
+ float toneMappedLuma = luma / (1. + luma);
+ color *= toneMappedLuma / luma;
+ return color;
+}
+
+vec3 WhitePreservingLumaBasedReinhardToneMapping(vec3 color, float white) { // 2.
+ float luma = dot(color, vec3(0.2126, 0.7152, 0.0722));
+ float toneMappedLuma = luma * (1. + luma / (white * white)) / (1. + luma);
+ color *= toneMappedLuma / luma;
+ return color;
+}
+
+vec3 RomBinDaHouseToneMapping(vec3 color) {
+ color = exp(-1. / (2.72 * color + 0.15));
+ return color;
+}
+
+vec3 FilmicToneMapping(vec3 color) {
+ color = max(vec3(0., 0., 0.), color - vec3(0.004, 0.004, 0.004));
+ color = (color * (6.2 * color + .5)) / (color * (6.2 * color + 1.7) + 0.06);
+ return color;
+}
+
+vec3 Uncharted2ToneMapping(vec3 color, float exposure) {
+ float A = 0.15;
+ float B = 0.50;
+ float C = 0.10;
+ float D = 0.20;
+ float E = 0.02;
+ float F = 0.30;
+ float W = 11.2;
+ color *= exposure;
+ color = ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F;
+ float white = ((W * (A * W + C * B) + D * E) / (W * (A * W + B) + D * F)) - E / F;
+ color /= white;
+ return color;
+}
+
+vec4 Sharpen(vec2 uv, float strength) {
+ vec4 up = texture2D(u_copyColor, uv + vec2(0, 1) / uResolution.xy);
+ vec4 left = texture2D(u_copyColor, uv + vec2(-1, 0) / uResolution.xy);
+ vec4 center = texture2D(u_copyColor, uv);
+ vec4 right = texture2D(u_copyColor, uv + vec2(1, 0) / uResolution.xy);
+ vec4 down = texture2D(u_copyColor, uv + vec2(0, -1) / uResolution.xy);
+
+ float exposure = uAAAParams[1].x;
+ up.xyz = SimpleReinhardToneMapping(up.xyz, exposure);
+ left.xyz = SimpleReinhardToneMapping(left.xyz, exposure);
+ center.xyz = SimpleReinhardToneMapping(center.xyz, exposure);
+ right.xyz = SimpleReinhardToneMapping(right.xyz, exposure);
+ down.xyz = SimpleReinhardToneMapping(down.xyz, exposure);
+
+ vec4 res = (1.0 + 4.0 * strength) * center - strength * (up + left + right + down);
+ return vec4(res.xyz, center.w);
+}
+
+void main() {
+#if 1
+ vec4 in_sample = Sharpen(v_texcoord0, uAAAParams[2].y);
+
+ vec3 color = in_sample.xyz;
+ float alpha = in_sample.w;
+#else
+ vec4 in_sample = texture2D(u_copyColor, v_texcoord0);
+
+ vec3 color = in_sample.xyz;
+ float alpha = in_sample.w;
+
+ float exposure = uAAAParams[1].x;
+ color = SimpleReinhardToneMapping(color, exposure);
+ //color = lumaBasedReinhardToneMapping(color);
+ //color = FilmicToneMapping(color);
+ //color = Uncharted2ToneMapping(color, exposure);
+#endif
+
+ // gamma correction
+ float inv_gamma = uAAAParams[1].y;
+ color = pow(color, vec3_splat(inv_gamma));
+
+ gl_FragColor = vec4(color, alpha);
+ gl_FragDepth = texture2D(u_copyDepth, v_texcoord0).r;
+}
diff --git a/app/resources/core/shader/compositing_varying.def b/app/resources/core/shader/compositing_varying.def
new file mode 100644
index 0000000..8fdde79
--- /dev/null
+++ b/app/resources/core/shader/compositing_varying.def
@@ -0,0 +1,4 @@
+vec2 v_texcoord0 : TEXCOORD0;
+
+vec3 a_position : POSITION;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/app/resources/core/shader/compositing_vs.sc b/app/resources/core/shader/compositing_vs.sc
new file mode 100644
index 0000000..38cbd27
--- /dev/null
+++ b/app/resources/core/shader/compositing_vs.sc
@@ -0,0 +1,10 @@
+$input a_position, a_texcoord0
+$output v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main() {
+ gl_Position = mul(u_modelViewProj, vec4(a_position, 1.0));
+ v_texcoord0 = a_texcoord0;
+}
diff --git a/app/resources/core/shader/copy_fs.sc b/app/resources/core/shader/copy_fs.sc
new file mode 100644
index 0000000..3f7b43f
--- /dev/null
+++ b/app/resources/core/shader/copy_fs.sc
@@ -0,0 +1,12 @@
+$input v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+SAMPLER2D(u_copyColor, 0);
+SAMPLER2D(u_copyDepth, 1);
+
+void main() {
+ gl_FragColor = texture2D(u_copyColor, v_texcoord0);
+ gl_FragDepth = texture2D(u_copyDepth, v_texcoord0).r;
+}
diff --git a/app/resources/core/shader/copy_varying.def b/app/resources/core/shader/copy_varying.def
new file mode 100644
index 0000000..8fdde79
--- /dev/null
+++ b/app/resources/core/shader/copy_varying.def
@@ -0,0 +1,4 @@
+vec2 v_texcoord0 : TEXCOORD0;
+
+vec3 a_position : POSITION;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/app/resources/core/shader/copy_vs.sc b/app/resources/core/shader/copy_vs.sc
new file mode 100644
index 0000000..38cbd27
--- /dev/null
+++ b/app/resources/core/shader/copy_vs.sc
@@ -0,0 +1,10 @@
+$input a_position, a_texcoord0
+$output v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main() {
+ gl_Position = mul(u_modelViewProj, vec4(a_position, 1.0));
+ v_texcoord0 = a_texcoord0;
+}
diff --git a/app/resources/core/shader/default.hps b/app/resources/core/shader/default.hps
new file mode 100644
index 0000000..861f19d
--- /dev/null
+++ b/app/resources/core/shader/default.hps
@@ -0,0 +1,3 @@
+{
+ "features": ["OptionalDiffuseMap", "OptionalSkinning"]
+}
diff --git a/app/resources/core/shader/default_fs.sc b/app/resources/core/shader/default_fs.sc
new file mode 100644
index 0000000..5a50f59
--- /dev/null
+++ b/app/resources/core/shader/default_fs.sc
@@ -0,0 +1,245 @@
+$input vWorldPos, vNormal, vTangent, vBinormal, vTexCoord0, vTexCoord1, vLinearShadowCoord0, vLinearShadowCoord1, vLinearShadowCoord2, vLinearShadowCoord3, vSpotShadowCoord, vProjPos, vPrevProjPos
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+// Surface attributes
+uniform vec4 uDiffuseColor;
+uniform vec4 uSpecularColor;
+uniform vec4 uSelfColor;
+
+// Texture slots
+SAMPLER2D(uDiffuseMap, 0); // PBR metalness in alpha
+SAMPLER2D(uSpecularMap, 1); // PBR roughness in alpha
+SAMPLER2D(uNormalMap, 2); // Parallax mapping elevation in alpha
+SAMPLER2D(uLightMap, 3);
+SAMPLER2D(uSelfMap, 4);
+SAMPLER2D(uOpacityMap, 5);
+SAMPLER2D(uAmbientMap, 6);
+SAMPLER2D(uReflectionMap, 7);
+
+//
+struct LightModelOut {
+ float i_diff;
+ float i_spec;
+};
+
+// Forward Phong
+LightModelOut PhongLightModel(vec3 V, vec3 N, vec3 R, vec3 L, float gloss) {
+ LightModelOut m;
+ m.i_diff = max(-dot(L, N), 0.0);
+ m.i_spec = pow(max(-dot(L, R), 0.0), gloss);
+ return m;
+}
+
+float LightAttenuation(vec3 L, vec3 D, float dist, float attn, float inner_rim, float outer_rim) {
+ float k = 1.0;
+ if (attn > 0.0)
+ k = max(1.0 - dist * attn, 0.0); // distance attenuation
+
+ if (outer_rim > 0.0) {
+ float c = dot(L, D);
+ k *= clamp(1.0 - (c - inner_rim) / (outer_rim - inner_rim), 0.0, 1.0); // spot attenuation
+ }
+ return k;
+}
+
+//
+vec3 DistanceFog(vec3 pos, vec3 color) {
+ if (uFogState.y == 0.0)
+ return color;
+
+ float k = clamp((pos.z - uFogState.x) * uFogState.y, 0.0, 1.0);
+ return mix(color, uFogColor.xyz, k);
+}
+
+float SampleHardShadow(sampler2DShadow map, vec4 coord, float bias) {
+ vec3 uv = coord.xyz / coord.w;
+ return shadow2D(map, vec3(uv.xy, uv.z - bias));
+}
+
+float SampleShadowPCF(sampler2DShadow map, vec4 coord, float inv_pixel_size, float bias) {
+ float k_pixel_size = inv_pixel_size * coord.w;
+
+ float k = 0.0;
+
+ k += SampleHardShadow(map, coord + vec4(vec2(-0.5, -0.5) * k_pixel_size, 0.0, 0.0), bias);
+ k += SampleHardShadow(map, coord + vec4(vec2( 0.5, -0.5) * k_pixel_size, 0.0, 0.0), bias);
+ k += SampleHardShadow(map, coord + vec4(vec2(-0.5, 0.5) * k_pixel_size, 0.0, 0.0), bias);
+ k += SampleHardShadow(map, coord + vec4(vec2( 0.5, 0.5) * k_pixel_size, 0.0, 0.0), bias);
+
+ return k / 4.0;
+}
+
+// Entry point of the forward pipeline default shader
+void main() {
+#if DEPTH_ONLY != 1
+#if USE_DIFFUSE_MAP
+#if DIFFUSE_UV_CHANNEL == 1
+ vec3 diff = texture2D(uDiffuseMap, vTexCoord1).xyz;
+#else // DIFFUSE_UV_CHANNEL == 1
+ vec3 diff = texture2D(uDiffuseMap, vTexCoord0).xyz;
+#endif // DIFFUSE_UV_CHANNEL == 1
+#else // USE_DIFFUSE_MAP
+ vec3 diff = uDiffuseColor.xyz;
+#endif // USE_DIFFUSE_MAP
+
+#if USE_SPECULAR_MAP
+#if SPECULAR_UV_CHANNEL == 1
+ vec3 spec = texture2D(uSpecularMap, vTexCoord1).xyz;
+#else // SPECULAR_UV_CHANNEL == 1
+ vec3 spec = texture2D(uSpecularMap, vTexCoord0).xyz;
+#endif // SPECULAR_UV_CHANNEL == 1
+#else // USE_SPECULAR_MAP
+ vec3 spec = uSpecularColor.xyz;
+#endif // USE_SPECULAR_MAP
+
+#if USE_SELF_MAP
+ vec3 self = texture2D(uSelfMap, vTexCoord0).xyz;
+#else // USE_SELF_MAP
+ vec3 self = uSelfColor.xyz;
+#endif // USE_SELF_MAP
+
+#if USE_AMBIENT_MAP
+#if AMBIENT_UV_CHANNEL == 1
+ vec3 ao = texture2D(uAmbientMap, vTexCoord1).xyz;
+#else // AMBIENT_UV_CHANNEL == 1
+ vec3 ao = texture2D(uAmbientMap, vTexCoord0).xyz;
+#endif // AMBIENT_UV_CHANNEL == 1
+#else // USE_AMBIENT_MAP
+ vec3 ao = vec3_splat(1.0);
+#endif // USE_AMBIENT_MAP
+
+#if USE_ADVANCED_BUFFERS
+ ao *= texture2D(uAmbientOcclusion, gl_FragCoord.xy / uResolution.xy).x;
+#endif // USE_ADVANCED_BUFFERS
+
+#if USE_LIGHT_MAP
+ vec3 light = texture2D(uLightMap, vTexCoord1).xyz;
+#else // USE_LIGHT_MAP
+ vec3 light = vec3_splat(0.0);
+#endif // USE_LIGHT_MAP
+
+ //
+ vec3 view = mul(u_view, vec4(vWorldPos,1.0)).xyz; // fragment view space pos
+ vec3 P = vWorldPos; // fragment world pos
+ vec3 V = normalize(GetT(u_invView) - P); // view vector
+ vec3 N = normalize(vNormal); // geometry normal
+
+#if USE_NORMAL_MAP
+ vec3 T = normalize(vTangent);
+ vec3 B = normalize(vBinormal);
+
+ mat3 TBN = MakeMat3(T, B, N);
+
+ N.xy = texture2D(uNormalMap, vTexCoord0).xy * 2.0 - 1.0;
+ N.z = sqrt(1.0 - dot(N.xy, N.xy));
+ N = normalize(mul(N, TBN));
+#endif // USE_NORMAL_MAP
+
+ vec3 R = reflect(-V, N); // view reflection vector around normal
+
+ float gloss = 64.0 / uSpecularColor.w;
+
+ // SLOT 0: linear light
+ vec3 c_diff, c_spec;
+
+ {
+ LightModelOut m = PhongLightModel(V, N, R, uLightDir[0].xyz, gloss);
+
+ float k = 1.0;
+#if SLOT0_SHADOWS
+ if(view.z < uLinearShadowSlice.x) {
+ k *= SampleShadowPCF(uLinearShadowMap, vLinearShadowCoord0, uShadowState.y * 0.5, uShadowState.z);
+ }
+ else if(view.z < uLinearShadowSlice.y) {
+ k *= SampleShadowPCF(uLinearShadowMap, vLinearShadowCoord1, uShadowState.y * 0.5, uShadowState.z);
+ }
+ else if(view.z < uLinearShadowSlice.z) {
+ k *= SampleShadowPCF(uLinearShadowMap, vLinearShadowCoord2, uShadowState.y * 0.5, uShadowState.z);
+ }
+ else if(view.z < uLinearShadowSlice.w) {
+ float pcf = SampleShadowPCF(uLinearShadowMap, vLinearShadowCoord3, uShadowState.y * 0.5, uShadowState.z);
+ float ramp_len = (uLinearShadowSlice.w - uLinearShadowSlice.z) * 0.25;
+ float ramp_k = clamp((view.z - (uLinearShadowSlice.w - ramp_len)) / ramp_len, 0.0, 1.0);
+ k *= pcf * (1.0 - ramp_k) + ramp_k;
+ }
+#endif // SLOT0_SHADOWS
+ c_diff = uLightDiffuse[0].xyz * m.i_diff * k;
+ c_spec = uLightSpecular[0].xyz * m.i_spec * k;
+ }
+
+ // SLOT 1: point/spot light (with optional shadows)
+ {
+ vec3 L = P - uLightPos[1].xyz; // incident
+
+ float D = length(L);
+ L /= D; // normalize
+
+ LightModelOut m = PhongLightModel(V, N, R, L, gloss);
+ float k = LightAttenuation(L, uLightDir[1].xyz, D, uLightPos[1].w, uLightDir[1].w, uLightDiffuse[1].w);
+
+#if SLOT1_SHADOWS
+ k *= SampleShadowPCF(uSpotShadowMap, vSpotShadowCoord, uShadowState.y, uShadowState.w);
+#endif // SLOT1_SHADOWS
+
+ c_diff += uLightDiffuse[1].xyz * m.i_diff * k;
+ c_spec += uLightSpecular[1].xyz * m.i_spec * k;
+ }
+
+ // SLOT 2-N: point/spot light (no shadows)
+ for (int i = 2; i < 8; ++i) {
+ vec3 L = P - uLightPos[i].xyz; // incident
+
+ float D = length(L);
+ L /= D; // normalize
+
+ LightModelOut m = PhongLightModel(V, N, R, L, gloss);
+ float k = LightAttenuation(L, uLightDir[i].xyz, D, uLightPos[i].w, uLightDir[i].w, uLightDiffuse[i].w);
+
+ c_diff += uLightDiffuse[i].xyz * m.i_diff * k;
+ c_spec += uLightSpecular[i].xyz * m.i_spec * k;
+ }
+
+ c_diff += uAmbientColor.xyz * ao.xyz;
+
+ vec3 color = diff * (c_diff + light) + spec * c_spec + self;
+
+#if USE_REFLECTION_MAP
+ vec4 reflection = texture2D(uReflectionMap, R.xy);
+ color += reflection.xyz;
+#endif // USE_REFLECTION_MAP
+
+ color = DistanceFog(view, color);
+#endif // DEPTH_ONLY != 1
+
+#if USE_OPACITY_MAP
+ float opacity = texture2D(uOpacityMap, vTexCoord0).x;
+
+#if ENABLE_ALPHA_CUT
+ if (opacity < 0.8)
+ discard;
+#endif // ENABLE_ALPHA_CUT
+#else // USE_OPACITY_MAP
+ float opacity = 1.0;
+#endif // USE_OPACITY_MAP
+
+#if DEPTH_ONLY != 1
+#if FORWARD_PIPELINE_AAA_PREPASS
+ vec3 N_view = mul(u_view, vec4(N, 0)).xyz;
+ vec2 velocity = vec2(vProjPos.xy / vProjPos.w - vPrevProjPos.xy / vPrevProjPos.w);
+ gl_FragData[0] = vec4(N_view.xyz, vProjPos.z);
+ gl_FragData[1] = vec4(velocity.xy, gloss, 0.); //
+#else // FORWARD_PIPELINE_AAA_PREPASS
+ // incorrectly apply gamma correction at fragment shader level in the non-AAA pipeline
+#if FORWARD_PIPELINE_AAA != 1
+ float gamma = 2.2;
+ color = pow(color, vec3_splat(1. / gamma));
+#endif // FORWARD_PIPELINE_AAA != 1
+
+ gl_FragColor = vec4(color, opacity);
+#endif // FORWARD_PIPELINE_AAA_PREPASS
+#else
+ gl_FragColor = vec4_splat(0.0); // note: fix required to stop glsl-optimizer from removing the whole function body
+#endif // DEPTH_ONLY
+}
diff --git a/app/resources/core/shader/default_varying.def b/app/resources/core/shader/default_varying.def
new file mode 100644
index 0000000..76d199d
--- /dev/null
+++ b/app/resources/core/shader/default_varying.def
@@ -0,0 +1,22 @@
+vec3 vWorldPos : POSITIONT;
+vec3 vNormal : NORMAL;
+vec3 vTangent : TANGENT0;
+vec3 vBinormal : BINORMAL0;
+vec2 vTexCoord0 : TEXCOORD0;
+vec2 vTexCoord1 : TEXCOORD1;
+vec4 vSpotShadowCoord : TEXCOORD2;
+vec4 vLinearShadowCoord0 : TEXCOORD3;
+vec4 vLinearShadowCoord1 : TEXCOORD4;
+vec4 vLinearShadowCoord2 : TEXCOORD5;
+vec4 vLinearShadowCoord3 : TEXCOORD6;
+vec4 vProjPos : TEXCOORD7;
+vec4 vPrevProjPos : TEXCOORD8;
+
+vec3 a_position : POSITION;
+vec3 a_normal : NORMAL;
+vec2 a_texcoord0 : TEXCOORD0;
+vec2 a_texcoord1 : TEXCOORD1;
+vec3 a_tangent : TANGENT0;
+vec3 a_bitangent : BITANGENT0;
+vec4 a_indices : BLENDINDICES;
+vec4 a_weight : BLENDWEIGHT;
diff --git a/app/resources/core/shader/default_vs.sc b/app/resources/core/shader/default_vs.sc
new file mode 100644
index 0000000..c54388c
--- /dev/null
+++ b/app/resources/core/shader/default_vs.sc
@@ -0,0 +1,111 @@
+$input a_position, a_normal, a_texcoord0, a_texcoord1, a_tangent, a_bitangent, a_indices, a_weight
+$output vWorldPos, vNormal, vTexCoord0, vTexCoord1, vTangent, vBinormal, vLinearShadowCoord0, vLinearShadowCoord1, vLinearShadowCoord2, vLinearShadowCoord3, vSpotShadowCoord, vProjPos, vPrevProjPos
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+mat3 normal_mat(mat4 m) {
+ return mat3(normalize(m[0].xyz), normalize(m[1].xyz), normalize(m[2].xyz));
+}
+
+void main() {
+ // position
+ vec4 vtx = vec4(a_position, 1.0);
+
+#if ENABLE_SKINNING
+ vec4 world_pos =
+ mul(u_model[int(a_indices.x * 256.0)], vtx) * a_weight.x +
+ mul(u_model[int(a_indices.y * 256.0)], vtx) * a_weight.y +
+ mul(u_model[int(a_indices.z * 256.0)], vtx) * a_weight.z +
+ mul(u_model[int(a_indices.w * 256.0)], vtx) * a_weight.w;
+
+#if FORWARD_PIPELINE_AAA_PREPASS
+ vec4 prv_world_pos =
+ mul(uPreviousModel[int(a_indices.x * 256.0)], vtx) * a_weight.x +
+ mul(uPreviousModel[int(a_indices.y * 256.0)], vtx) * a_weight.y +
+ mul(uPreviousModel[int(a_indices.z * 256.0)], vtx) * a_weight.z +
+ mul(uPreviousModel[int(a_indices.w * 256.0)], vtx) * a_weight.w;
+#endif // FORWARD_PIPELINE_AAA_PREPASS
+#else // ENABLE_SKINNING
+ vec4 world_pos = mul(u_model[0], vtx);
+
+#if FORWARD_PIPELINE_AAA_PREPASS
+ vec4 prv_world_pos = mul(uPreviousModel[0], vtx);
+#endif // FORWARD_PIPELINE_AAA_PREPASS
+#endif // ENABLE_SKINNING
+
+#if DEPTH_ONLY != 1
+ // normal
+ vec4 normal = vec4(a_normal * 2. - 1., 0.);
+
+#if ENABLE_SKINNING
+ vec4 skinned_normal =
+ mul(u_model[int(a_indices.x * 256.0)], normal) * a_weight.x +
+ mul(u_model[int(a_indices.y * 256.0)], normal) * a_weight.y +
+ mul(u_model[int(a_indices.z * 256.0)], normal) * a_weight.z +
+ mul(u_model[int(a_indices.w * 256.0)], normal) * a_weight.w;
+
+ skinned_normal = normalize(skinned_normal);
+
+ vNormal = skinned_normal.xyz;
+#else // ENABLE_SKINNING
+ vNormal = mul(normal_mat(u_model[0]), normal.xyz);
+#endif // ENABLE_SKINNING
+
+ // tangent frame
+#if USE_NORMAL_MAP
+ vec4 tangent = vec4(a_tangent * 2.0 - 1.0, 0.0);
+ vec4 binormal = vec4(a_bitangent * 2.0 - 1.0, 0.0);
+
+#if ENABLE_SKINNING
+ vec4 skinned_tangent =
+ mul(u_model[int(a_indices.x * 256.0)], tangent) * a_weight.x +
+ mul(u_model[int(a_indices.y * 256.0)], tangent) * a_weight.y +
+ mul(u_model[int(a_indices.z * 256.0)], tangent) * a_weight.z +
+ mul(u_model[int(a_indices.w * 256.0)], tangent) * a_weight.w;
+
+ vec4 skinned_binormal =
+ mul(u_model[int(a_indices.x * 256.0)], binormal) * a_weight.x +
+ mul(u_model[int(a_indices.y * 256.0)], binormal) * a_weight.y +
+ mul(u_model[int(a_indices.z * 256.0)], binormal) * a_weight.z +
+ mul(u_model[int(a_indices.w * 256.0)], binormal) * a_weight.w;
+
+ vTangent = skinned_tangent.xyz;
+ vBinormal = skinned_binormal.xyz;
+#else // ENABLE_SKINNING
+ vTangent = mul(u_model[0], tangent).xyz;
+ vBinormal = mul(u_model[0], binormal).xyz;
+#endif // ENABLE_SKINNING
+#endif // USE_NORMAL_MAP
+
+ // shadow data
+#if SLOT0_SHADOWS || SLOT1_SHADOWS
+ float shadowMapShrinkOffset = 0.01;
+ vec3 shadowVertexShrinkOffset = vNormal * shadowMapShrinkOffset;
+#endif // SLOT0_SHADOWS || SLOT1_SHADOWS
+
+#if SLOT0_SHADOWS
+ vLinearShadowCoord0 = mul(uLinearShadowMatrix[0], vec4(world_pos.xyz + shadowVertexShrinkOffset, 1.0));
+ vLinearShadowCoord1 = mul(uLinearShadowMatrix[1], vec4(world_pos.xyz + shadowVertexShrinkOffset, 1.0));
+ vLinearShadowCoord2 = mul(uLinearShadowMatrix[2], vec4(world_pos.xyz + shadowVertexShrinkOffset, 1.0));
+ vLinearShadowCoord3 = mul(uLinearShadowMatrix[3], vec4(world_pos.xyz + shadowVertexShrinkOffset, 1.0));
+#endif // SLOT0_SHADOWS
+
+#if SLOT1_SHADOWS
+ vSpotShadowCoord = mul(uSpotShadowMatrix, vec4(world_pos.xyz + shadowVertexShrinkOffset, 1.0));
+#endif // SLOT1_SHADOWS
+#endif // DEPTH_ONLY != 1
+
+ vWorldPos = world_pos.xyz;
+
+ vTexCoord0 = a_texcoord0;
+ vTexCoord1 = a_texcoord1;
+
+ vec4 proj_pos = mul(uViewProjUnjittered, world_pos);
+#if FORWARD_PIPELINE_AAA_PREPASS
+ vProjPos = proj_pos;
+ vPrevProjPos = mul(uPreviousViewProjection, prv_world_pos);
+#endif // FORWARD_PIPELINE_AAA_PREPASS
+
+ gl_Position = mul(u_viewProj, world_pos);
+}
diff --git a/app/resources/core/shader/denoise_fs.sc b/app/resources/core/shader/denoise_fs.sc
new file mode 100644
index 0000000..4909ae8
--- /dev/null
+++ b/app/resources/core/shader/denoise_fs.sc
@@ -0,0 +1,85 @@
+/*
+5x5 Median
+
+GLSL 1.0
+Morgan McGuire and Kyle Whitson, 2006
+Williams College
+http://graphics.cs.williams.edu
+
+Copyright (c) Morgan McGuire and Williams College, 2006
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include
+
+SAMPLER2D(u_source, 0);
+
+#define s2(a, b) temp = a; a = min(a, b); b = max(temp, b);
+#define t2(a, b) s2(v[a], v[b]);
+#define t24(a, b, c, d, e, f, g, h) t2(a, b); t2(c, d); t2(e, f); t2(g, h);
+#define t25(a, b, c, d, e, f, g, h, i, j) t24(a, b, c, d, e, f, g, h); t2(i, j);
+
+void main() {
+ vec2 uv = gl_FragCoord.xy / uResolution.xy;
+
+ vec4 v[25];
+
+ // add the pixels which make up our window to the pixel array
+ for(int dX = -2; dX <= 2; ++dX) {
+ for(int dY = -2; dY <= 2; ++dY) {
+ vec2 dt = vec2(float(dX), float(dY));
+
+ // If a pixel in the window is located at (x+dX, y+dY), put it at index (dX + R)(2R + 1) + (dY + R) of the
+ // pixel array. This will fill the pixel array, with the top left pixel of the window at pixel[0] and the
+ // bottom right pixel of the window at pixel[N-1].
+ v[(dX + 2) * 5 + (dY + 2)] = texture2D(u_source, uv + dt / uResolution.xy);
+ }
+ }
+
+ vec4 temp;
+
+ t25(0, 1, 3, 4, 2, 4, 2, 3, 6, 7);
+ t25(5, 7, 5, 6, 9, 7, 1, 7, 1, 4);
+ t25(12, 13, 11, 13, 11, 12, 15, 16, 14, 16);
+ t25(14, 15, 18, 19, 17, 19, 17, 18, 21, 22);
+ t25(20, 22, 20, 21, 23, 24, 2, 5, 3, 6);
+ t25(0, 6, 0, 3, 4, 7, 1, 7, 1, 4);
+ t25(11, 14, 8, 14, 8, 11, 12, 15, 9, 15);
+ t25(9, 12, 13, 16, 10, 16, 10, 13, 20, 23);
+ t25(17, 23, 17, 20, 21, 24, 18, 24, 18, 21);
+ t25(19, 22, 8, 17, 9, 18, 0, 18, 0, 9);
+ t25(10, 19, 1, 19, 1, 10, 11, 20, 2, 20);
+ t25(2, 11, 12, 21, 3, 21, 3, 12, 13, 22);
+ t25(4, 22, 4, 13, 14, 23, 5, 23, 5, 14);
+ t25(15, 24, 6, 24, 6, 15, 7, 16, 7, 19);
+ t25(3, 11, 5, 17, 11, 17, 9, 17, 4, 10);
+ t25(6, 12, 7, 14, 4, 6, 4, 7, 12, 14);
+ t25(10, 14, 6, 7, 10, 12, 6, 10, 6, 17);
+ t25(12, 17, 7, 17, 7, 10, 12, 18, 7, 12);
+ t24(10, 18, 12, 20, 10, 20, 10, 12);
+
+ gl_FragColor = v[12];
+}
diff --git a/app/resources/core/shader/denoise_varying.def b/app/resources/core/shader/denoise_varying.def
new file mode 100644
index 0000000..76522d5
--- /dev/null
+++ b/app/resources/core/shader/denoise_varying.def
@@ -0,0 +1 @@
+vec3 a_position : POSITION;
diff --git a/app/resources/core/shader/denoise_vs.sc b/app/resources/core/shader/denoise_vs.sc
new file mode 100644
index 0000000..8a5a43d
--- /dev/null
+++ b/app/resources/core/shader/denoise_vs.sc
@@ -0,0 +1,8 @@
+$input a_position
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main() {
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0., 1.));
+}
diff --git a/app/resources/core/shader/font_fs.sc b/app/resources/core/shader/font_fs.sc
new file mode 100644
index 0000000..2127b0e
--- /dev/null
+++ b/app/resources/core/shader/font_fs.sc
@@ -0,0 +1,12 @@
+$input v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+uniform vec4 u_color;
+SAMPLER2D(u_tex, 0);
+
+void main() {
+ float opacity = texture2D(u_tex, v_texcoord0).w * u_color.w;
+ gl_FragColor = vec4(u_color.xyz, opacity);
+}
diff --git a/app/resources/core/shader/font_varying.def b/app/resources/core/shader/font_varying.def
new file mode 100644
index 0000000..ece5127
--- /dev/null
+++ b/app/resources/core/shader/font_varying.def
@@ -0,0 +1,4 @@
+vec2 v_texcoord0 : TEXCOORD0;
+
+vec3 a_position : POSITION;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/app/resources/core/shader/font_vs.sc b/app/resources/core/shader/font_vs.sc
new file mode 100644
index 0000000..569636a
--- /dev/null
+++ b/app/resources/core/shader/font_vs.sc
@@ -0,0 +1,10 @@
+$input a_position, a_texcoord0
+$output v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main() {
+ gl_Position = mul(u_modelViewProj, vec4(a_position, 1.0));
+ v_texcoord0 = a_texcoord0;
+}
diff --git a/app/resources/core/shader/forward_pipeline.sh b/app/resources/core/shader/forward_pipeline.sh
new file mode 100644
index 0000000..a7fd130
--- /dev/null
+++ b/app/resources/core/shader/forward_pipeline.sh
@@ -0,0 +1,167 @@
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+
+// DO NOT MODIFY THIS FILE!
+
+#include
+
+#define PI 3.14159265359
+
+uniform vec4 uClock; // clock
+
+// Environment
+uniform vec4 uFogColor;
+uniform vec4 uFogState; // fog_near, 1.0/fog_range
+
+// Lighting environment
+uniform vec4 uAmbientColor;
+
+uniform vec4 uLightPos[8]; // pos.xyz, 1.0/radius
+uniform vec4 uLightDir[8]; // dir.xyz, inner_rim
+uniform vec4 uLightDiffuse[8]; // diffuse.xyz, outer_rim
+uniform vec4 uLightSpecular[8]; // specular.xyz, pssm_bias
+
+uniform mat4 uLinearShadowMatrix[4]; // slot 0: linear PSSM shadow matrices
+uniform vec4 uLinearShadowSlice; // slot 0: PSSM slice distances linear light
+uniform mat4 uSpotShadowMatrix; // slot 1: spot shadow matrix
+uniform vec4 uShadowState; // slot 0: inverse resolution, slot1: inverse resolution, slot0: bias, slot1: bias
+
+uniform vec4 uResolution; // xy: backbuffer resolution
+uniform vec4 uProjection;
+uniform mat4 uMainProjection; // projection for the main render (used by screenspace post-processes)
+uniform mat4 uMainInvProjection; // inverse projection for the main render (used by screenspace post-processes)
+
+uniform mat4 uPreviousViewProjection;
+uniform mat4 uPreviousModel[BGFX_CONFIG_MAX_BONES];
+uniform mat4 uViewProjUnjittered;
+uniform vec4 uAAAParams[3]; // [0].x: ssgi ratio, [0].y: ssr ratio, [0].z: temporal AA weight, [0].w: motion blur strength,
+ // [1].x: exposure, [1].y: 1/gamma, [1].z: sample count, [1].w: screenspace ray max length
+ // [2].x: specular weight, [2].y: sharpen
+
+uniform mat4 uMainInvView; // inversion view matrix
+uniform mat4 uProbeMatrix;
+uniform mat4 uInvProbeMatrix;
+uniform vec4 uProbeData;
+
+/*
+ Reserved texture units for the AAA forward pipeline.
+ Do not modify these slots, they are hardcoded on the C++ side.
+
+ If reserving new slots for the pipeline please keep in mind WebGL limitations: https://webglreport.com/?v=2
+ At the moment it is not advisable to use texture units beyond 16 for embedded platforms.
+*/
+SAMPLERCUBE(uIrradianceMap, 8);
+SAMPLERCUBE(uRadianceMap, 9);
+SAMPLER2D(uSSIrradianceMap, 10);
+SAMPLER2D(uSSRadianceMap, 11);
+SAMPLER2D(uBrdfMap, 12);
+SAMPLER2D(uNoiseMap, 13);
+SAMPLER2DSHADOW(uLinearShadowMap, 14);
+SAMPLER2DSHADOW(uSpotShadowMap, 15);
+
+//
+float sRGB2linear(float v) {
+ return (v < 0.04045) ? (v * 0.0773993808) : pow((v + 0.055) / 1.055, 2.4);
+}
+
+vec3 sRGB2linear(vec3 v) {
+ return vec3(sRGB2linear(v.x), sRGB2linear(v.y), sRGB2linear(v.z));
+}
+
+//
+mat3 MakeMat3(vec3 c0, vec3 c1, vec3 c2) {
+ return mat3(c0, c1, c2);
+}
+
+vec3 GetT(mat4 m) {
+#if BGFX_SHADER_LANGUAGE_GLSL
+ return vec3(m[3][0], m[3][1], m[3][2]);
+#else
+ return vec3(m[0][3], m[1][3], m[2][3]);
+#endif
+}
+
+float LinearDepth(float z) {
+ return uProjection.w / (z - uProjection.z);
+}
+
+// from screen space to view space
+vec3 Unproject(vec3 frag_coord) {
+ vec4 clip = vec4(((frag_coord.xy - u_viewRect.xy) / u_viewRect.zw) * 2. - 1., frag_coord.z, 1.);
+ vec4 ndc = mul(clip, uMainInvProjection);
+ return ndc.xyz / ndc.w;
+}
+
+vec3 ComputeFragCoordViewRay(vec2 frag_coord) {
+ vec2 sp = ((frag_coord - u_viewRect.xy) / u_viewRect.zw) * 2. - 1.;
+ sp.y *= -1.;
+
+ vec4 ndc = mul(uMainInvProjection, vec4(sp, 1., 1.)); // far ndc frustum plane
+ ndc /= ndc.w;
+ ndc /= ndc.z;
+
+ return ndc.xyz;
+}
+
+bool isNan(float val) { return (val <= 0.0 || 0.0 <= val) ? false : true; }
+
+//
+vec2 RaySphere(vec3 r0, vec3 rd, vec3 s0, float sr) {
+ float a = dot(rd, rd);
+ vec3 s0_r0 = r0 - s0;
+
+ float b = 2.0 * dot(rd, s0_r0);
+ float c = dot(s0_r0, s0_r0) - (sr * sr);
+ float disc = b * b - 4.0 * a* c;
+
+ if (disc < 0.0)
+ return vec2(-1.0, -1.0);
+
+ return vec2(-b - sqrt(disc), -b + sqrt(disc)) / (2.0 * a);
+}
+
+vec3 RayBox(vec3 ray_origin, vec3 ray_dir, vec3 minpos, vec3 maxpos) {
+ vec3 inverse_dir = 1.0 / ray_dir;
+ vec3 tbot = inverse_dir * (minpos - ray_origin);
+ vec3 ttop = inverse_dir * (maxpos - ray_origin);
+ vec3 tmin = min(ttop, tbot);
+ vec3 tmax = max(ttop, tbot);
+ vec2 traverse = max(tmin.xx, tmin.yz);
+ float traverselow = max(traverse.x, traverse.y);
+ traverse = min(tmax.xx, tmax.yz);
+ float traversehi = min(traverse.x, traverse.y);
+ return vec3(float(traversehi > max(traverselow, 0.0)), traversehi, traverselow);
+}
+
+vec3 ReprojectProbe(vec3 O, vec3 V) {
+ vec3 W;
+
+ if (uProbeData.x == 0.0) {
+ vec3 local_O = mul(uInvProbeMatrix, vec4(O, 1.0)).xyz; // move ray to probe volume space
+ vec3 local_V = mul(uInvProbeMatrix, vec4(V, 0.0)).xyz;
+ local_V = normalize(local_V);
+
+ vec2 T = RaySphere(local_O, local_V, vec3(0.0, 0.0, 0.0), 0.5);
+
+ if (T.y > -1.0) {
+ vec3 local_I = local_O + local_V * T.y;
+ W = normalize(mul(uProbeMatrix, vec4(local_I, 0.0)).xyz);
+ } else {
+ return V;
+ }
+ } else if (uProbeData.x == 1.0) {
+ vec3 local_O = mul(uInvProbeMatrix, vec4(O, 1.0)).xyz; // move ray to probe volume space
+ vec3 local_V = mul(uInvProbeMatrix, vec4(V, 0.0)).xyz;
+ local_V = normalize(local_V);
+
+ vec3 T = RayBox(local_O, local_V, vec3(-0.5, -0.5, -0.5), vec3(0.5, 0.5, 0.5)); // intersect with volume
+
+ if (T.x == 0.0) {
+ return V;
+ } else {
+ vec3 local_I = local_O + local_V * T.y;
+ W = normalize(mul(uProbeMatrix, vec4(local_I, 0.0)).xyz); // move intersection back to world space
+ }
+ }
+
+ return normalize(mix(V, W, uProbeData.y));
+}
diff --git a/app/resources/core/shader/hiz_compute_cs.sc b/app/resources/core/shader/hiz_compute_cs.sc
new file mode 100644
index 0000000..184e56c
--- /dev/null
+++ b/app/resources/core/shader/hiz_compute_cs.sc
@@ -0,0 +1,53 @@
+#include "bgfx_compute.sh"
+
+// Build the remaining levels of the minimum depth pyramid.
+
+IMAGE2D_RO(u_depthTexIn, rg32f, 0); // input: level i of the min depth pyramid
+IMAGE2D_WR(u_depthTexOut, rg32f, 1); // output: level i+1 of the min depth pyramid
+
+NUM_THREADS(16, 16, 1)
+void main() {
+ ivec2 sizeOut = imageSize(u_depthTexOut);
+ ivec2 coordOut = ivec2(gl_GlobalInvocationID.xy);
+
+ ivec2 sizeIn = imageSize(u_depthTexIn);
+ ivec2 coordIn = coordOut * 2;
+
+ vec2 z = vec2(1.0, 0.0);
+
+ // The computation is applied on all the texture area.
+ // It's not restricted to the actual viewport so we don't need to perform any extra check.
+ vec2 z0 = imageLoad(u_depthTexIn, coordIn).xy;
+ vec2 z2 = imageLoad(u_depthTexIn, coordIn + ivec2(0, 1)).xy;
+ vec2 z1 = imageLoad(u_depthTexIn, coordIn + ivec2(1, 0)).xy;
+ vec2 z3 = imageLoad(u_depthTexIn, coordIn + ivec2(1, 1)).xy;
+
+ z.x = min(min(z0.x, z1.x), min(z2.x, z3.x));
+ z.y = max(max(z0.y, z1.y), max(z2.y, z3.y));
+
+ // Here we handle the case where the size of the previous level is odd and we are on the boundaries
+ // of the output texture.
+ // In this case, we will need to sample an extra row or column.
+ bvec4 odd_last = bvec4(greaterThan(sizeIn.xy, 2*sizeOut.xy), equal(coordOut, sizeOut-ivec2(1,1)));
+ bvec2 extra_fetch = bvec2(all(odd_last.xz), all(odd_last.yw));
+ if(extra_fetch.x) {
+ vec2 z4 = imageLoad(u_depthTexIn, coordIn + ivec2(2,0)).xy;
+ vec2 z5 = imageLoad(u_depthTexIn, coordIn + ivec2(2,1)).xy;
+ z.x = min(z.x, min(z4.x, z5.x));
+ z.y = max(z.y, max(z4.y, z5.y));
+ }
+ if(extra_fetch.y) {
+ vec2 z6 = imageLoad(u_depthTexIn, coordIn + ivec2(0,2)).xy;
+ vec2 z7 = imageLoad(u_depthTexIn, coordIn + ivec2(1,2)).xy;
+ z.x = min(z.x, min(z6.x, z7.x));
+ z.y = max(z.y, max(z6.y, z7.y));
+
+ if(extra_fetch.x) {
+ vec2 z8 = imageLoad(u_depthTexIn, coordIn + ivec2(2,2)).xy;
+ z.x = min(z.x, z8.x);
+ z.y = max(z.y, z8.y);
+ }
+ }
+
+ imageStore(u_depthTexOut, coordOut, vec4(z.x, z.y, 0, 1));
+}
\ No newline at end of file
diff --git a/app/resources/core/shader/hiz_copy_cs.sc b/app/resources/core/shader/hiz_copy_cs.sc
new file mode 100644
index 0000000..4a64ae8
--- /dev/null
+++ b/app/resources/core/shader/hiz_copy_cs.sc
@@ -0,0 +1,41 @@
+#include "bgfx_compute.sh"
+
+// Initializes the level 0 of the minimum depth pyramid.
+
+SAMPLER2D(u_depth, 0);
+IMAGE2D_WR(u_depthTexOut, rg32f, 1); // output: level 0 of the min/max depth pyramid
+
+uniform mat4 u_projection;
+uniform vec4 u_zThickness;
+
+NUM_THREADS(16, 16, 1)
+void main() {
+ ivec4 viewport = ivec4(u_viewRect);
+ ivec2 coord = ivec2(gl_GlobalInvocationID.xy) + ivec2(u_viewRect.xy);
+
+#if BGFX_SHADER_LANGUAGE_GLSL
+ ivec2 tex_coord = ivec2(coord.x, textureSize(u_depth, 0).y - 1 - coord.y);
+#else
+ ivec2 tex_coord = coord;
+#endif
+
+ vec2 z;
+ if (all(bvec4(greaterThanEqual(coord, viewport.xy), lessThan(coord, viewport.xy + viewport.zw)))) {
+ z = texelFetch(u_depth, tex_coord, 0).ww;
+
+#if BGFX_SHADER_LANGUAGE_GLSL
+ vec2 q = vec2(u_projection[2].z, u_projection[3].z);
+#else
+ vec2 q = u_projection[2].zw;
+#endif
+ z.y += u_zThickness.x * q.x;
+
+ // Store logarithmic depth
+ z.xy = q.x * z.xy / (z.xy - q.yy);
+ } else {
+ // Set pixels outside the viewport to the far clipping distance.
+ z = vec2(1.0, 0.0);
+ }
+
+ imageStore(u_depthTexOut, coord, vec4(z.x, z.y, 0, 1));
+}
diff --git a/app/resources/core/shader/hiz_trace.sh b/app/resources/core/shader/hiz_trace.sh
new file mode 100644
index 0000000..3851d35
--- /dev/null
+++ b/app/resources/core/shader/hiz_trace.sh
@@ -0,0 +1,153 @@
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#ifndef HIZ_TRACE_SH_HEADER_GUARD
+#define HIZ_TRACE_SH_HEADER_GUARD
+
+// SAMPLER2D(u_depthTex, X); // input: minimum depth pyramid <= Must be declared by the user.
+
+uniform vec4 u_depthTexInfos; // width(x) heigh(y) start mipmap level(z) max mipmap level(w)
+
+//
+vec3 ray_step_cell(vec3 ray, vec3 dir, float step, vec2 z_range) {
+ float t = 100000000.0; // [EJ] any large value is ok
+
+ if (dir.x > 0.0)
+ t = min(t, (floor(ray.x / step + 1.0) * step - ray.x) / dir.x);
+ else if (dir.x < 0.0)
+ t = min(t, (ceil(ray.x / step - 1.0) * step - ray.x) / dir.x);
+
+ if (dir.y > 0.0)
+ t = min(t, (floor(ray.y / step + 1.0) * step - ray.y) / dir.y);
+ else if (dir.y < 0.0)
+ t = min(t, (ceil(ray.y / step - 1.0) * step - ray.y) / dir.y);
+
+ if (dir.z > 0.0) {
+ if (ray.z < z_range.x)
+ t = min(t, (z_range.x - ray.z) / dir.z);
+ } else if (dir.z < 0.0) {
+ if (ray.z > z_range.y)
+ t = min(t, (z_range.y - ray.z) / dir.z);
+ }
+
+ return ray + dir * t;
+}
+
+float hiz_trace(vec3 ray_o, vec3 ray_d, mat4 proj, float z_near, int max_iterations, out vec3 ray) {
+ vec3 viewport_min = vec3(u_viewRect.xy, 0.);
+ vec3 viewport_max = vec3(u_viewRect.xy + u_viewRect.zw, 1.);
+
+ int level_min = int(u_depthTexInfos.z);
+ int level_max = int(u_depthTexInfos.w);
+
+ // clip to the near plane
+ float ray_len = ((ray_o.z + ray_d.z * 1000.0) < z_near) ? (z_near - ray_o.z) / ray_d.z : 1000.0;
+ vec3 end_point = ray_o + ray_d * ray_len;
+
+ // project into homogeneous clip space
+ vec4 h0 = mul(proj, vec4(ray_o, 1.));
+ vec4 h1 = mul(proj, vec4(end_point, 1.));
+
+ // endpoints in screen space
+ vec3 p0 = h0.xyz / h0.w;
+ p0.y *= -1.0;
+ p0.xy = NDCToViewRect(p0.xy);
+
+ vec3 p1 = h1.xyz / h1.w;
+ p1.y *= -1.0;
+ p1.xy = NDCToViewRect(p1.xy);
+
+ //
+ ray = p0;
+ vec3 dir = normalize(p1 - p0);
+
+ vec2 uv_offset = sign(dir.xy) * 0.0001; // slight nudge to sample the correct cell
+
+#if 1
+ int level = level_min;
+
+ int iterations = 0;
+
+ while (level > -1) {
+ if (++iterations == max_iterations)
+ return -1.0;
+
+ if (any(lessThan(ray, viewport_min)))
+ return 0.0; // TODO ramp out
+ if (any(greaterThanEqual(ray, viewport_max)))
+ return 0.0; // TODO ramp out
+
+ float step = pow(2.0, level);
+ vec2 z_range = texelFetch(u_depthTex, ivec2(ray.xy / step + uv_offset), level).xy;
+
+ if (ray.z >= z_range.x && ray.z <= z_range.y) {
+ --level;
+ } else {
+ ray = ray_step_cell(ray, dir, step, z_range);
+ if (level < level_max - 2)
+ ++level;
+ }
+ }
+
+ vec2 k_fade = saturate((ray.xy - viewport_min.xy) / (u_viewRect.zw * 0.1));
+ k_fade *= saturate(vec2(1.0, 1.0) - (ray.xy - viewport_max.xy * 0.9) / (u_viewRect.zw * 0.1));
+
+ ray.xy /= u_depthTexInfos.xy;
+
+ return k_fade.x * k_fade.y; // hit
+#else
+ int level = 0; // reference implementation (works on any mip level)
+
+ for (int i = 0; i < 4096; ++i) {
+ if (any(lessThan(ray, viewport_min)))
+ return false;
+ if (any(greaterThanEqual(ray, viewport_max)))
+ return false;
+
+ float step = pow(2.0, level);
+ vec2 z_range = texelFetch(u_depthTex, ivec2(ray.xy / step), level).xy;
+
+ if (ray.z >= z_range.x && ray.z <= z_range.y) {
+ ray.xy = ray.xy / u_depthTexInfos.xy;
+ return true;
+ }
+
+ ray = ray_step_cell(ray, dir, step, z_range);
+ }
+
+ return 0.0;
+#endif
+}
+
+float TraceScreenRay(vec3 ray_o, vec3 ray_d, mat4 proj, float z_near, int max_iterations, out vec2 hit_pixel, out vec3 hit_point) {
+ vec3 ray;
+
+ float hit = hiz_trace(ray_o, ray_d, proj, z_near, max_iterations, ray);
+
+ if (hit > 0.0) {
+ // compute screen position of the hit pixel
+#if BGFX_SHADER_LANGUAGE_GLSL
+ hit_pixel = vec2(ray.x, 1.0 - ray.y) * floor(uResolution.xy / uv_ratio);
+#else
+ hit_pixel = ray.xy * floor(uResolution.xy / uv_ratio);
+#endif
+ hit_point = ray;
+ } else {
+ hit_pixel = vec2_splat(0.);
+ hit_point = vec3_splat(0.);
+ }
+
+ return hit;
+}
+
+float ComputeRayLogDepth(in mat4 projection, in vec3 ray) {
+ const float z_epsilon = 0.1; // [todo] parameter?
+
+ float za = texelFetch(u_depthTex, ivec2(floor(ray.xy * u_depthTexInfos.xy)), 0).x;
+ float zb = z_epsilon * (za - projection[2].z);
+#if BGFX_SHADER_LANGUAGE_GLSL
+ return (zb + projection[3].z * za) / (zb + projection[3].z);
+#else
+ return (zb + projection[2].w * za) / (zb + projection[2].w);
+#endif
+}
+
+#endif // HIZ_TRACE_SH_HEADER_GUARD
diff --git a/app/resources/core/shader/imgui_fs.sc b/app/resources/core/shader/imgui_fs.sc
new file mode 100644
index 0000000..9f14940
--- /dev/null
+++ b/app/resources/core/shader/imgui_fs.sc
@@ -0,0 +1,12 @@
+$input v_color0, v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+SAMPLER2D(s_tex, 0);
+
+void main()
+{
+ vec4 texel = texture2D(s_tex, v_texcoord0);
+ gl_FragColor = texel * v_color0;
+}
diff --git a/app/resources/core/shader/imgui_image_fs.sc b/app/resources/core/shader/imgui_image_fs.sc
new file mode 100644
index 0000000..c7ee13d
--- /dev/null
+++ b/app/resources/core/shader/imgui_image_fs.sc
@@ -0,0 +1,21 @@
+$input v_texcoord0
+
+/*
+ * Copyright 2014 Dario Manesku. All rights reserved.
+ * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
+ */
+
+#include
+
+uniform vec4 u_imageLodEnabled;
+SAMPLER2D(s_texColor, 0);
+
+#define u_imageLod u_imageLodEnabled.x
+#define u_imageEnabled u_imageLodEnabled.y
+
+void main()
+{
+ vec3 color = texture2DLod(s_texColor, v_texcoord0, u_imageLod).xyz;
+ float alpha = 0.2 + 0.8*u_imageEnabled;
+ gl_FragColor = vec4(color, alpha);
+}
diff --git a/app/resources/core/shader/imgui_image_varying.def b/app/resources/core/shader/imgui_image_varying.def
new file mode 100644
index 0000000..41b4dbd
--- /dev/null
+++ b/app/resources/core/shader/imgui_image_varying.def
@@ -0,0 +1,8 @@
+vec4 v_color0 : COLOR0 = vec4(1.0, 0.0, 0.0, 1.0);
+vec3 v_normal : NORMAL = vec3(0.0, 0.0, 1.0);
+vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0);
+
+vec3 a_position : POSITION;
+vec4 a_normal : NORMAL;
+vec4 a_color0 : COLOR0;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/app/resources/core/shader/imgui_image_vs.sc b/app/resources/core/shader/imgui_image_vs.sc
new file mode 100644
index 0000000..f1ae37c
--- /dev/null
+++ b/app/resources/core/shader/imgui_image_vs.sc
@@ -0,0 +1,15 @@
+$input a_position, a_texcoord0
+$output v_texcoord0
+
+/*
+ * Copyright 2014 Dario Manesku. All rights reserved.
+ * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
+ */
+
+#include
+
+void main()
+{
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0) );
+ v_texcoord0 = a_texcoord0;
+}
diff --git a/app/resources/core/shader/imgui_varying.def b/app/resources/core/shader/imgui_varying.def
new file mode 100644
index 0000000..41b4dbd
--- /dev/null
+++ b/app/resources/core/shader/imgui_varying.def
@@ -0,0 +1,8 @@
+vec4 v_color0 : COLOR0 = vec4(1.0, 0.0, 0.0, 1.0);
+vec3 v_normal : NORMAL = vec3(0.0, 0.0, 1.0);
+vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0);
+
+vec3 a_position : POSITION;
+vec4 a_normal : NORMAL;
+vec4 a_color0 : COLOR0;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/app/resources/core/shader/imgui_vs.sc b/app/resources/core/shader/imgui_vs.sc
new file mode 100644
index 0000000..f50f0d6
--- /dev/null
+++ b/app/resources/core/shader/imgui_vs.sc
@@ -0,0 +1,13 @@
+$input a_position, a_texcoord0, a_color0
+$output v_color0, v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main()
+{
+ vec2 pos = 2.0*a_position.xy*u_viewTexel.xy;
+ gl_Position = vec4(pos.x - 1.0, 1.0 - pos.y, 0.0, 1.0);
+ v_texcoord0 = a_texcoord0;
+ v_color0 = a_color0;
+}
diff --git a/app/resources/core/shader/missing_fs.sc b/app/resources/core/shader/missing_fs.sc
new file mode 100644
index 0000000..0c09174
--- /dev/null
+++ b/app/resources/core/shader/missing_fs.sc
@@ -0,0 +1,8 @@
+$input vWorldPos
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main() {
+ gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
+}
diff --git a/app/resources/core/shader/missing_varying.def b/app/resources/core/shader/missing_varying.def
new file mode 100644
index 0000000..abae8f0
--- /dev/null
+++ b/app/resources/core/shader/missing_varying.def
@@ -0,0 +1,3 @@
+vec3 vWorldPos : TEXCOORD1;
+
+vec3 a_position : POSITION;
diff --git a/app/resources/core/shader/missing_vs.sc b/app/resources/core/shader/missing_vs.sc
new file mode 100644
index 0000000..fd9b4fc
--- /dev/null
+++ b/app/resources/core/shader/missing_vs.sc
@@ -0,0 +1,10 @@
+$input a_position
+$output vWorldPos
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main() {
+ vWorldPos = mul(u_model[0], vec4(a_position, 1.0)).xyz;
+ gl_Position = mul(u_modelViewProj, vec4(a_position, 1.0));
+}
diff --git a/app/resources/core/shader/motion_blur_fs.sc b/app/resources/core/shader/motion_blur_fs.sc
new file mode 100644
index 0000000..fea5d93
--- /dev/null
+++ b/app/resources/core/shader/motion_blur_fs.sc
@@ -0,0 +1,26 @@
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+SAMPLER2D(u_color, 0);
+SAMPLER2D(u_attr0, 1);
+SAMPLER2D(u_attr1, 2);
+SAMPLER2D(u_noise, 3);
+
+#include
+
+void main() {
+ vec4 jitter = texture2D(u_noise, mod(gl_FragCoord.xy, vec2(64, 64)) / vec2(64, 64));
+
+ float strength = uAAAParams[0].w;
+
+ vec2 uv = gl_FragCoord.xy / uResolution.xy;
+ vec2 dt = GetVelocityVector(uv);
+
+ vec4 blur_out = vec4(0., 0., 0., 0.);
+ for (int i = 0; i < 8; ++i) {
+ float k = (((float(i) + jitter.x) / 8.) - 0.5) * strength;
+ blur_out += texture2D(u_color, uv + dt * k);
+ }
+
+ gl_FragColor = blur_out / 8.;
+}
diff --git a/app/resources/core/shader/motion_blur_varying.def b/app/resources/core/shader/motion_blur_varying.def
new file mode 100644
index 0000000..b7b69d9
--- /dev/null
+++ b/app/resources/core/shader/motion_blur_varying.def
@@ -0,0 +1,4 @@
+vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0);
+
+vec3 a_position : POSITION;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/app/resources/core/shader/motion_blur_vs.sc b/app/resources/core/shader/motion_blur_vs.sc
new file mode 100644
index 0000000..968f4f2
--- /dev/null
+++ b/app/resources/core/shader/motion_blur_vs.sc
@@ -0,0 +1,8 @@
+$input a_position, a_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main() {
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+}
diff --git a/app/resources/core/shader/pbr.hps b/app/resources/core/shader/pbr.hps
new file mode 100644
index 0000000..3bbcbb8
--- /dev/null
+++ b/app/resources/core/shader/pbr.hps
@@ -0,0 +1,3 @@
+{
+ "features": ["OptionalBaseColorOpacityMap", "OptionalOcclusionRoughnessMetalnessMap", "OptionalNormalMap", "OptionalAlphaCut", "OptionalSelfMap", "_OptionalSkinning"]
+}
diff --git a/app/resources/core/shader/pbr_fs.sc b/app/resources/core/shader/pbr_fs.sc
new file mode 100644
index 0000000..3e24b81
--- /dev/null
+++ b/app/resources/core/shader/pbr_fs.sc
@@ -0,0 +1,299 @@
+$input vWorldPos, vNormal, vTangent, vBinormal, vTexCoord0, vTexCoord1, vLinearShadowCoord0, vLinearShadowCoord1, vLinearShadowCoord2, vLinearShadowCoord3, vSpotShadowCoord, vProjPos, vPrevProjPos
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+// Surface attributes
+uniform vec4 uBaseOpacityColor;
+uniform vec4 uOcclusionRoughnessMetalnessColor;
+uniform vec4 uSelfColor;
+
+// Texture slots
+SAMPLER2D(uBaseOpacityMap, 0);
+SAMPLER2D(uOcclusionRoughnessMetalnessMap, 1);
+SAMPLER2D(uNormalMap, 2);
+SAMPLER2D(uSelfMap, 4);
+
+//
+float LightAttenuation(vec3 L, vec3 D, float dist, float attn, float inner_rim, float outer_rim) {
+ float k = 1.0;
+ if (attn > 0.0)
+ k = max(1.0 - dist * attn, 0.0); // distance attenuation
+
+ if (outer_rim > 0.0) {
+ float c = dot(L, D);
+ k *= clamp(1.0 - (c - inner_rim) / (outer_rim - inner_rim), 0.0, 1.0); // spot attenuation
+ }
+ return k;
+}
+
+float SampleHardShadow(sampler2DShadow map, vec4 coord, float bias) {
+ vec3 uv = coord.xyz / coord.w;
+ return shadow2D(map, vec3(uv.xy, uv.z - bias));
+}
+
+float SampleShadowPCF(sampler2DShadow map, vec4 coord, float inv_pixel_size, float bias, vec4 jitter) {
+ float k_pixel_size = inv_pixel_size * coord.w;
+
+ float k = 0.0;
+
+#if FORWARD_PIPELINE_AAA
+ #define PCF_SAMPLE_COUNT 2 // 3x3
+
+// ARRAY_BEGIN(float, weights, 9) 0.024879, 0.107973, 0.024879, 0.107973, 0.468592, 0.107973, 0.024879, 0.107973, 0.024879 ARRAY_END();
+ ARRAY_BEGIN(float, weights, 9) 0.011147, 0.083286, 0.011147, 0.083286, 0.622269, 0.083286, 0.011147, 0.083286, 0.011147 ARRAY_END();
+
+ for (int j = 0; j <= PCF_SAMPLE_COUNT; ++j) {
+ float v = 6.0 * (float(j) + jitter.y) / float(PCF_SAMPLE_COUNT) - 1.0;
+ for (int i = 0; i <= PCF_SAMPLE_COUNT; ++i) {
+ float u = 6.0 * (float(i) + jitter.x) / float(PCF_SAMPLE_COUNT) - 1.0;
+ k += SampleHardShadow(map, coord + vec4(vec2(u, v) * k_pixel_size, 0.0, 0.0), bias) * weights[j * 3 + i];
+ }
+ }
+#else // FORWARD_PIPELINE_AAA
+ // 2x2
+ k += SampleHardShadow(map, coord + vec4(vec2(-0.5, -0.5) * k_pixel_size, 0.0, 0.0), bias);
+ k += SampleHardShadow(map, coord + vec4(vec2( 0.5, -0.5) * k_pixel_size, 0.0, 0.0), bias);
+ k += SampleHardShadow(map, coord + vec4(vec2(-0.5, 0.5) * k_pixel_size, 0.0, 0.0), bias);
+ k += SampleHardShadow(map, coord + vec4(vec2( 0.5, 0.5) * k_pixel_size, 0.0, 0.0), bias);
+
+ k /= 4.0;
+#endif // FORWARD_PIPELINE_AAA
+
+ return k;
+}
+
+// Forward PBR GGX
+float DistributionGGX(float NdotH, float roughness) {
+ float a = roughness * roughness;
+ float a2 = a * a;
+
+ float divisor = NdotH * NdotH * (a2 - 1.0) + 1.0;
+ return a2 / max(PI * divisor * divisor, 1e-8);
+}
+
+float GeometrySchlickGGX(float NdotW, float k) {
+ float div = NdotW * (1.0 - k) + k;
+ return NdotW / ((abs(div) > 1e-8) ? div : 1e-8);
+}
+
+float GeometrySmith(float NdotV, float NdotL, float roughness) {
+ float r = roughness + 1.0;
+ float k = (r * r) / 8.0;
+ float ggx2 = GeometrySchlickGGX(NdotV, k);
+ float ggx1 = GeometrySchlickGGX(NdotL, k);
+ return ggx1 * ggx2;
+}
+
+vec3 FresnelSchlick(float cosTheta, vec3 F0) {
+ return F0 + (1.0 - F0) * pow(max(1.0 - cosTheta, 0.0), 5.0);
+}
+
+vec3 FresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness) {
+ return F0 + (max(vec3_splat(1.0 - roughness), F0) - F0) * pow(max(1.0 - cosTheta, 0.0), 5.0);
+}
+
+vec3 GGX(vec3 V, vec3 N, float NdotV, vec3 L, vec3 albedo, float roughness, float metalness, vec3 F0, vec3 diffuse_color, vec3 specular_color) {
+ vec3 H = normalize(V - L);
+
+ float NdotH = max(dot(N, H), 0.0);
+ float NdotL = max(-dot(N, L), 0.0);
+ float HdotV = max(dot(H, V), 0.0);
+
+ float D = DistributionGGX(NdotH, roughness);
+ float G = GeometrySmith(NdotV, NdotL, roughness);
+ vec3 F = FresnelSchlick(HdotV, F0);
+
+ vec3 specularBRDF = (F * D * G) / max(4.0 * NdotV * NdotL, 0.001);
+
+ vec3 kD = (vec3_splat(1.0) - F) * (1.0 - metalness); // metallic materials have no diffuse (NOTE: mimics mental ray and 3DX Max ART renderers behavior)
+ vec3 diffuseBRDF = kD * albedo;
+
+ return (diffuse_color * diffuseBRDF + specular_color * specularBRDF) * NdotL;
+}
+
+//
+vec3 DistanceFog(vec3 pos, vec3 color) {
+ if (uFogState.y == 0.0)
+ return color;
+
+ float k = clamp((pos.z - uFogState.x) * uFogState.y, 0.0, 1.0);
+ return mix(color, uFogColor.xyz, k);
+}
+
+// Entry point of the forward pipeline default uber shader (Phong and PBR)
+void main() {
+ //
+#if USE_BASE_COLOR_OPACITY_MAP
+ vec4 base_opacity = texture2D(uBaseOpacityMap, vTexCoord0);
+ base_opacity.xyz = sRGB2linear(base_opacity.xyz);
+#else // USE_BASE_COLOR_OPACITY_MAP
+ vec4 base_opacity = uBaseOpacityColor;
+#endif // USE_BASE_COLOR_OPACITY_MAP
+
+#if DEPTH_ONLY != 1
+#if USE_OCCLUSION_ROUGHNESS_METALNESS_MAP
+ vec4 occ_rough_metal = texture2D(uOcclusionRoughnessMetalnessMap, vTexCoord0);
+#else // USE_OCCLUSION_ROUGHNESS_METALNESS_MAP
+ vec4 occ_rough_metal = uOcclusionRoughnessMetalnessColor;
+#endif // USE_OCCLUSION_ROUGHNESS_METALNESS_MAP
+
+ //
+#if USE_SELF_MAP
+ vec4 self = texture2D(uSelfMap, vTexCoord0);
+#else // USE_SELF_MAP
+ vec4 self = uSelfColor;
+#endif // USE_SELF_MAP
+
+ //
+ vec3 view = mul(u_view, vec4(vWorldPos, 1.0)).xyz;
+ vec3 P = vWorldPos; // fragment world pos
+ vec3 V = normalize(GetT(u_invView) - P); // world space view vector
+ vec3 N = sign(dot(V, vNormal)) * normalize(vNormal); // geometry normal
+
+#if USE_NORMAL_MAP
+ vec3 T = normalize(vTangent);
+ vec3 B = normalize(vBinormal);
+
+ mat3 TBN = mtxFromRows(T, B, N);
+
+ N.xy = texture2D(uNormalMap, vTexCoord0).xy * 2.0 - 1.0;
+ N.z = sqrt(1.0 - dot(N.xy, N.xy));
+ N = normalize(mul(N, TBN));
+#endif // USE_NORMAL_MAP
+
+ vec3 R = reflect(-V, N); // view reflection vector around normal
+
+ float NdotV = clamp(dot(N, V), 0.0, 0.99);
+
+ vec3 F0 = vec3(0.04, 0.04, 0.04);
+ F0 = mix(F0, base_opacity.xyz, occ_rough_metal.b);
+
+ vec3 color = vec3(0.0, 0.0, 0.0);
+
+ // jitter
+#if FORWARD_PIPELINE_AAA
+ vec4 jitter = texture2D(uNoiseMap, mod(gl_FragCoord.xy, vec2(64, 64)) / vec2(64, 64));
+#else // FORWARD_PIPELINE_AAA
+ vec4 jitter = vec4_splat(0.);
+#endif // FORWARD_PIPELINE_AAA
+
+ // SLOT 0: linear light
+ {
+ float k_shadow = 1.0;
+#if SLOT0_SHADOWS
+ float k_fade_split = 1.0 - jitter.z * 0.3;
+
+ if(view.z < uLinearShadowSlice.x * k_fade_split) {
+ k_shadow *= SampleShadowPCF(uLinearShadowMap, vLinearShadowCoord0, uShadowState.y * 0.5, uShadowState.z, jitter);
+ } else if(view.z < uLinearShadowSlice.y * k_fade_split) {
+ k_shadow *= SampleShadowPCF(uLinearShadowMap, vLinearShadowCoord1, uShadowState.y * 0.5, uShadowState.z, jitter);
+ } else if(view.z < uLinearShadowSlice.z * k_fade_split) {
+ k_shadow *= SampleShadowPCF(uLinearShadowMap, vLinearShadowCoord2, uShadowState.y * 0.5, uShadowState.z, jitter);
+ } else if(view.z < uLinearShadowSlice.w * k_fade_split) {
+#if FORWARD_PIPELINE_AAA
+ k_shadow *= SampleShadowPCF(uLinearShadowMap, vLinearShadowCoord3, uShadowState.y * 0.5, uShadowState.z, jitter);
+#else // FORWARD_PIPELINE_AAA
+ float pcf = SampleShadowPCF(uLinearShadowMap, vLinearShadowCoord3, uShadowState.y * 0.5, uShadowState.z, jitter);
+ float ramp_len = (uLinearShadowSlice.w - uLinearShadowSlice.z) * 0.25;
+ float ramp_k = clamp((view.z - (uLinearShadowSlice.w - ramp_len)) / max(ramp_len, 1e-8), 0.0, 1.0);
+ k_shadow *= pcf * (1.0 - ramp_k) + ramp_k;
+#endif // FORWARD_PIPELINE_AAA
+ }
+#endif // SLOT0_SHADOWS
+ color += GGX(V, N, NdotV, uLightDir[0].xyz, base_opacity.xyz, occ_rough_metal.g, occ_rough_metal.b, F0, uLightDiffuse[0].xyz * k_shadow, uLightSpecular[0].xyz * k_shadow);
+ }
+ // SLOT 1: point/spot light (with optional shadows)
+ {
+ vec3 L = P - uLightPos[1].xyz;
+ float distance = length(L);
+ L /= max(distance, 1e-8);
+ float attenuation = LightAttenuation(L, uLightDir[1].xyz, distance, uLightPos[1].w, uLightDir[1].w, uLightDiffuse[1].w);
+
+#if SLOT1_SHADOWS
+ attenuation *=SampleShadowPCF(uSpotShadowMap, vSpotShadowCoord, uShadowState.y, uShadowState.w, jitter);
+#endif // SLOT1_SHADOWS
+ color += GGX(V, N, NdotV, L, base_opacity.xyz, occ_rough_metal.g, occ_rough_metal.b, F0, uLightDiffuse[1].xyz * attenuation, uLightSpecular[1].xyz * attenuation);
+ }
+ // SLOT 2-N: point/spot light (no shadows) [todo]
+ {
+ for (int i = 2; i < 8; ++i) {
+ vec3 L = P - uLightPos[i].xyz;
+ float distance = length(L);
+ L /= max(distance, 1e-8);
+ float attenuation = LightAttenuation(L, uLightDir[i].xyz, distance, uLightPos[i].w, uLightDir[i].w, uLightDiffuse[i].w);
+
+ color += GGX(V, N, NdotV, L, base_opacity.xyz, occ_rough_metal.g, occ_rough_metal.b, F0, uLightDiffuse[i].xyz * attenuation, uLightSpecular[i].xyz * attenuation);
+ }
+ }
+
+ // IBL
+ float MAX_REFLECTION_LOD = 10.;
+#if 0 // LOD selection
+ vec3 Ndx = normalize(N + ddx(N));
+ float dx = length(Ndx.xy / Ndx.z - N.xy / N.z) * 256.0;
+ vec3 Ndy = normalize(N + ddy(N));
+ float dy = length(Ndy.xy / Ndy.z - N.xy / N.z) * 256.0;
+
+ float dd = max(dx, dy);
+ float lod_level = log2(dd);
+#endif
+
+ vec3 irradiance = textureCube(uIrradianceMap, ReprojectProbe(P, N)).xyz;
+ vec3 radiance = textureCubeLod(uRadianceMap, ReprojectProbe(P, R), occ_rough_metal.y * MAX_REFLECTION_LOD).xyz;
+
+#if FORWARD_PIPELINE_AAA
+ vec4 ss_irradiance = texture2D(uSSIrradianceMap, gl_FragCoord.xy / uResolution.xy);
+ vec4 ss_radiance = texture2D(uSSRadianceMap, gl_FragCoord.xy / uResolution.xy);
+
+ irradiance = ss_irradiance.xyz; // mix(irradiance, ss_irradiance, ss_irradiance.w);
+ radiance = mix(radiance, ss_radiance.xyz, ss_radiance.w);
+#endif
+
+ vec3 diffuse = irradiance * base_opacity.xyz;
+ vec3 F = FresnelSchlickRoughness(NdotV, F0, occ_rough_metal.y);
+ vec2 brdf = texture2D(uBrdfMap, vec2(NdotV, occ_rough_metal.y)).xy;
+ vec3 specular = radiance * (F * brdf.x + brdf.y);
+#if FORWARD_PIPELINE_AAA
+ specular *= uAAAParams[2].x; // * specular weight
+#endif
+
+ vec3 kS = specular;
+ vec3 kD = vec3_splat(1.) - kS;
+ kD *= 1. - occ_rough_metal.z;
+
+ color += kD * diffuse;
+ color += specular;
+ color += uAmbientColor.xyz;
+ color *= occ_rough_metal.x;
+ color += self.xyz;
+
+ color = DistanceFog(view, color);
+#endif // DEPTH_ONLY != 1
+
+ float opacity = base_opacity.w;
+
+#if ENABLE_ALPHA_CUT
+ if (opacity < 0.8)
+ discard;
+#endif // ENABLE_ALPHA_CUT
+
+#if DEPTH_ONLY != 1
+#if FORWARD_PIPELINE_AAA_PREPASS
+ vec3 N_view = mul(u_view, vec4(N, 0)).xyz;
+ vec2 velocity = vec2(vProjPos.xy / vProjPos.w - vPrevProjPos.xy / vPrevProjPos.w);
+ gl_FragData[0] = vec4(N_view.xyz, vProjPos.z);
+ gl_FragData[1] = vec4(velocity.xy, occ_rough_metal.y, 0.);
+#else // FORWARD_PIPELINE_AAA_PREPASS
+ // incorrectly apply gamma correction at fragment shader level in the non-AAA pipeline
+#if FORWARD_PIPELINE_AAA != 1
+ float gamma = 2.2;
+ color = pow(color, vec3_splat(1. / gamma));
+#endif // FORWARD_PIPELINE_AAA != 1
+
+ gl_FragColor = vec4(color, opacity);
+#endif // FORWARD_PIPELINE_AAA_PREPASS
+#else
+ gl_FragColor = vec4_splat(0.0); // note: fix required to stop glsl-optimizer from removing the whole function body
+#endif // DEPTH_ONLY
+}
diff --git a/app/resources/core/shader/pbr_varying.def b/app/resources/core/shader/pbr_varying.def
new file mode 100644
index 0000000..76d199d
--- /dev/null
+++ b/app/resources/core/shader/pbr_varying.def
@@ -0,0 +1,22 @@
+vec3 vWorldPos : POSITIONT;
+vec3 vNormal : NORMAL;
+vec3 vTangent : TANGENT0;
+vec3 vBinormal : BINORMAL0;
+vec2 vTexCoord0 : TEXCOORD0;
+vec2 vTexCoord1 : TEXCOORD1;
+vec4 vSpotShadowCoord : TEXCOORD2;
+vec4 vLinearShadowCoord0 : TEXCOORD3;
+vec4 vLinearShadowCoord1 : TEXCOORD4;
+vec4 vLinearShadowCoord2 : TEXCOORD5;
+vec4 vLinearShadowCoord3 : TEXCOORD6;
+vec4 vProjPos : TEXCOORD7;
+vec4 vPrevProjPos : TEXCOORD8;
+
+vec3 a_position : POSITION;
+vec3 a_normal : NORMAL;
+vec2 a_texcoord0 : TEXCOORD0;
+vec2 a_texcoord1 : TEXCOORD1;
+vec3 a_tangent : TANGENT0;
+vec3 a_bitangent : BITANGENT0;
+vec4 a_indices : BLENDINDICES;
+vec4 a_weight : BLENDWEIGHT;
diff --git a/app/resources/core/shader/pbr_vs.sc b/app/resources/core/shader/pbr_vs.sc
new file mode 100644
index 0000000..2582a33
--- /dev/null
+++ b/app/resources/core/shader/pbr_vs.sc
@@ -0,0 +1,131 @@
+$input a_position, a_normal, a_texcoord0, a_texcoord1, a_tangent, a_bitangent, a_indices, a_weight
+$output vWorldPos, vNormal, vTexCoord0, vTexCoord1, vTangent, vBinormal, vLinearShadowCoord0, vLinearShadowCoord1, vLinearShadowCoord2, vLinearShadowCoord3, vSpotShadowCoord, vProjPos, vPrevProjPos
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+mat3 normal_mat(mat4 m) {
+#if BGFX_SHADER_LANGUAGE_GLSL
+ vec3 u = normalize(vec3(m[0].x, m[1].x, m[2].x));
+ vec3 v = normalize(vec3(m[0].y, m[1].y, m[2].y));
+ vec3 w = normalize(vec3(m[0].z, m[1].z, m[2].z));
+#else
+ vec3 u = normalize(m[0].xyz);
+ vec3 v = normalize(m[1].xyz);
+ vec3 w = normalize(m[2].xyz);
+#endif
+
+ return mtxFromRows(u, v, w);
+}
+
+void main() {
+ // position
+ vec4 vtx = vec4(a_position, 1.0);
+
+#if ENABLE_SKINNING
+ vec4 world_pos =
+ mul(u_model[int(a_indices.x * 256.0)], vtx) * a_weight.x +
+ mul(u_model[int(a_indices.y * 256.0)], vtx) * a_weight.y +
+ mul(u_model[int(a_indices.z * 256.0)], vtx) * a_weight.z +
+ mul(u_model[int(a_indices.w * 256.0)], vtx) * a_weight.w;
+
+#if FORWARD_PIPELINE_AAA_PREPASS
+ vec4 prv_world_pos =
+ mul(uPreviousModel[int(a_indices.x * 256.0)], vtx) * a_weight.x +
+ mul(uPreviousModel[int(a_indices.y * 256.0)], vtx) * a_weight.y +
+ mul(uPreviousModel[int(a_indices.z * 256.0)], vtx) * a_weight.z +
+ mul(uPreviousModel[int(a_indices.w * 256.0)], vtx) * a_weight.w;
+#endif // FORWARD_PIPELINE_AAA_PREPASS
+#else // ENABLE_SKINNING
+ vec4 world_pos = mul(u_model[0], vtx);
+
+#if FORWARD_PIPELINE_AAA_PREPASS
+ vec4 prv_world_pos = mul(uPreviousModel[0], vtx);
+#endif // FORWARD_PIPELINE_AAA_PREPASS
+#endif // ENABLE_SKINNING
+
+#if DEPTH_ONLY != 1
+ // normal
+ vec4 normal = vec4(a_normal * 2. - 1., 0.);
+
+#if ENABLE_SKINNING
+ vec4 skinned_normal =
+ mul(u_model[int(a_indices.x * 256.0)], normal) * a_weight.x +
+ mul(u_model[int(a_indices.y * 256.0)], normal) * a_weight.y +
+ mul(u_model[int(a_indices.z * 256.0)], normal) * a_weight.z +
+ mul(u_model[int(a_indices.w * 256.0)], normal) * a_weight.w;
+
+ skinned_normal = normalize(skinned_normal);
+
+ vNormal = skinned_normal.xyz;
+#else // ENABLE_SKINNING
+ vNormal = mul(normal_mat(u_model[0]), normal.xyz);
+#endif // ENABLE_SKINNING
+
+ // tangent frame
+#if USE_NORMAL_MAP // [EJ] FIXME this probably won't be the only condition to compute the tangent frame for long
+ vec4 tangent = vec4(a_tangent * 2.0 - 1.0, 0.0);
+ vec4 binormal = vec4(a_bitangent * 2.0 - 1.0, 0.0);
+
+#if ENABLE_SKINNING
+ vec4 skinned_tangent =
+ mul(u_model[int(a_indices.x * 256.0)], tangent) * a_weight.x +
+ mul(u_model[int(a_indices.y * 256.0)], tangent) * a_weight.y +
+ mul(u_model[int(a_indices.z * 256.0)], tangent) * a_weight.z +
+ mul(u_model[int(a_indices.w * 256.0)], tangent) * a_weight.w;
+
+ vec4 skinned_binormal =
+ mul(u_model[int(a_indices.x * 256.0)], binormal) * a_weight.x +
+ mul(u_model[int(a_indices.y * 256.0)], binormal) * a_weight.y +
+ mul(u_model[int(a_indices.z * 256.0)], binormal) * a_weight.z +
+ mul(u_model[int(a_indices.w * 256.0)], binormal) * a_weight.w;
+
+ vTangent = skinned_tangent.xyz;
+ vBinormal = skinned_binormal.xyz;
+#else // ENABLE_SKINNING
+ vTangent = mul(u_model[0], tangent).xyz;
+ vBinormal = mul(u_model[0], binormal).xyz;
+#endif // ENABLE_SKINNING
+#endif // USE_NORMAL_MAP
+
+ // shadow data
+#if SLOT0_SHADOWS || SLOT1_SHADOWS
+ float shadowMapShrinkOffset = 0.01;
+ vec3 shadowVertexShrinkOffset = vNormal * shadowMapShrinkOffset;
+#endif
+
+#if SLOT0_SHADOWS
+ vLinearShadowCoord0 = mul(uLinearShadowMatrix[0], vec4(world_pos.xyz + shadowVertexShrinkOffset, 1.0));
+ vLinearShadowCoord1 = mul(uLinearShadowMatrix[1], vec4(world_pos.xyz + shadowVertexShrinkOffset, 1.0));
+ vLinearShadowCoord2 = mul(uLinearShadowMatrix[2], vec4(world_pos.xyz + shadowVertexShrinkOffset, 1.0));
+ vLinearShadowCoord3 = mul(uLinearShadowMatrix[3], vec4(world_pos.xyz + shadowVertexShrinkOffset, 1.0));
+#endif
+
+#if SLOT1_SHADOWS
+ vSpotShadowCoord = mul(uSpotShadowMatrix, vec4(world_pos.xyz + shadowVertexShrinkOffset, 1.0));
+#endif
+#endif // DEPTH_ONLY
+
+ //
+ vWorldPos = world_pos.xyz;
+
+#if USE_BASE_COLOR_OPACITY_MAP || USE_OCCLUSION_ROUGHNESS_METALNESS_MAP || USE_DIFFUSE_MAP || USE_SPECULAR_MAP|| USE_NORMAL_MAP || USE_SELF_MAP || USE_OPACITY_MAP
+ vTexCoord0 = a_texcoord0;
+#endif
+
+#if DEPTH_ONLY != 1
+#if USE_LIGHT_MAP || USE_AMBIENT_MAP
+ vTexCoord1 = a_texcoord1;
+#endif
+#endif // DEPTH_ONLY != 1
+
+ //
+ vec4 proj_pos = mul(uViewProjUnjittered, world_pos);
+#if FORWARD_PIPELINE_AAA_PREPASS
+ vProjPos = proj_pos;
+ vPrevProjPos = mul(uPreviousViewProjection, prv_world_pos);
+#endif
+
+ //
+ gl_Position = mul(u_viewProj, world_pos);
+}
diff --git a/app/resources/core/shader/sao_blur_fs.sc b/app/resources/core/shader/sao_blur_fs.sc
new file mode 100644
index 0000000..f16bde6
--- /dev/null
+++ b/app/resources/core/shader/sao_blur_fs.sc
@@ -0,0 +1,54 @@
+$input v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+SAMPLER2D(u_attr0, 0);
+SAMPLER2D(u_input, 1);
+
+#define KERNEL_RADIUS 16
+
+uniform vec4 u_params[2];
+
+#define u_offset u_params[0].xy
+#define u_direction u_params[0].zw
+#define u_sharpness u_params[1].x
+
+float compute_weight(float r, float z0, float z) {
+ float sigma = float(KERNEL_RADIUS) * 0.5 + 0.5;
+ float falloff = 1.0 / (2.0 * sigma * sigma);
+ float delta = (z - z0) * u_sharpness;
+ return exp2(-r*r*falloff - delta*delta);
+}
+
+void main() {
+ float epsilon = 0.0001;
+
+ vec2 center = vec2(texture2D(u_attr0, v_texcoord0).w, LinearDepth(texture2D(u_input, v_texcoord0).r));
+
+ vec2 acc = vec2(center.x, 1.0);
+ for(int i=1; i<=KERNEL_RADIUS/2; i++) {
+ vec2 p = v_texcoord0 + float(i) * u_direction;
+ vec2 current = vec2(texture2D(u_attr0, p).w, LinearDepth(texture2D(u_input, p).r));
+ float weight = compute_weight(float(i), current.y, center.y);
+ acc += vec2(current.x*weight, weight);
+
+ p = v_texcoord0 - float(i) * u_direction;
+ current = vec2(texture2D(u_attr0, p).w, LinearDepth(texture2D(u_input, p).r));
+ weight = compute_weight(float(i), current.y, center.y);
+ acc += vec2(current.x*weight, weight);
+ }
+ for(int i=KERNEL_RADIUS/2 + 1; i<=KERNEL_RADIUS; i+=2) {
+ vec2 p = v_texcoord0 + float(i) * u_direction;
+ vec2 current = vec2(texture2D(u_attr0, p).w, LinearDepth(texture2D(u_input, p).r));
+ float weight = compute_weight(float(i), current.y, center.y);
+ acc += vec2(current.x*weight, weight);
+
+ p = v_texcoord0 - float(i) * u_direction;
+ current = vec2(texture2D(u_attr0, p).w, LinearDepth(texture2D(u_input, p).r));
+ weight = compute_weight(float(i), current.y, center.y);
+ acc += vec2(current.x*weight, weight);
+ }
+ float ao = acc.x / (acc.y + epsilon);
+ gl_FragColor = vec4(ao, ao, ao, 1.0);
+}
diff --git a/app/resources/core/shader/sao_blur_varying.def b/app/resources/core/shader/sao_blur_varying.def
new file mode 100644
index 0000000..b7b69d9
--- /dev/null
+++ b/app/resources/core/shader/sao_blur_varying.def
@@ -0,0 +1,4 @@
+vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0);
+
+vec3 a_position : POSITION;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/app/resources/core/shader/sao_blur_vs.sc b/app/resources/core/shader/sao_blur_vs.sc
new file mode 100644
index 0000000..7519a3d
--- /dev/null
+++ b/app/resources/core/shader/sao_blur_vs.sc
@@ -0,0 +1,10 @@
+$input a_position, a_texcoord0
+$output v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main() {
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0) );
+ v_texcoord0 = a_texcoord0;
+}
diff --git a/app/resources/core/shader/sao_compute_fs.sc b/app/resources/core/shader/sao_compute_fs.sc
new file mode 100644
index 0000000..d17d46e
--- /dev/null
+++ b/app/resources/core/shader/sao_compute_fs.sc
@@ -0,0 +1,74 @@
+$input v_viewRay
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+SAMPLER2D(u_attr0, 0);
+SAMPLER2D(u_attr1, 1);
+SAMPLER2D(u_noise, 2);
+
+uniform vec4 u_params[2];
+
+#define u_radius u_params[1].x
+#define u_sample_count floatBitsToUint(u_params[1].w)
+#define u_distance_scale u_params[1].y
+#define u_bias u_params[1].z
+
+vec3 pick(int index, vec4 jitter) {
+ float alpha = (float(index) + jitter.x) / float(u_sample_count);
+ float theta = (3.141592 * 2.) * (float(index) + jitter.y) / float(u_sample_count);
+ return vec3(cos(theta) * jitter.z, sin(theta) * jitter.z, alpha);
+}
+
+void main() {
+ //
+ ivec2 pos = ivec2(gl_FragCoord.xy);
+
+ vec4 jitter = texture2D(u_noise, mod(gl_FragCoord.xy, vec2(64, 64)) / vec2(64, 64));
+
+ vec2 attr0_size = vec2(textureSize(u_attr0, 0).xy);
+
+ // view space fragment coord
+ vec2 uv = gl_FragCoord.xy / attr0_size;
+ vec4 attr0 = texture2D(u_attr0, uv);
+
+ vec3 c = v_viewRay * attr0.w;
+ vec3 n = attr0.xyz;
+
+ //
+ float epsilon = 0.001;
+ float radius2 = u_radius * u_radius;
+ float projected_disc_radius = u_radius * u_distance_scale / c.z;
+
+ float ao = 0.;
+
+ for(int i = 0; i < u_sample_count; ++i) {
+ vec3 q_offset = pick(i, jitter);
+ q_offset.z = max(1., q_offset.z * projected_disc_radius);
+
+ vec2 q_coord = gl_FragCoord.xy + q_offset.xy * q_offset.z;
+
+ if (any(lessThan(q_coord, u_viewRect.xy)) || any(greaterThan(q_coord, u_viewRect.xy + u_viewRect.zw))) {
+ ao += 1.;
+ } else {
+ vec2 q_uv = q_coord / attr0_size;
+ float q_z = texture2D(u_attr0, q_uv).w;
+
+ vec3 q = ComputeFragCoordViewRay(q_coord) * q_z;
+
+ //
+ vec3 v = q - c;
+
+ float vv = dot(v, v);
+ float vn = dot(v, n);
+
+ float falloff = max(radius2 - vv, 0.);
+
+ ao += falloff * falloff * falloff * max(0., (vn - u_bias) / (epsilon + vv));
+ }
+ }
+
+ ao = max(0., 1. - 0.7 * ao * (5. / float(u_sample_count)) / (radius2 * radius2 * radius2));
+
+ gl_FragColor = vec4(ao, ao, ao, ao);
+}
diff --git a/app/resources/core/shader/sao_compute_varying.def b/app/resources/core/shader/sao_compute_varying.def
new file mode 100644
index 0000000..ff632a3
--- /dev/null
+++ b/app/resources/core/shader/sao_compute_varying.def
@@ -0,0 +1,4 @@
+vec3 v_viewRay : TEXCOORD0 = vec3(0.0, 0.0, 0.0);
+
+vec3 a_position : POSITION;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/app/resources/core/shader/sao_compute_vs.sc b/app/resources/core/shader/sao_compute_vs.sc
new file mode 100644
index 0000000..d02de49
--- /dev/null
+++ b/app/resources/core/shader/sao_compute_vs.sc
@@ -0,0 +1,18 @@
+$input a_position, a_texcoord0
+$output v_viewRay
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main() {
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0) );
+
+ vec2 sp = a_position.xy * 2. - 1.;
+ sp.y *= -1.;
+
+ vec4 ndc = mul(uMainInvProjection, vec4(sp, 1., 1.)); // far ndc frustum plane
+ ndc /= ndc.w;
+ ndc /= ndc.z;
+
+ v_viewRay = ndc.xyz;
+}
diff --git a/app/resources/core/shader/sao_upsample_fs.sc b/app/resources/core/shader/sao_upsample_fs.sc
new file mode 100644
index 0000000..4b16028
--- /dev/null
+++ b/app/resources/core/shader/sao_upsample_fs.sc
@@ -0,0 +1,47 @@
+$input v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+SAMPLER2D(u_attr0, 0);
+SAMPLER2D(u_input, 1);
+SAMPLER2D(u_depth_half, 2);
+
+uniform vec4 u_params[2];
+
+void main() {
+ float a = 0.25;
+ mat4 bilinear_weight = mat4(
+ vec4(9,3,3,1),
+ vec4(3,9,1,3),
+ vec4(3,1,9,3),
+ vec4(1,3,3,9)
+ );
+
+ float depth = LinearDepth(texture2D(u_input, v_texcoord0).r);
+
+ vec4 offset = floor((gl_FragCoord.xyxy + vec4( 1, 1,-1,-1)) / 2.0) * u_params[0].xyxy;
+
+ vec4 source;
+ source.x = texture2D(u_attr0, offset.zw).w;
+ source.y = texture2D(u_attr0, offset.zy).w;
+ source.z = texture2D(u_attr0, offset.xw).w;
+ source.w = texture2D(u_attr0, offset.xy).w;
+
+ vec4 half_res;
+ half_res.x = texture2D(u_depth_half, offset.zw).r;
+ half_res.y = texture2D(u_depth_half, offset.zy).r;
+ half_res.z = texture2D(u_depth_half, offset.xw).r;
+ half_res.w = texture2D(u_depth_half, offset.xy).r;
+
+ int i = int(mod(gl_FragCoord.y, 2.0)) * 2 + int(mod(gl_FragCoord.x, 2.0));
+ float w00 = bilinear_weight[i][0] / pow(1.0 + abs(half_res.x - depth), a);
+ float w01 = bilinear_weight[i][1] / pow(1.0 + abs(half_res.y - depth), a);
+ float w10 = bilinear_weight[i][2] / pow(1.0 + abs(half_res.z - depth), a);
+ float w11 = bilinear_weight[i][3] / pow(1.0 + abs(half_res.w - depth), a);
+
+ float w = w00 + w01 + w10 + w11;
+ float ao = ((w00 * source.x) + (w01 * source.y) + (w10 * source.z) + (w11 * source.w)) / w;
+
+ gl_FragColor = vec4(ao, ao, ao, 1.0);
+}
diff --git a/app/resources/core/shader/sao_upsample_varying.def b/app/resources/core/shader/sao_upsample_varying.def
new file mode 100644
index 0000000..b7b69d9
--- /dev/null
+++ b/app/resources/core/shader/sao_upsample_varying.def
@@ -0,0 +1,4 @@
+vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0);
+
+vec3 a_position : POSITION;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/app/resources/core/shader/sao_upsample_vs.sc b/app/resources/core/shader/sao_upsample_vs.sc
new file mode 100644
index 0000000..7519a3d
--- /dev/null
+++ b/app/resources/core/shader/sao_upsample_vs.sc
@@ -0,0 +1,10 @@
+$input a_position, a_texcoord0
+$output v_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main() {
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0) );
+ v_texcoord0 = a_texcoord0;
+}
diff --git a/app/resources/core/shader/ssgi_fs.sc b/app/resources/core/shader/ssgi_fs.sc
new file mode 100644
index 0000000..42156ea
--- /dev/null
+++ b/app/resources/core/shader/ssgi_fs.sc
@@ -0,0 +1,83 @@
+$input vTexCoord0, v_viewRay
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+SAMPLER2D(u_color, 0);
+SAMPLER2D(u_attr0, 1);
+SAMPLER2D(u_attr1, 2);
+SAMPLER2D(u_noise, 3);
+SAMPLERCUBE(u_probe, 4);
+SAMPLER2D(u_depthTex, 5); // input: minimum depth pyramid
+
+#define sample_count uAAAParams[1].z
+
+#define uv_ratio vec2_splat(uAAAParams[0].x)
+
+#include
+#include
+
+void main() {
+ vec4 color = vec4(0.0, 0.0, 0.0, 0.0);
+ vec4 jitter = texture2D(u_noise, mod(gl_FragCoord.xy, vec2(64, 64)) / vec2(64, 64));
+
+ // sample normal/depth
+ vec2 uv = GetAttributeTexCoord(vTexCoord0, vec2(textureSize(u_attr0, 0).xy));
+ vec4 attr0 = texture2D(u_attr0, uv);
+
+ vec3 n = normalize(attr0.xyz);
+ if (isNan(n.x) || isNan(n.y) || isNan(n.z))
+ n = vec3(0, 1, 0);
+
+ // compute ray origin & direction
+ vec3 ray_o = GetRayOrigin(uMainProjection, v_viewRay, attr0.w);
+
+ // spread
+ vec3 right = normalize(cross(n, vec3(1, 0, 0)));
+ vec3 up = cross(n, right);
+
+ //
+ const float z_min = 0.1;
+
+ for (int i = 0; i < int(sample_count); ++i) {
+ float r = (float(i) + jitter.y) / sample_count;
+ float spread = r * 3.141592 * 0.5 * 0.9;
+ float cos_spread = cos(spread), sin_spread = sin(spread);
+
+ for (int j = 0; j < int(sample_count); ++j) {
+ float angle = (float(j) + jitter.w) / sample_count * 2.0 * 3.141592;
+ float cos_angle = cos(angle), sin_angle = sin(angle);
+ vec3 ray_d_spread = (right * cos_angle + up * sin_angle) * sin_spread + n * cos_spread;
+
+ vec2 hit_pixel;
+ vec3 hit_point;
+ float k = TraceScreenRay(ray_o - v_viewRay * 0.05, ray_d_spread, uMainProjection, z_min, 192, hit_pixel, hit_point);
+
+ if (k > 0.0) {
+ // use hit pixel velocity to compensate the fact that we are sampling the previous frame
+ uv = hit_pixel * uv_ratio / uResolution.xy;
+ vec2 vel = GetVelocityVector(uv);
+
+ attr0 = texelFetch(u_attr0, ivec2(hit_pixel), 0);
+
+ float log_depth = ComputeRayLogDepth(uMainProjection, hit_point);
+
+ if ((dot(attr0.xyz, ray_d_spread) < 0.0) && (hit_point.z <= log_depth)) { // ray facing the collision
+ vec3 irradiance = texture2D(u_color, uv - vel * uv_ratio).xyz;
+ color += vec4(irradiance, 1.0);
+ } else {
+ color += vec4(0.0, 0.0, 0.0, 0.0); // backface hit
+ }
+ } else {
+ vec3 world_ray_d_spread = mul(uMainInvView, vec4(ray_d_spread, 0.0)).xyz;
+ vec3 world_ray_o = mul(uMainInvView, vec4(ray_o, 1.0)).xyz;
+ color += vec4(textureCubeLod(u_probe, ReprojectProbe(world_ray_o, world_ray_d_spread), 0).xyz, 0.);
+ }
+ }
+ }
+
+ color /= sample_count * sample_count;
+ color = (saturate(color) / 32.0) * 32.0;
+
+ gl_FragColor = color;
+}
diff --git a/app/resources/core/shader/ssgi_varying.def b/app/resources/core/shader/ssgi_varying.def
new file mode 100644
index 0000000..b42cb63
--- /dev/null
+++ b/app/resources/core/shader/ssgi_varying.def
@@ -0,0 +1,5 @@
+vec2 vTexCoord0 : TEXCOORD0;
+vec3 v_viewRay : TEXCOORD1 = vec3(0.0, 0.0, 0.0);
+
+vec3 a_position : POSITION;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/app/resources/core/shader/ssgi_vs.sc b/app/resources/core/shader/ssgi_vs.sc
new file mode 100644
index 0000000..6b7fbcf
--- /dev/null
+++ b/app/resources/core/shader/ssgi_vs.sc
@@ -0,0 +1,22 @@
+$input a_position, a_texcoord0
+$output vTexCoord0, v_viewRay
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+#define uv_ratio vec2_splat(uAAAParams[0].x)
+
+void main() {
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+
+ vec2 sp = a_position.xy * 2. - 1.;
+ sp.y *= -1.;
+
+ vec4 ndc = mul(uMainInvProjection, vec4(sp, 1., 1.)); // far ndc frustum plane
+ ndc /= ndc.w;
+ ndc /= ndc.z;
+
+ v_viewRay = ndc.xyz;
+
+ vTexCoord0 = a_texcoord0;
+}
diff --git a/app/resources/core/shader/ssr_fs.sc b/app/resources/core/shader/ssr_fs.sc
new file mode 100644
index 0000000..b7174c0
--- /dev/null
+++ b/app/resources/core/shader/ssr_fs.sc
@@ -0,0 +1,104 @@
+$input vTexCoord0, v_viewRay
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+SAMPLER2D(u_color, 0);
+SAMPLER2D(u_attr0, 1);
+SAMPLER2D(u_attr1, 2);
+SAMPLER2D(u_noise, 3);
+SAMPLERCUBE(u_probe, 4);
+SAMPLER2D(u_depthTex, 5); // input: minimum depth pyramid
+
+#define sample_count uAAAParams[1].z
+
+#define uv_ratio vec2_splat(uAAAParams[0].y)
+
+#include
+#include
+
+void main() {
+ vec4 color = vec4(0.0, 0.0, 0.0, 0.0);
+ vec4 jitter = texture2D(u_noise, mod(gl_FragCoord.xy, vec2(64, 64)) / vec2(64, 64));
+
+ // sample normal/depth
+ vec2 uv = GetAttributeTexCoord(vTexCoord0, vec2(textureSize(u_attr0, 0).xy));
+ vec4 attr0 = texture2D(u_attr0, uv);
+
+ vec3 n = normalize(attr0.xyz);
+ if (isNan(n.x) || isNan(n.y) || isNan(n.z))
+ n = vec3(0, 1, 0);
+
+ // compute ray origin & direction
+ vec3 ray_o = GetRayOrigin(uMainProjection, v_viewRay, attr0.w);
+ vec3 ray_d = reflect(normalize(ray_o), n);
+
+ const float z_min = 0.1;
+
+#if 0
+ vec2 hit_pixel;
+ vec3 hit_point;
+
+ float k = TraceScreenRay(ray_o - v_viewRay * 0.05, ray_d, uMainProjection, z_min, 4096, hit_pixel, hit_point);
+
+ if (k > 0.0) {
+ uv = hit_pixel * uv_ratio / uResolution.xy;
+ vec2 vel = GetVelocityVector(uv);
+ color = mix(color, vec4(texture2D(u_color, uv - vel * uv_ratio).xyz, 1.0), k);
+ } else if (k == 0.0) {
+ color = vec4(1.0, 0.0, 0.0, 0.0);
+ } else if (k == -1) {
+ color = vec4(0.0, 1.0, 0.0, 0.0); // max iteration reached (most likely due to a bug)
+ }
+#else
+ float roughness = texture2D(u_attr1, uv).z;
+ roughness = pow(roughness, 2.5);
+
+ vec3 right = cross(ray_d, vec3(0, 0, 1));
+ vec3 up = cross(ray_d, right);
+
+ //
+ vec3 world_ray_o = mul(uMainInvView, vec4(ray_o, 1.0)).xyz;
+
+ for (int i = 0; i < int(sample_count); ++i) {
+ float r = roughness * (float(i) + jitter.y) / sample_count;
+ float spread = r * 3.141592 * 0.5 * 0.99;
+ float cos_spread = cos(spread), sin_spread = sin(spread);
+
+ for (int j = 0; j < int(sample_count); ++j) {
+ float angle = (float(j) + jitter.w) / sample_count * 2.0 * 3.141592;
+ vec3 ray_d_spread = (right * cos(angle) + up * sin(angle)) * sin_spread + ray_d * cos_spread;
+
+ vec3 world_ray_d = mul(uMainInvView, vec4(ray_d_spread, 0.0)).xyz;
+ vec4 fallback = vec4(textureCubeLod(u_probe, ReprojectProbe(world_ray_o, world_ray_d), 0).xyz, 0.);
+
+ vec2 hit_pixel;
+ vec3 hit_point;
+ float k = TraceScreenRay(ray_o - v_viewRay * 0.05, ray_d_spread, uMainProjection, z_min, 192, hit_pixel, hit_point);
+
+ if (k > 0.0) {
+ // use hit pixel velocity to compensate the fact that we are sampling the previous frame
+ uv = hit_pixel * uv_ratio / uResolution.xy;
+ vec2 vel = GetVelocityVector(uv);
+
+ attr0 = texelFetch(u_attr0, ivec2(hit_pixel), 0);
+
+ float log_depth = ComputeRayLogDepth(uMainProjection, hit_point);
+
+ vec4 ss_output = vec4(0.0, 0.0, 0.0, 1.0); // assume backface hit
+ if (dot(attr0.xyz, ray_d_spread) < 0.0 && hit_point.z <= log_depth)
+ ss_output = vec4(texture2D(u_color, uv - vel * uv_ratio).xyz, 1.0); // front face hit
+
+ color += mix(fallback, ss_output, k);
+ } else {
+ color += fallback;
+ }
+ }
+ }
+
+ color /= sample_count * sample_count;
+ color = clamp(color, 0.0, 32.0); // [FG] Avoid high intensity HDR probes from saturating the SSR buffer.
+#endif
+
+ gl_FragColor = color;
+}
diff --git a/app/resources/core/shader/ssr_varying.def b/app/resources/core/shader/ssr_varying.def
new file mode 100644
index 0000000..b42cb63
--- /dev/null
+++ b/app/resources/core/shader/ssr_varying.def
@@ -0,0 +1,5 @@
+vec2 vTexCoord0 : TEXCOORD0;
+vec3 v_viewRay : TEXCOORD1 = vec3(0.0, 0.0, 0.0);
+
+vec3 a_position : POSITION;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/app/resources/core/shader/ssr_vs.sc b/app/resources/core/shader/ssr_vs.sc
new file mode 100644
index 0000000..6b33b32
--- /dev/null
+++ b/app/resources/core/shader/ssr_vs.sc
@@ -0,0 +1,20 @@
+$input a_position, a_texcoord0
+$output vTexCoord0, v_viewRay
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main() {
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+
+ vec2 sp = a_position.xy * 2. - 1.;
+ sp.y *= -1.;
+
+ vec4 ndc = mul(uMainInvProjection, vec4(sp, 1., 1.)); // far ndc frustum plane
+ ndc /= ndc.w;
+ ndc /= ndc.z;
+
+ v_viewRay = ndc.xyz;
+
+ vTexCoord0 = a_texcoord0;
+}
diff --git a/app/resources/core/shader/taa_fs.sc b/app/resources/core/shader/taa_fs.sc
new file mode 100644
index 0000000..bcf820c
--- /dev/null
+++ b/app/resources/core/shader/taa_fs.sc
@@ -0,0 +1,102 @@
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+SAMPLER2D(u_color, 0);
+SAMPLER2D(u_prv_color, 1);
+SAMPLER2D(u_attr0, 2);
+SAMPLER2D(u_attr1, 3);
+
+#include
+
+#define AABB_CLAMPING 0
+#define AABB_CLAMPING_FAST 1
+#define VARIANCE_CLIPPING_GAMMA 0 // https://community.arm.com/developer/tools-software/graphics/b/blog/posts/temporal-anti-aliasing
+#define LUMINANCE_AJDUST 1
+
+void main() {
+ vec2 uv = gl_FragCoord.xy / uResolution.xy;
+
+ // current contribution
+ vec3 color = texture2D(u_color, uv).xyz;
+
+ // fetch velocity to reproject history onto the current frame
+ vec2 dt = GetVelocityVector(uv);
+
+ // fetch history contribution
+ vec3 prv_color = texture2D(u_prv_color, uv - dt).xyz;
+
+ // reject invalid sample
+#if AABB_CLAMPING
+ vec3 neighbors[9];
+
+ neighbors[0] = texture2D(u_color, uv + vec2(-1, -1) / uResolution.xy).xyz;
+ neighbors[1] = texture2D(u_color, uv + vec2( 0, -1) / uResolution.xy).xyz;
+ neighbors[2] = texture2D(u_color, uv + vec2( 1, -1) / uResolution.xy).xyz;
+ neighbors[3] = texture2D(u_color, uv + vec2(-1, 0) / uResolution.xy).xyz;
+ neighbors[4] = color;
+ neighbors[5] = texture2D(u_color, uv + vec2( 1, 0) / uResolution.xy).xyz;
+ neighbors[6] = texture2D(u_color, uv + vec2(-1, 1) / uResolution.xy).xyz;
+ neighbors[7] = texture2D(u_color, uv + vec2( 0, 1) / uResolution.xy).xyz;
+ neighbors[8] = texture2D(u_color, uv + vec2( 1, 1) / uResolution.xy).xyz;
+
+ vec3 nmin = neighbors[0];
+ vec3 nmax = neighbors[0];
+
+ for(int i = 1; i < 9; ++i) {
+ nmin = min(nmin, neighbors[i]);
+ nmax = max(nmax, neighbors[i]);
+ }
+
+ prv_color = clamp(prv_color, nmin, nmax);
+#endif
+
+#if AABB_CLAMPING_FAST
+ vec3 c0 = texture2D(u_color, uv + vec2( 1, 0) / uResolution.xy).xyz;
+ vec3 c1 = texture2D(u_color, uv + vec2( 0, 1) / uResolution.xy).xyz;
+ vec3 c2 = texture2D(u_color, uv + vec2(-1, 0) / uResolution.xy).xyz;
+ vec3 c3 = texture2D(u_color, uv + vec2( 0, -1) / uResolution.xy).xyz;
+
+ vec3 box_min = min(color, min(c0, min(c1, min(c2, c3))));
+ vec3 box_max = max(color, max(c0, max(c1, max(c2, c3))));;
+
+ prv_color = clamp(prv_color, box_min, box_max);
+#endif
+
+#if VARIANCE_CLIPPING_GAMMA
+ float clipping_gamma = 2.2;
+
+ vec3 c0 = texture2D(u_color, uv + vec2( 1, 0) / uResolution.xy).xyz;
+ vec3 c1 = texture2D(u_color, uv + vec2( 0, 1) / uResolution.xy).xyz;
+ vec3 c2 = texture2D(u_color, uv + vec2(-1, 0) / uResolution.xy).xyz;
+ vec3 c3 = texture2D(u_color, uv + vec2( 0, -1) / uResolution.xy).xyz;
+
+ // Compute the two moments
+ vec3 M1 = color + c0 + c1 + c2 + c3;
+ vec3 M2 = color * color + c0 * c0 + c1 * c1 + c2 * c2 + c3 * c3;
+
+ vec3 MU = M1 / 5.;
+ vec3 Sigma = sqrt(M2 / 5. - MU * MU);
+
+ vec3 box_min = MU - clipping_gamma * Sigma;
+ vec3 box_max = MU + clipping_gamma * Sigma;
+
+ prv_color = clamp(prv_color, box_min, box_max);
+#endif
+
+#if LUMINANCE_AJDUST
+ const vec3 luminance = vec3(0.2127, 0.7152, 0.0722);
+
+ float l0 = dot(luminance, prv_color);
+ float l1 = dot(luminance, color);
+
+ float w1 = (uAAAParams[0].z) / (1.0 + l1);
+ float w0 = (1.0 - uAAAParams[0].z) / (1.0 + l0);
+
+ vec3 taa_out = (w1 * color + w0 * prv_color) / max(w0 + w1, 0.00001);
+ gl_FragColor = vec4(taa_out, 1.);
+#else
+ // TAA
+ vec3 taa_out = color * uAAAParams[0].z + prv_color * (1. - uAAAParams[0].z);
+ gl_FragColor = vec4(taa_out, 1.);
+#endif
+}
diff --git a/app/resources/core/shader/taa_varying.def b/app/resources/core/shader/taa_varying.def
new file mode 100644
index 0000000..b7b69d9
--- /dev/null
+++ b/app/resources/core/shader/taa_varying.def
@@ -0,0 +1,4 @@
+vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0);
+
+vec3 a_position : POSITION;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/app/resources/core/shader/taa_vs.sc b/app/resources/core/shader/taa_vs.sc
new file mode 100644
index 0000000..4747f03
--- /dev/null
+++ b/app/resources/core/shader/taa_vs.sc
@@ -0,0 +1,8 @@
+$input a_position, a_texcoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main() {
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+}
diff --git a/app/resources/core/shader/temporal_accumulation_fs.sc b/app/resources/core/shader/temporal_accumulation_fs.sc
new file mode 100644
index 0000000..46f7045
--- /dev/null
+++ b/app/resources/core/shader/temporal_accumulation_fs.sc
@@ -0,0 +1,40 @@
+$input vTexCoord0
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+SAMPLER2D(u_current, 0);
+SAMPLER2D(u_previous, 1);
+SAMPLER2D(u_attr1, 2);
+
+#include
+
+vec2 GetVelocityVector(in vec2 uv, vec2 ratio) {
+#if BGFX_SHADER_LANGUAGE_GLSL
+ const vec2 offset = vec2(0.5, 0.5);
+#else
+ const vec2 offset = vec2(0.5, -0.5);
+#endif
+ return texture2D(u_attr1, uv).xy * offset * ratio / (uResolution.xy / u_viewRect.zw);
+}
+
+void main() {
+ ivec2 coord = ivec2(gl_FragCoord.xy);
+
+ vec2 input_size = vec2(textureSize(u_previous, 0));
+ vec2 uv = gl_FragCoord.xy / input_size;
+ vec2 dt = GetVelocityVector(uv, uResolution.xy / input_size.xy);
+
+ vec2 uv_curr = GetAttributeTexCoord(vTexCoord0, vec2(textureSize(u_current, 0).xy));
+ vec4 current = texture2D(u_current, uv_curr);
+
+ vec4 c0 = texture2DLodOffset(u_current, uv_curr, 0, ivec2(0, 1));
+ vec4 c1 = texture2DLodOffset(u_current, uv_curr, 0, ivec2(0, -1));
+ vec4 c2 = texture2DLodOffset(u_current, uv_curr, 0, ivec2(1, 0));
+ vec4 c3 = texture2DLodOffset(u_current, uv_curr, 0, ivec2(-1, 0));
+ vec4 neighbour_min = min(min(c0, c1), min(c2, c3));
+ vec4 neighbour_max = max(max(c0, c1), max(c2, c3));
+
+ vec4 previous = clamp(texture2D(u_previous, uv - dt, 0), neighbour_min, neighbour_max);
+ gl_FragColor = mix(previous, current, uAAAParams[0].z);
+}
diff --git a/app/resources/core/shader/temporal_accumulation_varying.def b/app/resources/core/shader/temporal_accumulation_varying.def
new file mode 100644
index 0000000..f91907c
--- /dev/null
+++ b/app/resources/core/shader/temporal_accumulation_varying.def
@@ -0,0 +1,4 @@
+vec2 vTexCoord0 : TEXCOORD0;
+
+vec3 a_position : POSITION;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/app/resources/core/shader/temporal_accumulation_vs.sc b/app/resources/core/shader/temporal_accumulation_vs.sc
new file mode 100644
index 0000000..a85563e
--- /dev/null
+++ b/app/resources/core/shader/temporal_accumulation_vs.sc
@@ -0,0 +1,10 @@
+$input a_position, a_texcoord0
+$output vTexCoord0,
+
+// HARFANG(R) Copyright (C) 2022 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
+#include
+
+void main() {
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+ vTexCoord0 = a_texcoord0;
+}
diff --git a/app/resources/main.scn b/app/resources/main.scn
new file mode 100644
index 0000000..a76b707
--- /dev/null
+++ b/app/resources/main.scn
@@ -0,0 +1,568 @@
+{
+ "cameras": [
+ {
+ "fov": 0.3490658402442932,
+ "ortho": false,
+ "size": 1.0,
+ "zrange": {
+ "zfar": 1000.0,
+ "znear": 1.0
+ }
+ }
+ ],
+ "canvas": {
+ "clear_color": true,
+ "clear_z": true,
+ "color": [
+ 0,
+ 0,
+ 0,
+ 255
+ ]
+ },
+ "environment": {
+ "ambient": [
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "brdf_map": "core/pbr/brdf.dds",
+ "current_camera": 0,
+ "fog_color": [
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "fog_far": 0.0,
+ "fog_near": 0.0,
+ "probe": {
+ "irradiance_map": "core/pbr/probe.hdr.irradiance",
+ "parallax": 0.0,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "radiance_map": "core/pbr/probe.hdr.radiance",
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "type": "sphere"
+ }
+ },
+ "instances": [
+ {
+ "name": "vehicles/generic_vehicle/drivable_car.scn"
+ },
+ {
+ "name": "road_blocks/block_highway_straight/block_highway_straight.scn"
+ },
+ {
+ "name": "road_blocks/block_highway_straight/block_highway_straight.scn"
+ },
+ {
+ "name": "road_blocks/block_highway_straight/block_highway_straight.scn"
+ },
+ {
+ "name": "road_blocks/block_highway_straight/block_highway_straight.scn"
+ },
+ {
+ "name": "road_blocks/block_highway_straight/block_highway_straight.scn"
+ },
+ {
+ "name": "road_blocks/block_highway_straight/block_highway_straight.scn"
+ },
+ {
+ "name": "road_blocks/block_highway_straight/block_highway_straight.scn"
+ },
+ {
+ "name": "road_blocks/block_highway_straight/block_highway_straight.scn"
+ },
+ {
+ "name": "road_blocks/block_highway_straight/block_highway_straight.scn"
+ },
+ {
+ "name": "road_blocks/block_highway_straight/block_highway_straight.scn"
+ },
+ {
+ "name": "road_blocks/block_highway_straight/block_highway_straight.scn"
+ }
+ ],
+ "key_values": null,
+ "lights": [
+ {
+ "diffuse": [
+ 512,
+ 512,
+ 512,
+ 255
+ ],
+ "diffuse_intensity": 1.0,
+ "inner_angle": 0.5235987901687622,
+ "outer_angle": 0.7853981852531433,
+ "priority": 1.0,
+ "pssm_split": [
+ 2.0,
+ 8.0,
+ 16.0,
+ 64.0
+ ],
+ "radius": 0.0,
+ "shadow_bias": 0.0010000000474974513,
+ "shadow_type": "map",
+ "specular": [
+ 0,
+ 0,
+ 0,
+ 255
+ ],
+ "specular_intensity": 1.0,
+ "type": "linear"
+ }
+ ],
+ "nodes": [
+ {
+ "components": [
+ 0,
+ 0,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 0,
+ "name": "Camera"
+ },
+ {
+ "components": [
+ 1,
+ 4294967295,
+ 4294967295,
+ 0,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 1,
+ "name": "Light"
+ },
+ {
+ "components": [
+ 2,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 2,
+ "instance": 0,
+ "name": "car"
+ },
+ {
+ "components": [
+ 3,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 3,
+ "instance": 1,
+ "name": "block_highway_straight"
+ },
+ {
+ "components": [
+ 13,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 27,
+ "instance": 11,
+ "name": "block_highway_straight"
+ },
+ {
+ "components": [
+ 4,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 28,
+ "instance": 2,
+ "name": "block_highway_straight"
+ },
+ {
+ "components": [
+ 5,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 30,
+ "instance": 3,
+ "name": "block_highway_straight"
+ },
+ {
+ "components": [
+ 6,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 32,
+ "instance": 4,
+ "name": "block_highway_straight"
+ },
+ {
+ "components": [
+ 7,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 34,
+ "instance": 5,
+ "name": "block_highway_straight"
+ },
+ {
+ "components": [
+ 8,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 36,
+ "instance": 6,
+ "name": "block_highway_straight"
+ },
+ {
+ "components": [
+ 9,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 38,
+ "instance": 7,
+ "name": "block_highway_straight"
+ },
+ {
+ "components": [
+ 10,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 40,
+ "instance": 8,
+ "name": "block_highway_straight"
+ },
+ {
+ "components": [
+ 11,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 42,
+ "instance": 9,
+ "name": "block_highway_straight"
+ },
+ {
+ "components": [
+ 12,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 44,
+ "instance": 10,
+ "name": "block_highway_straight"
+ }
+ ],
+ "transforms": [
+ {
+ "parent": null,
+ "pos": [
+ 20.769710540771484,
+ 12.37807559967041,
+ 13.72885799407959
+ ],
+ "rot": [
+ 18.90964698791504,
+ -122.79573059082031,
+ 9.935133675753605e-07
+ ],
+ "scl": [
+ 0.9999998211860657,
+ 0.9999755620956421,
+ 0.9999617338180542
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 2.9797675609588623,
+ 6.607077598571777,
+ 3.641082763671875
+ ],
+ "rot": [
+ 26.666213989257813,
+ -160.28970336914063,
+ -159.97998046875
+ ],
+ "scl": [
+ 0.9999996423721313,
+ 0.9999997615814209,
+ 0.9999993443489075
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 2.434762716293335,
+ 0.0
+ ],
+ "rot": [
+ -0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 5000.0
+ ],
+ "rot": [
+ -0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 7500.0
+ ],
+ "rot": [
+ -0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 10000.0
+ ],
+ "rot": [
+ -0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 12500.0
+ ],
+ "rot": [
+ -0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 15000.0
+ ],
+ "rot": [
+ -0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 17500.0
+ ],
+ "rot": [
+ -0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 20000.0
+ ],
+ "rot": [
+ -0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 22500.0
+ ],
+ "rot": [
+ -0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 25000.0
+ ],
+ "rot": [
+ -0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 2500.0
+ ],
+ "rot": [
+ -0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/app/resources/main.scn.aaa b/app/resources/main.scn.aaa
new file mode 100644
index 0000000..03b674f
--- /dev/null
+++ b/app/resources/main.scn.aaa
@@ -0,0 +1,12 @@
+{
+ "bloom_bias": 0.5,
+ "bloom_intensity": 0.10000000149011612,
+ "bloom_threshold": 5.0,
+ "exposure": 1.0,
+ "gamma": 2.200000047683716,
+ "max_distance": 100.0,
+ "motion_blur": 1.0,
+ "sample_count": 2,
+ "taa_weight": 0.10000000149011612,
+ "z_thickness": 0.10000000149011612
+}
\ No newline at end of file
diff --git a/app/resources/main.scn.editor b/app/resources/main.scn.editor
new file mode 100644
index 0000000..1ced81a
--- /dev/null
+++ b/app/resources/main.scn.editor
@@ -0,0 +1,190 @@
+{
+ "editor": {
+ "animeditor_plugin": {
+ "quantize_time": true,
+ "show_trajectories": null,
+ "trajectories_tick_seconds": 1.0,
+ "trajectories_tick_size": 0.10000000149011612
+ },
+ "explorer": {
+ "node_custom_order": {
+ "refs": null,
+ "roots": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 27,
+ 28,
+ 30,
+ 32,
+ 34,
+ 36,
+ 38,
+ 40,
+ 42,
+ 44
+ ]
+ },
+ "node_sort_method": "custom",
+ "show_node_uid": false
+ },
+ "grid_plugin": {
+ "enabled": true,
+ "grid_color_b": 1.0,
+ "grid_color_g": 1.0,
+ "grid_color_r": 1.0,
+ "n_subdivs": 10,
+ "offset": 0.0,
+ "opacity": 0.5,
+ "subdiv_size": 1.0
+ },
+ "navigation_plugin": {
+ "orbit_distance": 5.0,
+ "speed": 0.10000000149011612,
+ "turbo": 1.0
+ },
+ "transform_gizmo_plugin": {
+ "mode": "local",
+ "snap": "none",
+ "snap_rotation": 5.0,
+ "snap_rotation_fine": 1.0,
+ "snap_scale": 10.0,
+ "snap_scale_fine": 1.0,
+ "snap_translation": 1.0,
+ "snap_translation_fine": 0.10000000149011612,
+ "tool": "move"
+ },
+ "view_plugin": {
+ "show_cameras": true,
+ "show_collisions": true,
+ "show_lights": true,
+ "show_nodes": true,
+ "show_probe": true
+ },
+ "views": {
+ "back": [
+ -0.9999999403953552,
+ 0.0,
+ -8.742277657347586e-08,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 8.742277657347586e-08,
+ -0.0,
+ -0.9999999403953552,
+ 0.0
+ ],
+ "bottom": [
+ 1.0,
+ -0.0,
+ -0.0,
+ 0.0,
+ -0.0,
+ -8.742277657347586e-08,
+ 0.9999999403953552,
+ 0.0,
+ -0.0,
+ -0.9999999403953552,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "bottom_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "current_camera": 0,
+ "front": [
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0
+ ],
+ "left": [
+ -8.742277657347586e-08,
+ 0.0,
+ 0.9999999403953552,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ -0.9999999403953552,
+ 0.0,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "left_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "orthographic_size": 1.0,
+ "perspective": [
+ 1.0000081062316895,
+ 0.0015469788340851665,
+ 0.004526082891970873,
+ 3.0016093254089355,
+ 0.0,
+ 0.9463406801223755,
+ -0.32330530881881714,
+ 41.481101989746094,
+ -0.00478630606085062,
+ 0.3232990801334381,
+ 0.9463456869125366,
+ -24.189163208007813
+ ],
+ "perspective_fov": 0.8872777223587036,
+ "perspective_zrange": {
+ "zfar": 1000.0,
+ "znear": 1.0
+ },
+ "right": [
+ -8.742277657347586e-08,
+ 0.0,
+ -0.9999999403953552,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 0.9999999403953552,
+ -0.0,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "right_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "scale": 0.05000000074505806,
+ "top": [
+ 1.0,
+ 0.0,
+ -0.0,
+ 0.0,
+ -0.0,
+ -8.742277657347586e-08,
+ -0.9999999403953552,
+ 0.0,
+ 0.0,
+ 0.9999999403953552,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "top_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/resources/materials/body.mat b/app/resources/materials/body.mat
new file mode 100644
index 0000000..318aef4
--- /dev/null
+++ b/app/resources/materials/body.mat
@@ -0,0 +1,56 @@
+{
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_Body_albedo.png",
+ "stage": 0
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "vehicles/generic_vehicle/Car03_Body_ORM.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.7372549176216125,
+ 0.7372549176216125,
+ 0.7372549176216125,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+}
\ No newline at end of file
diff --git a/app/resources/materials/body_packed.mat b/app/resources/materials/body_packed.mat
new file mode 100644
index 0000000..a118f76
--- /dev/null
+++ b/app/resources/materials/body_packed.mat
@@ -0,0 +1,61 @@
+{
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_pack_albedo.png",
+ "stage": 0
+ },
+ {
+ "name": "uNormalMap",
+ "path": "vehicles/generic_vehicle/Car03_pack_normal.png",
+ "stage": 2
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "vehicles/generic_vehicle/Car03_pack_ORM.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.75,
+ 0.75,
+ 0.75,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.10000000149011612,
+ 1.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+}
\ No newline at end of file
diff --git a/app/resources/materials/glass.mat b/app/resources/materials/glass.mat
new file mode 100644
index 0000000..836bd01
--- /dev/null
+++ b/app/resources/materials/glass.mat
@@ -0,0 +1,44 @@
+{
+ "blend_mode": "alpha",
+ "depth_test": "less",
+ "face_culling": "disabled",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.1411764770746231,
+ 0.1764705926179886,
+ 0.24705883860588074,
+ 0.3720000088214874
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.17800000309944153,
+ 1.0,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+}
\ No newline at end of file
diff --git a/app/resources/materials/grill.mat b/app/resources/materials/grill.mat
new file mode 100644
index 0000000..c29eca0
--- /dev/null
+++ b/app/resources/materials/grill.mat
@@ -0,0 +1,61 @@
+{
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_Grill_Color.tga",
+ "stage": 0
+ },
+ {
+ "name": "uNormalMap",
+ "path": "vehicles/generic_vehicle/Car03_Grill_Normal.png",
+ "stage": 2
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "vehicles/generic_vehicle/Car03_Grill_ORM.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.2742616534233093,
+ 0.2742616534233093,
+ 0.2742616534233093,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+}
\ No newline at end of file
diff --git a/app/resources/materials/interior.mat b/app/resources/materials/interior.mat
new file mode 100644
index 0000000..4022ce0
--- /dev/null
+++ b/app/resources/materials/interior.mat
@@ -0,0 +1,61 @@
+{
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_Interior_Albedo01.png",
+ "stage": 0
+ },
+ {
+ "name": "uNormalMap",
+ "path": "vehicles/generic_vehicle/Car03_Interior_Normal.png",
+ "stage": 2
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "vehicles/generic_vehicle/Car03_Interior_ORM.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.6039215922355652,
+ 0.6039215922355652,
+ 0.6039215922355652,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+}
\ No newline at end of file
diff --git a/app/resources/materials/lights_emissive.mat b/app/resources/materials/lights_emissive.mat
new file mode 100644
index 0000000..2ac75ef
--- /dev/null
+++ b/app/resources/materials/lights_emissive.mat
@@ -0,0 +1,51 @@
+{
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_Lights_Emissive.hdr",
+ "stage": 0
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.1411764770746231,
+ 0.1764705926179886,
+ 0.24705883860588074,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+}
\ No newline at end of file
diff --git a/app/resources/materials/parts.mat b/app/resources/materials/parts.mat
new file mode 100644
index 0000000..4f7ae3f
--- /dev/null
+++ b/app/resources/materials/parts.mat
@@ -0,0 +1,61 @@
+{
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_Parts_Albedo01.png",
+ "stage": 0
+ },
+ {
+ "name": "uNormalMap",
+ "path": "vehicles/generic_vehicle/Car03_Parts_Normal.png",
+ "stage": 2
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "vehicles/generic_vehicle/Car03_Parts_ORM.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.43529415130615234,
+ 0.43529415130615234,
+ 0.43529415130615234,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+}
\ No newline at end of file
diff --git a/app/resources/materials/wheel.mat b/app/resources/materials/wheel.mat
new file mode 100644
index 0000000..37146b5
--- /dev/null
+++ b/app/resources/materials/wheel.mat
@@ -0,0 +1,61 @@
+{
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_Wheel_Albedo01.png",
+ "stage": 0
+ },
+ {
+ "name": "uNormalMap",
+ "path": "vehicles/generic_vehicle/Car03_Wheel_Normal.png",
+ "stage": 2
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "vehicles/generic_vehicle/Car03_Wheel_ORM.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+}
\ No newline at end of file
diff --git a/app/resources/materials/wiper.mat b/app/resources/materials/wiper.mat
new file mode 100644
index 0000000..864281f
--- /dev/null
+++ b/app/resources/materials/wiper.mat
@@ -0,0 +1,48 @@
+{
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "stage": 0
+ },
+ {
+ "name": "uNormalMap",
+ "stage": 2
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.1350211501121521,
+ 0.1350211501121521,
+ 0.1350211501121521,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 0.01600000075995922,
+ 0.8700000047683716,
+ 0.25,
+ 0.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+}
\ No newline at end of file
diff --git a/app/resources/primitives/cube.geo b/app/resources/primitives/cube.geo
new file mode 100644
index 0000000..debd23c
Binary files /dev/null and b/app/resources/primitives/cube.geo differ
diff --git a/app/resources/primitives/fbx_importer_cfg.txt b/app/resources/primitives/fbx_importer_cfg.txt
new file mode 100644
index 0000000..7704e1f
--- /dev/null
+++ b/app/resources/primitives/fbx_importer_cfg.txt
@@ -0,0 +1,16 @@
+"anim_policy":"1"
+"detect_geometry_instances":"1"
+"fbx_file_path":"c:/works/ortec/sonovision-poc-work/primitives/primitives.FBX"
+"finalizer_script":""
+"fix_geometry_orientation":"1"
+"geometry_policy":"1"
+"geometry_scale":"1.000000"
+"material_policy":"1"
+"max_smoothing_angle":"70.000000"
+"output_folder":"primitives"
+"recalculate_normals":"0"
+"recalculate_tangents":"0"
+"scale":"1.000000"
+"scene_policy":"1"
+"texture_policy":"1"
+"use_finalizer_script":"0"
diff --git a/app/resources/primitives/plane.geo b/app/resources/primitives/plane.geo
new file mode 100644
index 0000000..1439fe9
Binary files /dev/null and b/app/resources/primitives/plane.geo differ
diff --git a/app/resources/primitives/primitives.scn b/app/resources/primitives/primitives.scn
new file mode 100644
index 0000000..b38ebbb
--- /dev/null
+++ b/app/resources/primitives/primitives.scn
@@ -0,0 +1,415 @@
+{
+ "canvas": {
+ "clear_color": true,
+ "clear_z": true,
+ "color": [
+ 60,
+ 85,
+ 91,
+ 255
+ ]
+ },
+ "environment": {
+ "ambient": [
+ 0,
+ 0,
+ 0,
+ 255
+ ],
+ "brdf_map": "core/pbr/brdf.dds",
+ "current_camera": null,
+ "fog_color": [
+ 255,
+ 255,
+ 255,
+ 255
+ ],
+ "fog_far": 0.0,
+ "fog_near": 0.0,
+ "irradiance_map": "core/pbr/probe.hdr.irradiance",
+ "radiance_map": "core/pbr/probe.hdr.radiance"
+ },
+ "key_values": null,
+ "lights": [
+ {
+ "diffuse": [
+ 255,
+ 255,
+ 255,
+ 255
+ ],
+ "diffuse_intensity": 1.0,
+ "inner_angle": 0.5235987901687622,
+ "outer_angle": 0.7853981852531433,
+ "priority": 0.0,
+ "pssm_split": [
+ 10.0,
+ 50.0,
+ 100.0,
+ 500.0
+ ],
+ "radius": 0.0,
+ "shadow_bias": 9.999999747378752e-06,
+ "shadow_type": "none",
+ "specular": [
+ 0,
+ 0,
+ 0,
+ 255
+ ],
+ "specular_intensity": 1.0,
+ "type": "point"
+ }
+ ],
+ "nodes": [
+ {
+ "components": [
+ 0,
+ 4294967295,
+ 0,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 0,
+ "name": "cube"
+ },
+ {
+ "components": [
+ 1,
+ 4294967295,
+ 1,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 1,
+ "name": "sphere"
+ },
+ {
+ "components": [
+ 2,
+ 4294967295,
+ 2,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 2,
+ "name": "plane"
+ },
+ {
+ "components": [
+ 3,
+ 4294967295,
+ 4294967295,
+ 0,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 3,
+ "name": "Light"
+ }
+ ],
+ "objects": [
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "default"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.16877639293670654,
+ 0.16877470910549164,
+ 0.16877470910549164,
+ 1.0
+ ]
+ },
+ {
+ "name": "uDiffuseColor",
+ "type": "vec4",
+ "value": [
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.9459999799728394,
+ 0.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ },
+ {
+ "name": "uSpecularColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.03124999813735485
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ }
+ ],
+ "name": "primitives/cube.geo"
+ },
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "default"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.16877639293670654,
+ 0.16877470910549164,
+ 0.16877470910549164,
+ 1.0
+ ]
+ },
+ {
+ "name": "uDiffuseColor",
+ "type": "vec4",
+ "value": [
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.9459999799728394,
+ 0.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ },
+ {
+ "name": "uSpecularColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.03124999813735485
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ }
+ ],
+ "name": "primitives/sphere.geo"
+ },
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "default"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.16877639293670654,
+ 0.16877470910549164,
+ 0.16877470910549164,
+ 1.0
+ ]
+ },
+ {
+ "name": "uDiffuseColor",
+ "type": "vec4",
+ "value": [
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.9459999799728394,
+ 0.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ },
+ {
+ "name": "uSpecularColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.03124999813735485
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ }
+ ],
+ "name": "primitives/plane.geo"
+ }
+ ],
+ "transforms": [
+ {
+ "parent": null,
+ "pos": [
+ 1.5859694480895996,
+ 0.0,
+ 0.0
+ ],
+ "rot": [
+ -7.0167078561561656e-15,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "rot": [
+ -7.0167078561561656e-15,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ -1.5,
+ 0.0,
+ 0.0
+ ],
+ "rot": [
+ -7.0167078561561656e-15,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 2.685239315032959,
+ 2.008998394012451,
+ 2.5896778106689453
+ ],
+ "rot": [
+ -0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/app/resources/primitives/primitives.scn.editor b/app/resources/primitives/primitives.scn.editor
new file mode 100644
index 0000000..60b9954
--- /dev/null
+++ b/app/resources/primitives/primitives.scn.editor
@@ -0,0 +1,139 @@
+{
+ "editor": {
+ "animeditor_plugin": {
+ "show_trajectories": 0,
+ "trajectories_tick_seconds": 1.0,
+ "trajectories_tick_size": 0.10000000149011612
+ },
+ "explorer": {
+ "node_custom_order": {
+ "refs": null,
+ "roots": [
+ 0,
+ 1,
+ 2,
+ 3
+ ]
+ },
+ "node_sort_method": "custom",
+ "show_node_uid": false
+ },
+ "navigation_plugin": {
+ "orbit_distance": 4.779956817626953,
+ "speed": 0.10000000149011612,
+ "turbo": 1.0
+ },
+ "transform_gizmo_plugin": {
+ "mode": "local",
+ "snap": "none",
+ "snap_rotation": 5.0,
+ "snap_rotation_fine": 1.0,
+ "snap_scale": 10.0,
+ "snap_scale_fine": 1.0,
+ "snap_translation": 1.0,
+ "snap_translation_fine": 0.10000000149011612,
+ "tool": "move"
+ },
+ "view_plugin": {
+ "show_cameras": true,
+ "show_lights": true,
+ "show_node_origin": true
+ },
+ "views": {
+ "bottom": [
+ 1.0,
+ -0.0,
+ -0.0,
+ 0.0,
+ -0.0,
+ -8.742277657347586e-08,
+ 1.0,
+ 0.0,
+ -0.0,
+ -1.0,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "bottom_zrange": {
+ "zfar": 1000.0,
+ "znear": -1000.0
+ },
+ "current_camera": 0,
+ "left": [
+ -8.742277657347586e-08,
+ 0.0,
+ 1.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ -1.0,
+ 0.0,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "left_zrange": {
+ "zfar": 1000.0,
+ "znear": -1000.0
+ },
+ "orthographic_size": 1.0,
+ "perspective": [
+ -0.9890074729919434,
+ 0.04369646683335304,
+ 0.14125820994377136,
+ -0.49296334385871887,
+ 0.0,
+ 0.9553386569023132,
+ -0.2955215871334076,
+ 1.573938012123108,
+ -0.14786334335803986,
+ -0.29227232933044434,
+ -0.9448360800743103,
+ 4.619147777557373
+ ],
+ "perspective_fov": 0.6361725330352783,
+ "perspective_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "right": [
+ -8.742277657347586e-08,
+ 0.0,
+ -1.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "right_zrange": {
+ "zfar": 1000.0,
+ "znear": -1000.0
+ },
+ "scale": 0.05000000074505806,
+ "top": [
+ 1.0,
+ 0.0,
+ -0.0,
+ 0.0,
+ -0.0,
+ -8.742277657347586e-08,
+ -1.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "top_zrange": {
+ "zfar": 1000.0,
+ "znear": -1000.0
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/resources/primitives/sphere.geo b/app/resources/primitives/sphere.geo
new file mode 100644
index 0000000..495ee9e
Binary files /dev/null and b/app/resources/primitives/sphere.geo differ
diff --git a/app/resources/project.prj b/app/resources/project.prj
new file mode 100644
index 0000000..e69de29
diff --git a/app/resources/road_blocks/block_highway_staight_col/block_highway_straight_col.scn b/app/resources/road_blocks/block_highway_staight_col/block_highway_straight_col.scn
new file mode 100644
index 0000000..d523c04
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_staight_col/block_highway_straight_col.scn
@@ -0,0 +1,307 @@
+{
+ "canvas": {
+ "clear_color": true,
+ "clear_z": true,
+ "color": [
+ 0,
+ 0,
+ 0,
+ 255
+ ]
+ },
+ "environment": {
+ "ambient": [
+ 75,
+ 75,
+ 75,
+ 255
+ ],
+ "brdf_map": "core/pbr/brdf.dds",
+ "current_camera": null,
+ "fog_color": [
+ 255,
+ 255,
+ 255,
+ 255
+ ],
+ "fog_far": 0.0,
+ "fog_near": 0.0,
+ "probe": {
+ "irradiance_map": "core/pbr/probe.hdr.irradiance",
+ "parallax": 0.0,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "radiance_map": "core/pbr/probe.hdr.radiance",
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "type": "sphere"
+ }
+ },
+ "key_values": null,
+ "nodes": [
+ {
+ "components": [
+ 0,
+ 4294967295,
+ 0,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 0,
+ "name": "block_highway_straight_col"
+ },
+ {
+ "components": [
+ 1,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 1,
+ "name": "Optimized_Optimized_Optimized_Shape001"
+ },
+ {
+ "components": [
+ 2,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 2,
+ "name": "Optimized_Optimized_Optimized_Shape002"
+ }
+ ],
+ "objects": [
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "col_0"
+ },
+ {
+ "name": "col_1"
+ },
+ {
+ "name": "col_3"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.15294118225574493,
+ 0.6823529601097107,
+ 0.0784313753247261,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.5137255191802979,
+ 0.8078432083129883,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.8823530077934265,
+ 0.4549019932746887,
+ 0.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ }
+ ],
+ "name": "road_blocks/block_highway_staight_col/block_highway_straight_col_40.geo"
+ }
+ ],
+ "scene_anims": [
+ {
+ "anim": 4294967295,
+ "frame_duration": 50000000,
+ "name": "block_highway_straight_col",
+ "node_anims": null,
+ "t_end": 60000000000,
+ "t_start": 0
+ }
+ ],
+ "transforms": [
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "rot": [
+ 90.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "rot": [
+ 90.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "rot": [
+ 90.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/app/resources/road_blocks/block_highway_staight_col/block_highway_straight_col_40.geo b/app/resources/road_blocks/block_highway_staight_col/block_highway_straight_col_40.geo
new file mode 100644
index 0000000..fa743a1
Binary files /dev/null and b/app/resources/road_blocks/block_highway_staight_col/block_highway_straight_col_40.geo differ
diff --git a/app/resources/road_blocks/block_highway_staight_col/fbx_importer_cfg.txt b/app/resources/road_blocks/block_highway_staight_col/fbx_importer_cfg.txt
new file mode 100644
index 0000000..2fd5d88
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_staight_col/fbx_importer_cfg.txt
@@ -0,0 +1,23 @@
+"anim_policy":"1"
+"anim_simplify_color_tolerance":"0.001000"
+"anim_simplify_rotation_tolerance":"0.100000"
+"anim_simplify_scale_tolerance":"0.001000"
+"anim_simplify_translation_tolerance":"0.001000"
+"detect_geometry_instances":"1"
+"fbx_file_path":"c:/Users/clem/Documents/GitHub/mycarsim/app/resources/road_blocks/block_highway_straight_col.fbx"
+"finalizer_script":""
+"fix_geometry_orientation":"0"
+"frames_per_second":"24"
+"geometry_policy":"1"
+"geometry_scale":"1.000000"
+"import_animations":"1"
+"material_policy":"1"
+"max_smoothing_angle":"45.000000"
+"output_folder":"road_blocks/block_highway_staight_col"
+"profile":"1"
+"recalculate_normals":"0"
+"recalculate_tangents":"0"
+"scale":"1.000000"
+"scene_policy":"1"
+"texture_policy":"1"
+"use_finalizer_script":"0"
diff --git a/app/resources/road_blocks/block_highway_straight/block_highway_straight.scn b/app/resources/road_blocks/block_highway_straight/block_highway_straight.scn
new file mode 100644
index 0000000..75f754e
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_straight/block_highway_straight.scn
@@ -0,0 +1,2890 @@
+{
+ "canvas": {
+ "clear_color": true,
+ "clear_z": true,
+ "color": [
+ 0,
+ 0,
+ 0,
+ 255
+ ]
+ },
+ "collisions": [
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ 0.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ 100.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ 200.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ 300.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ 400.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ 0.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ 0.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ 0.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ 100.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ 100.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ 100.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ 200.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ 200.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ 200.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ 300.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ 300.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ 300.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ 400.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ 400.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ 400.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ 500.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ 500.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ 500.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ 500.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ 600.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ 600.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ 600.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ 600.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ 700.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ 700.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ 700.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ 700.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ 800.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ 800.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ 800.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ 800.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ 900.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ 900.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ 900.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ 900.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ 1000.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ 1000.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ 1000.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ 1000.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ 1100.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ 1100.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ 1100.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ 1100.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ 1200.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ 1200.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ 1200.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ 1200.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ 1200.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ -100.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ -100.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ -100.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ -100.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ -200.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ -200.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ -200.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ -200.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ -300.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ -300.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ -300.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ -300.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ -400.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ -400.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ -400.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ -400.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ -500.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ -500.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ -500.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ -500.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ -600.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ -600.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ -600.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ -600.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ -700.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ -700.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ -700.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ -700.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ -800.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ -800.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ -800.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ -800.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ -900.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ -900.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ -900.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ -900.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ -1000.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ -1000.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ -1000.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ -1000.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ -1100.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ -1100.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ -1100.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ -1100.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ -24.05500030517578,
+ -1200.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 100.0,
+ 50.0,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 0.25,
+ 1.25,
+ -1200.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ 18.0,
+ 1.25,
+ -1200.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 0.0,
+ "path": "",
+ "pos": [
+ -17.299999237060547,
+ 1.25,
+ -1200.0
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 0.75,
+ 1.25,
+ 100.0
+ ],
+ "type": "cube"
+ }
+ ],
+ "environment": {
+ "ambient": [
+ 0,
+ 0,
+ 0,
+ 255
+ ],
+ "brdf_map": "core/pbr/brdf.dds",
+ "current_camera": null,
+ "fog_color": [
+ 255,
+ 255,
+ 255,
+ 255
+ ],
+ "fog_far": 0.0,
+ "fog_near": 0.0,
+ "probe": {
+ "irradiance_map": "core/pbr/probe.hdr.irradiance",
+ "parallax": 0.0,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "radiance_map": "core/pbr/probe.hdr.radiance",
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "type": "sphere"
+ }
+ },
+ "key_values": null,
+ "nodes": [
+ {
+ "collisions": [
+ {
+ "idx": 0
+ },
+ {
+ "idx": 1
+ },
+ {
+ "idx": 2
+ },
+ {
+ "idx": 3
+ },
+ {
+ "idx": 4
+ },
+ {
+ "idx": 5
+ },
+ {
+ "idx": 6
+ },
+ {
+ "idx": 7
+ },
+ {
+ "idx": 8
+ },
+ {
+ "idx": 9
+ },
+ {
+ "idx": 10
+ },
+ {
+ "idx": 11
+ },
+ {
+ "idx": 12
+ },
+ {
+ "idx": 13
+ },
+ {
+ "idx": 14
+ },
+ {
+ "idx": 15
+ },
+ {
+ "idx": 16
+ },
+ {
+ "idx": 17
+ },
+ {
+ "idx": 18
+ },
+ {
+ "idx": 19
+ },
+ {
+ "idx": 20
+ },
+ {
+ "idx": 21
+ },
+ {
+ "idx": 22
+ },
+ {
+ "idx": 23
+ },
+ {
+ "idx": 24
+ },
+ {
+ "idx": 25
+ },
+ {
+ "idx": 26
+ },
+ {
+ "idx": 27
+ },
+ {
+ "idx": 28
+ },
+ {
+ "idx": 29
+ },
+ {
+ "idx": 30
+ },
+ {
+ "idx": 31
+ },
+ {
+ "idx": 32
+ },
+ {
+ "idx": 33
+ },
+ {
+ "idx": 34
+ },
+ {
+ "idx": 35
+ },
+ {
+ "idx": 36
+ },
+ {
+ "idx": 37
+ },
+ {
+ "idx": 38
+ },
+ {
+ "idx": 39
+ },
+ {
+ "idx": 40
+ },
+ {
+ "idx": 41
+ },
+ {
+ "idx": 42
+ },
+ {
+ "idx": 43
+ },
+ {
+ "idx": 44
+ },
+ {
+ "idx": 45
+ },
+ {
+ "idx": 46
+ },
+ {
+ "idx": 47
+ },
+ {
+ "idx": 48
+ },
+ {
+ "idx": 49
+ },
+ {
+ "idx": 50
+ },
+ {
+ "idx": 51
+ },
+ {
+ "idx": 52
+ },
+ {
+ "idx": 53
+ },
+ {
+ "idx": 54
+ },
+ {
+ "idx": 55
+ },
+ {
+ "idx": 56
+ },
+ {
+ "idx": 57
+ },
+ {
+ "idx": 58
+ },
+ {
+ "idx": 59
+ },
+ {
+ "idx": 60
+ },
+ {
+ "idx": 61
+ },
+ {
+ "idx": 62
+ },
+ {
+ "idx": 63
+ },
+ {
+ "idx": 64
+ },
+ {
+ "idx": 65
+ },
+ {
+ "idx": 66
+ },
+ {
+ "idx": 67
+ },
+ {
+ "idx": 68
+ },
+ {
+ "idx": 69
+ },
+ {
+ "idx": 70
+ },
+ {
+ "idx": 71
+ },
+ {
+ "idx": 72
+ },
+ {
+ "idx": 73
+ },
+ {
+ "idx": 74
+ },
+ {
+ "idx": 75
+ },
+ {
+ "idx": 76
+ },
+ {
+ "idx": 77
+ },
+ {
+ "idx": 78
+ },
+ {
+ "idx": 79
+ },
+ {
+ "idx": 80
+ },
+ {
+ "idx": 81
+ },
+ {
+ "idx": 82
+ },
+ {
+ "idx": 83
+ },
+ {
+ "idx": 84
+ },
+ {
+ "idx": 85
+ },
+ {
+ "idx": 86
+ },
+ {
+ "idx": 87
+ },
+ {
+ "idx": 88
+ },
+ {
+ "idx": 89
+ },
+ {
+ "idx": 90
+ },
+ {
+ "idx": 91
+ },
+ {
+ "idx": 92
+ },
+ {
+ "idx": 93
+ },
+ {
+ "idx": 94
+ },
+ {
+ "idx": 95
+ },
+ {
+ "idx": 96
+ },
+ {
+ "idx": 97
+ },
+ {
+ "idx": 98
+ },
+ {
+ "idx": 99
+ },
+ {
+ "idx": 100
+ }
+ ],
+ "components": [
+ 0,
+ 4294967295,
+ 0,
+ 4294967295,
+ 0
+ ],
+ "disabled": false,
+ "idx": 0,
+ "name": "block_highway_straight"
+ }
+ ],
+ "objects": [
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "generic_concrete"
+ },
+ {
+ "name": "ground_field"
+ },
+ {
+ "name": "rambardes"
+ },
+ {
+ "name": "cement_dirt"
+ },
+ {
+ "name": "bit40m3v"
+ },
+ {
+ "name": "bit15m3v"
+ },
+ {
+ "name": "center_wall"
+ },
+ {
+ "name": "road_sides"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "common_maps/concrete_generic_albedo.png",
+ "stage": 0
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.5879999995231628,
+ 0.5879999995231628,
+ 0.5879999995231628,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "common_maps/block_highway_straight_ground_ao.png",
+ "stage": 0
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.5879999995231628,
+ 0.5879999995231628,
+ 0.5879999995231628,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "common_maps/diffuse_tille_rambardes_02.tga",
+ "stage": 0
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "common_maps/diffuse_cement_dirty_03.png",
+ "stage": 0
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "common_maps/spec_cement_dirty_03.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "common_maps/bit40m3v_02.dds",
+ "stage": 0
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "common_maps/spec_3ways_01.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "common_maps/bit15m3v_02.dds",
+ "stage": 0
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "common_maps/spec_3ways_01.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "common_maps/diffuse_middle_wall.png",
+ "stage": 0
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "common_maps/spec_metal_red.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "common_maps/diffuse_road_sides.png",
+ "stage": 0
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "common_maps/spec_road_sides.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ }
+ ],
+ "name": "road_blocks/block_highway_straight/block_highway_straight_43.geo"
+ }
+ ],
+ "rigid_bodies": [
+ {
+ "angular_damping": 0.0,
+ "friction": 0.49803924560546875,
+ "linear_damping": 0.0,
+ "restitution": 0.0,
+ "rolling_friction": 0.0,
+ "type": "dynamic"
+ }
+ ],
+ "transforms": [
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "rot": [
+ -7.0167078561561656e-15,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/app/resources/road_blocks/block_highway_straight/block_highway_straight.scn.aaa b/app/resources/road_blocks/block_highway_straight/block_highway_straight.scn.aaa
new file mode 100644
index 0000000..03b674f
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_straight/block_highway_straight.scn.aaa
@@ -0,0 +1,12 @@
+{
+ "bloom_bias": 0.5,
+ "bloom_intensity": 0.10000000149011612,
+ "bloom_threshold": 5.0,
+ "exposure": 1.0,
+ "gamma": 2.200000047683716,
+ "max_distance": 100.0,
+ "motion_blur": 1.0,
+ "sample_count": 2,
+ "taa_weight": 0.10000000149011612,
+ "z_thickness": 0.10000000149011612
+}
\ No newline at end of file
diff --git a/app/resources/road_blocks/block_highway_straight/block_highway_straight.scn.editor b/app/resources/road_blocks/block_highway_straight/block_highway_straight.scn.editor
new file mode 100644
index 0000000..4034500
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_straight/block_highway_straight.scn.editor
@@ -0,0 +1,177 @@
+{
+ "editor": {
+ "animeditor_plugin": {
+ "quantize_time": true,
+ "show_trajectories": null,
+ "trajectories_tick_seconds": 1.0,
+ "trajectories_tick_size": 0.10000000149011612
+ },
+ "explorer": {
+ "node_custom_order": {
+ "refs": null,
+ "roots": [
+ 0
+ ]
+ },
+ "node_sort_method": "custom",
+ "show_node_uid": false
+ },
+ "grid_plugin": {
+ "enabled": true,
+ "grid_color_b": 1.0,
+ "grid_color_g": 1.0,
+ "grid_color_r": 1.0,
+ "n_subdivs": 10,
+ "offset": 0.0,
+ "opacity": 0.5,
+ "subdiv_size": 1.0
+ },
+ "navigation_plugin": {
+ "orbit_distance": 785.8326416015625,
+ "speed": 0.10000000149011612,
+ "turbo": 1.0
+ },
+ "transform_gizmo_plugin": {
+ "mode": "local",
+ "snap": "none",
+ "snap_rotation": 5.0,
+ "snap_rotation_fine": 1.0,
+ "snap_scale": 10.0,
+ "snap_scale_fine": 1.0,
+ "snap_translation": 1.0,
+ "snap_translation_fine": 0.10000000149011612,
+ "tool": "move"
+ },
+ "view_plugin": {
+ "show_cameras": true,
+ "show_collisions": true,
+ "show_lights": true,
+ "show_nodes": true,
+ "show_probe": true
+ },
+ "views": {
+ "back": [
+ -0.9999999403953552,
+ 0.0,
+ -8.742277657347586e-08,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 8.742277657347586e-08,
+ -0.0,
+ -0.9999999403953552,
+ 0.0
+ ],
+ "bottom": [
+ 1.0,
+ -0.0,
+ -0.0,
+ 0.0,
+ -0.0,
+ -8.742277657347586e-08,
+ 0.9999999403953552,
+ 0.0,
+ -0.0,
+ -0.9999999403953552,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "bottom_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "current_camera": 0,
+ "front": [
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0
+ ],
+ "left": [
+ -8.742277657347586e-08,
+ 0.0,
+ 0.9999999403953552,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ -0.9999999403953552,
+ 0.0,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "left_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "orthographic_size": 1.0,
+ "perspective": [
+ -0.352803111076355,
+ 0.37014487385749817,
+ 0.8594328165054321,
+ -189.03387451171875,
+ 0.0,
+ 0.9184803366661072,
+ -0.3955743908882141,
+ 105.64411163330078,
+ -0.9357239603996277,
+ -0.13955280184745789,
+ -0.324028879404068,
+ -1113.5811767578125
+ ],
+ "perspective_fov": 0.7853981852531433,
+ "perspective_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "right": [
+ -8.742277657347586e-08,
+ 0.0,
+ -0.9999999403953552,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 0.9999999403953552,
+ -0.0,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "right_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "scale": 0.05000000074505806,
+ "top": [
+ 1.0,
+ 0.0,
+ -0.0,
+ 0.0,
+ -0.0,
+ -8.742277657347586e-08,
+ -0.9999999403953552,
+ 0.0,
+ 0.0,
+ 0.9999999403953552,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "top_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/resources/road_blocks/block_highway_straight/block_highway_straight_43.geo b/app/resources/road_blocks/block_highway_straight/block_highway_straight_43.geo
new file mode 100644
index 0000000..f557433
Binary files /dev/null and b/app/resources/road_blocks/block_highway_straight/block_highway_straight_43.geo differ
diff --git a/app/resources/road_blocks/block_highway_straight/block_highway_straight_ground_ao.png b/app/resources/road_blocks/block_highway_straight/block_highway_straight_ground_ao.png
new file mode 100644
index 0000000..e28f877
Binary files /dev/null and b/app/resources/road_blocks/block_highway_straight/block_highway_straight_ground_ao.png differ
diff --git a/app/resources/road_blocks/block_highway_straight/fbx_importer_cfg.txt b/app/resources/road_blocks/block_highway_straight/fbx_importer_cfg.txt
new file mode 100644
index 0000000..dd87702
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_straight/fbx_importer_cfg.txt
@@ -0,0 +1,23 @@
+"anim_policy":"1"
+"anim_simplify_color_tolerance":"0.001000"
+"anim_simplify_rotation_tolerance":"0.100000"
+"anim_simplify_scale_tolerance":"0.001000"
+"anim_simplify_translation_tolerance":"0.001000"
+"detect_geometry_instances":"1"
+"fbx_file_path":"d:/projects/carsim/work/model/roads_buildings/block_highway_straight.fbx"
+"finalizer_script":""
+"fix_geometry_orientation":"1"
+"frames_per_second":"24"
+"geometry_policy":"1"
+"geometry_scale":"1.000000"
+"import_animations":"1"
+"material_policy":"1"
+"max_smoothing_angle":"45.000000"
+"output_folder":"road_blocks/block_highway_straight"
+"profile":"1"
+"recalculate_normals":"0"
+"recalculate_tangents":"0"
+"scale":"1.000000"
+"scene_policy":"1"
+"texture_policy":"1"
+"use_finalizer_script":"0"
diff --git a/app/resources/road_blocks/block_highway_straight_col.fbx b/app/resources/road_blocks/block_highway_straight_col.fbx
new file mode 100644
index 0000000..6170897
Binary files /dev/null and b/app/resources/road_blocks/block_highway_straight_col.fbx differ
diff --git a/app/resources/road_blocks/block_highway_turn_in.fbx b/app/resources/road_blocks/block_highway_turn_in.fbx
new file mode 100644
index 0000000..708cf01
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_in.fbx differ
diff --git a/app/resources/road_blocks/block_highway_turn_in/bit15m3v_02.dds b/app/resources/road_blocks/block_highway_turn_in/bit15m3v_02.dds
new file mode 100644
index 0000000..fdccf96
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_in/bit15m3v_02.dds differ
diff --git a/app/resources/road_blocks/block_highway_turn_in/bit40m3v_02.dds b/app/resources/road_blocks/block_highway_turn_in/bit40m3v_02.dds
new file mode 100644
index 0000000..f965e92
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_in/bit40m3v_02.dds differ
diff --git a/app/resources/road_blocks/block_highway_turn_in/block_highway_turn_in.scn b/app/resources/road_blocks/block_highway_turn_in/block_highway_turn_in.scn
new file mode 100644
index 0000000..a35bf09
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_turn_in/block_highway_turn_in.scn
@@ -0,0 +1,514 @@
+{
+ "canvas": {
+ "clear_color": true,
+ "clear_z": true,
+ "color": [
+ 0,
+ 0,
+ 0,
+ 255
+ ]
+ },
+ "environment": {
+ "ambient": [
+ 75,
+ 75,
+ 75,
+ 255
+ ],
+ "brdf_map": "core/pbr/brdf.dds",
+ "current_camera": null,
+ "fog_color": [
+ 255,
+ 255,
+ 255,
+ 255
+ ],
+ "fog_far": 0.0,
+ "fog_near": 0.0,
+ "probe": {
+ "irradiance_map": "core/pbr/probe.hdr.irradiance",
+ "parallax": 0.0,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "radiance_map": "core/pbr/probe.hdr.radiance",
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "type": "sphere"
+ }
+ },
+ "key_values": null,
+ "nodes": [
+ {
+ "components": [
+ 0,
+ 4294967295,
+ 0,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 0,
+ "name": "block_highway_turn_in"
+ }
+ ],
+ "objects": [
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "rambardes"
+ },
+ {
+ "name": "cement_dirt"
+ },
+ {
+ "name": "bit40m3v"
+ },
+ {
+ "name": "bit15m3v"
+ },
+ {
+ "name": "center_wall"
+ },
+ {
+ "name": "road_sides"
+ },
+ {
+ "name": "Block_Grass_VertexColor"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "road_blocks/block_highway_turn_in/diffuse_tille_rambardes_02.tga",
+ "stage": 0
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "road_blocks/block_highway_turn_in/diffuse_cement_dirty_03.png",
+ "stage": 0
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "road_blocks/block_highway_turn_in/spec_cement_dirty_03.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "road_blocks/block_highway_turn_in/bit40m3v_02.dds",
+ "stage": 0
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "road_blocks/block_highway_turn_in/spec_3ways_01.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "road_blocks/block_highway_turn_in/bit15m3v_02.dds",
+ "stage": 0
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "road_blocks/block_highway_turn_in/spec_3ways_01.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "road_blocks/block_highway_turn_in/diffuse_middle_wall.png",
+ "stage": 0
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "road_blocks/block_highway_turn_in/spec_metal_red.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "road_blocks/block_highway_turn_in/diffuse_road_sides.png",
+ "stage": 0
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "road_blocks/block_highway_turn_in/spec_road_sides.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "road_blocks/block_highway_turn_in/diffuse_blank_field_tile.png",
+ "stage": 0
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "road_blocks/block_highway_turn_in/spec_grass.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ }
+ ],
+ "name": "road_blocks/block_highway_turn_in/block_highway_turn_in_42.geo"
+ }
+ ],
+ "scene_anims": [
+ {
+ "anim": 4294967295,
+ "frame_duration": 50000000,
+ "name": "block_highway_turn_in",
+ "node_anims": null,
+ "t_end": 60000000000,
+ "t_start": 0
+ }
+ ],
+ "transforms": [
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "rot": [
+ -2.504477834008867e-06,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/app/resources/road_blocks/block_highway_turn_in/block_highway_turn_in.scn.aaa b/app/resources/road_blocks/block_highway_turn_in/block_highway_turn_in.scn.aaa
new file mode 100644
index 0000000..03b674f
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_turn_in/block_highway_turn_in.scn.aaa
@@ -0,0 +1,12 @@
+{
+ "bloom_bias": 0.5,
+ "bloom_intensity": 0.10000000149011612,
+ "bloom_threshold": 5.0,
+ "exposure": 1.0,
+ "gamma": 2.200000047683716,
+ "max_distance": 100.0,
+ "motion_blur": 1.0,
+ "sample_count": 2,
+ "taa_weight": 0.10000000149011612,
+ "z_thickness": 0.10000000149011612
+}
\ No newline at end of file
diff --git a/app/resources/road_blocks/block_highway_turn_in/block_highway_turn_in.scn.editor b/app/resources/road_blocks/block_highway_turn_in/block_highway_turn_in.scn.editor
new file mode 100644
index 0000000..44f46ba
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_turn_in/block_highway_turn_in.scn.editor
@@ -0,0 +1,177 @@
+{
+ "editor": {
+ "animeditor_plugin": {
+ "quantize_time": true,
+ "show_trajectories": null,
+ "trajectories_tick_seconds": 1.0,
+ "trajectories_tick_size": 0.10000000149011612
+ },
+ "explorer": {
+ "node_custom_order": {
+ "refs": null,
+ "roots": [
+ 0
+ ]
+ },
+ "node_sort_method": "custom",
+ "show_node_uid": false
+ },
+ "grid_plugin": {
+ "enabled": true,
+ "grid_color_b": 1.0,
+ "grid_color_g": 1.0,
+ "grid_color_r": 1.0,
+ "n_subdivs": 10,
+ "offset": 0.0,
+ "opacity": 0.5,
+ "subdiv_size": 1.0
+ },
+ "navigation_plugin": {
+ "orbit_distance": 10.0,
+ "speed": 0.10000000149011612,
+ "turbo": 1.0
+ },
+ "transform_gizmo_plugin": {
+ "mode": "local",
+ "snap": "none",
+ "snap_rotation": 5.0,
+ "snap_rotation_fine": 1.0,
+ "snap_scale": 10.0,
+ "snap_scale_fine": 1.0,
+ "snap_translation": 1.0,
+ "snap_translation_fine": 0.10000000149011612,
+ "tool": "move"
+ },
+ "view_plugin": {
+ "show_cameras": true,
+ "show_collisions": false,
+ "show_lights": true,
+ "show_nodes": true,
+ "show_probe": true
+ },
+ "views": {
+ "back": [
+ -0.9999999403953552,
+ 0.0,
+ -8.742277657347586e-08,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 8.742277657347586e-08,
+ -0.0,
+ -0.9999999403953552,
+ 0.0
+ ],
+ "bottom": [
+ 1.0,
+ -0.0,
+ -0.0,
+ 0.0,
+ -0.0,
+ -8.742277657347586e-08,
+ 0.9999999403953552,
+ 0.0,
+ -0.0,
+ -0.9999999403953552,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "bottom_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "current_camera": 0,
+ "front": [
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0
+ ],
+ "left": [
+ -8.742277657347586e-08,
+ 0.0,
+ 0.9999999403953552,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ -0.9999999403953552,
+ 0.0,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "left_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "orthographic_size": 1.0,
+ "perspective": [
+ -0.48231270909309387,
+ -0.45354053378105164,
+ -0.7494532465934753,
+ 405.5787353515625,
+ 0.0,
+ 0.8555404543876648,
+ -0.51774001121521,
+ 127.10601806640625,
+ 0.8760018944740295,
+ -0.24971231818199158,
+ -0.41263824701309204,
+ -996.0026245117188
+ ],
+ "perspective_fov": 0.7853981852531433,
+ "perspective_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "right": [
+ -8.742277657347586e-08,
+ 0.0,
+ -0.9999999403953552,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 0.9999999403953552,
+ -0.0,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "right_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "scale": 0.05000000074505806,
+ "top": [
+ 1.0,
+ 0.0,
+ -0.0,
+ 0.0,
+ -0.0,
+ -8.742277657347586e-08,
+ -0.9999999403953552,
+ 0.0,
+ 0.0,
+ 0.9999999403953552,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "top_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/resources/road_blocks/block_highway_turn_in/block_highway_turn_in_42.geo b/app/resources/road_blocks/block_highway_turn_in/block_highway_turn_in_42.geo
new file mode 100644
index 0000000..c041fea
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_in/block_highway_turn_in_42.geo differ
diff --git a/app/resources/road_blocks/block_highway_turn_in/block_highway_turn_in_42.physics b/app/resources/road_blocks/block_highway_turn_in/block_highway_turn_in_42.physics
new file mode 100644
index 0000000..32d1f6d
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_turn_in/block_highway_turn_in_42.physics
@@ -0,0 +1,10 @@
+{
+ "collision": {
+ "input": [{
+ "geometry": "road_blocks/block_highway_turn_in_col/block_highway_turn_in_col_40.geo",
+ "matrix": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
+ "type": "triangle"
+ }],
+ "type": "tree"
+ }
+}
\ No newline at end of file
diff --git a/app/resources/road_blocks/block_highway_turn_in/diffuse_blank_field_tile.png b/app/resources/road_blocks/block_highway_turn_in/diffuse_blank_field_tile.png
new file mode 100644
index 0000000..2127fb1
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_in/diffuse_blank_field_tile.png differ
diff --git a/app/resources/road_blocks/block_highway_turn_in/diffuse_cement_dirty_03.png b/app/resources/road_blocks/block_highway_turn_in/diffuse_cement_dirty_03.png
new file mode 100644
index 0000000..f41b1ec
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_in/diffuse_cement_dirty_03.png differ
diff --git a/app/resources/road_blocks/block_highway_turn_in/diffuse_middle_wall.png b/app/resources/road_blocks/block_highway_turn_in/diffuse_middle_wall.png
new file mode 100644
index 0000000..df1205f
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_in/diffuse_middle_wall.png differ
diff --git a/app/resources/road_blocks/block_highway_turn_in/diffuse_road_sides.png b/app/resources/road_blocks/block_highway_turn_in/diffuse_road_sides.png
new file mode 100644
index 0000000..79477c2
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_in/diffuse_road_sides.png differ
diff --git a/app/resources/road_blocks/block_highway_turn_in/diffuse_tille_rambardes_02.tga b/app/resources/road_blocks/block_highway_turn_in/diffuse_tille_rambardes_02.tga
new file mode 100644
index 0000000..ccea15e
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_in/diffuse_tille_rambardes_02.tga differ
diff --git a/app/resources/road_blocks/block_highway_turn_in/fbx_importer_cfg.txt b/app/resources/road_blocks/block_highway_turn_in/fbx_importer_cfg.txt
new file mode 100644
index 0000000..64ff9bb
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_turn_in/fbx_importer_cfg.txt
@@ -0,0 +1,23 @@
+"anim_policy":"1"
+"anim_simplify_color_tolerance":"0.001000"
+"anim_simplify_rotation_tolerance":"0.100000"
+"anim_simplify_scale_tolerance":"0.001000"
+"anim_simplify_translation_tolerance":"0.001000"
+"detect_geometry_instances":"1"
+"fbx_file_path":"c:/Users/clem/Documents/GitHub/mycarsim/app/resources/road_blocks/block_highway_turn_in.fbx"
+"finalizer_script":""
+"fix_geometry_orientation":"0"
+"frames_per_second":"24"
+"geometry_policy":"1"
+"geometry_scale":"1.000000"
+"import_animations":"1"
+"material_policy":"1"
+"max_smoothing_angle":"45.000000"
+"output_folder":"road_blocks/block_highway_turn_in"
+"profile":"1"
+"recalculate_normals":"0"
+"recalculate_tangents":"0"
+"scale":"1.000000"
+"scene_policy":"1"
+"texture_policy":"1"
+"use_finalizer_script":"0"
diff --git a/app/resources/road_blocks/block_highway_turn_in/spec_3ways_01.png b/app/resources/road_blocks/block_highway_turn_in/spec_3ways_01.png
new file mode 100644
index 0000000..383f6e8
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_in/spec_3ways_01.png differ
diff --git a/app/resources/road_blocks/block_highway_turn_in/spec_cement_dirty_03.png b/app/resources/road_blocks/block_highway_turn_in/spec_cement_dirty_03.png
new file mode 100644
index 0000000..a51233b
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_in/spec_cement_dirty_03.png differ
diff --git a/app/resources/road_blocks/block_highway_turn_in/spec_grass.png b/app/resources/road_blocks/block_highway_turn_in/spec_grass.png
new file mode 100644
index 0000000..32523d5
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_in/spec_grass.png differ
diff --git a/app/resources/road_blocks/block_highway_turn_in/spec_metal_red.png b/app/resources/road_blocks/block_highway_turn_in/spec_metal_red.png
new file mode 100644
index 0000000..25b7f71
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_in/spec_metal_red.png differ
diff --git a/app/resources/road_blocks/block_highway_turn_in/spec_road_sides.png b/app/resources/road_blocks/block_highway_turn_in/spec_road_sides.png
new file mode 100644
index 0000000..c535a83
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_in/spec_road_sides.png differ
diff --git a/app/resources/road_blocks/block_highway_turn_in_col.fbx b/app/resources/road_blocks/block_highway_turn_in_col.fbx
new file mode 100644
index 0000000..bdfad34
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_in_col.fbx differ
diff --git a/app/resources/road_blocks/block_highway_turn_in_col/block_highway_turn_in_col.scn b/app/resources/road_blocks/block_highway_turn_in_col/block_highway_turn_in_col.scn
new file mode 100644
index 0000000..7a476ef
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_turn_in_col/block_highway_turn_in_col.scn
@@ -0,0 +1,307 @@
+{
+ "canvas": {
+ "clear_color": true,
+ "clear_z": true,
+ "color": [
+ 0,
+ 0,
+ 0,
+ 255
+ ]
+ },
+ "environment": {
+ "ambient": [
+ 75,
+ 75,
+ 75,
+ 255
+ ],
+ "brdf_map": "core/pbr/brdf.dds",
+ "current_camera": null,
+ "fog_color": [
+ 255,
+ 255,
+ 255,
+ 255
+ ],
+ "fog_far": 0.0,
+ "fog_near": 0.0,
+ "probe": {
+ "irradiance_map": "core/pbr/probe.hdr.irradiance",
+ "parallax": 0.0,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "radiance_map": "core/pbr/probe.hdr.radiance",
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "type": "sphere"
+ }
+ },
+ "key_values": null,
+ "nodes": [
+ {
+ "components": [
+ 0,
+ 4294967295,
+ 0,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 0,
+ "name": "block_highway_turn_in_col"
+ },
+ {
+ "components": [
+ 1,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 1,
+ "name": "Optimized_Shape001"
+ },
+ {
+ "components": [
+ 2,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 2,
+ "name": "Optimized_Shape002"
+ }
+ ],
+ "objects": [
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "col_0"
+ },
+ {
+ "name": "col_1"
+ },
+ {
+ "name": "col_3"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.15294118225574493,
+ 0.6823529601097107,
+ 0.0784313753247261,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.5137255191802979,
+ 0.8078432083129883,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.8823530077934265,
+ 0.4549019932746887,
+ 0.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ }
+ ],
+ "name": "road_blocks/block_highway_turn_in_col/block_highway_turn_in_col_40.geo"
+ }
+ ],
+ "scene_anims": [
+ {
+ "anim": 4294967295,
+ "frame_duration": 50000000,
+ "name": "block_highway_turn_in_collision",
+ "node_anims": null,
+ "t_end": 60000000000,
+ "t_start": 0
+ }
+ ],
+ "transforms": [
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "rot": [
+ -2.504477834008867e-06,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "rot": [
+ 90.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "rot": [
+ 90.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/app/resources/road_blocks/block_highway_turn_in_col/block_highway_turn_in_col.scn.aaa b/app/resources/road_blocks/block_highway_turn_in_col/block_highway_turn_in_col.scn.aaa
new file mode 100644
index 0000000..03b674f
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_turn_in_col/block_highway_turn_in_col.scn.aaa
@@ -0,0 +1,12 @@
+{
+ "bloom_bias": 0.5,
+ "bloom_intensity": 0.10000000149011612,
+ "bloom_threshold": 5.0,
+ "exposure": 1.0,
+ "gamma": 2.200000047683716,
+ "max_distance": 100.0,
+ "motion_blur": 1.0,
+ "sample_count": 2,
+ "taa_weight": 0.10000000149011612,
+ "z_thickness": 0.10000000149011612
+}
\ No newline at end of file
diff --git a/app/resources/road_blocks/block_highway_turn_in_col/block_highway_turn_in_col.scn.editor b/app/resources/road_blocks/block_highway_turn_in_col/block_highway_turn_in_col.scn.editor
new file mode 100644
index 0000000..424252c
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_turn_in_col/block_highway_turn_in_col.scn.editor
@@ -0,0 +1,179 @@
+{
+ "editor": {
+ "animeditor_plugin": {
+ "quantize_time": true,
+ "show_trajectories": null,
+ "trajectories_tick_seconds": 1.0,
+ "trajectories_tick_size": 0.10000000149011612
+ },
+ "explorer": {
+ "node_custom_order": {
+ "refs": null,
+ "roots": [
+ 0,
+ 1,
+ 2
+ ]
+ },
+ "node_sort_method": "custom",
+ "show_node_uid": false
+ },
+ "grid_plugin": {
+ "enabled": true,
+ "grid_color_b": 1.0,
+ "grid_color_g": 1.0,
+ "grid_color_r": 1.0,
+ "n_subdivs": 10,
+ "offset": 0.0,
+ "opacity": 0.5,
+ "subdiv_size": 1.0
+ },
+ "navigation_plugin": {
+ "orbit_distance": 10.0,
+ "speed": 0.10000000149011612,
+ "turbo": 1.0
+ },
+ "transform_gizmo_plugin": {
+ "mode": "local",
+ "snap": "snap",
+ "snap_rotation": 5.0,
+ "snap_rotation_fine": 1.0,
+ "snap_scale": 10.0,
+ "snap_scale_fine": 1.0,
+ "snap_translation": 1.0,
+ "snap_translation_fine": 0.10000000149011612,
+ "tool": "move"
+ },
+ "view_plugin": {
+ "show_cameras": true,
+ "show_collisions": false,
+ "show_lights": true,
+ "show_nodes": true,
+ "show_probe": true
+ },
+ "views": {
+ "back": [
+ -0.9999999403953552,
+ 0.0,
+ -8.742277657347586e-08,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 8.742277657347586e-08,
+ -0.0,
+ -0.9999999403953552,
+ 0.0
+ ],
+ "bottom": [
+ 1.0,
+ -0.0,
+ -0.0,
+ 0.0,
+ -0.0,
+ -8.742277657347586e-08,
+ 0.9999999403953552,
+ 0.0,
+ -0.0,
+ -0.9999999403953552,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "bottom_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "current_camera": 0,
+ "front": [
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0
+ ],
+ "left": [
+ -8.742277657347586e-08,
+ 0.0,
+ 0.9999999403953552,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ -0.9999999403953552,
+ 0.0,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "left_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "orthographic_size": 1.0,
+ "perspective": [
+ 0.1461838036775589,
+ 0.01809782348573208,
+ -0.9890967607498169,
+ -490.35260009765625,
+ 0.0,
+ 0.9998367428779602,
+ 0.018293416127562523,
+ 50.78435516357422,
+ 0.9892602562904358,
+ -0.00267412350513041,
+ 0.1461590975522995,
+ 265.1768798828125
+ ],
+ "perspective_fov": 0.7853981852531433,
+ "perspective_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "right": [
+ -8.742277657347586e-08,
+ 0.0,
+ -0.9999999403953552,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 0.9999999403953552,
+ -0.0,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "right_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "scale": 0.05000000074505806,
+ "top": [
+ 1.0,
+ 0.0,
+ -0.0,
+ 0.0,
+ -0.0,
+ -8.742277657347586e-08,
+ -0.9999999403953552,
+ 0.0,
+ 0.0,
+ 0.9999999403953552,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "top_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/resources/road_blocks/block_highway_turn_in_col/block_highway_turn_in_col_40.geo b/app/resources/road_blocks/block_highway_turn_in_col/block_highway_turn_in_col_40.geo
new file mode 100644
index 0000000..06082a4
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_in_col/block_highway_turn_in_col_40.geo differ
diff --git a/app/resources/road_blocks/block_highway_turn_in_col/fbx_importer_cfg.txt b/app/resources/road_blocks/block_highway_turn_in_col/fbx_importer_cfg.txt
new file mode 100644
index 0000000..ee26419
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_turn_in_col/fbx_importer_cfg.txt
@@ -0,0 +1,23 @@
+"anim_policy":"1"
+"anim_simplify_color_tolerance":"0.001000"
+"anim_simplify_rotation_tolerance":"0.100000"
+"anim_simplify_scale_tolerance":"0.001000"
+"anim_simplify_translation_tolerance":"0.001000"
+"detect_geometry_instances":"1"
+"fbx_file_path":"c:/Users/clem/Documents/GitHub/mycarsim/app/resources/road_blocks/block_highway_turn_in_col.fbx"
+"finalizer_script":""
+"fix_geometry_orientation":"0"
+"frames_per_second":"24"
+"geometry_policy":"1"
+"geometry_scale":"1.000000"
+"import_animations":"1"
+"material_policy":"1"
+"max_smoothing_angle":"45.000000"
+"output_folder":"road_blocks/block_highway_turn_in_col"
+"profile":"1"
+"recalculate_normals":"0"
+"recalculate_tangents":"0"
+"scale":"1.000000"
+"scene_policy":"1"
+"texture_policy":"1"
+"use_finalizer_script":"0"
diff --git a/app/resources/road_blocks/block_highway_turn_out.fbx b/app/resources/road_blocks/block_highway_turn_out.fbx
new file mode 100644
index 0000000..b783020
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_out.fbx differ
diff --git a/app/resources/road_blocks/block_highway_turn_out/bit15m3v_02.dds b/app/resources/road_blocks/block_highway_turn_out/bit15m3v_02.dds
new file mode 100644
index 0000000..fdccf96
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_out/bit15m3v_02.dds differ
diff --git a/app/resources/road_blocks/block_highway_turn_out/bit40m3v_02.dds b/app/resources/road_blocks/block_highway_turn_out/bit40m3v_02.dds
new file mode 100644
index 0000000..f965e92
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_out/bit40m3v_02.dds differ
diff --git a/app/resources/road_blocks/block_highway_turn_out/block_highway_turn_out.scn b/app/resources/road_blocks/block_highway_turn_out/block_highway_turn_out.scn
new file mode 100644
index 0000000..12d21f1
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_turn_out/block_highway_turn_out.scn
@@ -0,0 +1,514 @@
+{
+ "canvas": {
+ "clear_color": true,
+ "clear_z": true,
+ "color": [
+ 0,
+ 0,
+ 0,
+ 255
+ ]
+ },
+ "environment": {
+ "ambient": [
+ 75,
+ 75,
+ 75,
+ 255
+ ],
+ "brdf_map": "core/pbr/brdf.dds",
+ "current_camera": null,
+ "fog_color": [
+ 255,
+ 255,
+ 255,
+ 255
+ ],
+ "fog_far": 0.0,
+ "fog_near": 0.0,
+ "probe": {
+ "irradiance_map": "core/pbr/probe.hdr.irradiance",
+ "parallax": 0.0,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "radiance_map": "core/pbr/probe.hdr.radiance",
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "type": "sphere"
+ }
+ },
+ "key_values": null,
+ "nodes": [
+ {
+ "components": [
+ 0,
+ 4294967295,
+ 0,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 0,
+ "name": "block_highway_turn_out"
+ }
+ ],
+ "objects": [
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "rambardes"
+ },
+ {
+ "name": "cement_dirt"
+ },
+ {
+ "name": "bit40m3v"
+ },
+ {
+ "name": "bit15m3v"
+ },
+ {
+ "name": "center_wall"
+ },
+ {
+ "name": "road_sides"
+ },
+ {
+ "name": "Block_Grass_VertexColor"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "road_blocks/block_highway_turn_out/diffuse_tille_rambardes_02.tga",
+ "stage": 0
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "road_blocks/block_highway_turn_out/diffuse_cement_dirty_03.png",
+ "stage": 0
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "road_blocks/block_highway_turn_out/spec_cement_dirty_03.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "road_blocks/block_highway_turn_out/bit40m3v_02.dds",
+ "stage": 0
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "road_blocks/block_highway_turn_out/spec_3ways_01.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "road_blocks/block_highway_turn_out/bit15m3v_02.dds",
+ "stage": 0
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "road_blocks/block_highway_turn_out/spec_3ways_01.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "road_blocks/block_highway_turn_out/diffuse_middle_wall.png",
+ "stage": 0
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "road_blocks/block_highway_turn_out/spec_metal_red.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "road_blocks/block_highway_turn_out/diffuse_road_sides.png",
+ "stage": 0
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "road_blocks/block_highway_turn_out/spec_road_sides.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "road_blocks/block_highway_turn_out/diffuse_blank_field_tile.png",
+ "stage": 0
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "road_blocks/block_highway_turn_out/spec_grass.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ }
+ ],
+ "name": "road_blocks/block_highway_turn_out/block_highway_turn_out_42.geo"
+ }
+ ],
+ "scene_anims": [
+ {
+ "anim": 4294967295,
+ "frame_duration": 50000000,
+ "name": "block_highway_turn_out",
+ "node_anims": null,
+ "t_end": 60000000000,
+ "t_start": 0
+ }
+ ],
+ "transforms": [
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "rot": [
+ -2.504477834008867e-06,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/app/resources/road_blocks/block_highway_turn_out/block_highway_turn_out_42.geo b/app/resources/road_blocks/block_highway_turn_out/block_highway_turn_out_42.geo
new file mode 100644
index 0000000..c5e565f
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_out/block_highway_turn_out_42.geo differ
diff --git a/app/resources/road_blocks/block_highway_turn_out/diffuse_blank_field_tile.png b/app/resources/road_blocks/block_highway_turn_out/diffuse_blank_field_tile.png
new file mode 100644
index 0000000..2127fb1
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_out/diffuse_blank_field_tile.png differ
diff --git a/app/resources/road_blocks/block_highway_turn_out/diffuse_cement_dirty_03.png b/app/resources/road_blocks/block_highway_turn_out/diffuse_cement_dirty_03.png
new file mode 100644
index 0000000..f41b1ec
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_out/diffuse_cement_dirty_03.png differ
diff --git a/app/resources/road_blocks/block_highway_turn_out/diffuse_middle_wall.png b/app/resources/road_blocks/block_highway_turn_out/diffuse_middle_wall.png
new file mode 100644
index 0000000..df1205f
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_out/diffuse_middle_wall.png differ
diff --git a/app/resources/road_blocks/block_highway_turn_out/diffuse_road_sides.png b/app/resources/road_blocks/block_highway_turn_out/diffuse_road_sides.png
new file mode 100644
index 0000000..79477c2
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_out/diffuse_road_sides.png differ
diff --git a/app/resources/road_blocks/block_highway_turn_out/diffuse_tille_rambardes_02.tga b/app/resources/road_blocks/block_highway_turn_out/diffuse_tille_rambardes_02.tga
new file mode 100644
index 0000000..ccea15e
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_out/diffuse_tille_rambardes_02.tga differ
diff --git a/app/resources/road_blocks/block_highway_turn_out/fbx_importer_cfg.txt b/app/resources/road_blocks/block_highway_turn_out/fbx_importer_cfg.txt
new file mode 100644
index 0000000..5f77877
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_turn_out/fbx_importer_cfg.txt
@@ -0,0 +1,23 @@
+"anim_policy":"1"
+"anim_simplify_color_tolerance":"0.001000"
+"anim_simplify_rotation_tolerance":"0.100000"
+"anim_simplify_scale_tolerance":"0.001000"
+"anim_simplify_translation_tolerance":"0.001000"
+"detect_geometry_instances":"1"
+"fbx_file_path":"c:/Users/clem/Documents/GitHub/mycarsim/app/resources/road_blocks/block_highway_turn_out.fbx"
+"finalizer_script":""
+"fix_geometry_orientation":"0"
+"frames_per_second":"24"
+"geometry_policy":"1"
+"geometry_scale":"1.000000"
+"import_animations":"1"
+"material_policy":"1"
+"max_smoothing_angle":"45.000000"
+"output_folder":"road_blocks/block_highway_turn_out"
+"profile":"1"
+"recalculate_normals":"0"
+"recalculate_tangents":"0"
+"scale":"1.000000"
+"scene_policy":"1"
+"texture_policy":"1"
+"use_finalizer_script":"0"
diff --git a/app/resources/road_blocks/block_highway_turn_out/spec_3ways_01.png b/app/resources/road_blocks/block_highway_turn_out/spec_3ways_01.png
new file mode 100644
index 0000000..383f6e8
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_out/spec_3ways_01.png differ
diff --git a/app/resources/road_blocks/block_highway_turn_out/spec_cement_dirty_03.png b/app/resources/road_blocks/block_highway_turn_out/spec_cement_dirty_03.png
new file mode 100644
index 0000000..a51233b
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_out/spec_cement_dirty_03.png differ
diff --git a/app/resources/road_blocks/block_highway_turn_out/spec_grass.png b/app/resources/road_blocks/block_highway_turn_out/spec_grass.png
new file mode 100644
index 0000000..32523d5
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_out/spec_grass.png differ
diff --git a/app/resources/road_blocks/block_highway_turn_out/spec_metal_red.png b/app/resources/road_blocks/block_highway_turn_out/spec_metal_red.png
new file mode 100644
index 0000000..25b7f71
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_out/spec_metal_red.png differ
diff --git a/app/resources/road_blocks/block_highway_turn_out/spec_road_sides.png b/app/resources/road_blocks/block_highway_turn_out/spec_road_sides.png
new file mode 100644
index 0000000..c535a83
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_out/spec_road_sides.png differ
diff --git a/app/resources/road_blocks/block_highway_turn_out_col.fbx b/app/resources/road_blocks/block_highway_turn_out_col.fbx
new file mode 100644
index 0000000..c097161
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_out_col.fbx differ
diff --git a/app/resources/road_blocks/block_highway_turn_out_col/block_highway_turn_out_col.scn b/app/resources/road_blocks/block_highway_turn_out_col/block_highway_turn_out_col.scn
new file mode 100644
index 0000000..9647cad
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_turn_out_col/block_highway_turn_out_col.scn
@@ -0,0 +1,307 @@
+{
+ "canvas": {
+ "clear_color": true,
+ "clear_z": true,
+ "color": [
+ 0,
+ 0,
+ 0,
+ 255
+ ]
+ },
+ "environment": {
+ "ambient": [
+ 75,
+ 75,
+ 75,
+ 255
+ ],
+ "brdf_map": "core/pbr/brdf.dds",
+ "current_camera": null,
+ "fog_color": [
+ 255,
+ 255,
+ 255,
+ 255
+ ],
+ "fog_far": 0.0,
+ "fog_near": 0.0,
+ "probe": {
+ "irradiance_map": "core/pbr/probe.hdr.irradiance",
+ "parallax": 0.0,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "radiance_map": "core/pbr/probe.hdr.radiance",
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "type": "sphere"
+ }
+ },
+ "key_values": null,
+ "nodes": [
+ {
+ "components": [
+ 0,
+ 4294967295,
+ 0,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 0,
+ "name": "block_highway_turn_out_col"
+ },
+ {
+ "components": [
+ 1,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 1,
+ "name": "Optimized_Shape001"
+ },
+ {
+ "components": [
+ 2,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 2,
+ "name": "Optimized_Shape002"
+ }
+ ],
+ "objects": [
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "col_0"
+ },
+ {
+ "name": "col_1"
+ },
+ {
+ "name": "col_3"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.15294118225574493,
+ 0.6823529601097107,
+ 0.0784313753247261,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.5137255191802979,
+ 0.8078432083129883,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.8823530077934265,
+ 0.4549019932746887,
+ 0.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ }
+ ],
+ "name": "road_blocks/block_highway_turn_out_col/block_highway_turn_out_col_40.geo"
+ }
+ ],
+ "scene_anims": [
+ {
+ "anim": 4294967295,
+ "frame_duration": 50000000,
+ "name": "block_highway_turn_out_collision",
+ "node_anims": null,
+ "t_end": 60000000000,
+ "t_start": 0
+ }
+ ],
+ "transforms": [
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "rot": [
+ -2.504477834008867e-06,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "rot": [
+ 90.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "rot": [
+ 90.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/app/resources/road_blocks/block_highway_turn_out_col/block_highway_turn_out_col_40.geo b/app/resources/road_blocks/block_highway_turn_out_col/block_highway_turn_out_col_40.geo
new file mode 100644
index 0000000..cd6dbde
Binary files /dev/null and b/app/resources/road_blocks/block_highway_turn_out_col/block_highway_turn_out_col_40.geo differ
diff --git a/app/resources/road_blocks/block_highway_turn_out_col/fbx_importer_cfg.txt b/app/resources/road_blocks/block_highway_turn_out_col/fbx_importer_cfg.txt
new file mode 100644
index 0000000..3bcc1dc
--- /dev/null
+++ b/app/resources/road_blocks/block_highway_turn_out_col/fbx_importer_cfg.txt
@@ -0,0 +1,23 @@
+"anim_policy":"1"
+"anim_simplify_color_tolerance":"0.001000"
+"anim_simplify_rotation_tolerance":"0.100000"
+"anim_simplify_scale_tolerance":"0.001000"
+"anim_simplify_translation_tolerance":"0.001000"
+"detect_geometry_instances":"1"
+"fbx_file_path":"c:/Users/clem/Documents/GitHub/mycarsim/app/resources/road_blocks/block_highway_turn_out_col.fbx"
+"finalizer_script":""
+"fix_geometry_orientation":"0"
+"frames_per_second":"24"
+"geometry_policy":"1"
+"geometry_scale":"1.000000"
+"import_animations":"1"
+"material_policy":"1"
+"max_smoothing_angle":"45.000000"
+"output_folder":"road_blocks/block_highway_turn_out_col"
+"profile":"1"
+"recalculate_normals":"0"
+"recalculate_tangents":"0"
+"scale":"1.000000"
+"scene_policy":"1"
+"texture_policy":"1"
+"use_finalizer_script":"0"
diff --git a/app/resources/shaders/bgfx_shader.sh b/app/resources/shaders/bgfx_shader.sh
new file mode 100644
index 0000000..f11bcd2
--- /dev/null
+++ b/app/resources/shaders/bgfx_shader.sh
@@ -0,0 +1,645 @@
+/*
+ * Copyright 2011-2021 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
+ */
+
+#ifndef BGFX_SHADER_H_HEADER_GUARD
+#define BGFX_SHADER_H_HEADER_GUARD
+
+#if !defined(BGFX_CONFIG_MAX_BONES)
+# define BGFX_CONFIG_MAX_BONES 32
+#endif // !defined(BGFX_CONFIG_MAX_BONES)
+
+#ifndef __cplusplus
+
+#if BGFX_SHADER_LANGUAGE_HLSL > 300
+# define BRANCH [branch]
+# define LOOP [loop]
+# define UNROLL [unroll]
+#else
+# define BRANCH
+# define LOOP
+# define UNROLL
+#endif // BGFX_SHADER_LANGUAGE_HLSL > 300
+
+#if BGFX_SHADER_LANGUAGE_HLSL > 300 && BGFX_SHADER_TYPE_FRAGMENT
+# define EARLY_DEPTH_STENCIL [earlydepthstencil]
+#else
+# define EARLY_DEPTH_STENCIL
+#endif // BGFX_SHADER_LANGUAGE_HLSL > 300 && BGFX_SHADER_TYPE_FRAGMENT
+
+#if BGFX_SHADER_LANGUAGE_GLSL
+# define ARRAY_BEGIN(_type, _name, _count) _type _name[_count] = _type[](
+# define ARRAY_END() )
+#else
+# define ARRAY_BEGIN(_type, _name, _count) _type _name[_count] = {
+# define ARRAY_END() }
+#endif // BGFX_SHADER_LANGUAGE_GLSL
+
+#if BGFX_SHADER_LANGUAGE_HLSL \
+ || BGFX_SHADER_LANGUAGE_PSSL \
+ || BGFX_SHADER_LANGUAGE_SPIRV \
+ || BGFX_SHADER_LANGUAGE_METAL
+# define CONST(_x) static const _x
+# define dFdx(_x) ddx(_x)
+# define dFdy(_y) ddy(-_y)
+# define inversesqrt(_x) rsqrt(_x)
+# define fract(_x) frac(_x)
+
+# define bvec2 bool2
+# define bvec3 bool3
+# define bvec4 bool4
+
+// To be able to patch the uav registers on the DXBC SPDB Chunk (D3D11 renderer) the whitespaces around
+// '_type[_reg]' are necessary. This only affects shaders with debug info (i.e., those that have the SPDB Chunk).
+# if BGFX_SHADER_LANGUAGE_HLSL > 400
+# define REGISTER(_type, _reg) register( _type[_reg] )
+# else
+# define REGISTER(_type, _reg) register(_type ## _reg)
+# endif // BGFX_SHADER_LANGUAGE_HLSL
+
+# if BGFX_SHADER_LANGUAGE_HLSL > 300 || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL
+# if BGFX_SHADER_LANGUAGE_HLSL > 400 || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL
+# define dFdxCoarse(_x) ddx_coarse(_x)
+# define dFdxFine(_x) ddx_fine(_x)
+# define dFdyCoarse(_y) ddy_coarse(-_y)
+# define dFdyFine(_y) ddy_fine(-_y)
+# endif // BGFX_SHADER_LANGUAGE_HLSL > 400
+
+# if BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL
+float intBitsToFloat(int _x) { return asfloat(_x); }
+vec2 intBitsToFloat(uint2 _x) { return asfloat(_x); }
+vec3 intBitsToFloat(uint3 _x) { return asfloat(_x); }
+vec4 intBitsToFloat(uint4 _x) { return asfloat(_x); }
+# endif // BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL
+
+float uintBitsToFloat(uint _x) { return asfloat(_x); }
+vec2 uintBitsToFloat(uint2 _x) { return asfloat(_x); }
+vec3 uintBitsToFloat(uint3 _x) { return asfloat(_x); }
+vec4 uintBitsToFloat(uint4 _x) { return asfloat(_x); }
+
+uint floatBitsToUint(float _x) { return asuint(_x); }
+uvec2 floatBitsToUint(vec2 _x) { return asuint(_x); }
+uvec3 floatBitsToUint(vec3 _x) { return asuint(_x); }
+uvec4 floatBitsToUint(vec4 _x) { return asuint(_x); }
+
+int floatBitsToInt(float _x) { return asint(_x); }
+ivec2 floatBitsToInt(vec2 _x) { return asint(_x); }
+ivec3 floatBitsToInt(vec3 _x) { return asint(_x); }
+ivec4 floatBitsToInt(vec4 _x) { return asint(_x); }
+
+uint bitfieldReverse(uint _x) { return reversebits(_x); }
+uint2 bitfieldReverse(uint2 _x) { return reversebits(_x); }
+uint3 bitfieldReverse(uint3 _x) { return reversebits(_x); }
+uint4 bitfieldReverse(uint4 _x) { return reversebits(_x); }
+
+# if !BGFX_SHADER_LANGUAGE_SPIRV
+uint packHalf2x16(vec2 _x)
+{
+ return (f32tof16(_x.y)<<16) | f32tof16(_x.x);
+}
+
+vec2 unpackHalf2x16(uint _x)
+{
+ return vec2(f16tof32(_x & 0xffff), f16tof32(_x >> 16) );
+}
+# endif // !BGFX_SHADER_LANGUAGE_SPIRV
+
+struct BgfxSampler2D
+{
+ SamplerState m_sampler;
+ Texture2D m_texture;
+};
+
+struct BgfxISampler2D
+{
+ Texture2D m_texture;
+};
+
+struct BgfxUSampler2D
+{
+ Texture2D m_texture;
+};
+
+struct BgfxSampler2DArray
+{
+ SamplerState m_sampler;
+ Texture2DArray m_texture;
+};
+
+struct BgfxSampler2DShadow
+{
+ SamplerComparisonState m_sampler;
+ Texture2D m_texture;
+};
+
+struct BgfxSampler2DArrayShadow
+{
+ SamplerComparisonState m_sampler;
+ Texture2DArray m_texture;
+};
+
+struct BgfxSampler3D
+{
+ SamplerState m_sampler;
+ Texture3D m_texture;
+};
+
+struct BgfxISampler3D
+{
+ Texture3D m_texture;
+};
+
+struct BgfxUSampler3D
+{
+ Texture3D m_texture;
+};
+
+struct BgfxSamplerCube
+{
+ SamplerState m_sampler;
+ TextureCube m_texture;
+};
+
+struct BgfxSamplerCubeShadow
+{
+ SamplerComparisonState m_sampler;
+ TextureCube m_texture;
+};
+
+struct BgfxSampler2DMS
+{
+ Texture2DMS m_texture;
+};
+
+vec4 bgfxTexture2D(BgfxSampler2D _sampler, vec2 _coord)
+{
+ return _sampler.m_texture.Sample(_sampler.m_sampler, _coord);
+}
+
+vec4 bgfxTexture2DBias(BgfxSampler2D _sampler, vec2 _coord, float _bias)
+{
+ return _sampler.m_texture.SampleBias(_sampler.m_sampler, _coord, _bias);
+}
+
+vec4 bgfxTexture2DLod(BgfxSampler2D _sampler, vec2 _coord, float _level)
+{
+ return _sampler.m_texture.SampleLevel(_sampler.m_sampler, _coord, _level);
+}
+
+vec4 bgfxTexture2DLodOffset(BgfxSampler2D _sampler, vec2 _coord, float _level, ivec2 _offset)
+{
+ return _sampler.m_texture.SampleLevel(_sampler.m_sampler, _coord, _level, _offset);
+}
+
+vec4 bgfxTexture2DProj(BgfxSampler2D _sampler, vec3 _coord)
+{
+ vec2 coord = _coord.xy * rcp(_coord.z);
+ return _sampler.m_texture.Sample(_sampler.m_sampler, coord);
+}
+
+vec4 bgfxTexture2DProj(BgfxSampler2D _sampler, vec4 _coord)
+{
+ vec2 coord = _coord.xy * rcp(_coord.w);
+ return _sampler.m_texture.Sample(_sampler.m_sampler, coord);
+}
+
+vec4 bgfxTexture2DGrad(BgfxSampler2D _sampler, vec2 _coord, vec2 _dPdx, vec2 _dPdy)
+{
+ return _sampler.m_texture.SampleGrad(_sampler.m_sampler, _coord, _dPdx, _dPdy);
+}
+
+vec4 bgfxTexture2DArray(BgfxSampler2DArray _sampler, vec3 _coord)
+{
+ return _sampler.m_texture.Sample(_sampler.m_sampler, _coord);
+}
+
+vec4 bgfxTexture2DArrayLod(BgfxSampler2DArray _sampler, vec3 _coord, float _lod)
+{
+ return _sampler.m_texture.SampleLevel(_sampler.m_sampler, _coord, _lod);
+}
+
+vec4 bgfxTexture2DArrayLodOffset(BgfxSampler2DArray _sampler, vec3 _coord, float _level, ivec2 _offset)
+{
+ return _sampler.m_texture.SampleLevel(_sampler.m_sampler, _coord, _level, _offset);
+}
+
+float bgfxShadow2D(BgfxSampler2DShadow _sampler, vec3 _coord)
+{
+ return _sampler.m_texture.SampleCmpLevelZero(_sampler.m_sampler, _coord.xy, _coord.z);
+}
+
+float bgfxShadow2DProj(BgfxSampler2DShadow _sampler, vec4 _coord)
+{
+ vec3 coord = _coord.xyz * rcp(_coord.w);
+ return _sampler.m_texture.SampleCmpLevelZero(_sampler.m_sampler, coord.xy, coord.z);
+}
+
+vec4 bgfxShadow2DArray(BgfxSampler2DArrayShadow _sampler, vec4 _coord)
+{
+ return _sampler.m_texture.SampleCmpLevelZero(_sampler.m_sampler, _coord.xyz, _coord.w);
+}
+
+vec4 bgfxTexture3D(BgfxSampler3D _sampler, vec3 _coord)
+{
+ return _sampler.m_texture.Sample(_sampler.m_sampler, _coord);
+}
+
+vec4 bgfxTexture3DLod(BgfxSampler3D _sampler, vec3 _coord, float _level)
+{
+ return _sampler.m_texture.SampleLevel(_sampler.m_sampler, _coord, _level);
+}
+
+ivec4 bgfxTexture3D(BgfxISampler3D _sampler, vec3 _coord)
+{
+ uvec3 size;
+ _sampler.m_texture.GetDimensions(size.x, size.y, size.z);
+ return _sampler.m_texture.Load(ivec4(_coord * size, 0) );
+}
+
+uvec4 bgfxTexture3D(BgfxUSampler3D _sampler, vec3 _coord)
+{
+ uvec3 size;
+ _sampler.m_texture.GetDimensions(size.x, size.y, size.z);
+ return _sampler.m_texture.Load(ivec4(_coord * size, 0) );
+}
+
+vec4 bgfxTextureCube(BgfxSamplerCube _sampler, vec3 _coord)
+{
+ return _sampler.m_texture.Sample(_sampler.m_sampler, _coord);
+}
+
+vec4 bgfxTextureCubeBias(BgfxSamplerCube _sampler, vec3 _coord, float _bias)
+{
+ return _sampler.m_texture.SampleBias(_sampler.m_sampler, _coord, _bias);
+}
+
+vec4 bgfxTextureCubeLod(BgfxSamplerCube _sampler, vec3 _coord, float _level)
+{
+ return _sampler.m_texture.SampleLevel(_sampler.m_sampler, _coord, _level);
+}
+
+float bgfxShadowCube(BgfxSamplerCubeShadow _sampler, vec4 _coord)
+{
+ return _sampler.m_texture.SampleCmpLevelZero(_sampler.m_sampler, _coord.xyz, _coord.w);
+}
+
+vec4 bgfxTexelFetch(BgfxSampler2D _sampler, ivec2 _coord, int _lod)
+{
+ return _sampler.m_texture.Load(ivec3(_coord, _lod) );
+}
+
+vec4 bgfxTexelFetchOffset(BgfxSampler2D _sampler, ivec2 _coord, int _lod, ivec2 _offset)
+{
+ return _sampler.m_texture.Load(ivec3(_coord, _lod), _offset );
+}
+
+vec2 bgfxTextureSize(BgfxSampler2D _sampler, int _lod)
+{
+ vec2 result;
+ _sampler.m_texture.GetDimensions(result.x, result.y);
+ return result;
+}
+
+vec4 bgfxTextureGather(BgfxSampler2D _sampler, vec2 _coord)
+{
+ return _sampler.m_texture.GatherRed(_sampler.m_sampler, _coord );
+}
+vec4 bgfxTextureGatherOffset(BgfxSampler2D _sampler, vec2 _coord, ivec2 _offset)
+{
+ return _sampler.m_texture.GatherRed(_sampler.m_sampler, _coord, _offset );
+}
+vec4 bgfxTextureGather(BgfxSampler2DArray _sampler, vec3 _coord)
+{
+ return _sampler.m_texture.GatherRed(_sampler.m_sampler, _coord );
+}
+
+ivec4 bgfxTexelFetch(BgfxISampler2D _sampler, ivec2 _coord, int _lod)
+{
+ return _sampler.m_texture.Load(ivec3(_coord, _lod) );
+}
+
+uvec4 bgfxTexelFetch(BgfxUSampler2D _sampler, ivec2 _coord, int _lod)
+{
+ return _sampler.m_texture.Load(ivec3(_coord, _lod) );
+}
+
+vec4 bgfxTexelFetch(BgfxSampler2DMS _sampler, ivec2 _coord, int _sampleIdx)
+{
+ return _sampler.m_texture.Load(_coord, _sampleIdx);
+}
+
+vec4 bgfxTexelFetch(BgfxSampler2DArray _sampler, ivec3 _coord, int _lod)
+{
+ return _sampler.m_texture.Load(ivec4(_coord, _lod) );
+}
+
+vec4 bgfxTexelFetch(BgfxSampler3D _sampler, ivec3 _coord, int _lod)
+{
+ return _sampler.m_texture.Load(ivec4(_coord, _lod) );
+}
+
+vec3 bgfxTextureSize(BgfxSampler3D _sampler, int _lod)
+{
+ vec3 result;
+ _sampler.m_texture.GetDimensions(result.x, result.y, result.z);
+ return result;
+}
+
+# define SAMPLER2D(_name, _reg) \
+ uniform SamplerState _name ## Sampler : REGISTER(s, _reg); \
+ uniform Texture2D _name ## Texture : REGISTER(t, _reg); \
+ static BgfxSampler2D _name = { _name ## Sampler, _name ## Texture }
+# define ISAMPLER2D(_name, _reg) \
+ uniform Texture2D _name ## Texture : REGISTER(t, _reg); \
+ static BgfxISampler2D _name = { _name ## Texture }
+# define USAMPLER2D(_name, _reg) \
+ uniform Texture2D _name ## Texture : REGISTER(t, _reg); \
+ static BgfxUSampler2D _name = { _name ## Texture }
+# define sampler2D BgfxSampler2D
+# define texture2D(_sampler, _coord) bgfxTexture2D(_sampler, _coord)
+# define texture2DBias(_sampler, _coord, _bias) bgfxTexture2DBias(_sampler, _coord, _bias)
+# define texture2DLod(_sampler, _coord, _level) bgfxTexture2DLod(_sampler, _coord, _level)
+# define texture2DLodOffset(_sampler, _coord, _level, _offset) bgfxTexture2DLodOffset(_sampler, _coord, _level, _offset)
+# define texture2DProj(_sampler, _coord) bgfxTexture2DProj(_sampler, _coord)
+# define texture2DGrad(_sampler, _coord, _dPdx, _dPdy) bgfxTexture2DGrad(_sampler, _coord, _dPdx, _dPdy)
+
+# define SAMPLER2DARRAY(_name, _reg) \
+ uniform SamplerState _name ## Sampler : REGISTER(s, _reg); \
+ uniform Texture2DArray _name ## Texture : REGISTER(t, _reg); \
+ static BgfxSampler2DArray _name = { _name ## Sampler, _name ## Texture }
+# define sampler2DArray BgfxSampler2DArray
+# define texture2DArray(_sampler, _coord) bgfxTexture2DArray(_sampler, _coord)
+# define texture2DArrayLod(_sampler, _coord, _lod) bgfxTexture2DArrayLod(_sampler, _coord, _lod)
+# define texture2DArrayLodOffset(_sampler, _coord, _level, _offset) bgfxTexture2DArrayLodOffset(_sampler, _coord, _level, _offset)
+
+# define SAMPLER2DMS(_name, _reg) \
+ uniform Texture2DMS _name ## Texture : REGISTER(t, _reg); \
+ static BgfxSampler2DMS _name = { _name ## Texture }
+# define sampler2DMS BgfxSampler2DMS
+
+# define SAMPLER2DSHADOW(_name, _reg) \
+ uniform SamplerComparisonState _name ## SamplerComparison : REGISTER(s, _reg); \
+ uniform Texture2D _name ## Texture : REGISTER(t, _reg); \
+ static BgfxSampler2DShadow _name = { _name ## SamplerComparison, _name ## Texture }
+# define sampler2DShadow BgfxSampler2DShadow
+# define shadow2D(_sampler, _coord) bgfxShadow2D(_sampler, _coord)
+# define shadow2DProj(_sampler, _coord) bgfxShadow2DProj(_sampler, _coord)
+
+# define SAMPLER2DARRAYSHADOW(_name, _reg) \
+ uniform SamplerComparisonState _name ## SamplerComparison : REGISTER(s, _reg); \
+ uniform Texture2DArray _name ## Texture : REGISTER(t, _reg); \
+ static BgfxSampler2DArrayShadow _name = { _name ## SamplerComparison, _name ## Texture }
+# define sampler2DArrayShadow BgfxSampler2DArrayShadow
+# define shadow2DArray(_sampler, _coord) bgfxShadow2DArray(_sampler, _coord)
+
+# define SAMPLER3D(_name, _reg) \
+ uniform SamplerState _name ## Sampler : REGISTER(s, _reg); \
+ uniform Texture3D _name ## Texture : REGISTER(t, _reg); \
+ static BgfxSampler3D _name = { _name ## Sampler, _name ## Texture }
+# define ISAMPLER3D(_name, _reg) \
+ uniform Texture3D _name ## Texture : REGISTER(t, _reg); \
+ static BgfxISampler3D _name = { _name ## Texture }
+# define USAMPLER3D(_name, _reg) \
+ uniform Texture3D _name ## Texture : REGISTER(t, _reg); \
+ static BgfxUSampler3D _name = { _name ## Texture }
+# define sampler3D BgfxSampler3D
+# define texture3D(_sampler, _coord) bgfxTexture3D(_sampler, _coord)
+# define texture3DLod(_sampler, _coord, _level) bgfxTexture3DLod(_sampler, _coord, _level)
+
+# define SAMPLERCUBE(_name, _reg) \
+ uniform SamplerState _name ## Sampler : REGISTER(s, _reg); \
+ uniform TextureCube _name ## Texture : REGISTER(t, _reg); \
+ static BgfxSamplerCube _name = { _name ## Sampler, _name ## Texture }
+# define samplerCube BgfxSamplerCube
+# define textureCube(_sampler, _coord) bgfxTextureCube(_sampler, _coord)
+# define textureCubeBias(_sampler, _coord, _bias) bgfxTextureCubeBias(_sampler, _coord, _bias)
+# define textureCubeLod(_sampler, _coord, _level) bgfxTextureCubeLod(_sampler, _coord, _level)
+
+# define SAMPLERCUBESHADOW(_name, _reg) \
+ uniform SamplerComparisonState _name ## SamplerComparison : REGISTER(s, _reg); \
+ uniform TextureCube _name ## Texture : REGISTER(t, _reg); \
+ static BgfxSamplerCubeShadow _name = { _name ## SamplerComparison, _name ## Texture }
+# define samplerCubeShadow BgfxSamplerCubeShadow
+# define shadowCube(_sampler, _coord) bgfxShadowCube(_sampler, _coord)
+
+# define texelFetch(_sampler, _coord, _lod) bgfxTexelFetch(_sampler, _coord, _lod)
+# define texelFetchOffset(_sampler, _coord, _lod, _offset) bgfxTexelFetchOffset(_sampler, _coord, _lod, _offset)
+# define textureSize(_sampler, _lod) bgfxTextureSize(_sampler, _lod)
+# define textureGather(_sampler, _coord) bgfxTextureGather(_sampler, _coord)
+# define textureGatherOffset(_sampler, _coord, _offset) bgfxTextureGatherOffset(_sampler, _coord, _offset)
+# else
+
+# define sampler2DShadow sampler2D
+
+vec4 bgfxTexture2DProj(sampler2D _sampler, vec3 _coord)
+{
+ return tex2Dproj(_sampler, vec4(_coord.xy, 0.0, _coord.z) );
+}
+
+vec4 bgfxTexture2DProj(sampler2D _sampler, vec4 _coord)
+{
+ return tex2Dproj(_sampler, _coord);
+}
+
+float bgfxShadow2D(sampler2DShadow _sampler, vec3 _coord)
+{
+#if 0
+ float occluder = tex2D(_sampler, _coord.xy).x;
+ return step(_coord.z, occluder);
+#else
+ return tex2Dproj(_sampler, vec4(_coord.xy, _coord.z, 1.0) ).x;
+#endif // 0
+}
+
+float bgfxShadow2DProj(sampler2DShadow _sampler, vec4 _coord)
+{
+#if 0
+ vec3 coord = _coord.xyz * rcp(_coord.w);
+ float occluder = tex2D(_sampler, coord.xy).x;
+ return step(coord.z, occluder);
+#else
+ return tex2Dproj(_sampler, _coord).x;
+#endif // 0
+}
+
+# define SAMPLER2D(_name, _reg) uniform sampler2D _name : REGISTER(s, _reg)
+# define SAMPLER2DMS(_name, _reg) uniform sampler2DMS _name : REGISTER(s, _reg)
+# define texture2D(_sampler, _coord) tex2D(_sampler, _coord)
+# define texture2DProj(_sampler, _coord) bgfxTexture2DProj(_sampler, _coord)
+
+# define SAMPLER2DARRAY(_name, _reg) SAMPLER2D(_name, _reg)
+# define texture2DArray(_sampler, _coord) texture2D(_sampler, (_coord).xy)
+# define texture2DArrayLod(_sampler, _coord, _lod) texture2DLod(_sampler, _coord, _lod)
+
+# define SAMPLER2DSHADOW(_name, _reg) uniform sampler2DShadow _name : REGISTER(s, _reg)
+# define shadow2D(_sampler, _coord) bgfxShadow2D(_sampler, _coord)
+# define shadow2DProj(_sampler, _coord) bgfxShadow2DProj(_sampler, _coord)
+
+# define SAMPLER3D(_name, _reg) uniform sampler3D _name : REGISTER(s, _reg)
+# define texture3D(_sampler, _coord) tex3D(_sampler, _coord)
+
+# define SAMPLERCUBE(_name, _reg) uniform samplerCUBE _name : REGISTER(s, _reg)
+# define textureCube(_sampler, _coord) texCUBE(_sampler, _coord)
+
+# define texture2DLod(_sampler, _coord, _level) tex2Dlod(_sampler, vec4( (_coord).xy, 0.0, _level) )
+# define texture2DGrad(_sampler, _coord, _dPdx, _dPdy) tex2Dgrad(_sampler, _coord, _dPdx, _dPdy)
+# define texture3DLod(_sampler, _coord, _level) tex3Dlod(_sampler, vec4( (_coord).xyz, _level) )
+# define textureCubeLod(_sampler, _coord, _level) texCUBElod(_sampler, vec4( (_coord).xyz, _level) )
+
+# endif // BGFX_SHADER_LANGUAGE_HLSL > 300
+
+vec3 instMul(vec3 _vec, mat3 _mtx) { return mul(_mtx, _vec); }
+vec3 instMul(mat3 _mtx, vec3 _vec) { return mul(_vec, _mtx); }
+vec4 instMul(vec4 _vec, mat4 _mtx) { return mul(_mtx, _vec); }
+vec4 instMul(mat4 _mtx, vec4 _vec) { return mul(_vec, _mtx); }
+
+bvec2 lessThan(vec2 _a, vec2 _b) { return _a < _b; }
+bvec3 lessThan(vec3 _a, vec3 _b) { return _a < _b; }
+bvec4 lessThan(vec4 _a, vec4 _b) { return _a < _b; }
+
+bvec2 lessThanEqual(vec2 _a, vec2 _b) { return _a <= _b; }
+bvec3 lessThanEqual(vec3 _a, vec3 _b) { return _a <= _b; }
+bvec4 lessThanEqual(vec4 _a, vec4 _b) { return _a <= _b; }
+
+bvec2 greaterThan(vec2 _a, vec2 _b) { return _a > _b; }
+bvec3 greaterThan(vec3 _a, vec3 _b) { return _a > _b; }
+bvec4 greaterThan(vec4 _a, vec4 _b) { return _a > _b; }
+
+bvec2 greaterThanEqual(vec2 _a, vec2 _b) { return _a >= _b; }
+bvec3 greaterThanEqual(vec3 _a, vec3 _b) { return _a >= _b; }
+bvec4 greaterThanEqual(vec4 _a, vec4 _b) { return _a >= _b; }
+
+bvec2 notEqual(vec2 _a, vec2 _b) { return _a != _b; }
+bvec3 notEqual(vec3 _a, vec3 _b) { return _a != _b; }
+bvec4 notEqual(vec4 _a, vec4 _b) { return _a != _b; }
+
+bvec2 equal(vec2 _a, vec2 _b) { return _a == _b; }
+bvec3 equal(vec3 _a, vec3 _b) { return _a == _b; }
+bvec4 equal(vec4 _a, vec4 _b) { return _a == _b; }
+
+float mix(float _a, float _b, float _t) { return lerp(_a, _b, _t); }
+vec2 mix(vec2 _a, vec2 _b, vec2 _t) { return lerp(_a, _b, _t); }
+vec3 mix(vec3 _a, vec3 _b, vec3 _t) { return lerp(_a, _b, _t); }
+vec4 mix(vec4 _a, vec4 _b, vec4 _t) { return lerp(_a, _b, _t); }
+
+float mod(float _a, float _b) { return _a - _b * floor(_a / _b); }
+vec2 mod(vec2 _a, vec2 _b) { return _a - _b * floor(_a / _b); }
+vec3 mod(vec3 _a, vec3 _b) { return _a - _b * floor(_a / _b); }
+vec4 mod(vec4 _a, vec4 _b) { return _a - _b * floor(_a / _b); }
+
+#else
+# define CONST(_x) const _x
+# define atan2(_x, _y) atan(_x, _y)
+# define mul(_a, _b) ( (_a) * (_b) )
+# define saturate(_x) clamp(_x, 0.0, 1.0)
+# define SAMPLER2D(_name, _reg) uniform sampler2D _name
+# define SAMPLER2DMS(_name, _reg) uniform sampler2DMS _name
+# define SAMPLER3D(_name, _reg) uniform sampler3D _name
+# define SAMPLERCUBE(_name, _reg) uniform samplerCube _name
+# define SAMPLER2DSHADOW(_name, _reg) uniform sampler2DShadow _name
+
+# define SAMPLER2DARRAY(_name, _reg) uniform sampler2DArray _name
+# define SAMPLER2DMSARRAY(_name, _reg) uniform sampler2DMSArray _name
+# define SAMPLERCUBEARRAY(_name, _reg) uniform samplerCubeArray _name
+# define SAMPLER2DARRAYSHADOW(_name, _reg) uniform sampler2DArrayShadow _name
+
+# define ISAMPLER2D(_name, _reg) uniform isampler2D _name
+# define USAMPLER2D(_name, _reg) uniform usampler2D _name
+# define ISAMPLER3D(_name, _reg) uniform isampler3D _name
+# define USAMPLER3D(_name, _reg) uniform usampler3D _name
+
+# define texture2DBias(_sampler, _coord, _bias) texture2D(_sampler, _coord, _bias)
+# define textureCubeBias(_sampler, _coord, _bias) textureCube(_sampler, _coord, _bias)
+
+# if BGFX_SHADER_LANGUAGE_GLSL >= 130
+# define texture2D(_sampler, _coord) texture(_sampler, _coord)
+# define texture2DArray(_sampler, _coord) texture(_sampler, _coord)
+# define texture3D(_sampler, _coord) texture(_sampler, _coord)
+# define texture2DLod(_sampler, _coord, _lod) textureLod(_sampler, _coord, _lod)
+# define texture2DLodOffset(_sampler, _coord, _lod, _offset) textureLodOffset(_sampler, _coord, _lod, _offset)
+# endif // BGFX_SHADER_LANGUAGE_GLSL >= 130
+
+vec3 instMul(vec3 _vec, mat3 _mtx) { return mul(_vec, _mtx); }
+vec3 instMul(mat3 _mtx, vec3 _vec) { return mul(_mtx, _vec); }
+vec4 instMul(vec4 _vec, mat4 _mtx) { return mul(_vec, _mtx); }
+vec4 instMul(mat4 _mtx, vec4 _vec) { return mul(_mtx, _vec); }
+
+float rcp(float _a) { return 1.0/_a; }
+vec2 rcp(vec2 _a) { return vec2(1.0)/_a; }
+vec3 rcp(vec3 _a) { return vec3(1.0)/_a; }
+vec4 rcp(vec4 _a) { return vec4(1.0)/_a; }
+#endif // BGFX_SHADER_LANGUAGE_*
+
+vec2 vec2_splat(float _x) { return vec2(_x, _x); }
+vec3 vec3_splat(float _x) { return vec3(_x, _x, _x); }
+vec4 vec4_splat(float _x) { return vec4(_x, _x, _x, _x); }
+
+#if BGFX_SHADER_LANGUAGE_GLSL >= 130 || BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL
+uvec2 uvec2_splat(uint _x) { return uvec2(_x, _x); }
+uvec3 uvec3_splat(uint _x) { return uvec3(_x, _x, _x); }
+uvec4 uvec4_splat(uint _x) { return uvec4(_x, _x, _x, _x); }
+#endif // BGFX_SHADER_LANGUAGE_GLSL >= 130 || BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL
+
+mat4 mtxFromRows(vec4 _0, vec4 _1, vec4 _2, vec4 _3)
+{
+#if BGFX_SHADER_LANGUAGE_GLSL
+ return transpose(mat4(_0, _1, _2, _3) );
+#else
+ return mat4(_0, _1, _2, _3);
+#endif // BGFX_SHADER_LANGUAGE_GLSL
+}
+mat4 mtxFromCols(vec4 _0, vec4 _1, vec4 _2, vec4 _3)
+{
+#if BGFX_SHADER_LANGUAGE_GLSL
+ return mat4(_0, _1, _2, _3);
+#else
+ return transpose(mat4(_0, _1, _2, _3) );
+#endif // BGFX_SHADER_LANGUAGE_GLSL
+}
+mat3 mtxFromRows(vec3 _0, vec3 _1, vec3 _2)
+{
+#if BGFX_SHADER_LANGUAGE_GLSL
+ return transpose(mat3(_0, _1, _2) );
+#else
+ return mat3(_0, _1, _2);
+#endif // BGFX_SHADER_LANGUAGE_GLSL
+}
+mat3 mtxFromCols(vec3 _0, vec3 _1, vec3 _2)
+{
+#if BGFX_SHADER_LANGUAGE_GLSL
+ return mat3(_0, _1, _2);
+#else
+ return transpose(mat3(_0, _1, _2) );
+#endif // BGFX_SHADER_LANGUAGE_GLSL
+}
+
+#if BGFX_SHADER_LANGUAGE_GLSL
+#define mtxFromRows3(_0, _1, _2) transpose(mat3(_0, _1, _2) )
+#define mtxFromRows4(_0, _1, _2, _3) transpose(mat4(_0, _1, _2, _3) )
+#define mtxFromCols3(_0, _1, _2) mat3(_0, _1, _2)
+#define mtxFromCols4(_0, _1, _2, _3) mat4(_0, _1, _2, _3)
+#else
+#define mtxFromRows3(_0, _1, _2) mat3(_0, _1, _2)
+#define mtxFromRows4(_0, _1, _2, _3) mat4(_0, _1, _2, _3)
+#define mtxFromCols3(_0, _1, _2) transpose(mat3(_0, _1, _2) )
+#define mtxFromCols4(_0, _1, _2, _3) transpose(mat4(_0, _1, _2, _3) )
+#endif // BGFX_SHADER_LANGUAGE_GLSL
+
+uniform vec4 u_viewRect;
+uniform vec4 u_viewTexel;
+uniform mat4 u_view;
+uniform mat4 u_invView;
+uniform mat4 u_proj;
+uniform mat4 u_invProj;
+uniform mat4 u_viewProj;
+uniform mat4 u_invViewProj;
+uniform mat4 u_model[BGFX_CONFIG_MAX_BONES];
+uniform mat4 u_modelView;
+uniform mat4 u_modelViewProj;
+uniform vec4 u_alphaRef4;
+#define u_alphaRef u_alphaRef4.x
+
+#endif // __cplusplus
+
+#endif // BGFX_SHADER_H_HEADER_GUARD
diff --git a/app/resources/shaders/forward_pipeline.sh b/app/resources/shaders/forward_pipeline.sh
new file mode 100644
index 0000000..0e96e35
--- /dev/null
+++ b/app/resources/shaders/forward_pipeline.sh
@@ -0,0 +1,95 @@
+#include
+
+#define PI 3.14159265359
+
+uniform vec4 uClock; // clock
+
+// Environment
+uniform vec4 uFogColor;
+uniform vec4 uFogState; // fog_near, 1.0/fog_range
+
+// Lighting environment
+uniform vec4 uAmbientColor;
+
+uniform vec4 uLightPos[8]; // pos.xyz, 1.0/radius
+uniform vec4 uLightDir[8]; // dir.xyz, inner_rim
+uniform vec4 uLightDiffuse[8]; // diffuse.xyz, outer_rim
+uniform vec4 uLightSpecular[8]; // specular.xyz, pssm_bias
+
+uniform mat4 uLinearShadowMatrix[4]; // slot 0: linear PSSM shadow matrices
+uniform vec4 uLinearShadowSlice; // slot 0: PSSM slice distances linear light
+uniform mat4 uSpotShadowMatrix; // slot 1: spot shadow matrix
+uniform vec4 uShadowState; // slot 0: inverse resolution, slot1: inverse resolution, slot0: bias, slot1: bias
+
+uniform vec4 uResolution; // xy: backbuffer resolution
+uniform vec4 uProjection;
+uniform mat4 uMainProjection; // projection for the main render (used by screenspace post-processes)
+uniform mat4 uMainInvProjection; // inverse projection for the main render (used by screenspace post-processes)
+
+uniform mat4 uPreviousViewProjection;
+uniform mat4 uPreviousModel[BGFX_CONFIG_MAX_BONES];
+uniform mat4 uViewProjUnjittered;
+uniform vec4 uAAAParams[2]; // [0].x: ssgi ratio, [0].y: ssr ratio, [0].z: temporal AA weight, [0].w: motion blur strength
+ // [1].x: exposure, [1].y: 1/gamma, [1].z: sample count, [1].w: max radius
+
+uniform mat4 uMainInvView; // inversion view matrix
+
+#if FORWARD_PIPELINE_AAA
+SAMPLER2D(uIrradianceMap, 8);
+SAMPLER2D(uRadianceMap, 9);
+#else
+SAMPLERCUBE(uIrradianceMap, 8);
+SAMPLERCUBE(uRadianceMap, 9);
+#endif
+SAMPLER2D(uBrdfMap, 10);
+SAMPLER2D(uNoiseMap, 11);
+SAMPLER2D(uAmbientOcclusion, 13);
+SAMPLER2DSHADOW(uLinearShadowMap, 14);
+SAMPLER2DSHADOW(uSpotShadowMap, 15);
+
+//
+float sRGB2linear(float v) {
+ return (v < 0.04045) ? (v * 0.0773993808) : pow((v + 0.055) / 1.055, 2.4);
+}
+
+vec3 sRGB2linear(vec3 v) {
+ return vec3(sRGB2linear(v.x), sRGB2linear(v.y), sRGB2linear(v.z));
+}
+
+//
+mat3 MakeMat3(vec3 c0, vec3 c1, vec3 c2) {
+ return mat3(c0, c1, c2);
+}
+
+vec3 GetT(mat4 m) {
+#if BGFX_SHADER_LANGUAGE_GLSL
+ return vec3(m[3][0], m[3][1], m[3][2]);
+#else
+ return vec3(m[0][3], m[1][3], m[2][3]);
+#endif
+}
+
+float LinearDepth(float z) {
+ return uProjection.w / (z - uProjection.z);
+}
+
+// from screen space to view space
+vec3 Unproject(vec3 frag_coord) {
+ vec4 clip = vec4(((frag_coord.xy - u_viewRect.xy) / u_viewRect.zw) * 2. - 1., frag_coord.z, 1.);
+ vec4 ndc = mul(clip, uMainInvProjection);
+ return ndc.xyz / ndc.w;
+}
+
+vec3 ComputeFragCoordViewRay(vec2 frag_coord)
+{
+ vec2 sp = ((frag_coord - u_viewRect.xy) / u_viewRect.zw) * 2. - 1.;
+ sp.y *= -1.;
+
+ vec4 ndc = mul(uMainInvProjection, vec4(sp, 1., 1.)); // far ndc frustum plane
+ ndc /= ndc.w;
+ ndc /= ndc.z;
+
+ return ndc.xyz;
+}
+
+bool isNan(float val) { return (val <= 0.0 || 0.0 <= val) ? false : true; }
diff --git a/app/resources/shaders/pos_rgb_fs.sc b/app/resources/shaders/pos_rgb_fs.sc
new file mode 100644
index 0000000..42dd87d
--- /dev/null
+++ b/app/resources/shaders/pos_rgb_fs.sc
@@ -0,0 +1,7 @@
+$input v_color0
+
+#include
+
+void main() {
+ gl_FragColor = v_color0;
+}
diff --git a/app/resources/shaders/pos_rgb_varying.def b/app/resources/shaders/pos_rgb_varying.def
new file mode 100644
index 0000000..e894ac9
--- /dev/null
+++ b/app/resources/shaders/pos_rgb_varying.def
@@ -0,0 +1,4 @@
+vec4 v_color0 : COLOR0;
+
+vec3 a_position : POSITION;
+vec4 a_color0 : COLOR0;
diff --git a/app/resources/shaders/pos_rgb_vs.sc b/app/resources/shaders/pos_rgb_vs.sc
new file mode 100644
index 0000000..b0b00b6
--- /dev/null
+++ b/app/resources/shaders/pos_rgb_vs.sc
@@ -0,0 +1,9 @@
+$input a_position, a_color0
+$output v_color0
+
+#include
+
+void main() {
+ v_color0 = a_color0;
+ gl_Position = mul(u_modelViewProj, vec4(a_position, 1.0));
+}
diff --git a/app/resources/shaders/sprite_fs.sc b/app/resources/shaders/sprite_fs.sc
new file mode 100644
index 0000000..cad56a1
--- /dev/null
+++ b/app/resources/shaders/sprite_fs.sc
@@ -0,0 +1,11 @@
+$input v_texcoord0
+
+#include
+
+uniform vec4 color;
+
+SAMPLER2D(s_tex, 0);
+
+void main() {
+ gl_FragColor = texture2D(s_tex, v_texcoord0)*color;
+}
diff --git a/app/resources/shaders/sprite_varying.def b/app/resources/shaders/sprite_varying.def
new file mode 100644
index 0000000..bfaea00
--- /dev/null
+++ b/app/resources/shaders/sprite_varying.def
@@ -0,0 +1,3 @@
+vec2 v_texcoord0 : TEXCOORD0;
+vec3 a_position : POSITION;
+
diff --git a/app/resources/shaders/sprite_vs.sc b/app/resources/shaders/sprite_vs.sc
new file mode 100644
index 0000000..86d02a2
--- /dev/null
+++ b/app/resources/shaders/sprite_vs.sc
@@ -0,0 +1,9 @@
+$input a_position
+$output v_texcoord0
+
+#include
+
+void main() {
+ gl_Position = mul(u_modelViewProj, vec4(a_position, 1.0));
+ v_texcoord0 = vec2(a_position.x+0.5,a_position.z+0.5);
+}
diff --git a/app/resources/vehicles/generic_vehicle/Car03_Wheel_Albedo01.png b/app/resources/vehicles/generic_vehicle/Car03_Wheel_Albedo01.png
new file mode 100644
index 0000000..ef1f1f4
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/Car03_Wheel_Albedo01.png differ
diff --git a/app/resources/vehicles/generic_vehicle/Car03_Wheel_Albedo01.png.meta b/app/resources/vehicles/generic_vehicle/Car03_Wheel_Albedo01.png.meta
new file mode 100644
index 0000000..eeb3afa
--- /dev/null
+++ b/app/resources/vehicles/generic_vehicle/Car03_Wheel_Albedo01.png.meta
@@ -0,0 +1,7 @@
+{
+ "profiles": {
+ "default": {
+ "compression": "BC1"
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/resources/vehicles/generic_vehicle/Car03_Wheel_Normal.png b/app/resources/vehicles/generic_vehicle/Car03_Wheel_Normal.png
new file mode 100644
index 0000000..9821666
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/Car03_Wheel_Normal.png differ
diff --git a/app/resources/vehicles/generic_vehicle/Car03_Wheel_Normal.png.meta b/app/resources/vehicles/generic_vehicle/Car03_Wheel_Normal.png.meta
new file mode 100644
index 0000000..703aaae
--- /dev/null
+++ b/app/resources/vehicles/generic_vehicle/Car03_Wheel_Normal.png.meta
@@ -0,0 +1,8 @@
+{
+ "profiles": {
+ "default": {
+ "compression": "BC5",
+ "type": "NormalMap"
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/resources/vehicles/generic_vehicle/Car03_Wheel_ORM.png b/app/resources/vehicles/generic_vehicle/Car03_Wheel_ORM.png
new file mode 100644
index 0000000..7f11f60
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/Car03_Wheel_ORM.png differ
diff --git a/app/resources/vehicles/generic_vehicle/Car03_Wheel_ORM.png.meta b/app/resources/vehicles/generic_vehicle/Car03_Wheel_ORM.png.meta
new file mode 100644
index 0000000..eeb3afa
--- /dev/null
+++ b/app/resources/vehicles/generic_vehicle/Car03_Wheel_ORM.png.meta
@@ -0,0 +1,7 @@
+{
+ "profiles": {
+ "default": {
+ "compression": "BC1"
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/resources/vehicles/generic_vehicle/Car03_pack_ORM.png b/app/resources/vehicles/generic_vehicle/Car03_pack_ORM.png
new file mode 100644
index 0000000..6ca016f
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/Car03_pack_ORM.png differ
diff --git a/app/resources/vehicles/generic_vehicle/Car03_pack_albedo.png b/app/resources/vehicles/generic_vehicle/Car03_pack_albedo.png
new file mode 100644
index 0000000..0f5ff01
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/Car03_pack_albedo.png differ
diff --git a/app/resources/vehicles/generic_vehicle/Car03_pack_normal.png b/app/resources/vehicles/generic_vehicle/Car03_pack_normal.png
new file mode 100644
index 0000000..9b10f22
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/Car03_pack_normal.png differ
diff --git a/app/resources/vehicles/generic_vehicle/car_body_44.geo b/app/resources/vehicles/generic_vehicle/car_body_44.geo
new file mode 100644
index 0000000..ecbdda6
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/car_body_44.geo differ
diff --git a/app/resources/vehicles/generic_vehicle/carlights/Car03_Lights_Emissive.hdr b/app/resources/vehicles/generic_vehicle/carlights/Car03_Lights_Emissive.hdr
new file mode 100644
index 0000000..ff701bc
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/carlights/Car03_Lights_Emissive.hdr differ
diff --git a/app/resources/vehicles/generic_vehicle/carlights/carlight_backLight_48.geo b/app/resources/vehicles/generic_vehicle/carlights/carlight_backLight_48.geo
new file mode 100644
index 0000000..45a724a
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/carlights/carlight_backLight_48.geo differ
diff --git a/app/resources/vehicles/generic_vehicle/carlights/carlight_brake_47.geo b/app/resources/vehicles/generic_vehicle/carlights/carlight_brake_47.geo
new file mode 100644
index 0000000..5f38b0e
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/carlights/carlight_brake_47.geo differ
diff --git a/app/resources/vehicles/generic_vehicle/carlights/carlight_day_light_46.geo b/app/resources/vehicles/generic_vehicle/carlights/carlight_day_light_46.geo
new file mode 100644
index 0000000..0c0124a
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/carlights/carlight_day_light_46.geo differ
diff --git a/app/resources/vehicles/generic_vehicle/carlights/carlight_head_light_45.geo b/app/resources/vehicles/generic_vehicle/carlights/carlight_head_light_45.geo
new file mode 100644
index 0000000..ad771e2
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/carlights/carlight_head_light_45.geo differ
diff --git a/app/resources/vehicles/generic_vehicle/carlights/carlight_reverse_44.geo b/app/resources/vehicles/generic_vehicle/carlights/carlight_reverse_44.geo
new file mode 100644
index 0000000..f987dfe
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/carlights/carlight_reverse_44.geo differ
diff --git a/app/resources/vehicles/generic_vehicle/carlights/carlight_turn_left_49.geo b/app/resources/vehicles/generic_vehicle/carlights/carlight_turn_left_49.geo
new file mode 100644
index 0000000..7da8387
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/carlights/carlight_turn_left_49.geo differ
diff --git a/app/resources/vehicles/generic_vehicle/carlights/carlight_turn_right_50.geo b/app/resources/vehicles/generic_vehicle/carlights/carlight_turn_right_50.geo
new file mode 100644
index 0000000..a5ce412
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/carlights/carlight_turn_right_50.geo differ
diff --git a/app/resources/vehicles/generic_vehicle/carlights/carlights.scn b/app/resources/vehicles/generic_vehicle/carlights/carlights.scn
new file mode 100644
index 0000000..0b4c87d
--- /dev/null
+++ b/app/resources/vehicles/generic_vehicle/carlights/carlights.scn
@@ -0,0 +1,667 @@
+{
+ "canvas": {
+ "clear_color": true,
+ "clear_z": true,
+ "color": [
+ 0,
+ 0,
+ 0,
+ 255
+ ]
+ },
+ "environment": {
+ "ambient": [
+ 0,
+ 0,
+ 0,
+ 255
+ ],
+ "brdf_map": "core/pbr/brdf.dds",
+ "current_camera": null,
+ "fog_color": [
+ 255,
+ 255,
+ 255,
+ 255
+ ],
+ "fog_far": 0.0,
+ "fog_near": 0.0,
+ "probe": {
+ "irradiance_map": "core/pbr/probe.hdr.irradiance",
+ "parallax": 0.0,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "radiance_map": "core/pbr/probe.hdr.radiance",
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "type": "sphere"
+ }
+ },
+ "key_values": null,
+ "nodes": [
+ {
+ "components": [
+ 0,
+ 4294967295,
+ 0,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 0,
+ "name": "carlight_reverse"
+ },
+ {
+ "components": [
+ 1,
+ 4294967295,
+ 1,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 1,
+ "name": "carlight_head_light"
+ },
+ {
+ "components": [
+ 2,
+ 4294967295,
+ 2,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 2,
+ "name": "carlight_day_light"
+ },
+ {
+ "components": [
+ 3,
+ 4294967295,
+ 3,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 3,
+ "name": "carlight_brake"
+ },
+ {
+ "components": [
+ 4,
+ 4294967295,
+ 4,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 4,
+ "name": "carlight_backLight"
+ },
+ {
+ "components": [
+ 5,
+ 4294967295,
+ 5,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 5,
+ "name": "carlight_turn_left"
+ },
+ {
+ "components": [
+ 6,
+ 4294967295,
+ 6,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 6,
+ "name": "carlight_turn_right"
+ }
+ ],
+ "objects": [
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "carlights"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "add",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/carlights/Car03_Lights_Emissive.hdr",
+ "stage": 0
+ },
+ {
+ "name": "uSelfMap",
+ "path": "vehicles/generic_vehicle/carlights/Car03_Lights_Emissive.hdr",
+ "stage": 4
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": false
+ }
+ ],
+ "name": "vehicles/generic_vehicle/carlights/carlight_reverse_44.geo"
+ },
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "carlights"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "add",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/carlights/Car03_Lights_Emissive.hdr",
+ "stage": 0
+ },
+ {
+ "name": "uSelfMap",
+ "path": "vehicles/generic_vehicle/carlights/Car03_Lights_Emissive.hdr",
+ "stage": 4
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": false
+ }
+ ],
+ "name": "vehicles/generic_vehicle/carlights/carlight_head_light_45.geo"
+ },
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "carlights"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "add",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/carlights/Car03_Lights_Emissive.hdr",
+ "stage": 0
+ },
+ {
+ "name": "uSelfMap",
+ "path": "vehicles/generic_vehicle/carlights/Car03_Lights_Emissive.hdr",
+ "stage": 4
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": false
+ }
+ ],
+ "name": "vehicles/generic_vehicle/carlights/carlight_day_light_46.geo"
+ },
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "carlights"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "add",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/carlights/Car03_Lights_Emissive.hdr",
+ "stage": 0
+ },
+ {
+ "name": "uSelfMap",
+ "path": "vehicles/generic_vehicle/carlights/Car03_Lights_Emissive.hdr",
+ "stage": 4
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": false
+ }
+ ],
+ "name": "vehicles/generic_vehicle/carlights/carlight_brake_47.geo"
+ },
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "carlights"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "add",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/carlights/Car03_Lights_Emissive.hdr",
+ "stage": 0
+ },
+ {
+ "name": "uSelfMap",
+ "path": "vehicles/generic_vehicle/carlights/Car03_Lights_Emissive.hdr",
+ "stage": 4
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": false
+ }
+ ],
+ "name": "vehicles/generic_vehicle/carlights/carlight_backLight_48.geo"
+ },
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "carlights"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "add",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/carlights/Car03_Lights_Emissive.hdr",
+ "stage": 0
+ },
+ {
+ "name": "uSelfMap",
+ "path": "vehicles/generic_vehicle/carlights/Car03_Lights_Emissive.hdr",
+ "stage": 4
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": false
+ }
+ ],
+ "name": "vehicles/generic_vehicle/carlights/carlight_turn_left_49.geo"
+ },
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "carlights"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "add",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/carlights/Car03_Lights_Emissive.hdr",
+ "stage": 0
+ },
+ {
+ "name": "uSelfMap",
+ "path": "vehicles/generic_vehicle/carlights/Car03_Lights_Emissive.hdr",
+ "stage": 4
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": false
+ }
+ ],
+ "name": "vehicles/generic_vehicle/carlights/carlight_turn_right_50.geo"
+ }
+ ],
+ "transforms": [
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.8885716199874878,
+ 1.7383638620376587
+ ],
+ "rot": [
+ 90.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 0.9999998807907104,
+ 0.9999998807907104
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.7301385998725891,
+ -2.1214568614959717
+ ],
+ "rot": [
+ 90.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 0.9999998807907104,
+ 0.9999998807907104
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.7210953235626221,
+ -2.153395175933838
+ ],
+ "rot": [
+ 90.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 0.9999998807907104,
+ 0.9999998807907104
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.9400854706764221,
+ 1.674100399017334
+ ],
+ "rot": [
+ 90.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 0.9999998807907104,
+ 0.9999998807907104
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.9224253296852112,
+ 1.6755602359771729
+ ],
+ "rot": [
+ 90.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 0.9999998807907104,
+ 0.9999998807907104
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ 0.6175822019577026,
+ 0.8686914443969727,
+ -0.25292491912841797
+ ],
+ "rot": [
+ 90.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 0.9999998807907104,
+ 0.9999998807907104
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ -0.6175822019577026,
+ 0.8686914443969727,
+ -0.25292491912841797
+ ],
+ "rot": [
+ 90.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 0.9999998807907104,
+ 0.9999998807907104
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/app/resources/vehicles/generic_vehicle/carlights/carlights.scn.aaa b/app/resources/vehicles/generic_vehicle/carlights/carlights.scn.aaa
new file mode 100644
index 0000000..03b674f
--- /dev/null
+++ b/app/resources/vehicles/generic_vehicle/carlights/carlights.scn.aaa
@@ -0,0 +1,12 @@
+{
+ "bloom_bias": 0.5,
+ "bloom_intensity": 0.10000000149011612,
+ "bloom_threshold": 5.0,
+ "exposure": 1.0,
+ "gamma": 2.200000047683716,
+ "max_distance": 100.0,
+ "motion_blur": 1.0,
+ "sample_count": 2,
+ "taa_weight": 0.10000000149011612,
+ "z_thickness": 0.10000000149011612
+}
\ No newline at end of file
diff --git a/app/resources/vehicles/generic_vehicle/carlights/carlights.scn.editor b/app/resources/vehicles/generic_vehicle/carlights/carlights.scn.editor
new file mode 100644
index 0000000..fee2444
--- /dev/null
+++ b/app/resources/vehicles/generic_vehicle/carlights/carlights.scn.editor
@@ -0,0 +1,183 @@
+{
+ "editor": {
+ "animeditor_plugin": {
+ "quantize_time": true,
+ "show_trajectories": null,
+ "trajectories_tick_seconds": 1.0,
+ "trajectories_tick_size": 0.10000000149011612
+ },
+ "explorer": {
+ "node_custom_order": {
+ "refs": null,
+ "roots": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6
+ ]
+ },
+ "node_sort_method": "custom",
+ "show_node_uid": false
+ },
+ "grid_plugin": {
+ "enabled": true,
+ "grid_color_b": 1.0,
+ "grid_color_g": 1.0,
+ "grid_color_r": 1.0,
+ "n_subdivs": 10,
+ "offset": 0.0,
+ "opacity": 0.5,
+ "subdiv_size": 1.0
+ },
+ "navigation_plugin": {
+ "orbit_distance": 2.2876787185668945,
+ "speed": 0.10000000149011612,
+ "turbo": 1.0
+ },
+ "transform_gizmo_plugin": {
+ "mode": "local",
+ "snap": "none",
+ "snap_rotation": 5.0,
+ "snap_rotation_fine": 1.0,
+ "snap_scale": 10.0,
+ "snap_scale_fine": 1.0,
+ "snap_translation": 1.0,
+ "snap_translation_fine": 0.10000000149011612,
+ "tool": "move"
+ },
+ "view_plugin": {
+ "show_cameras": true,
+ "show_collisions": false,
+ "show_lights": true,
+ "show_nodes": true,
+ "show_probe": true
+ },
+ "views": {
+ "back": [
+ -0.9999999403953552,
+ 0.0,
+ -8.742277657347586e-08,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 8.742277657347586e-08,
+ -0.0,
+ -0.9999999403953552,
+ 0.0
+ ],
+ "bottom": [
+ 1.0,
+ -0.0,
+ -0.0,
+ 0.0,
+ -0.0,
+ -8.742277657347586e-08,
+ 0.9999999403953552,
+ 0.0,
+ -0.0,
+ -0.9999999403953552,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "bottom_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "current_camera": 0,
+ "front": [
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0
+ ],
+ "left": [
+ -8.742277657347586e-08,
+ 0.0,
+ 0.9999999403953552,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ -0.9999999403953552,
+ 0.0,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "left_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "orthographic_size": 1.0,
+ "perspective": [
+ -0.7759953737258911,
+ -0.2158089280128479,
+ -0.5926706194877625,
+ 0.9999239444732666,
+ 0.0,
+ 0.9396447539329529,
+ -0.3421517014503479,
+ 1.0851624011993408,
+ 0.6307393908500671,
+ -0.2655084431171417,
+ -0.7291604280471802,
+ 2.2410531044006348
+ ],
+ "perspective_fov": 0.7853981852531433,
+ "perspective_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "right": [
+ -8.742277657347586e-08,
+ 0.0,
+ -0.9999999403953552,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 0.9999999403953552,
+ -0.0,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "right_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "scale": 0.05000000074505806,
+ "top": [
+ 1.0,
+ 0.0,
+ -0.0,
+ 0.0,
+ -0.0,
+ -8.742277657347586e-08,
+ -0.9999999403953552,
+ 0.0,
+ 0.0,
+ 0.9999999403953552,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "top_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/resources/vehicles/generic_vehicle/carlights/fbx_importer_cfg.txt b/app/resources/vehicles/generic_vehicle/carlights/fbx_importer_cfg.txt
new file mode 100644
index 0000000..984ac65
--- /dev/null
+++ b/app/resources/vehicles/generic_vehicle/carlights/fbx_importer_cfg.txt
@@ -0,0 +1,23 @@
+"anim_policy":"1"
+"anim_simplify_color_tolerance":"0.001000"
+"anim_simplify_rotation_tolerance":"0.100000"
+"anim_simplify_scale_tolerance":"0.001000"
+"anim_simplify_translation_tolerance":"0.001000"
+"detect_geometry_instances":"1"
+"fbx_file_path":"d:/projects/carsim/work/model/carlights.fbx"
+"finalizer_script":""
+"fix_geometry_orientation":"0"
+"frames_per_second":"24"
+"geometry_policy":"1"
+"geometry_scale":"1.000000"
+"import_animations":"1"
+"material_policy":"1"
+"max_smoothing_angle":"45.000000"
+"output_folder":"vehicles/generic_vehicle/carlights"
+"profile":"1"
+"recalculate_normals":"0"
+"recalculate_tangents":"0"
+"scale":"1.000000"
+"scene_policy":"1"
+"texture_policy":"1"
+"use_finalizer_script":"0"
diff --git a/app/resources/vehicles/generic_vehicle/drivable_car.scn b/app/resources/vehicles/generic_vehicle/drivable_car.scn
new file mode 100644
index 0000000..0277cb7
--- /dev/null
+++ b/app/resources/vehicles/generic_vehicle/drivable_car.scn
@@ -0,0 +1,1895 @@
+{
+ "cameras": [
+ {
+ "fov": 0.8883586525917053,
+ "ortho": false,
+ "size": 1.0,
+ "zrange": {
+ "zfar": 1000.0,
+ "znear": 0.30000001192092896
+ }
+ },
+ {
+ "fov": 0.8883586525917053,
+ "ortho": false,
+ "size": 1.0,
+ "zrange": {
+ "zfar": 1000.0,
+ "znear": 0.5
+ }
+ }
+ ],
+ "canvas": {
+ "clear_color": true,
+ "clear_z": true,
+ "color": [
+ 148,
+ 223,
+ 255,
+ 255
+ ]
+ },
+ "collisions": [
+ {
+ "mass": 250.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.22499999403953552
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.7999999523162842,
+ 0.20000000298023224,
+ 1.7999999523162842
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 125.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ 0.0,
+ 2.049999952316284
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.7000000476837158,
+ 0.20000000298023224,
+ 0.25
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 125.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ 0.0,
+ -1.5499999523162842
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.7000000476837158,
+ 0.20000000298023224,
+ 0.15000000596046448
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 250.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ 0.20000000298023224,
+ 2.0999999046325684
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 1.5707963705062866
+ ],
+ "scl": [
+ 0.3499999940395355,
+ 0.949999988079071,
+ 1.0
+ ],
+ "type": "capsule"
+ },
+ {
+ "mass": 125.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ 0.20000000298023224,
+ -1.5499999523162842
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 1.5707963705062866
+ ],
+ "scl": [
+ 0.30000001192092896,
+ 1.2000000476837158,
+ 1.0
+ ],
+ "type": "capsule"
+ },
+ {
+ "mass": 25.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ 1.0750000476837158,
+ -0.5
+ ],
+ "rot": [
+ -0.04363323003053665,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.2000000476837158,
+ 0.10000000149011612,
+ 1.600000023841858
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 25.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ 0.9150000214576721,
+ 0.699999988079071
+ ],
+ "rot": [
+ 0.4363323152065277,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.2000000476837158,
+ 0.10000000149011612,
+ 1.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 25.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ 0.8500000238418579,
+ -1.4500000476837158
+ ],
+ "rot": [
+ -0.7853981852531433,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.2000000476837158,
+ 0.10000000149011612,
+ 0.550000011920929
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 50.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ 0.5199999809265137,
+ -1.5499999523162842
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 1.5707963705062866
+ ],
+ "scl": [
+ 0.25,
+ 1.0,
+ 1.0
+ ],
+ "type": "capsule"
+ },
+ {
+ "mass": 125.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ 0.5849999785423279,
+ 1.649999976158142
+ ],
+ "rot": [
+ 0.1745329201221466,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.350000023841858,
+ 0.10000000149011612,
+ 1.0
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 50.0,
+ "path": "",
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.20000000298023224
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 0.20000000298023224,
+ 3.5
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 50.0,
+ "path": "",
+ "pos": [
+ 0.75,
+ 0.4000000059604645,
+ 0.20000000298023224
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.13962633907794952
+ ],
+ "scl": [
+ 0.20000000298023224,
+ 0.699999988079071,
+ 1.7999999523162842
+ ],
+ "type": "cube"
+ },
+ {
+ "mass": 50.0,
+ "path": "",
+ "pos": [
+ -0.75,
+ 0.4000000059604645,
+ 0.20000000298023224
+ ],
+ "rot": [
+ 0.0,
+ 0.0,
+ -0.13962633907794952
+ ],
+ "scl": [
+ 0.20000000298023224,
+ 0.699999988079071,
+ 1.7999999523162842
+ ],
+ "type": "cube"
+ }
+ ],
+ "environment": {
+ "ambient": [
+ 0,
+ 0,
+ 0,
+ 255
+ ],
+ "brdf_map": "core/pbr/brdf.dds",
+ "current_camera": 10,
+ "fog_color": [
+ 255,
+ 255,
+ 255,
+ 255
+ ],
+ "fog_far": 0.0,
+ "fog_near": 0.0,
+ "probe": {
+ "irradiance_map": "core/pbr/probe.hdr.irradiance",
+ "parallax": 0.0,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "radiance_map": "core/pbr/probe.hdr.radiance",
+ "rot": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "type": "sphere"
+ }
+ },
+ "instances": [
+ {
+ "name": "vehicles/generic_vehicle/carlights/carlights.scn"
+ }
+ ],
+ "key_values": null,
+ "lights": [
+ {
+ "diffuse": [
+ 255,
+ 255,
+ 255,
+ 255
+ ],
+ "diffuse_intensity": 10.0,
+ "inner_angle": 0.1745329201221466,
+ "outer_angle": 0.2617993950843811,
+ "priority": 1.0,
+ "pssm_split": [
+ 10.0,
+ 50.0,
+ 100.0,
+ 200.0
+ ],
+ "radius": 0.0,
+ "shadow_bias": 9.999999747378752e-05,
+ "shadow_type": "map",
+ "specular": [
+ 255,
+ 255,
+ 255,
+ 255
+ ],
+ "specular_intensity": 10.0,
+ "type": "spot"
+ }
+ ],
+ "nodes": [
+ {
+ "collisions": [
+ {
+ "idx": 0
+ },
+ {
+ "idx": 1
+ },
+ {
+ "idx": 2
+ },
+ {
+ "idx": 3
+ },
+ {
+ "idx": 4
+ },
+ {
+ "idx": 5
+ },
+ {
+ "idx": 6
+ },
+ {
+ "idx": 7
+ },
+ {
+ "idx": 8
+ },
+ {
+ "idx": 9
+ },
+ {
+ "idx": 10
+ },
+ {
+ "idx": 11
+ },
+ {
+ "idx": 12
+ }
+ ],
+ "components": [
+ 0,
+ 4294967295,
+ 0,
+ 4294967295,
+ 0
+ ],
+ "disabled": false,
+ "idx": 0,
+ "name": "car_body"
+ },
+ {
+ "components": [
+ 1,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 1,
+ "name": "steering_wheel_pivot"
+ },
+ {
+ "components": [
+ 2,
+ 4294967295,
+ 1,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 2,
+ "name": "steering_wheel"
+ },
+ {
+ "components": [
+ 3,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 3,
+ "name": "thrust"
+ },
+ {
+ "components": [
+ 4,
+ 4294967295,
+ 2,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 4,
+ "name": "wheel_0"
+ },
+ {
+ "components": [
+ 5,
+ 4294967295,
+ 3,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 5,
+ "name": "wheel_1"
+ },
+ {
+ "components": [
+ 6,
+ 4294967295,
+ 4,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 6,
+ "name": "wheel_2"
+ },
+ {
+ "components": [
+ 7,
+ 4294967295,
+ 5,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 7,
+ "name": "wheel_3"
+ },
+ {
+ "components": [
+ 8,
+ 4294967295,
+ 6,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 8,
+ "name": "wiper_0"
+ },
+ {
+ "components": [
+ 9,
+ 4294967295,
+ 7,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 9,
+ "name": "wiper_1"
+ },
+ {
+ "components": [
+ 11,
+ 0,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 10,
+ "name": "camera_interior"
+ },
+ {
+ "components": [
+ 10,
+ 4294967295,
+ 4294967295,
+ 0,
+ 4294967295
+ ],
+ "disabled": true,
+ "idx": 11,
+ "name": "Light"
+ },
+ {
+ "components": [
+ 12,
+ 4294967295,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 12,
+ "instance": 0,
+ "name": "carlights"
+ },
+ {
+ "components": [
+ 13,
+ 1,
+ 4294967295,
+ 4294967295,
+ 4294967295
+ ],
+ "disabled": false,
+ "idx": 13,
+ "name": "camera_exterior_rear"
+ }
+ ],
+ "objects": [
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "Car03_Body_Mat01"
+ },
+ {
+ "name": "Car03_Parts_Mat01"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_pack_albedo.png",
+ "stage": 0
+ },
+ {
+ "name": "uNormalMap",
+ "path": "vehicles/generic_vehicle/Car03_pack_normal.png",
+ "stage": 2
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "vehicles/generic_vehicle/Car03_pack_ORM.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.75,
+ 0.75,
+ 0.75,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.10000000149011612,
+ 1.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "alpha",
+ "depth_test": "less",
+ "face_culling": "disabled",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.1411764770746231,
+ 0.1764705926179886,
+ 0.24705883860588074,
+ 0.3720000088214874
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.17800000309944153,
+ 1.0,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ }
+ ],
+ "name": "vehicles/generic_vehicle/car_body_44.geo"
+ },
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "Car03_Body_Mat01"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_pack_albedo.png",
+ "stage": 0
+ },
+ {
+ "name": "uNormalMap",
+ "path": "vehicles/generic_vehicle/Car03_pack_normal.png",
+ "stage": 2
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "vehicles/generic_vehicle/Car03_pack_ORM.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.75,
+ 0.75,
+ 0.75,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.10000000149011612,
+ 1.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ }
+ ],
+ "name": "vehicles/generic_vehicle/steering_wheel_56.geo"
+ },
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "Car03_Wheel_Mat01"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_Wheel_Albedo01.png",
+ "stage": 0
+ },
+ {
+ "name": "uNormalMap",
+ "path": "vehicles/generic_vehicle/Car03_Wheel_Normal.png",
+ "stage": 2
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "vehicles/generic_vehicle/Car03_Wheel_ORM.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ }
+ ],
+ "name": "vehicles/generic_vehicle/wheel_0_51.geo"
+ },
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "Car03_Wheel_Mat01"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_Wheel_Albedo01.png",
+ "stage": 0
+ },
+ {
+ "name": "uNormalMap",
+ "path": "vehicles/generic_vehicle/Car03_Wheel_Normal.png",
+ "stage": 2
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "vehicles/generic_vehicle/Car03_Wheel_ORM.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ }
+ ],
+ "name": "vehicles/generic_vehicle/wheel_1_52.geo"
+ },
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "Car03_Wheel_Mat01"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_Wheel_Albedo01.png",
+ "stage": 0
+ },
+ {
+ "name": "uNormalMap",
+ "path": "vehicles/generic_vehicle/Car03_Wheel_Normal.png",
+ "stage": 2
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "vehicles/generic_vehicle/Car03_Wheel_ORM.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ }
+ ],
+ "name": "vehicles/generic_vehicle/wheel_2_53.geo"
+ },
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "Car03_Wheel_Mat01"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_Wheel_Albedo01.png",
+ "stage": 0
+ },
+ {
+ "name": "uNormalMap",
+ "path": "vehicles/generic_vehicle/Car03_Wheel_Normal.png",
+ "stage": 2
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "vehicles/generic_vehicle/Car03_Wheel_ORM.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 0.5882353186607361,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ }
+ ],
+ "name": "vehicles/generic_vehicle/wheel_3_54.geo"
+ },
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "Car03_Body_Mat01"
+ },
+ {
+ "name": "Car03_Parts_Mat01"
+ },
+ {
+ "name": "Car03_Interior_Mat01"
+ },
+ {
+ "name": "Car03_Grill_Mat01"
+ },
+ {
+ "name": "Car03_Glass_Mat"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.7372549176216125,
+ 0.7372549176216125,
+ 0.7372549176216125,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_Parts_Albedo01.png",
+ "stage": 0
+ },
+ {
+ "name": "uNormalMap",
+ "path": "vehicles/generic_vehicle/Car03_Parts_Normal.tga",
+ "stage": 2
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "vehicles/generic_vehicle/Car03_Parts_Albedo01.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.43529415130615234,
+ 0.43529415130615234,
+ 0.43529415130615234,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_Interior_Albedo01.png",
+ "stage": 0
+ },
+ {
+ "name": "uNormalMap",
+ "path": "vehicles/generic_vehicle/Car03_Interior_Normal.tga",
+ "stage": 2
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.6039215922355652,
+ 0.6039215922355652,
+ 0.6039215922355652,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_Grill_AO.tga",
+ "stage": 0
+ },
+ {
+ "name": "uNormalMap",
+ "path": "vehicles/generic_vehicle/Car03_Grill_Normal.tga",
+ "stage": 2
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.007843137718737125,
+ 0.007843137718737125,
+ 0.007843137718737125,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.1411764770746231,
+ 0.1764705926179886,
+ 0.24705883860588074,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ }
+ ],
+ "name": "vehicles/generic_vehicle/wiper_0_55.geo"
+ },
+ {
+ "bones": [],
+ "material_infos": [
+ {
+ "name": "Car03_Body_Mat01"
+ },
+ {
+ "name": "Car03_Parts_Mat01"
+ },
+ {
+ "name": "Car03_Interior_Mat01"
+ },
+ {
+ "name": "Car03_Grill_Mat01"
+ },
+ {
+ "name": "Car03_Glass_Mat"
+ }
+ ],
+ "materials": [
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.7372549176216125,
+ 0.7372549176216125,
+ 0.7372549176216125,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_Parts_Albedo01.png",
+ "stage": 0
+ },
+ {
+ "name": "uNormalMap",
+ "path": "vehicles/generic_vehicle/Car03_Parts_Normal.tga",
+ "stage": 2
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessMap",
+ "path": "vehicles/generic_vehicle/Car03_Parts_Albedo01.png",
+ "stage": 1
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.43529415130615234,
+ 0.43529415130615234,
+ 0.43529415130615234,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_Interior_Albedo01.png",
+ "stage": 0
+ },
+ {
+ "name": "uNormalMap",
+ "path": "vehicles/generic_vehicle/Car03_Interior_Normal.tga",
+ "stage": 2
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.6039215922355652,
+ 0.6039215922355652,
+ 0.6039215922355652,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "textures": [
+ {
+ "name": "uBaseOpacityMap",
+ "path": "vehicles/generic_vehicle/Car03_Grill_AO.tga",
+ "stage": 0
+ },
+ {
+ "name": "uNormalMap",
+ "path": "vehicles/generic_vehicle/Car03_Grill_Normal.tga",
+ "stage": 2
+ }
+ ],
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.007843137718737125,
+ 0.007843137718737125,
+ 0.007843137718737125,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ },
+ {
+ "blend_mode": "opaque",
+ "depth_test": "less",
+ "face_culling": "cw",
+ "flags": [],
+ "program": "core/shader/pbr.hps",
+ "values": [
+ {
+ "name": "uBaseOpacityColor",
+ "type": "vec4",
+ "value": [
+ 0.1411764770746231,
+ 0.1764705926179886,
+ 0.24705883860588074,
+ 1.0
+ ]
+ },
+ {
+ "name": "uOcclusionRoughnessMetalnessColor",
+ "type": "vec4",
+ "value": [
+ 1.0,
+ 0.5,
+ 0.25,
+ 0.0
+ ]
+ },
+ {
+ "name": "uSelfColor",
+ "type": "vec4",
+ "value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0
+ ]
+ }
+ ],
+ "write_a": true,
+ "write_b": true,
+ "write_g": true,
+ "write_r": true,
+ "write_z": true
+ }
+ ],
+ "name": "vehicles/generic_vehicle/wiper_1_56.geo"
+ }
+ ],
+ "rigid_bodies": [
+ {
+ "angular_damping": 0.0,
+ "friction": 0.49803924560546875,
+ "linear_damping": 0.0,
+ "restitution": 0.0,
+ "rolling_friction": 0.0,
+ "type": "dynamic"
+ }
+ ],
+ "transforms": [
+ {
+ "parent": null,
+ "pos": [
+ 0.0,
+ 0.31996679306030273,
+ -1.3986192648474116e-08
+ ],
+ "rot": [
+ -7.0167078561561656e-15,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": 0,
+ "pos": [
+ -0.39944934844970703,
+ 0.6040751934051514,
+ 0.526599645614624
+ ],
+ "rot": [
+ 69.99999237060547,
+ 180.0,
+ 180.0
+ ],
+ "scl": [
+ 1.0,
+ 0.9999999403953552,
+ 0.9999999403953552
+ ]
+ },
+ {
+ "parent": 1,
+ "pos": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "rot": [
+ -1.2195682525634766,
+ -180.0,
+ -2.2316842660075054e-05
+ ],
+ "scl": [
+ 1.0,
+ 1.0000004768371582,
+ 1.0000004768371582
+ ]
+ },
+ {
+ "parent": 0,
+ "pos": [
+ 0.0,
+ 0.02603328227996826,
+ -1.1022948026657104
+ ],
+ "rot": [
+ -9.334663445770275e-06,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": 0,
+ "pos": [
+ -0.7600023746490479,
+ 0.026033222675323486,
+ 1.549896478652954
+ ],
+ "rot": [
+ -0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": 0,
+ "pos": [
+ 0.7600018978118896,
+ 0.026032984256744385,
+ 1.549896478652954
+ ],
+ "rot": [
+ -0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": 0,
+ "pos": [
+ 0.7600023746490479,
+ -0.05000000074505806,
+ -1.102294683456421
+ ],
+ "rot": [
+ -0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": 0,
+ "pos": [
+ -0.7600018978118896,
+ -0.05000000074505806,
+ -1.102295160293579
+ ],
+ "rot": [
+ -0.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": 0,
+ "pos": [
+ -0.641943633556366,
+ 0.6765738725662231,
+ 1.1661123037338257
+ ],
+ "rot": [
+ -52.89224624633789,
+ -24.409929275512695,
+ 1.8647468090057373
+ ],
+ "scl": [
+ 1.0000004768371582,
+ 0.9999995231628418,
+ 0.9999998211860657
+ ]
+ },
+ {
+ "parent": 0,
+ "pos": [
+ -0.11100274324417114,
+ 0.6827141046524048,
+ 1.2891757488250732
+ ],
+ "rot": [
+ -59.218345642089844,
+ 3.5092766284942627,
+ -20.389284133911133
+ ],
+ "scl": [
+ 1.0,
+ 0.9999995231628418,
+ 0.9999997615814209
+ ]
+ },
+ {
+ "parent": null,
+ "pos": [
+ -2.2742974758148193,
+ 4.887114524841309,
+ 2.2901885509490967
+ ],
+ "rot": [
+ 53.091861724853516,
+ 124.34111785888672,
+ 130.51171875
+ ],
+ "scl": [
+ 0.9999994039535522,
+ 0.999999463558197,
+ 0.999999463558197
+ ]
+ },
+ {
+ "parent": 0,
+ "pos": [
+ -0.33685609698295593,
+ 0.8500000238418579,
+ 1.3986192648474116e-08
+ ],
+ "rot": [
+ 1.9999992847442627,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "parent": 0,
+ "pos": [
+ 0.0,
+ -0.3199999928474426,
+ -2.6796326919960666e-20
+ ],
+ "rot": [
+ 7.016710820771481e-15,
+ -179.99989318847656,
+ 0.0
+ ],
+ "scl": [
+ 0.9999997615814209,
+ 1.0,
+ 0.9999997615814209
+ ]
+ },
+ {
+ "parent": 0,
+ "pos": [
+ 0.0,
+ 4.0,
+ -6.0
+ ],
+ "rot": [
+ 30.0,
+ 0.0,
+ 0.0
+ ],
+ "scl": [
+ 1.0,
+ 0.9999998807907104,
+ 0.9999998807907104
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/app/resources/vehicles/generic_vehicle/drivable_car.scn.aaa b/app/resources/vehicles/generic_vehicle/drivable_car.scn.aaa
new file mode 100644
index 0000000..03b674f
--- /dev/null
+++ b/app/resources/vehicles/generic_vehicle/drivable_car.scn.aaa
@@ -0,0 +1,12 @@
+{
+ "bloom_bias": 0.5,
+ "bloom_intensity": 0.10000000149011612,
+ "bloom_threshold": 5.0,
+ "exposure": 1.0,
+ "gamma": 2.200000047683716,
+ "max_distance": 100.0,
+ "motion_blur": 1.0,
+ "sample_count": 2,
+ "taa_weight": 0.10000000149011612,
+ "z_thickness": 0.10000000149011612
+}
\ No newline at end of file
diff --git a/app/resources/vehicles/generic_vehicle/drivable_car.scn.editor b/app/resources/vehicles/generic_vehicle/drivable_car.scn.editor
new file mode 100644
index 0000000..3d1ff8d
--- /dev/null
+++ b/app/resources/vehicles/generic_vehicle/drivable_car.scn.editor
@@ -0,0 +1,201 @@
+{
+ "editor": {
+ "animeditor_plugin": {
+ "quantize_time": true,
+ "show_trajectories": null,
+ "trajectories_tick_seconds": 1.0,
+ "trajectories_tick_size": 0.10000000149011612
+ },
+ "explorer": {
+ "node_custom_order": {
+ "refs": [
+ {
+ "children": [
+ 1,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 12,
+ 10,
+ 13
+ ],
+ "ref": 0
+ },
+ {
+ "children": [
+ 2
+ ],
+ "ref": 1
+ }
+ ],
+ "roots": [
+ 0,
+ 11
+ ]
+ },
+ "node_sort_method": "custom",
+ "show_node_uid": false
+ },
+ "grid_plugin": {
+ "enabled": true,
+ "grid_color_b": 1.0,
+ "grid_color_g": 1.0,
+ "grid_color_r": 1.0,
+ "n_subdivs": 10,
+ "offset": 0.0,
+ "opacity": 0.5,
+ "subdiv_size": 1.0
+ },
+ "navigation_plugin": {
+ "orbit_distance": 0.7504730224609375,
+ "speed": 0.10000000149011612,
+ "turbo": 1.0
+ },
+ "transform_gizmo_plugin": {
+ "mode": "global",
+ "snap": "none",
+ "snap_rotation": 5.0,
+ "snap_rotation_fine": 1.0,
+ "snap_scale": 10.0,
+ "snap_scale_fine": 1.0,
+ "snap_translation": 1.0,
+ "snap_translation_fine": 0.10000000149011612,
+ "tool": "move"
+ },
+ "view_plugin": {
+ "show_cameras": true,
+ "show_collisions": true,
+ "show_lights": true,
+ "show_nodes": true,
+ "show_probe": true
+ },
+ "views": {
+ "back": [
+ -0.9999999403953552,
+ 0.0,
+ -8.742277657347586e-08,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 8.742277657347586e-08,
+ -0.0,
+ -0.9999999403953552,
+ 0.0
+ ],
+ "bottom": [
+ 1.0,
+ -0.0,
+ -0.0,
+ 0.0,
+ -0.0,
+ -8.742277657347586e-08,
+ 0.9999999403953552,
+ 0.0,
+ -0.0,
+ -0.9999999403953552,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "bottom_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "current_camera": 7,
+ "front": [
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0
+ ],
+ "left": [
+ -8.742277657347586e-08,
+ 0.0,
+ 0.9999999403953552,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ -0.9999999403953552,
+ 0.0,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "left_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "orthographic_size": 1.0,
+ "perspective": [
+ 0.9637460708618164,
+ -0.07485629618167877,
+ -0.2562549114227295,
+ 0.29608088731765747,
+ 0.0,
+ 0.9599119424819946,
+ -0.280399888753891,
+ 1.2031794786453247,
+ 0.266948401927948,
+ 0.2702454924583435,
+ 0.9251277446746826,
+ 0.09421604871749878
+ ],
+ "perspective_fov": 0.7853981852531433,
+ "perspective_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "right": [
+ -8.742277657347586e-08,
+ 0.0,
+ -0.9999999403953552,
+ 0.0,
+ 0.0,
+ 1.0,
+ -0.0,
+ 0.0,
+ 0.9999999403953552,
+ -0.0,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "right_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ },
+ "scale": 0.05000000074505806,
+ "top": [
+ 1.0,
+ 0.0,
+ -0.0,
+ 0.0,
+ -0.0,
+ -8.742277657347586e-08,
+ -0.9999999403953552,
+ 0.0,
+ 0.0,
+ 0.9999999403953552,
+ -8.742277657347586e-08,
+ 0.0
+ ],
+ "top_zrange": {
+ "zfar": 1000.0,
+ "znear": 0.009999999776482582
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/resources/vehicles/generic_vehicle/fbx_importer_cfg.txt b/app/resources/vehicles/generic_vehicle/fbx_importer_cfg.txt
new file mode 100644
index 0000000..f40b41b
--- /dev/null
+++ b/app/resources/vehicles/generic_vehicle/fbx_importer_cfg.txt
@@ -0,0 +1,23 @@
+"anim_policy":"1"
+"anim_simplify_color_tolerance":"0.001000"
+"anim_simplify_rotation_tolerance":"0.100000"
+"anim_simplify_scale_tolerance":"0.001000"
+"anim_simplify_translation_tolerance":"0.001000"
+"detect_geometry_instances":"1"
+"fbx_file_path":"d:/projects/carsim/work/model/drivable_car.fbx"
+"finalizer_script":""
+"fix_geometry_orientation":"1"
+"frames_per_second":"24"
+"geometry_policy":"1"
+"geometry_scale":"1.000000"
+"import_animations":"1"
+"material_policy":"1"
+"max_smoothing_angle":"45.000000"
+"output_folder":"vehicles/generic_vehicle"
+"profile":"1"
+"recalculate_normals":"0"
+"recalculate_tangents":"0"
+"scale":"1.000000"
+"scene_policy":"1"
+"texture_policy":"1"
+"use_finalizer_script":"0"
diff --git a/app/resources/vehicles/generic_vehicle/steering_wheel_56.geo b/app/resources/vehicles/generic_vehicle/steering_wheel_56.geo
new file mode 100644
index 0000000..88fadfa
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/steering_wheel_56.geo differ
diff --git a/app/resources/vehicles/generic_vehicle/wheel_0_51.geo b/app/resources/vehicles/generic_vehicle/wheel_0_51.geo
new file mode 100644
index 0000000..d1cb462
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/wheel_0_51.geo differ
diff --git a/app/resources/vehicles/generic_vehicle/wheel_1_52.geo b/app/resources/vehicles/generic_vehicle/wheel_1_52.geo
new file mode 100644
index 0000000..96f4e2d
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/wheel_1_52.geo differ
diff --git a/app/resources/vehicles/generic_vehicle/wheel_2_53.geo b/app/resources/vehicles/generic_vehicle/wheel_2_53.geo
new file mode 100644
index 0000000..ee68e01
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/wheel_2_53.geo differ
diff --git a/app/resources/vehicles/generic_vehicle/wheel_3_54.geo b/app/resources/vehicles/generic_vehicle/wheel_3_54.geo
new file mode 100644
index 0000000..c9ee64e
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/wheel_3_54.geo differ
diff --git a/app/resources/vehicles/generic_vehicle/wiper_0_55.geo b/app/resources/vehicles/generic_vehicle/wiper_0_55.geo
new file mode 100644
index 0000000..9f7685f
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/wiper_0_55.geo differ
diff --git a/app/resources/vehicles/generic_vehicle/wiper_1_56.geo b/app/resources/vehicles/generic_vehicle/wiper_1_56.geo
new file mode 100644
index 0000000..519c7d9
Binary files /dev/null and b/app/resources/vehicles/generic_vehicle/wiper_1_56.geo differ
diff --git a/app/template_physics.physics b/app/template_physics.physics
new file mode 100644
index 0000000..21c5d51
--- /dev/null
+++ b/app/template_physics.physics
@@ -0,0 +1 @@
+{"collision":{"input":[{"geometry":"GEOMETRY_PATH","matrix":[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],"type":"triangle"}],"type":"tree"}}
\ No newline at end of file
diff --git a/app/utils.py b/app/utils.py
new file mode 100644
index 0000000..3835645
--- /dev/null
+++ b/app/utils.py
@@ -0,0 +1,18 @@
+def clamp(val, low1, high1):
+ return min(max(val, low1), high1)
+
+def range_adjust(val, low1, high1, low2, high2):
+ return low2 + (val - low1) * (high2 - low2) / (high1 - low1)
+
+def EaseInOutQuick(x):
+ x = clamp(x, 0.0, 1.0)
+ return (x * x * (3 - 2 * x))
+
+def Map(value, min1, max1, min2, max2):
+ return min2 + (value - min1) * (max2 - min2) / (max1 - min1)
+
+def metersPerSecondToKMH(meterspersecond):
+ return meterspersecond * 3.6 # * 3600 to get the time in hours / 1000 to get in kilometers
+
+def KMHtoMPS(kmh):
+ return kmh / 3.6
\ No newline at end of file
diff --git a/img/generic_car_20221002110516.png b/img/generic_car_20221002110516.png
new file mode 100644
index 0000000..4ea4102
Binary files /dev/null and b/img/generic_car_20221002110516.png differ
diff --git a/img/generic_car_20221002110523.png b/img/generic_car_20221002110523.png
new file mode 100644
index 0000000..48d4270
Binary files /dev/null and b/img/generic_car_20221002110523.png differ
diff --git a/img/generic_car_20221002110544.png b/img/generic_car_20221002110544.png
new file mode 100644
index 0000000..7384116
Binary files /dev/null and b/img/generic_car_20221002110544.png differ