commit d723f0896980f2415824a6ea6317d74d8bef4f59 Author: dox Date: Sat Feb 11 23:18:45 2023 -0500 first commit diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..38cef35 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,51 @@ +cmake_minimum_required(VERSION 3.10) + +project(orbit-plus C) + +set_target_properties(PROPERTIES LINKER_LANGUAGE C) + +include_directories(include) +include_directories(${GLEW_INCLUDE_DIRS}) + +file(GLOB src + "${PROJECT_SOURCE_DIR}/src/*.c" + "${PROJECT_SOURCE_DIR}/src/engine/*.c" + "${PROJECT_SOURCE_DIR}/src/game/*.c" + "${PROJECT_SOURCE_DIR}/src/game/ecs/*.c" + "${PROJECT_SOURCE_DIR}/src/game/state/*.c" + "${PROJECT_SOURCE_DIR}/src/game/shader/*.c" + "${PROJECT_SOURCE_DIR}/src/util/*.c" +) + +add_executable(${PROJECT_NAME} ${src}) + +find_package(SDL2 REQUIRED) +find_package(SDL2_mixer REQUIRED) +find_package(SDL2_ttf REQUIRED) +find_package(SDL2_image REQUIRED) +find_package(GLEW REQUIRED) + +if (EMSCRIPTEN) + +else() + if (CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_C_FLAGS "-O2 -Wno-discarded-qualifiers -Wno-pointer-arith -Wno-unused-variable -Wno-unused-parameter -Wall -Wextra -pedantic -g") + endif() + + if (CMAKE_BUILD_TYPE STREQUAL "Release") + set(CMAKE_C_FLAGS "-O2") + endif() + + target_link_libraries(${PROJECT_NAME} m GL SDL2::SDL2 SDL2_mixer::SDL2_mixer SDL2_ttf::SDL2_ttf SDL2_image::SDL2_image GLEW::GLEW) + + if (WIN32) + set(CMAKE_C_FLAGS "-mwindows ${CMAKE_C_FLAGS}") + target_link_libraries(${PROJECT_NAME} mingw32 m GL SDL2::SDL2 SDL2_mixer::SDL2_mixer SDL2_ttf::SDL2_ttf SDL2_image::SDL2_image GLEW::GLEW) + endif() +endif() + +message("System: ${CMAKE_SYSTEM_NAME}") +message("Project: ${PROJECT_NAME}") +message("Build: ${CMAKE_BUILD_TYPE}") +message("Flags: ${CMAKE_C_FLAGS}") + diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..fe2fe8a --- /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/README.md b/README.md new file mode 100644 index 0000000..f8d0d6d --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# Orbit+ + +A clone of the 2007 Adobe Flash game by Jacob Grahn ("Jiggmin"), using OpenGL and SDL. + +## Build + +### Dependencies + + - SDL2 + - SDL_image + - SDL_mixer + - SDL_ttf + +### Linux/MinGW + +This repository uses CMake to compile, so: + +`mkdir build` +`cd build` +`cmake .. +`make` + +Make sure you've got the games's resources downloaded and in the same directory as the executable. You can get that [here](https://shweetz.net/download/games/orbit-plus-resources.7z). diff --git a/include/cglm/affine-mat.h b/include/cglm/affine-mat.h new file mode 100644 index 0000000..75607e7 --- /dev/null +++ b/include/cglm/affine-mat.h @@ -0,0 +1,178 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_mul(mat4 m1, mat4 m2, mat4 dest); + CGLM_INLINE void glm_inv_tr(mat4 mat); + */ + +#ifndef cglm_affine_mat_h +#define cglm_affine_mat_h + +#include "common.h" +#include "mat4.h" +#include "mat3.h" + +#ifdef CGLM_SSE_FP +# include "simd/sse2/affine.h" +#endif + +#ifdef CGLM_AVX_FP +# include "simd/avx/affine.h" +#endif + +#ifdef CGLM_NEON_FP +# include "simd/neon/affine.h" +#endif + +/*! + * @brief this is similar to glm_mat4_mul but specialized to affine transform + * + * Matrix format should be: + * R R R X + * R R R Y + * R R R Z + * 0 0 0 W + * + * this reduces some multiplications. It should be faster than mat4_mul. + * if you are not sure about matrix format then DON'T use this! use mat4_mul + * + * @param[in] m1 affine matrix 1 + * @param[in] m2 affine matrix 2 + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_mul(mat4 m1, mat4 m2, mat4 dest) { +#ifdef __AVX__ + glm_mul_avx(m1, m2, dest); +#elif defined( __SSE__ ) || defined( __SSE2__ ) + glm_mul_sse2(m1, m2, dest); +#elif defined(CGLM_NEON_FP) + glm_mul_neon(m1, m2, dest); +#else + float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3], + a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3], + a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], a23 = m1[2][3], + a30 = m1[3][0], a31 = m1[3][1], a32 = m1[3][2], a33 = m1[3][3], + + b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], + b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], + b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2], + b30 = m2[3][0], b31 = m2[3][1], b32 = m2[3][2], b33 = m2[3][3]; + + dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02; + dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02; + dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02; + dest[0][3] = a03 * b00 + a13 * b01 + a23 * b02; + + dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12; + dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12; + dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12; + dest[1][3] = a03 * b10 + a13 * b11 + a23 * b12; + + dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22; + dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22; + dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22; + dest[2][3] = a03 * b20 + a13 * b21 + a23 * b22; + + dest[3][0] = a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33; + dest[3][1] = a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33; + dest[3][2] = a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33; + dest[3][3] = a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33; +#endif +} + +/*! + * @brief this is similar to glm_mat4_mul but specialized to affine transform + * + * Right Matrix format should be: + * R R R 0 + * R R R 0 + * R R R 0 + * 0 0 0 1 + * + * this reduces some multiplications. It should be faster than mat4_mul. + * if you are not sure about matrix format then DON'T use this! use mat4_mul + * + * @param[in] m1 affine matrix 1 + * @param[in] m2 affine matrix 2 + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_mul_rot(mat4 m1, mat4 m2, mat4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glm_mul_rot_sse2(m1, m2, dest); +#elif defined(CGLM_NEON_FP) + glm_mul_rot_neon(m1, m2, dest); +#else + float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3], + a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3], + a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], a23 = m1[2][3], + a30 = m1[3][0], a31 = m1[3][1], a32 = m1[3][2], a33 = m1[3][3], + + b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], + b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], + b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2]; + + dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02; + dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02; + dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02; + dest[0][3] = a03 * b00 + a13 * b01 + a23 * b02; + + dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12; + dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12; + dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12; + dest[1][3] = a03 * b10 + a13 * b11 + a23 * b12; + + dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22; + dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22; + dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22; + dest[2][3] = a03 * b20 + a13 * b21 + a23 * b22; + + dest[3][0] = a30; + dest[3][1] = a31; + dest[3][2] = a32; + dest[3][3] = a33; +#endif +} + +/*! + * @brief inverse orthonormal rotation + translation matrix (ridig-body) + * + * @code + * X = | R T | X' = | R' -R'T | + * | 0 1 | | 0 1 | + * @endcode + * + * @param[in,out] mat matrix + */ +CGLM_INLINE +void +glm_inv_tr(mat4 mat) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glm_inv_tr_sse2(mat); +#elif defined(CGLM_NEON_FP) + glm_inv_tr_neon(mat); +#else + CGLM_ALIGN_MAT mat3 r; + CGLM_ALIGN(8) vec3 t; + + /* rotate */ + glm_mat4_pick3t(mat, r); + glm_mat4_ins3(r, mat); + + /* translate */ + glm_mat3_mulv(r, mat[3], t); + glm_vec3_negate(t); + glm_vec3_copy(t, mat[3]); +#endif +} + +#endif /* cglm_affine_mat_h */ diff --git a/include/cglm/affine-post.h b/include/cglm/affine-post.h new file mode 100644 index 0000000..d32cd1a --- /dev/null +++ b/include/cglm/affine-post.h @@ -0,0 +1,247 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_affine_post_h +#define cglm_affine_post_h + +/* + Functions: + CGLM_INLINE void glm_translated_to(mat4 m, vec3 v, mat4 dest); + CGLM_INLINE void glm_translated(mat4 m, vec3 v); + CGLM_INLINE void glm_translated_x(mat4 m, float to); + CGLM_INLINE void glm_translated_y(mat4 m, float to); + CGLM_INLINE void glm_translated_z(mat4 m, float to); + CGLM_INLINE void glm_rotated_x(mat4 m, float angle, mat4 dest); + CGLM_INLINE void glm_rotated_y(mat4 m, float angle, mat4 dest); + CGLM_INLINE void glm_rotated_z(mat4 m, float angle, mat4 dest); + CGLM_INLINE void glm_rotated(mat4 m, float angle, vec3 axis); + CGLM_INLINE void glm_rotated_at(mat4 m, vec3 pivot, float angle, vec3 axis); + CGLM_INLINE void glm_spinned(mat4 m, float angle, vec3 axis); + */ + +#include "common.h" +#include "util.h" +#include "vec3.h" +#include "vec4.h" +#include "mat4.h" +#include "affine-mat.h" + +/*! + * @brief translate existing transform matrix by v vector + * and stores result in same matrix + * + * this is POST transform, applies to existing transform as last transfrom + * + * @param[in, out] m affine transfrom + * @param[in] v translate vector [x, y, z] + */ +CGLM_INLINE +void +glm_translated(mat4 m, vec3 v) { + glm_vec3_add(m[3], v, m[3]); +} + +/*! + * @brief translate existing transform matrix by v vector + * and store result in dest + * + * source matrix will remain same + * + * this is POST transform, applies to existing transform as last transfrom + * + * @param[in] m affine transfrom + * @param[in] v translate vector [x, y, z] + * @param[out] dest translated matrix + */ +CGLM_INLINE +void +glm_translated_to(mat4 m, vec3 v, mat4 dest) { + glm_mat4_copy(m, dest); + glm_translated(dest, v); +} + +/*! + * @brief translate existing transform matrix by x factor + * + * this is POST transform, applies to existing transform as last transfrom + * + * @param[in, out] m affine transfrom + * @param[in] x x factor + */ +CGLM_INLINE +void +glm_translated_x(mat4 m, float x) { + m[3][0] += x; +} + +/*! + * @brief translate existing transform matrix by y factor + * + * this is POST transform, applies to existing transform as last transfrom + * + * @param[in, out] m affine transfrom + * @param[in] y y factor + */ +CGLM_INLINE +void +glm_translated_y(mat4 m, float y) { + m[3][1] += y; +} + +/*! + * @brief translate existing transform matrix by z factor + * + * this is POST transform, applies to existing transform as last transfrom + * + * @param[in, out] m affine transfrom + * @param[in] z z factor + */ +CGLM_INLINE +void +glm_translated_z(mat4 m, float z) { + m[3][2] += z; +} + +/*! + * @brief rotate existing transform matrix around X axis by angle + * and store result in dest + * + * this is POST transform, applies to existing transform as last transfrom + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @param[out] dest rotated matrix + */ +CGLM_INLINE +void +glm_rotated_x(mat4 m, float angle, mat4 dest) { + CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; + float c, s; + + c = cosf(angle); + s = sinf(angle); + + t[1][1] = c; + t[1][2] = s; + t[2][1] = -s; + t[2][2] = c; + + glm_mul_rot(t, m, dest); +} + +/*! + * @brief rotate existing transform matrix around Y axis by angle + * and store result in dest + * + * this is POST transform, applies to existing transform as last transfrom + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @param[out] dest rotated matrix + */ +CGLM_INLINE +void +glm_rotated_y(mat4 m, float angle, mat4 dest) { + CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; + float c, s; + + c = cosf(angle); + s = sinf(angle); + + t[0][0] = c; + t[0][2] = -s; + t[2][0] = s; + t[2][2] = c; + + glm_mul_rot(t, m, dest); +} + +/*! + * @brief rotate existing transform matrix around Z axis by angle + * and store result in dest + * + * this is POST transform, applies to existing transform as last transfrom + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @param[out] dest rotated matrix + */ +CGLM_INLINE +void +glm_rotated_z(mat4 m, float angle, mat4 dest) { + CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; + float c, s; + + c = cosf(angle); + s = sinf(angle); + + t[0][0] = c; + t[0][1] = s; + t[1][0] = -s; + t[1][1] = c; + + glm_mul_rot(t, m, dest); +} + +/*! + * @brief rotate existing transform matrix around given axis by angle + * + * this is POST transform, applies to existing transform as last transfrom + * + * @param[in, out] m affine transfrom + * @param[in] angle angle (radians) + * @param[in] axis axis + */ +CGLM_INLINE +void +glm_rotated(mat4 m, float angle, vec3 axis) { + CGLM_ALIGN_MAT mat4 rot; + glm_rotate_make(rot, angle, axis); + glm_mul_rot(rot, m, m); +} + +/*! + * @brief rotate existing transform + * around given axis by angle at given pivot point (rotation center) + * + * this is POST transform, applies to existing transform as last transfrom + * + * @param[in, out] m affine transfrom + * @param[in] pivot rotation center + * @param[in] angle angle (radians) + * @param[in] axis axis + */ +CGLM_INLINE +void +glm_rotated_at(mat4 m, vec3 pivot, float angle, vec3 axis) { + CGLM_ALIGN(8) vec3 pivotInv; + + glm_vec3_negate_to(pivot, pivotInv); + + glm_translated(m, pivot); + glm_rotated(m, angle, axis); + glm_translated(m, pivotInv); +} + +/*! + * @brief rotate existing transform matrix around given axis by angle around self (doesn't affected by position) + * + * this is POST transform, applies to existing transform as last transfrom + * + * @param[in, out] m affine transfrom + * @param[in] angle angle (radians) + * @param[in] axis axis + */ +CGLM_INLINE +void +glm_spinned(mat4 m, float angle, vec3 axis) { + CGLM_ALIGN_MAT mat4 rot; + glm_rotate_atm(rot, m[3], angle, axis); + glm_mat4_mul(rot, m, m); +} + +#endif /* cglm_affine_post_h */ diff --git a/include/cglm/affine-pre.h b/include/cglm/affine-pre.h new file mode 100644 index 0000000..43652ff --- /dev/null +++ b/include/cglm/affine-pre.h @@ -0,0 +1,285 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_affine_pre_h +#define cglm_affine_pre_h + +/* + Functions: + CGLM_INLINE void glm_translate_to(mat4 m, vec3 v, mat4 dest); + CGLM_INLINE void glm_translate(mat4 m, vec3 v); + CGLM_INLINE void glm_translate_x(mat4 m, float to); + CGLM_INLINE void glm_translate_y(mat4 m, float to); + CGLM_INLINE void glm_translate_z(mat4 m, float to); + CGLM_INLINE void glm_rotate_x(mat4 m, float angle, mat4 dest); + CGLM_INLINE void glm_rotate_y(mat4 m, float angle, mat4 dest); + CGLM_INLINE void glm_rotate_z(mat4 m, float angle, mat4 dest); + CGLM_INLINE void glm_rotate(mat4 m, float angle, vec3 axis); + CGLM_INLINE void glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis); + CGLM_INLINE void glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis); + CGLM_INLINE void glm_spin(mat4 m, float angle, vec3 axis); + */ + +#include "common.h" +#include "util.h" +#include "vec3.h" +#include "vec4.h" +#include "mat4.h" +#include "affine-mat.h" + +/*! + * @brief translate existing transform matrix by v vector + * and stores result in same matrix + * + * @param[in, out] m affine transfrom + * @param[in] v translate vector [x, y, z] + */ +CGLM_INLINE +void +glm_translate(mat4 m, vec3 v) { +#if defined(CGLM_SIMD) + glmm_128 m0, m1, m2, m3; + + m0 = glmm_load(m[0]); + m1 = glmm_load(m[1]); + m2 = glmm_load(m[2]); + m3 = glmm_load(m[3]); + + glmm_store(m[3], + glmm_fmadd(m0, glmm_set1(v[0]), + glmm_fmadd(m1, glmm_set1(v[1]), + glmm_fmadd(m2, glmm_set1(v[2]), m3)))); +#else + glm_vec4_muladds(m[0], v[0], m[3]); + glm_vec4_muladds(m[1], v[1], m[3]); + glm_vec4_muladds(m[2], v[2], m[3]); +#endif +} + +/*! + * @brief translate existing transform matrix by v vector + * and store result in dest + * + * source matrix will remain same + * + * @param[in] m affine transfrom + * @param[in] v translate vector [x, y, z] + * @param[out] dest translated matrix + */ +CGLM_INLINE +void +glm_translate_to(mat4 m, vec3 v, mat4 dest) { + glm_mat4_copy(m, dest); + glm_translate(dest, v); +} + +/*! + * @brief translate existing transform matrix by x factor + * + * @param[in, out] m affine transfrom + * @param[in] x x factor + */ +CGLM_INLINE +void +glm_translate_x(mat4 m, float x) { +#if defined(CGLM_SIMD) + glmm_store(m[3], glmm_fmadd(glmm_load(m[0]), glmm_set1(x), glmm_load(m[3]))); +#else + vec4 v1; + glm_vec4_scale(m[0], x, v1); + glm_vec4_add(v1, m[3], m[3]); +#endif +} + +/*! + * @brief translate existing transform matrix by y factor + * + * @param[in, out] m affine transfrom + * @param[in] y y factor + */ +CGLM_INLINE +void +glm_translate_y(mat4 m, float y) { +#if defined(CGLM_SIMD) + glmm_store(m[3], glmm_fmadd(glmm_load(m[1]), glmm_set1(y), glmm_load(m[3]))); +#else + vec4 v1; + glm_vec4_scale(m[1], y, v1); + glm_vec4_add(v1, m[3], m[3]); +#endif +} + +/*! + * @brief translate existing transform matrix by z factor + * + * @param[in, out] m affine transfrom + * @param[in] z z factor + */ +CGLM_INLINE +void +glm_translate_z(mat4 m, float z) { +#if defined(CGLM_SIMD) + glmm_store(m[3], glmm_fmadd(glmm_load(m[2]), glmm_set1(z), glmm_load(m[3]))); +#else + vec4 v1; + glm_vec4_scale(m[2], z, v1); + glm_vec4_add(v1, m[3], m[3]); +#endif +} + +/*! + * @brief rotate existing transform matrix around X axis by angle + * and store result in dest + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @param[out] dest rotated matrix + */ +CGLM_INLINE +void +glm_rotate_x(mat4 m, float angle, mat4 dest) { + CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; + float c, s; + + c = cosf(angle); + s = sinf(angle); + + t[1][1] = c; + t[1][2] = s; + t[2][1] = -s; + t[2][2] = c; + + glm_mul_rot(m, t, dest); +} + +/*! + * @brief rotate existing transform matrix around Y axis by angle + * and store result in dest + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @param[out] dest rotated matrix + */ +CGLM_INLINE +void +glm_rotate_y(mat4 m, float angle, mat4 dest) { + CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; + float c, s; + + c = cosf(angle); + s = sinf(angle); + + t[0][0] = c; + t[0][2] = -s; + t[2][0] = s; + t[2][2] = c; + + glm_mul_rot(m, t, dest); +} + +/*! + * @brief rotate existing transform matrix around Z axis by angle + * and store result in dest + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @param[out] dest rotated matrix + */ +CGLM_INLINE +void +glm_rotate_z(mat4 m, float angle, mat4 dest) { + CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; + float c, s; + + c = cosf(angle); + s = sinf(angle); + + t[0][0] = c; + t[0][1] = s; + t[1][0] = -s; + t[1][1] = c; + + glm_mul_rot(m, t, dest); +} + +/*! + * @brief rotate existing transform matrix around given axis by angle + * + * @param[in, out] m affine transfrom + * @param[in] angle angle (radians) + * @param[in] axis axis + */ +CGLM_INLINE +void +glm_rotate(mat4 m, float angle, vec3 axis) { + CGLM_ALIGN_MAT mat4 rot; + glm_rotate_make(rot, angle, axis); + glm_mul_rot(m, rot, m); +} + +/*! + * @brief rotate existing transform + * around given axis by angle at given pivot point (rotation center) + * + * @param[in, out] m affine transfrom + * @param[in] pivot rotation center + * @param[in] angle angle (radians) + * @param[in] axis axis + */ +CGLM_INLINE +void +glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis) { + CGLM_ALIGN(8) vec3 pivotInv; + + glm_vec3_negate_to(pivot, pivotInv); + + glm_translate(m, pivot); + glm_rotate(m, angle, axis); + glm_translate(m, pivotInv); +} + +/*! + * @brief creates NEW rotation matrix by angle and axis at given point + * + * this creates rotation matrix, it assumes you don't have a matrix + * + * this should work faster than glm_rotate_at because it reduces + * one glm_translate. + * + * @param[out] m affine transfrom + * @param[in] pivot rotation center + * @param[in] angle angle (radians) + * @param[in] axis axis + */ +CGLM_INLINE +void +glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis) { + CGLM_ALIGN(8) vec3 pivotInv; + + glm_vec3_negate_to(pivot, pivotInv); + + glm_translate_make(m, pivot); + glm_rotate(m, angle, axis); + glm_translate(m, pivotInv); +} + +/*! + * @brief rotate existing transform matrix around given axis by angle around self (doesn't affected by position) + * + * @param[in, out] m affine transfrom + * @param[in] angle angle (radians) + * @param[in] axis axis + */ +CGLM_INLINE +void +glm_spin(mat4 m, float angle, vec3 axis) { + CGLM_ALIGN_MAT mat4 rot; + glm_rotate_atm(rot, m[3], angle, axis); + glm_mat4_mul(m, rot, m); +} + +#endif /* cglm_affine_pre_h */ diff --git a/include/cglm/affine.h b/include/cglm/affine.h new file mode 100644 index 0000000..78d7dbf --- /dev/null +++ b/include/cglm/affine.h @@ -0,0 +1,238 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_translate_to(mat4 m, vec3 v, mat4 dest); + CGLM_INLINE void glm_translate(mat4 m, vec3 v); + CGLM_INLINE void glm_translate_x(mat4 m, float to); + CGLM_INLINE void glm_translate_y(mat4 m, float to); + CGLM_INLINE void glm_translate_z(mat4 m, float to); + CGLM_INLINE void glm_translate_make(mat4 m, vec3 v); + CGLM_INLINE void glm_scale_to(mat4 m, vec3 v, mat4 dest); + CGLM_INLINE void glm_scale_make(mat4 m, vec3 v); + CGLM_INLINE void glm_scale(mat4 m, vec3 v); + CGLM_INLINE void glm_scale_uni(mat4 m, float s); + CGLM_INLINE void glm_rotate_x(mat4 m, float angle, mat4 dest); + CGLM_INLINE void glm_rotate_y(mat4 m, float angle, mat4 dest); + CGLM_INLINE void glm_rotate_z(mat4 m, float angle, mat4 dest); + CGLM_INLINE void glm_rotate_make(mat4 m, float angle, vec3 axis); + CGLM_INLINE void glm_rotate(mat4 m, float angle, vec3 axis); + CGLM_INLINE void glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis); + CGLM_INLINE void glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis); + CGLM_INLINE void glm_spin(mat4 m, float angle, vec3 axis); + CGLM_INLINE void glm_decompose_scalev(mat4 m, vec3 s); + CGLM_INLINE bool glm_uniscaled(mat4 m); + CGLM_INLINE void glm_decompose_rs(mat4 m, mat4 r, vec3 s); + CGLM_INLINE void glm_decompose(mat4 m, vec4 t, mat4 r, vec3 s); + */ + +#ifndef cglm_affine_h +#define cglm_affine_h + +#include "common.h" +#include "util.h" +#include "vec3.h" +#include "vec4.h" +#include "mat4.h" +#include "affine-mat.h" + +/*! + * @brief creates NEW translate transform matrix by v vector + * + * @param[out] m affine transfrom + * @param[in] v translate vector [x, y, z] + */ +CGLM_INLINE +void +glm_translate_make(mat4 m, vec3 v) { + glm_mat4_identity(m); + glm_vec3_copy(v, m[3]); +} + +/*! + * @brief scale existing transform matrix by v vector + * and store result in dest + * + * @param[in] m affine transfrom + * @param[in] v scale vector [x, y, z] + * @param[out] dest scaled matrix + */ +CGLM_INLINE +void +glm_scale_to(mat4 m, vec3 v, mat4 dest) { + glm_vec4_scale(m[0], v[0], dest[0]); + glm_vec4_scale(m[1], v[1], dest[1]); + glm_vec4_scale(m[2], v[2], dest[2]); + + glm_vec4_copy(m[3], dest[3]); +} + +/*! + * @brief creates NEW scale matrix by v vector + * + * @param[out] m affine transfrom + * @param[in] v scale vector [x, y, z] + */ +CGLM_INLINE +void +glm_scale_make(mat4 m, vec3 v) { + glm_mat4_identity(m); + m[0][0] = v[0]; + m[1][1] = v[1]; + m[2][2] = v[2]; +} + +/*! + * @brief scales existing transform matrix by v vector + * and stores result in same matrix + * + * @param[in, out] m affine transfrom + * @param[in] v scale vector [x, y, z] + */ +CGLM_INLINE +void +glm_scale(mat4 m, vec3 v) { + glm_scale_to(m, v, m); +} + +/*! + * @brief applies uniform scale to existing transform matrix v = [s, s, s] + * and stores result in same matrix + * + * @param[in, out] m affine transfrom + * @param[in] s scale factor + */ +CGLM_INLINE +void +glm_scale_uni(mat4 m, float s) { + CGLM_ALIGN(8) vec3 v = { s, s, s }; + glm_scale_to(m, v, m); +} + +/*! + * @brief creates NEW rotation matrix by angle and axis + * + * axis will be normalized so you don't need to normalize it + * + * @param[out] m affine transfrom + * @param[in] angle angle (radians) + * @param[in] axis axis + */ +CGLM_INLINE +void +glm_rotate_make(mat4 m, float angle, vec3 axis) { + CGLM_ALIGN(8) vec3 axisn, v, vs; + float c; + + c = cosf(angle); + + glm_vec3_normalize_to(axis, axisn); + glm_vec3_scale(axisn, 1.0f - c, v); + glm_vec3_scale(axisn, sinf(angle), vs); + + glm_vec3_scale(axisn, v[0], m[0]); + glm_vec3_scale(axisn, v[1], m[1]); + glm_vec3_scale(axisn, v[2], m[2]); + + m[0][0] += c; m[1][0] -= vs[2]; m[2][0] += vs[1]; + m[0][1] += vs[2]; m[1][1] += c; m[2][1] -= vs[0]; + m[0][2] -= vs[1]; m[1][2] += vs[0]; m[2][2] += c; + + m[0][3] = m[1][3] = m[2][3] = m[3][0] = m[3][1] = m[3][2] = 0.0f; + m[3][3] = 1.0f; +} + +/*! + * @brief decompose scale vector + * + * @param[in] m affine transform + * @param[out] s scale vector (Sx, Sy, Sz) + */ +CGLM_INLINE +void +glm_decompose_scalev(mat4 m, vec3 s) { + s[0] = glm_vec3_norm(m[0]); + s[1] = glm_vec3_norm(m[1]); + s[2] = glm_vec3_norm(m[2]); +} + +/*! + * @brief returns true if matrix is uniform scaled. This is helpful for + * creating normal matrix. + * + * @param[in] m m + * + * @return boolean + */ +CGLM_INLINE +bool +glm_uniscaled(mat4 m) { + CGLM_ALIGN(8) vec3 s; + glm_decompose_scalev(m, s); + return glm_vec3_eq_all(s); +} + +/*! + * @brief decompose rotation matrix (mat4) and scale vector [Sx, Sy, Sz] + * DON'T pass projected matrix here + * + * @param[in] m affine transform + * @param[out] r rotation matrix + * @param[out] s scale matrix + */ +CGLM_INLINE +void +glm_decompose_rs(mat4 m, mat4 r, vec3 s) { + CGLM_ALIGN(16) vec4 t = {0.0f, 0.0f, 0.0f, 1.0f}; + CGLM_ALIGN(8) vec3 v; + + glm_vec4_copy(m[0], r[0]); + glm_vec4_copy(m[1], r[1]); + glm_vec4_copy(m[2], r[2]); + glm_vec4_copy(t, r[3]); + + s[0] = glm_vec3_norm(m[0]); + s[1] = glm_vec3_norm(m[1]); + s[2] = glm_vec3_norm(m[2]); + + glm_vec4_scale(r[0], 1.0f/s[0], r[0]); + glm_vec4_scale(r[1], 1.0f/s[1], r[1]); + glm_vec4_scale(r[2], 1.0f/s[2], r[2]); + + /* Note from Apple Open Source (assume that the matrix is orthonormal): + check for a coordinate system flip. If the determinant + is -1, then negate the matrix and the scaling factors. */ + glm_vec3_cross(m[0], m[1], v); + if (glm_vec3_dot(v, m[2]) < 0.0f) { + glm_vec4_negate(r[0]); + glm_vec4_negate(r[1]); + glm_vec4_negate(r[2]); + glm_vec3_negate(s); + } +} + +/*! + * @brief decompose affine transform, TODO: extract shear factors. + * DON'T pass projected matrix here + * + * @param[in] m affine transfrom + * @param[out] t translation vector + * @param[out] r rotation matrix (mat4) + * @param[out] s scaling vector [X, Y, Z] + */ +CGLM_INLINE +void +glm_decompose(mat4 m, vec4 t, mat4 r, vec3 s) { + glm_vec4_copy(m[3], t); + glm_decompose_rs(m, r, s); +} + +#include "affine-pre.h" +#include "affine-post.h" + +#endif /* cglm_affine_h */ diff --git a/include/cglm/affine2d.h b/include/cglm/affine2d.h new file mode 100644 index 0000000..bb66289 --- /dev/null +++ b/include/cglm/affine2d.h @@ -0,0 +1,268 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_translate2d(mat3 m, vec2 v) + CGLM_INLINE void glm_translate2d_to(mat3 m, vec2 v, mat3 dest) + CGLM_INLINE void glm_translate2d_x(mat3 m, float x) + CGLM_INLINE void glm_translate2d_y(mat3 m, float y) + CGLM_INLINE void glm_translate2d_make(mat3 m, vec2 v) + CGLM_INLINE void glm_scale2d_to(mat3 m, vec2 v, mat3 dest) + CGLM_INLINE void glm_scale2d_make(mat3 m, vec2 v) + CGLM_INLINE void glm_scale2d(mat3 m, vec2 v) + CGLM_INLINE void glm_scale2d_uni(mat3 m, float s) + CGLM_INLINE void glm_rotate2d_make(mat3 m, float angle) + CGLM_INLINE void glm_rotate2d(mat3 m, float angle) + CGLM_INLINE void glm_rotate2d_to(mat3 m, float angle, mat3 dest) + */ + +#ifndef cglm_affine2d_h +#define cglm_affine2d_h + +#include "common.h" +#include "util.h" +#include "vec2.h" +#include "mat3.h" + +/*! + * @brief translate existing 2d transform matrix by v vector + * and stores result in same matrix + * + * @param[in, out] m affine transfrom + * @param[in] v translate vector [x, y] + */ +CGLM_INLINE +void +glm_translate2d(mat3 m, vec2 v) { + m[2][0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0]; + m[2][1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1]; + m[2][2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2]; +} + +/*! + * @brief translate existing 2d transform matrix by v vector + * and store result in dest + * + * source matrix will remain same + * + * @param[in] m affine transfrom + * @param[in] v translate vector [x, y] + * @param[out] dest translated matrix + */ +CGLM_INLINE +void +glm_translate2d_to(mat3 m, vec2 v, mat3 dest) { + glm_mat3_copy(m, dest); + glm_translate2d(dest, v); +} + +/*! + * @brief translate existing 2d transform matrix by x factor + * + * @param[in, out] m affine transfrom + * @param[in] x x factor + */ +CGLM_INLINE +void +glm_translate2d_x(mat3 m, float x) { + m[2][0] = m[0][0] * x + m[2][0]; + m[2][1] = m[0][1] * x + m[2][1]; + m[2][2] = m[0][2] * x + m[2][2]; +} + +/*! + * @brief translate existing 2d transform matrix by y factor + * + * @param[in, out] m affine transfrom + * @param[in] y y factor + */ +CGLM_INLINE +void +glm_translate2d_y(mat3 m, float y) { + m[2][0] = m[1][0] * y + m[2][0]; + m[2][1] = m[1][1] * y + m[2][1]; + m[2][2] = m[1][2] * y + m[2][2]; +} + +/*! + * @brief creates NEW translate 2d transform matrix by v vector + * + * @param[out] m affine transfrom + * @param[in] v translate vector [x, y] + */ +CGLM_INLINE +void +glm_translate2d_make(mat3 m, vec2 v) { + glm_mat3_identity(m); + m[2][0] = v[0]; + m[2][1] = v[1]; +} + +/*! + * @brief scale existing 2d transform matrix by v vector + * and store result in dest + * + * @param[in] m affine transfrom + * @param[in] v scale vector [x, y] + * @param[out] dest scaled matrix + */ +CGLM_INLINE +void +glm_scale2d_to(mat3 m, vec2 v, mat3 dest) { + dest[0][0] = m[0][0] * v[0]; + dest[0][1] = m[0][1] * v[0]; + dest[0][2] = m[0][2] * v[0]; + + dest[1][0] = m[1][0] * v[1]; + dest[1][1] = m[1][1] * v[1]; + dest[1][2] = m[1][2] * v[1]; + + dest[2][0] = m[2][0]; + dest[2][1] = m[2][1]; + dest[2][2] = m[2][2]; +} + +/*! + * @brief creates NEW 2d scale matrix by v vector + * + * @param[out] m affine transfrom + * @param[in] v scale vector [x, y] + */ +CGLM_INLINE +void +glm_scale2d_make(mat3 m, vec2 v) { + glm_mat3_identity(m); + m[0][0] = v[0]; + m[1][1] = v[1]; +} + +/*! + * @brief scales existing 2d transform matrix by v vector + * and stores result in same matrix + * + * @param[in, out] m affine transfrom + * @param[in] v scale vector [x, y] + */ +CGLM_INLINE +void +glm_scale2d(mat3 m, vec2 v) { + m[0][0] = m[0][0] * v[0]; + m[0][1] = m[0][1] * v[0]; + m[0][2] = m[0][2] * v[0]; + + m[1][0] = m[1][0] * v[1]; + m[1][1] = m[1][1] * v[1]; + m[1][2] = m[1][2] * v[1]; +} + +/*! + * @brief applies uniform scale to existing 2d transform matrix v = [s, s] + * and stores result in same matrix + * + * @param[in, out] m affine transfrom + * @param[in] s scale factor + */ +CGLM_INLINE +void +glm_scale2d_uni(mat3 m, float s) { + m[0][0] = m[0][0] * s; + m[0][1] = m[0][1] * s; + m[0][2] = m[0][2] * s; + + m[1][0] = m[1][0] * s; + m[1][1] = m[1][1] * s; + m[1][2] = m[1][2] * s; +} + +/*! + * @brief creates NEW rotation matrix by angle around Z axis + * + * @param[out] m affine transfrom + * @param[in] angle angle (radians) + */ +CGLM_INLINE +void +glm_rotate2d_make(mat3 m, float angle) { + float c, s; + + s = sinf(angle); + c = cosf(angle); + + m[0][0] = c; + m[0][1] = s; + m[0][2] = 0; + + m[1][0] = -s; + m[1][1] = c; + m[1][2] = 0; + + m[2][0] = 0.0f; + m[2][1] = 0.0f; + m[2][2] = 1.0f; +} + +/*! + * @brief rotate existing 2d transform matrix around Z axis by angle + * and store result in same matrix + * + * @param[in, out] m affine transfrom + * @param[in] angle angle (radians) + */ +CGLM_INLINE +void +glm_rotate2d(mat3 m, float angle) { + float m00 = m[0][0], m10 = m[1][0], + m01 = m[0][1], m11 = m[1][1], + m02 = m[0][2], m12 = m[1][2]; + float c, s; + + s = sinf(angle); + c = cosf(angle); + + m[0][0] = m00 * c + m10 * s; + m[0][1] = m01 * c + m11 * s; + m[0][2] = m02 * c + m12 * s; + + m[1][0] = m00 * -s + m10 * c; + m[1][1] = m01 * -s + m11 * c; + m[1][2] = m02 * -s + m12 * c; +} + +/*! + * @brief rotate existing 2d transform matrix around Z axis by angle + * and store result in dest + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_rotate2d_to(mat3 m, float angle, mat3 dest) { + float m00 = m[0][0], m10 = m[1][0], + m01 = m[0][1], m11 = m[1][1], + m02 = m[0][2], m12 = m[1][2]; + float c, s; + + s = sinf(angle); + c = cosf(angle); + + dest[0][0] = m00 * c + m10 * s; + dest[0][1] = m01 * c + m11 * s; + dest[0][2] = m02 * c + m12 * s; + + dest[1][0] = m00 * -s + m10 * c; + dest[1][1] = m01 * -s + m11 * c; + dest[1][2] = m02 * -s + m12 * c; + + dest[2][0] = m[2][0]; + dest[2][1] = m[2][1]; + dest[2][2] = m[2][2]; +} + +#endif /* cglm_affine2d_h */ diff --git a/include/cglm/applesimd.h b/include/cglm/applesimd.h new file mode 100644 index 0000000..3608bb3 --- /dev/null +++ b/include/cglm/applesimd.h @@ -0,0 +1,95 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_applesimd_h +#define cglm_applesimd_h +#if defined(__APPLE__) \ + && defined(SIMD_COMPILER_HAS_REQUIRED_FEATURES) \ + && defined(SIMD_BASE) \ + && defined(SIMD_TYPES) \ + && defined(SIMD_VECTOR_TYPES) + +#include "common.h" + +/*! +* @brief converts mat4 to Apple's simd type simd_float4x4 +* @return simd_float4x4 +*/ +CGLM_INLINE +simd_float4x4 +glm_mat4_applesimd(mat4 m) { + simd_float4x4 t; + + t.columns[0][0] = m[0][0]; + t.columns[0][1] = m[0][1]; + t.columns[0][2] = m[0][2]; + t.columns[0][3] = m[0][3]; + + t.columns[1][0] = m[1][0]; + t.columns[1][1] = m[1][1]; + t.columns[1][2] = m[1][2]; + t.columns[1][3] = m[1][3]; + + t.columns[2][0] = m[2][0]; + t.columns[2][1] = m[2][1]; + t.columns[2][2] = m[2][2]; + t.columns[2][3] = m[2][3]; + + t.columns[3][0] = m[3][0]; + t.columns[3][1] = m[3][1]; + t.columns[3][2] = m[3][2]; + t.columns[3][3] = m[3][3]; + + return t; +} + +/*! +* @brief converts mat3 to Apple's simd type simd_float3x3 +* @return simd_float3x3 +*/ +CGLM_INLINE +simd_float3x3 +glm_mat3_applesimd(mat3 m) { + simd_float3x3 t; + + t.columns[0][0] = m[0][0]; + t.columns[0][1] = m[0][1]; + t.columns[0][2] = m[0][2]; + + t.columns[1][0] = m[1][0]; + t.columns[1][1] = m[1][1]; + t.columns[1][2] = m[1][2]; + + t.columns[2][0] = m[2][0]; + t.columns[2][1] = m[2][1]; + t.columns[2][2] = m[2][2]; + + return t; +} + +/*! +* @brief converts vec4 to Apple's simd type simd_float4 +* @return simd_float4 +*/ +CGLM_INLINE +simd_float4 +glm_vec4_applesimd(vec4 v) { + return (simd_float4){v[0], v[1], v[2], v[3]}; +} + +/*! +* @brief converts vec3 to Apple's simd type simd_float3 +* @return v +*/ +CGLM_INLINE +simd_float3 +glm_vec3_applesimd(vec3 v) { + return (simd_float3){v[0], v[1], v[2]}; +} + +#endif +#endif /* cglm_applesimd_h */ diff --git a/include/cglm/bezier.h b/include/cglm/bezier.h new file mode 100644 index 0000000..2bbe09f --- /dev/null +++ b/include/cglm/bezier.h @@ -0,0 +1,154 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_bezier_h +#define cglm_bezier_h + +#include "common.h" + +#define GLM_BEZIER_MAT_INIT {{-1.0f, 3.0f, -3.0f, 1.0f}, \ + { 3.0f, -6.0f, 3.0f, 0.0f}, \ + {-3.0f, 3.0f, 0.0f, 0.0f}, \ + { 1.0f, 0.0f, 0.0f, 0.0f}} +#define GLM_HERMITE_MAT_INIT {{ 2.0f, -3.0f, 0.0f, 1.0f}, \ + {-2.0f, 3.0f, 0.0f, 0.0f}, \ + { 1.0f, -2.0f, 1.0f, 0.0f}, \ + { 1.0f, -1.0f, 0.0f, 0.0f}} +/* for C only */ +#define GLM_BEZIER_MAT ((mat4)GLM_BEZIER_MAT_INIT) +#define GLM_HERMITE_MAT ((mat4)GLM_HERMITE_MAT_INIT) + +#define CGLM_DECASTEL_EPS 1e-9f +#define CGLM_DECASTEL_MAX 1000.0f +#define CGLM_DECASTEL_SMALL 1e-20f + +/*! + * @brief cubic bezier interpolation + * + * Formula: + * B(s) = P0*(1-s)^3 + 3*C0*s*(1-s)^2 + 3*C1*s^2*(1-s) + P1*s^3 + * + * similar result using matrix: + * B(s) = glm_smc(t, GLM_BEZIER_MAT, (vec4){p0, c0, c1, p1}) + * + * glm_eq(glm_smc(...), glm_bezier(...)) should return TRUE + * + * @param[in] s parameter between 0 and 1 + * @param[in] p0 begin point + * @param[in] c0 control point 1 + * @param[in] c1 control point 2 + * @param[in] p1 end point + * + * @return B(s) + */ +CGLM_INLINE +float +glm_bezier(float s, float p0, float c0, float c1, float p1) { + float x, xx, ss, xs3, a; + + x = 1.0f - s; + xx = x * x; + ss = s * s; + xs3 = (s - ss) * 3.0f; + a = p0 * xx + c0 * xs3; + + return a + s * (c1 * xs3 + p1 * ss - a); +} + +/*! + * @brief cubic hermite interpolation + * + * Formula: + * H(s) = P0*(2*s^3 - 3*s^2 + 1) + T0*(s^3 - 2*s^2 + s) + * + P1*(-2*s^3 + 3*s^2) + T1*(s^3 - s^2) + * + * similar result using matrix: + * H(s) = glm_smc(t, GLM_HERMITE_MAT, (vec4){p0, p1, c0, c1}) + * + * glm_eq(glm_smc(...), glm_hermite(...)) should return TRUE + * + * @param[in] s parameter between 0 and 1 + * @param[in] p0 begin point + * @param[in] t0 tangent 1 + * @param[in] t1 tangent 2 + * @param[in] p1 end point + * + * @return H(s) + */ +CGLM_INLINE +float +glm_hermite(float s, float p0, float t0, float t1, float p1) { + float ss, d, a, b, c, e, f; + + ss = s * s; + a = ss + ss; + c = a + ss; + b = a * s; + d = s * ss; + f = d - ss; + e = b - c; + + return p0 * (e + 1.0f) + t0 * (f - ss + s) + t1 * f - p1 * e; +} + +/*! + * @brief iterative way to solve cubic equation + * + * @param[in] prm parameter between 0 and 1 + * @param[in] p0 begin point + * @param[in] c0 control point 1 + * @param[in] c1 control point 2 + * @param[in] p1 end point + * + * @return parameter to use in cubic equation + */ +CGLM_INLINE +float +glm_decasteljau(float prm, float p0, float c0, float c1, float p1) { + float u, v, a, b, c, d, e, f; + int i; + + if (prm - p0 < CGLM_DECASTEL_SMALL) + return 0.0f; + + if (p1 - prm < CGLM_DECASTEL_SMALL) + return 1.0f; + + u = 0.0f; + v = 1.0f; + + for (i = 0; i < CGLM_DECASTEL_MAX; i++) { + /* de Casteljau Subdivision */ + a = (p0 + c0) * 0.5f; + b = (c0 + c1) * 0.5f; + c = (c1 + p1) * 0.5f; + d = (a + b) * 0.5f; + e = (b + c) * 0.5f; + f = (d + e) * 0.5f; /* this one is on the curve! */ + + /* The curve point is close enough to our wanted t */ + if (fabsf(f - prm) < CGLM_DECASTEL_EPS) + return glm_clamp_zo((u + v) * 0.5f); + + /* dichotomy */ + if (f < prm) { + p0 = f; + c0 = e; + c1 = c; + u = (u + v) * 0.5f; + } else { + c0 = a; + c1 = d; + p1 = f; + v = (u + v) * 0.5f; + } + } + + return glm_clamp_zo((u + v) * 0.5f); +} + +#endif /* cglm_bezier_h */ diff --git a/include/cglm/box.h b/include/cglm/box.h new file mode 100644 index 0000000..4400797 --- /dev/null +++ b/include/cglm/box.h @@ -0,0 +1,281 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_box_h +#define cglm_box_h + +#include "common.h" +#include "vec3.h" +#include "vec4.h" +#include "util.h" + +/*! + * @brief apply transform to Axis-Aligned Bounding Box + * + * @param[in] box bounding box + * @param[in] m transform matrix + * @param[out] dest transformed bounding box + */ +CGLM_INLINE +void +glm_aabb_transform(vec3 box[2], mat4 m, vec3 dest[2]) { + vec3 v[2], xa, xb, ya, yb, za, zb; + + glm_vec3_scale(m[0], box[0][0], xa); + glm_vec3_scale(m[0], box[1][0], xb); + + glm_vec3_scale(m[1], box[0][1], ya); + glm_vec3_scale(m[1], box[1][1], yb); + + glm_vec3_scale(m[2], box[0][2], za); + glm_vec3_scale(m[2], box[1][2], zb); + + /* translation + min(xa, xb) + min(ya, yb) + min(za, zb) */ + glm_vec3(m[3], v[0]); + glm_vec3_minadd(xa, xb, v[0]); + glm_vec3_minadd(ya, yb, v[0]); + glm_vec3_minadd(za, zb, v[0]); + + /* translation + max(xa, xb) + max(ya, yb) + max(za, zb) */ + glm_vec3(m[3], v[1]); + glm_vec3_maxadd(xa, xb, v[1]); + glm_vec3_maxadd(ya, yb, v[1]); + glm_vec3_maxadd(za, zb, v[1]); + + glm_vec3_copy(v[0], dest[0]); + glm_vec3_copy(v[1], dest[1]); +} + +/*! + * @brief merges two AABB bounding box and creates new one + * + * two box must be in same space, if one of box is in different space then + * you should consider to convert it's space by glm_box_space + * + * @param[in] box1 bounding box 1 + * @param[in] box2 bounding box 2 + * @param[out] dest merged bounding box + */ +CGLM_INLINE +void +glm_aabb_merge(vec3 box1[2], vec3 box2[2], vec3 dest[2]) { + dest[0][0] = glm_min(box1[0][0], box2[0][0]); + dest[0][1] = glm_min(box1[0][1], box2[0][1]); + dest[0][2] = glm_min(box1[0][2], box2[0][2]); + + dest[1][0] = glm_max(box1[1][0], box2[1][0]); + dest[1][1] = glm_max(box1[1][1], box2[1][1]); + dest[1][2] = glm_max(box1[1][2], box2[1][2]); +} + +/*! + * @brief crops a bounding box with another one. + * + * this could be useful for gettng a bbox which fits with view frustum and + * object bounding boxes. In this case you crop view frustum box with objects + * box + * + * @param[in] box bounding box 1 + * @param[in] cropBox crop box + * @param[out] dest cropped bounding box + */ +CGLM_INLINE +void +glm_aabb_crop(vec3 box[2], vec3 cropBox[2], vec3 dest[2]) { + dest[0][0] = glm_max(box[0][0], cropBox[0][0]); + dest[0][1] = glm_max(box[0][1], cropBox[0][1]); + dest[0][2] = glm_max(box[0][2], cropBox[0][2]); + + dest[1][0] = glm_min(box[1][0], cropBox[1][0]); + dest[1][1] = glm_min(box[1][1], cropBox[1][1]); + dest[1][2] = glm_min(box[1][2], cropBox[1][2]); +} + +/*! + * @brief crops a bounding box with another one. + * + * this could be useful for gettng a bbox which fits with view frustum and + * object bounding boxes. In this case you crop view frustum box with objects + * box + * + * @param[in] box bounding box + * @param[in] cropBox crop box + * @param[in] clampBox miniumum box + * @param[out] dest cropped bounding box + */ +CGLM_INLINE +void +glm_aabb_crop_until(vec3 box[2], + vec3 cropBox[2], + vec3 clampBox[2], + vec3 dest[2]) { + glm_aabb_crop(box, cropBox, dest); + glm_aabb_merge(clampBox, dest, dest); +} + +/*! + * @brief check if AABB intersects with frustum planes + * + * this could be useful for frustum culling using AABB. + * + * OPTIMIZATION HINT: + * if planes order is similar to LEFT, RIGHT, BOTTOM, TOP, NEAR, FAR + * then this method should run even faster because it would only use two + * planes if object is not inside the two planes + * fortunately cglm extracts planes as this order! just pass what you got! + * + * @param[in] box bounding box + * @param[in] planes frustum planes + */ +CGLM_INLINE +bool +glm_aabb_frustum(vec3 box[2], vec4 planes[6]) { + float *p, dp; + int i; + + for (i = 0; i < 6; i++) { + p = planes[i]; + dp = p[0] * box[p[0] > 0.0f][0] + + p[1] * box[p[1] > 0.0f][1] + + p[2] * box[p[2] > 0.0f][2]; + + if (dp < -p[3]) + return false; + } + + return true; +} + +/*! + * @brief invalidate AABB min and max values + * + * @param[in, out] box bounding box + */ +CGLM_INLINE +void +glm_aabb_invalidate(vec3 box[2]) { + glm_vec3_broadcast(FLT_MAX, box[0]); + glm_vec3_broadcast(-FLT_MAX, box[1]); +} + +/*! + * @brief check if AABB is valid or not + * + * @param[in] box bounding box + */ +CGLM_INLINE +bool +glm_aabb_isvalid(vec3 box[2]) { + return glm_vec3_max(box[0]) != FLT_MAX + && glm_vec3_min(box[1]) != -FLT_MAX; +} + +/*! + * @brief distance between of min and max + * + * @param[in] box bounding box + */ +CGLM_INLINE +float +glm_aabb_size(vec3 box[2]) { + return glm_vec3_distance(box[0], box[1]); +} + +/*! + * @brief radius of sphere which surrounds AABB + * + * @param[in] box bounding box + */ +CGLM_INLINE +float +glm_aabb_radius(vec3 box[2]) { + return glm_aabb_size(box) * 0.5f; +} + +/*! + * @brief computes center point of AABB + * + * @param[in] box bounding box + * @param[out] dest center of bounding box + */ +CGLM_INLINE +void +glm_aabb_center(vec3 box[2], vec3 dest) { + glm_vec3_center(box[0], box[1], dest); +} + +/*! + * @brief check if two AABB intersects + * + * @param[in] box bounding box + * @param[in] other other bounding box + */ +CGLM_INLINE +bool +glm_aabb_aabb(vec3 box[2], vec3 other[2]) { + return (box[0][0] <= other[1][0] && box[1][0] >= other[0][0]) + && (box[0][1] <= other[1][1] && box[1][1] >= other[0][1]) + && (box[0][2] <= other[1][2] && box[1][2] >= other[0][2]); +} + +/*! + * @brief check if AABB intersects with sphere + * + * https://github.com/erich666/GraphicsGems/blob/master/gems/BoxSphere.c + * Solid Box - Solid Sphere test. + * + * Sphere Representation in cglm: [center.x, center.y, center.z, radii] + * + * @param[in] box solid bounding box + * @param[in] s solid sphere + */ +CGLM_INLINE +bool +glm_aabb_sphere(vec3 box[2], vec4 s) { + float dmin; + int a, b, c; + + a = (s[0] < box[0][0]) + (s[0] > box[1][0]); + b = (s[1] < box[0][1]) + (s[1] > box[1][1]); + c = (s[2] < box[0][2]) + (s[2] > box[1][2]); + + dmin = glm_pow2((s[0] - box[!(a - 1)][0]) * (a != 0)) + + glm_pow2((s[1] - box[!(b - 1)][1]) * (b != 0)) + + glm_pow2((s[2] - box[!(c - 1)][2]) * (c != 0)); + + return dmin <= glm_pow2(s[3]); +} + +/*! + * @brief check if point is inside of AABB + * + * @param[in] box bounding box + * @param[in] point point + */ +CGLM_INLINE +bool +glm_aabb_point(vec3 box[2], vec3 point) { + return (point[0] >= box[0][0] && point[0] <= box[1][0]) + && (point[1] >= box[0][1] && point[1] <= box[1][1]) + && (point[2] >= box[0][2] && point[2] <= box[1][2]); +} + +/*! + * @brief check if AABB contains other AABB + * + * @param[in] box bounding box + * @param[in] other other bounding box + */ +CGLM_INLINE +bool +glm_aabb_contains(vec3 box[2], vec3 other[2]) { + return (box[0][0] <= other[0][0] && box[1][0] >= other[1][0]) + && (box[0][1] <= other[0][1] && box[1][1] >= other[1][1]) + && (box[0][2] <= other[0][2] && box[1][2] >= other[1][2]); +} + +#endif /* cglm_box_h */ diff --git a/include/cglm/call.h b/include/cglm/call.h new file mode 100644 index 0000000..734bd46 --- /dev/null +++ b/include/cglm/call.h @@ -0,0 +1,43 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_call_h +#define cglm_call_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "cglm.h" +#include "call/vec2.h" +#include "call/vec3.h" +#include "call/vec4.h" +#include "call/ivec2.h" +#include "call/ivec3.h" +#include "call/ivec4.h" +#include "call/mat2.h" +#include "call/mat3.h" +#include "call/mat4.h" +#include "call/affine.h" +#include "call/cam.h" +#include "call/quat.h" +#include "call/euler.h" +#include "call/plane.h" +#include "call/frustum.h" +#include "call/box.h" +#include "call/io.h" +#include "call/project.h" +#include "call/sphere.h" +#include "call/ease.h" +#include "call/curve.h" +#include "call/bezier.h" +#include "call/ray.h" +#include "call/affine2d.h" + +#ifdef __cplusplus +} +#endif +#endif /* cglm_call_h */ diff --git a/include/cglm/call/affine.h b/include/cglm/call/affine.h new file mode 100644 index 0000000..52b8501 --- /dev/null +++ b/include/cglm/call/affine.h @@ -0,0 +1,167 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_affine_h +#define cglmc_affine_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +void +glmc_translate_make(mat4 m, vec3 v); + +CGLM_EXPORT +void +glmc_translate_to(mat4 m, vec3 v, mat4 dest); + +CGLM_EXPORT +void +glmc_translate(mat4 m, vec3 v); + +CGLM_EXPORT +void +glmc_translate_x(mat4 m, float to); + +CGLM_EXPORT +void +glmc_translate_y(mat4 m, float to); + +CGLM_EXPORT +void +glmc_translate_z(mat4 m, float to); + +CGLM_EXPORT +void +glmc_scale_make(mat4 m, vec3 v); + +CGLM_EXPORT +void +glmc_scale_to(mat4 m, vec3 v, mat4 dest); + +CGLM_EXPORT +void +glmc_scale(mat4 m, vec3 v); + +CGLM_EXPORT +void +glmc_scale_uni(mat4 m, float s); + +CGLM_EXPORT +void +glmc_rotate_x(mat4 m, float rad, mat4 dest); + +CGLM_EXPORT +void +glmc_rotate_y(mat4 m, float rad, mat4 dest); + +CGLM_EXPORT +void +glmc_rotate_z(mat4 m, float rad, mat4 dest); + +CGLM_EXPORT +void +glmc_rotate_make(mat4 m, float angle, vec3 axis); + +CGLM_EXPORT +void +glmc_rotate(mat4 m, float angle, vec3 axis); + +CGLM_EXPORT +void +glmc_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis); + +CGLM_EXPORT +void +glmc_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis); + +CGLM_EXPORT +void +glmc_spin(mat4 m, float angle, vec3 axis); + +CGLM_EXPORT +void +glmc_decompose_scalev(mat4 m, vec3 s); + +CGLM_EXPORT +bool +glmc_uniscaled(mat4 m); + +CGLM_EXPORT +void +glmc_decompose_rs(mat4 m, mat4 r, vec3 s); + +CGLM_EXPORT +void +glmc_decompose(mat4 m, vec4 t, mat4 r, vec3 s); + +/* affine-post */ + +CGLM_EXPORT +void +glmc_translated(mat4 m, vec3 v); + +CGLM_EXPORT +void +glmc_translated_to(mat4 m, vec3 v, mat4 dest); + +CGLM_EXPORT +void +glmc_translated_x(mat4 m, float x); + +CGLM_EXPORT +void +glmc_translated_y(mat4 m, float y); + +CGLM_EXPORT +void +glmc_translated_z(mat4 m, float z); + +CGLM_EXPORT +void +glmc_rotated_x(mat4 m, float angle, mat4 dest); + +CGLM_EXPORT +void +glmc_rotated_y(mat4 m, float angle, mat4 dest); + +CGLM_EXPORT +void +glmc_rotated_z(mat4 m, float angle, mat4 dest); + +CGLM_EXPORT +void +glmc_rotated(mat4 m, float angle, vec3 axis); + +CGLM_EXPORT +void +glmc_rotated_at(mat4 m, vec3 pivot, float angle, vec3 axis); + +CGLM_EXPORT +void +glmc_spinned(mat4 m, float angle, vec3 axis); + +/* affine-mat */ + +CGLM_EXPORT +void +glmc_mul(mat4 m1, mat4 m2, mat4 dest); + +CGLM_EXPORT +void +glmc_mul_rot(mat4 m1, mat4 m2, mat4 dest); + +CGLM_EXPORT +void +glmc_inv_tr(mat4 mat); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_affine_h */ diff --git a/include/cglm/call/affine2d.h b/include/cglm/call/affine2d.h new file mode 100644 index 0000000..e1b9462 --- /dev/null +++ b/include/cglm/call/affine2d.h @@ -0,0 +1,67 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_affine2d_h +#define cglmc_affine2d_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +void +glmc_translate2d_make(mat3 m, vec2 v); + +CGLM_EXPORT +void +glmc_translate2d_to(mat3 m, vec2 v, mat3 dest); + +CGLM_EXPORT +void +glmc_translate2d(mat3 m, vec2 v); + +CGLM_EXPORT +void +glmc_translate2d_x(mat3 m, float to); + +CGLM_EXPORT +void +glmc_translate2d_y(mat3 m, float to); + +CGLM_EXPORT +void +glmc_scale2d_to(mat3 m, vec2 v, mat3 dest); + +CGLM_EXPORT +void +glmc_scale2d_make(mat3 m, vec2 v); + +CGLM_EXPORT +void +glmc_scale2d(mat3 m, vec2 v); + +CGLM_EXPORT +void +glmc_scale2d_uni(mat3 m, float s); + +CGLM_EXPORT +void +glmc_rotate2d_make(mat3 m, float angle); + +CGLM_EXPORT +void +glmc_rotate2d(mat3 m, float angle); + +CGLM_EXPORT +void +glmc_rotate2d_to(mat3 m, float angle, mat3 dest); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_affine2d_h */ diff --git a/include/cglm/call/bezier.h b/include/cglm/call/bezier.h new file mode 100644 index 0000000..a6a0eb4 --- /dev/null +++ b/include/cglm/call/bezier.h @@ -0,0 +1,31 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_bezier_h +#define cglmc_bezier_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +float +glmc_bezier(float s, float p0, float c0, float c1, float p1); + +CGLM_EXPORT +float +glmc_hermite(float s, float p0, float t0, float t1, float p1); + +CGLM_EXPORT +float +glmc_decasteljau(float prm, float p0, float c0, float c1, float p1); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_bezier_h */ diff --git a/include/cglm/call/box.h b/include/cglm/call/box.h new file mode 100644 index 0000000..afb7558 --- /dev/null +++ b/include/cglm/call/box.h @@ -0,0 +1,79 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_box_h +#define cglmc_box_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +void +glmc_aabb_transform(vec3 box[2], mat4 m, vec3 dest[2]); + +CGLM_EXPORT +void +glmc_aabb_merge(vec3 box1[2], vec3 box2[2], vec3 dest[2]); + +CGLM_EXPORT +void +glmc_aabb_crop(vec3 box[2], vec3 cropBox[2], vec3 dest[2]); + +CGLM_EXPORT +void +glmc_aabb_crop_until(vec3 box[2], + vec3 cropBox[2], + vec3 clampBox[2], + vec3 dest[2]); + +CGLM_EXPORT +bool +glmc_aabb_frustum(vec3 box[2], vec4 planes[6]); + +CGLM_EXPORT +void +glmc_aabb_invalidate(vec3 box[2]); + +CGLM_EXPORT +bool +glmc_aabb_isvalid(vec3 box[2]); + +CGLM_EXPORT +float +glmc_aabb_size(vec3 box[2]); + +CGLM_EXPORT +float +glmc_aabb_radius(vec3 box[2]); + +CGLM_EXPORT +void +glmc_aabb_center(vec3 box[2], vec3 dest); + +CGLM_EXPORT +bool +glmc_aabb_aabb(vec3 box[2], vec3 other[2]); + +CGLM_EXPORT +bool +glmc_aabb_point(vec3 box[2], vec3 point); + +CGLM_EXPORT +bool +glmc_aabb_contains(vec3 box[2], vec3 other[2]); + +CGLM_EXPORT +bool +glmc_aabb_sphere(vec3 box[2], vec4 s); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_box_h */ + diff --git a/include/cglm/call/cam.h b/include/cglm/call/cam.h new file mode 100644 index 0000000..d9567ec --- /dev/null +++ b/include/cglm/call/cam.h @@ -0,0 +1,133 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_cam_h +#define cglmc_cam_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +void +glmc_frustum(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest); + +CGLM_EXPORT +void +glmc_ortho(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_aabb(vec3 box[2], mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_aabb_p(vec3 box[2], float padding, mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_aabb_pz(vec3 box[2], float padding, mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_default(float aspect, mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_default_s(float aspect, float size, mat4 dest); + +CGLM_EXPORT +void +glmc_perspective(float fovy, float aspect, float nearZ, float farZ, mat4 dest); + +CGLM_EXPORT +void +glmc_persp_move_far(mat4 proj, float deltaFar); + +CGLM_EXPORT +void +glmc_perspective_default(float aspect, mat4 dest); + +CGLM_EXPORT +void +glmc_perspective_resize(float aspect, mat4 proj); + +CGLM_EXPORT +void +glmc_lookat(vec3 eye, vec3 center, vec3 up, mat4 dest); + +CGLM_EXPORT +void +glmc_look(vec3 eye, vec3 dir, vec3 up, mat4 dest); + +CGLM_EXPORT +void +glmc_look_anyup(vec3 eye, vec3 dir, mat4 dest); + +CGLM_EXPORT +void +glmc_persp_decomp(mat4 proj, + float * __restrict nearZ, + float * __restrict farZ, + float * __restrict top, + float * __restrict bottom, + float * __restrict left, + float * __restrict right); + +CGLM_EXPORT +void +glmc_persp_decompv(mat4 proj, float dest[6]); + +CGLM_EXPORT +void +glmc_persp_decomp_x(mat4 proj, + float * __restrict left, + float * __restrict right); + +CGLM_EXPORT +void +glmc_persp_decomp_y(mat4 proj, + float * __restrict top, + float * __restrict bottom); + +CGLM_EXPORT +void +glmc_persp_decomp_z(mat4 proj, + float * __restrict nearZ, + float * __restrict farZ); + +CGLM_EXPORT +void +glmc_persp_decomp_far(mat4 proj, float * __restrict farZ); + +CGLM_EXPORT +void +glmc_persp_decomp_near(mat4 proj, float * __restrict nearZ); + +CGLM_EXPORT +float +glmc_persp_fovy(mat4 proj); + +CGLM_EXPORT +float +glmc_persp_aspect(mat4 proj); + +CGLM_EXPORT +void +glmc_persp_sizes(mat4 proj, float fovy, vec4 dest); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_cam_h */ diff --git a/include/cglm/call/clipspace/ortho_lh_no.h b/include/cglm/call/clipspace/ortho_lh_no.h new file mode 100644 index 0000000..3e26fa9 --- /dev/null +++ b/include/cglm/call/clipspace/ortho_lh_no.h @@ -0,0 +1,46 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_ortho_lh_no_h +#define cglmc_ortho_lh_no_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../cglm.h" + +CGLM_EXPORT +void +glmc_ortho_lh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_aabb_lh_no(vec3 box[2], mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_aabb_p_lh_no(vec3 box[2], float padding, mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_aabb_pz_lh_no(vec3 box[2], float padding, mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_default_lh_no(float aspect, mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_default_s_lh_no(float aspect, float size, mat4 dest); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_ortho_lh_no_h */ diff --git a/include/cglm/call/clipspace/ortho_lh_zo.h b/include/cglm/call/clipspace/ortho_lh_zo.h new file mode 100644 index 0000000..dc4c610 --- /dev/null +++ b/include/cglm/call/clipspace/ortho_lh_zo.h @@ -0,0 +1,46 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_ortho_lh_zo_h +#define cglmc_ortho_lh_zo_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../cglm.h" + +CGLM_EXPORT +void +glmc_ortho_lh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_aabb_lh_zo(vec3 box[2], mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_aabb_p_lh_zo(vec3 box[2], float padding, mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_aabb_pz_lh_zo(vec3 box[2], float padding, mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_default_lh_zo(float aspect, mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_default_s_lh_zo(float aspect, float size, mat4 dest); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_ortho_lh_zo_h */ diff --git a/include/cglm/call/clipspace/ortho_rh_no.h b/include/cglm/call/clipspace/ortho_rh_no.h new file mode 100644 index 0000000..dbba497 --- /dev/null +++ b/include/cglm/call/clipspace/ortho_rh_no.h @@ -0,0 +1,46 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_ortho_rh_no_h +#define cglmc_ortho_rh_no_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../cglm.h" + +CGLM_EXPORT +void +glmc_ortho_rh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_aabb_rh_no(vec3 box[2], mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_aabb_p_rh_no(vec3 box[2], float padding, mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_aabb_pz_rh_no(vec3 box[2], float padding, mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_default_rh_no(float aspect, mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_default_s_rh_no(float aspect, float size, mat4 dest); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_ortho_rh_no_h */ diff --git a/include/cglm/call/clipspace/ortho_rh_zo.h b/include/cglm/call/clipspace/ortho_rh_zo.h new file mode 100644 index 0000000..e79ae83 --- /dev/null +++ b/include/cglm/call/clipspace/ortho_rh_zo.h @@ -0,0 +1,46 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_ortho_rh_zo_h +#define cglmc_ortho_rh_zo_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../cglm.h" + +CGLM_EXPORT +void +glmc_ortho_rh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_aabb_rh_zo(vec3 box[2], mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_aabb_p_rh_zo(vec3 box[2], float padding, mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_aabb_pz_rh_zo(vec3 box[2], float padding, mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_default_rh_zo(float aspect, mat4 dest); + +CGLM_EXPORT +void +glmc_ortho_default_s_rh_zo(float aspect, float size, mat4 dest); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_ortho_rh_zo_h */ diff --git a/include/cglm/call/clipspace/persp_lh_no.h b/include/cglm/call/clipspace/persp_lh_no.h new file mode 100644 index 0000000..4bdbcfe --- /dev/null +++ b/include/cglm/call/clipspace/persp_lh_no.h @@ -0,0 +1,87 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_persp_lh_no_h +#define cglmc_persp_lh_no_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../cglm.h" + +CGLM_EXPORT +void +glmc_frustum_lh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest); + +CGLM_EXPORT +void +glmc_perspective_lh_no(float fovy, + float aspect, + float nearVal, + float farVal, + mat4 dest); + +CGLM_EXPORT +void +glmc_persp_move_far_lh_no(mat4 proj, float deltaFar); + +CGLM_EXPORT +void +glmc_persp_decomp_lh_no(mat4 proj, + float * __restrict nearZ, float * __restrict farZ, + float * __restrict top, float * __restrict bottom, + float * __restrict left, float * __restrict right); + +CGLM_EXPORT +void +glmc_persp_decompv_lh_no(mat4 proj, float dest[6]); + +CGLM_EXPORT +void +glmc_persp_decomp_x_lh_no(mat4 proj, + float * __restrict left, + float * __restrict right); + +CGLM_EXPORT +void +glmc_persp_decomp_y_lh_no(mat4 proj, + float * __restrict top, + float * __restrict bottom); + +CGLM_EXPORT +void +glmc_persp_decomp_z_lh_no(mat4 proj, + float * __restrict nearZ, + float * __restrict farZ); + +CGLM_EXPORT +void +glmc_persp_decomp_far_lh_no(mat4 proj, float * __restrict farZ); + +CGLM_EXPORT +void +glmc_persp_decomp_near_lh_no(mat4 proj, float * __restrict nearZ); + +CGLM_EXPORT +void +glmc_persp_sizes_lh_no(mat4 proj, float fovy, vec4 dest); + +CGLM_EXPORT +float +glmc_persp_fovy_lh_no(mat4 proj); + +CGLM_EXPORT +float +glmc_persp_aspect_lh_no(mat4 proj); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_persp_lh_no_h */ diff --git a/include/cglm/call/clipspace/persp_lh_zo.h b/include/cglm/call/clipspace/persp_lh_zo.h new file mode 100644 index 0000000..53c2c1c --- /dev/null +++ b/include/cglm/call/clipspace/persp_lh_zo.h @@ -0,0 +1,87 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_persp_lh_zo_h +#define cglmc_persp_lh_zo_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../cglm.h" + +CGLM_EXPORT +void +glmc_frustum_lh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest); + +CGLM_EXPORT +void +glmc_perspective_lh_zo(float fovy, + float aspect, + float nearVal, + float farVal, + mat4 dest); + +CGLM_EXPORT +void +glmc_persp_move_far_lh_zo(mat4 proj, float deltaFar); + +CGLM_EXPORT +void +glmc_persp_decomp_lh_zo(mat4 proj, + float * __restrict nearZ, float * __restrict farZ, + float * __restrict top, float * __restrict bottom, + float * __restrict left, float * __restrict right); + +CGLM_EXPORT +void +glmc_persp_decompv_lh_zo(mat4 proj, float dest[6]); + +CGLM_EXPORT +void +glmc_persp_decomp_x_lh_zo(mat4 proj, + float * __restrict left, + float * __restrict right); + +CGLM_EXPORT +void +glmc_persp_decomp_y_lh_zo(mat4 proj, + float * __restrict top, + float * __restrict bottom); + +CGLM_EXPORT +void +glmc_persp_decomp_z_lh_zo(mat4 proj, + float * __restrict nearZ, + float * __restrict farZ); + +CGLM_EXPORT +void +glmc_persp_decomp_far_lh_zo(mat4 proj, float * __restrict farZ); + +CGLM_EXPORT +void +glmc_persp_decomp_near_lh_zo(mat4 proj, float * __restrict nearZ); + +CGLM_EXPORT +void +glmc_persp_sizes_lh_zo(mat4 proj, float fovy, vec4 dest); + +CGLM_EXPORT +float +glmc_persp_fovy_lh_zo(mat4 proj); + +CGLM_EXPORT +float +glmc_persp_aspect_lh_zo(mat4 proj); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_persp_lh_zo_h */ diff --git a/include/cglm/call/clipspace/persp_rh_no.h b/include/cglm/call/clipspace/persp_rh_no.h new file mode 100644 index 0000000..9c0d65d --- /dev/null +++ b/include/cglm/call/clipspace/persp_rh_no.h @@ -0,0 +1,87 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_persp_rh_no_h +#define cglmc_persp_rh_no_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../cglm.h" + +CGLM_EXPORT +void +glmc_frustum_rh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest); + +CGLM_EXPORT +void +glmc_perspective_rh_no(float fovy, + float aspect, + float nearVal, + float farVal, + mat4 dest); + +CGLM_EXPORT +void +glmc_persp_move_far_rh_no(mat4 proj, float deltaFar); + +CGLM_EXPORT +void +glmc_persp_decomp_rh_no(mat4 proj, + float * __restrict nearZ, float * __restrict farZ, + float * __restrict top, float * __restrict bottom, + float * __restrict left, float * __restrict right); + +CGLM_EXPORT +void +glmc_persp_decompv_rh_no(mat4 proj, float dest[6]); + +CGLM_EXPORT +void +glmc_persp_decomp_x_rh_no(mat4 proj, + float * __restrict left, + float * __restrict right); + +CGLM_EXPORT +void +glmc_persp_decomp_y_rh_no(mat4 proj, + float * __restrict top, + float * __restrict bottom); + +CGLM_EXPORT +void +glmc_persp_decomp_z_rh_no(mat4 proj, + float * __restrict nearZ, + float * __restrict farZ); + +CGLM_EXPORT +void +glmc_persp_decomp_far_rh_no(mat4 proj, float * __restrict farZ); + +CGLM_EXPORT +void +glmc_persp_decomp_near_rh_no(mat4 proj, float * __restrict nearZ); + +CGLM_EXPORT +void +glmc_persp_sizes_rh_no(mat4 proj, float fovy, vec4 dest); + +CGLM_EXPORT +float +glmc_persp_fovy_rh_no(mat4 proj); + +CGLM_EXPORT +float +glmc_persp_aspect_rh_no(mat4 proj); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_persp_rh_no_h */ diff --git a/include/cglm/call/clipspace/persp_rh_zo.h b/include/cglm/call/clipspace/persp_rh_zo.h new file mode 100644 index 0000000..718d4ad --- /dev/null +++ b/include/cglm/call/clipspace/persp_rh_zo.h @@ -0,0 +1,87 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_persp_rh_zo_h +#define cglmc_persp_rh_zo_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../cglm.h" + +CGLM_EXPORT +void +glmc_frustum_rh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest); + +CGLM_EXPORT +void +glmc_perspective_rh_zo(float fovy, + float aspect, + float nearVal, + float farVal, + mat4 dest); + +CGLM_EXPORT +void +glmc_persp_move_far_rh_zo(mat4 proj, float deltaFar); + +CGLM_EXPORT +void +glmc_persp_decomp_rh_zo(mat4 proj, + float * __restrict nearZ, float * __restrict farZ, + float * __restrict top, float * __restrict bottom, + float * __restrict left, float * __restrict right); + +CGLM_EXPORT +void +glmc_persp_decompv_rh_zo(mat4 proj, float dest[6]); + +CGLM_EXPORT +void +glmc_persp_decomp_x_rh_zo(mat4 proj, + float * __restrict left, + float * __restrict right); + +CGLM_EXPORT +void +glmc_persp_decomp_y_rh_zo(mat4 proj, + float * __restrict top, + float * __restrict bottom); + +CGLM_EXPORT +void +glmc_persp_decomp_z_rh_zo(mat4 proj, + float * __restrict nearZ, + float * __restrict farZ); + +CGLM_EXPORT +void +glmc_persp_decomp_far_rh_zo(mat4 proj, float * __restrict farZ); + +CGLM_EXPORT +void +glmc_persp_decomp_near_rh_zo(mat4 proj, float * __restrict nearZ); + +CGLM_EXPORT +void +glmc_persp_sizes_rh_zo(mat4 proj, float fovy, vec4 dest); + +CGLM_EXPORT +float +glmc_persp_fovy_rh_zo(mat4 proj); + +CGLM_EXPORT +float +glmc_persp_aspect_rh_zo(mat4 proj); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_persp_rh_zo_h */ diff --git a/include/cglm/call/clipspace/project_no.h b/include/cglm/call/clipspace/project_no.h new file mode 100644 index 0000000..3cba860 --- /dev/null +++ b/include/cglm/call/clipspace/project_no.h @@ -0,0 +1,31 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_project_no_h +#define cglmc_project_no_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../cglm.h" + +CGLM_EXPORT +void +glmc_unprojecti_no(vec3 pos, mat4 invMat, vec4 vp, vec3 dest); + +CGLM_EXPORT +void +glmc_project_no(vec3 pos, mat4 m, vec4 vp, vec3 dest); + +CGLM_EXPORT +float +glmc_project_z_no(vec3 pos, mat4 m); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_project_no_h */ diff --git a/include/cglm/call/clipspace/project_zo.h b/include/cglm/call/clipspace/project_zo.h new file mode 100644 index 0000000..d2a6c62 --- /dev/null +++ b/include/cglm/call/clipspace/project_zo.h @@ -0,0 +1,31 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_project_zo_h +#define cglmc_project_zo_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../cglm.h" + +CGLM_EXPORT +void +glmc_unprojecti_zo(vec3 pos, mat4 invMat, vec4 vp, vec3 dest); + +CGLM_EXPORT +void +glmc_project_zo(vec3 pos, mat4 m, vec4 vp, vec3 dest); + +CGLM_EXPORT +float +glmc_project_z_zo(vec3 pos, mat4 m); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_project_zo_h */ diff --git a/include/cglm/call/clipspace/view_lh_no.h b/include/cglm/call/clipspace/view_lh_no.h new file mode 100644 index 0000000..3b58c84 --- /dev/null +++ b/include/cglm/call/clipspace/view_lh_no.h @@ -0,0 +1,31 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_view_lh_no_h +#define cglmc_view_lh_no_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../cglm.h" + +CGLM_EXPORT +void +glmc_lookat_lh_no(vec3 eye, vec3 center, vec3 up, mat4 dest); + +CGLM_EXPORT +void +glmc_look_lh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest); + +CGLM_EXPORT +void +glmc_look_anyup_lh_no(vec3 eye, vec3 dir, mat4 dest); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_view_lh_no_h */ diff --git a/include/cglm/call/clipspace/view_lh_zo.h b/include/cglm/call/clipspace/view_lh_zo.h new file mode 100644 index 0000000..c877367 --- /dev/null +++ b/include/cglm/call/clipspace/view_lh_zo.h @@ -0,0 +1,31 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_view_lh_zo_h +#define cglmc_view_lh_zo_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../cglm.h" + +CGLM_EXPORT +void +glmc_lookat_lh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest); + +CGLM_EXPORT +void +glmc_look_lh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest); + +CGLM_EXPORT +void +glmc_look_anyup_lh_zo(vec3 eye, vec3 dir, mat4 dest); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_view_lh_zo_h */ diff --git a/include/cglm/call/clipspace/view_rh_no.h b/include/cglm/call/clipspace/view_rh_no.h new file mode 100644 index 0000000..6303dbf --- /dev/null +++ b/include/cglm/call/clipspace/view_rh_no.h @@ -0,0 +1,31 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_view_rh_no_h +#define cglmc_view_rh_no_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../cglm.h" + +CGLM_EXPORT +void +glmc_lookat_rh_no(vec3 eye, vec3 center, vec3 up, mat4 dest); + +CGLM_EXPORT +void +glmc_look_rh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest); + +CGLM_EXPORT +void +glmc_look_anyup_rh_no(vec3 eye, vec3 dir, mat4 dest); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_view_rh_no_h */ diff --git a/include/cglm/call/clipspace/view_rh_zo.h b/include/cglm/call/clipspace/view_rh_zo.h new file mode 100644 index 0000000..00b8707 --- /dev/null +++ b/include/cglm/call/clipspace/view_rh_zo.h @@ -0,0 +1,31 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_view_rh_zo_h +#define cglmc_view_rh_zo_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../cglm.h" + +CGLM_EXPORT +void +glmc_lookat_rh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest); + +CGLM_EXPORT +void +glmc_look_rh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest); + +CGLM_EXPORT +void +glmc_look_anyup_rh_zo(vec3 eye, vec3 dir, mat4 dest); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_view_rh_zo_h */ diff --git a/include/cglm/call/curve.h b/include/cglm/call/curve.h new file mode 100644 index 0000000..061fdb9 --- /dev/null +++ b/include/cglm/call/curve.h @@ -0,0 +1,23 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_curve_h +#define cglmc_curve_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +float +glmc_smc(float s, mat4 m, vec4 c); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_curve_h */ diff --git a/include/cglm/call/ease.h b/include/cglm/call/ease.h new file mode 100644 index 0000000..87e39ca --- /dev/null +++ b/include/cglm/call/ease.h @@ -0,0 +1,143 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_ease_h +#define cglmc_ease_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +float +glmc_ease_linear(float t); + +CGLM_EXPORT +float +glmc_ease_sine_in(float t); + +CGLM_EXPORT +float +glmc_ease_sine_out(float t); + +CGLM_EXPORT +float +glmc_ease_sine_inout(float t); + +CGLM_EXPORT +float +glmc_ease_quad_in(float t); + +CGLM_EXPORT +float +glmc_ease_quad_out(float t); + +CGLM_EXPORT +float +glmc_ease_quad_inout(float t); + +CGLM_EXPORT +float +glmc_ease_cubic_in(float t); + +CGLM_EXPORT +float +glmc_ease_cubic_out(float t); + +CGLM_EXPORT +float +glmc_ease_cubic_inout(float t); + +CGLM_EXPORT +float +glmc_ease_quart_in(float t); + +CGLM_EXPORT +float +glmc_ease_quart_out(float t); + +CGLM_EXPORT +float +glmc_ease_quart_inout(float t); + +CGLM_EXPORT +float +glmc_ease_quint_in(float t); + +CGLM_EXPORT +float +glmc_ease_quint_out(float t); + +CGLM_EXPORT +float +glmc_ease_quint_inout(float t); + +CGLM_EXPORT +float +glmc_ease_exp_in(float t); + +CGLM_EXPORT +float +glmc_ease_exp_out(float t); + +CGLM_EXPORT +float +glmc_ease_exp_inout(float t); + +CGLM_EXPORT +float +glmc_ease_circ_in(float t); + +CGLM_EXPORT +float +glmc_ease_circ_out(float t); + +CGLM_EXPORT +float +glmc_ease_circ_inout(float t); + +CGLM_EXPORT +float +glmc_ease_back_in(float t); + +CGLM_EXPORT +float +glmc_ease_back_out(float t); + +CGLM_EXPORT +float +glmc_ease_back_inout(float t); + +CGLM_EXPORT +float +glmc_ease_elast_in(float t); + +CGLM_EXPORT +float +glmc_ease_elast_out(float t); + +CGLM_EXPORT +float +glmc_ease_elast_inout(float t); + +CGLM_EXPORT +float +glmc_ease_bounce_out(float t); + +CGLM_EXPORT +float +glmc_ease_bounce_in(float t); + +CGLM_EXPORT +float +glmc_ease_bounce_inout(float t); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_ease_h */ diff --git a/include/cglm/call/euler.h b/include/cglm/call/euler.h new file mode 100644 index 0000000..2de68fb --- /dev/null +++ b/include/cglm/call/euler.h @@ -0,0 +1,55 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_euler_h +#define cglmc_euler_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +void +glmc_euler_angles(mat4 m, vec3 dest); + +CGLM_EXPORT +void +glmc_euler(vec3 angles, mat4 dest); + +CGLM_EXPORT +void +glmc_euler_xyz(vec3 angles, mat4 dest); + +CGLM_EXPORT +void +glmc_euler_zyx(vec3 angles, mat4 dest); + +CGLM_EXPORT +void +glmc_euler_zxy(vec3 angles, mat4 dest); + +CGLM_EXPORT +void +glmc_euler_xzy(vec3 angles, mat4 dest); + +CGLM_EXPORT +void +glmc_euler_yzx(vec3 angles, mat4 dest); + +CGLM_EXPORT +void +glmc_euler_yxz(vec3 angles, mat4 dest); + +CGLM_EXPORT +void +glmc_euler_by_order(vec3 angles, glm_euler_seq axis, mat4 dest); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_euler_h */ diff --git a/include/cglm/call/frustum.h b/include/cglm/call/frustum.h new file mode 100644 index 0000000..6b4facb --- /dev/null +++ b/include/cglm/call/frustum.h @@ -0,0 +1,41 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_frustum_h +#define cglmc_frustum_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +void +glmc_frustum_planes(mat4 m, vec4 dest[6]); + +CGLM_EXPORT +void +glmc_frustum_corners(mat4 invMat, vec4 dest[8]); + +CGLM_EXPORT +void +glmc_frustum_center(vec4 corners[8], vec4 dest); + +CGLM_EXPORT +void +glmc_frustum_box(vec4 corners[8], mat4 m, vec3 box[2]); + +CGLM_EXPORT +void +glmc_frustum_corners_at(vec4 corners[8], + float splitDist, + float farDist, + vec4 planeCorners[4]); +#ifdef __cplusplus +} +#endif +#endif /* cglmc_frustum_h */ diff --git a/include/cglm/call/io.h b/include/cglm/call/io.h new file mode 100644 index 0000000..19ea06f --- /dev/null +++ b/include/cglm/call/io.h @@ -0,0 +1,45 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_io_h +#define cglmc_io_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +void +glmc_mat4_print(mat4 matrix, + FILE * __restrict ostream); + +CGLM_EXPORT +void +glmc_mat3_print(mat3 matrix, + FILE * __restrict ostream); + +CGLM_EXPORT +void +glmc_vec4_print(vec4 vec, + FILE * __restrict ostream); + +CGLM_EXPORT +void +glmc_vec3_print(vec3 vec, + FILE * __restrict ostream); + +CGLM_EXPORT +void +glmc_versor_print(versor vec, + FILE * __restrict ostream); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_io_h */ diff --git a/include/cglm/call/ivec2.h b/include/cglm/call/ivec2.h new file mode 100644 index 0000000..ec1d2b3 --- /dev/null +++ b/include/cglm/call/ivec2.h @@ -0,0 +1,83 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_ivec2_h +#define cglmc_ivec2_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +void +glmc_ivec2(int * __restrict v, ivec2 dest); + +CGLM_EXPORT +void +glmc_ivec2_copy(ivec2 a, ivec2 dest); + +CGLM_EXPORT +void +glmc_ivec2_zero(ivec2 v); + +CGLM_EXPORT +void +glmc_ivec2_one(ivec2 v); + +CGLM_EXPORT +void +glmc_ivec2_add(ivec2 a, ivec2 b, ivec2 dest); + +CGLM_EXPORT +void +glmc_ivec2_adds(ivec2 v, int s, ivec2 dest); + +CGLM_EXPORT +void +glmc_ivec2_sub(ivec2 a, ivec2 b, ivec2 dest); + +CGLM_EXPORT +void +glmc_ivec2_subs(ivec2 v, int s, ivec2 dest); + +CGLM_EXPORT +void +glmc_ivec2_mul(ivec2 a, ivec2 b, ivec2 dest); + +CGLM_EXPORT +void +glmc_ivec2_scale(ivec2 v, int s, ivec2 dest); + +CGLM_EXPORT +int +glmc_ivec2_distance2(ivec2 a, ivec2 b); + +CGLM_EXPORT +float +glmc_ivec2_distance(ivec2 a, ivec2 b); + +CGLM_EXPORT +void +glmc_ivec2_maxv(ivec2 a, ivec2 b, ivec2 dest); + +CGLM_EXPORT +void +glmc_ivec2_minv(ivec2 a, ivec2 b, ivec2 dest); + +CGLM_EXPORT +void +glmc_ivec2_clamp(ivec2 v, int minVal, int maxVal); + +CGLM_EXPORT +void +glmc_ivec2_abs(ivec2 v, ivec2 dest); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_ivec2_h */ diff --git a/include/cglm/call/ivec3.h b/include/cglm/call/ivec3.h new file mode 100644 index 0000000..c24b2a7 --- /dev/null +++ b/include/cglm/call/ivec3.h @@ -0,0 +1,83 @@ +/* + * Copyright (c);, Recep Aslantas. + * + * MIT License (MIT);, http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_ivec3_h +#define cglmc_ivec3_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +void +glmc_ivec3(ivec4 v4, ivec3 dest); + +CGLM_EXPORT +void +glmc_ivec3_copy(ivec3 a, ivec3 dest); + +CGLM_EXPORT +void +glmc_ivec3_zero(ivec3 v); + +CGLM_EXPORT +void +glmc_ivec3_one(ivec3 v); + +CGLM_EXPORT +void +glmc_ivec3_add(ivec3 a, ivec3 b, ivec3 dest); + +CGLM_EXPORT +void +glmc_ivec3_adds(ivec3 v, int s, ivec3 dest); + +CGLM_EXPORT +void +glmc_ivec3_sub(ivec3 a, ivec3 b, ivec3 dest); + +CGLM_EXPORT +void +glmc_ivec3_subs(ivec3 v, int s, ivec3 dest); + +CGLM_EXPORT +void +glmc_ivec3_mul(ivec3 a, ivec3 b, ivec3 dest); + +CGLM_EXPORT +void +glmc_ivec3_scale(ivec3 v, int s, ivec3 dest); + +CGLM_EXPORT +int +glmc_ivec3_distance2(ivec3 a, ivec3 b); + +CGLM_EXPORT +float +glmc_ivec3_distance(ivec3 a, ivec3 b); + +CGLM_EXPORT +void +glmc_ivec3_maxv(ivec3 a, ivec3 b, ivec3 dest); + +CGLM_EXPORT +void +glmc_ivec3_minv(ivec3 a, ivec3 b, ivec3 dest); + +CGLM_EXPORT +void +glmc_ivec3_clamp(ivec3 v, int minVal, int maxVal); + +CGLM_EXPORT +void +glmc_ivec3_abs(ivec3 v, ivec3 dest); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_ivec3_h */ diff --git a/include/cglm/call/ivec4.h b/include/cglm/call/ivec4.h new file mode 100644 index 0000000..be80f89 --- /dev/null +++ b/include/cglm/call/ivec4.h @@ -0,0 +1,83 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_ivec4_h +#define cglmc_ivec4_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +void +glmc_ivec4(ivec3 v3, int last, ivec4 dest); + +CGLM_EXPORT +void +glmc_ivec4_copy(ivec4 a, ivec4 dest); + +CGLM_EXPORT +void +glmc_ivec4_zero(ivec4 v); + +CGLM_EXPORT +void +glmc_ivec4_one(ivec4 v); + +CGLM_EXPORT +void +glmc_ivec4_add(ivec4 a, ivec4 b, ivec4 dest); + +CGLM_EXPORT +void +glmc_ivec4_adds(ivec4 v, int s, ivec4 dest); + +CGLM_EXPORT +void +glmc_ivec4_sub(ivec4 a, ivec4 b, ivec4 dest); + +CGLM_EXPORT +void +glmc_ivec4_subs(ivec4 v, int s, ivec4 dest); + +CGLM_EXPORT +void +glmc_ivec4_mul(ivec4 a, ivec4 b, ivec4 dest); + +CGLM_EXPORT +void +glmc_ivec4_scale(ivec4 v, int s, ivec4 dest); + +CGLM_EXPORT +int +glmc_ivec4_distance2(ivec4 a, ivec4 b); + +CGLM_EXPORT +float +glmc_ivec4_distance(ivec4 a, ivec4 b); + +CGLM_EXPORT +void +glmc_ivec4_maxv(ivec4 a, ivec4 b, ivec4 dest); + +CGLM_EXPORT +void +glmc_ivec4_minv(ivec4 a, ivec4 b, ivec4 dest); + +CGLM_EXPORT +void +glmc_ivec4_clamp(ivec4 v, int minVal, int maxVal); + +CGLM_EXPORT +void +glmc_ivec4_abs(ivec4 v, ivec4 dest); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_ivec4_h */ diff --git a/include/cglm/call/mat2.h b/include/cglm/call/mat2.h new file mode 100644 index 0000000..91234a3 --- /dev/null +++ b/include/cglm/call/mat2.h @@ -0,0 +1,79 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_mat2_h +#define cglmc_mat2_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +void +glmc_mat2_copy(mat2 mat, mat2 dest); + +CGLM_EXPORT +void +glmc_mat2_identity(mat2 mat); + +CGLM_EXPORT +void +glmc_mat2_identity_array(mat2 * __restrict mat, size_t count); + +CGLM_EXPORT +void +glmc_mat2_zero(mat2 mat); + +CGLM_EXPORT +void +glmc_mat2_mul(mat2 m1, mat2 m2, mat2 dest); + +CGLM_EXPORT +void +glmc_mat2_transpose_to(mat2 m, mat2 dest); + +CGLM_EXPORT +void +glmc_mat2_transpose(mat2 m); + +CGLM_EXPORT +void +glmc_mat2_mulv(mat2 m, vec2 v, vec2 dest); + +CGLM_EXPORT +float +glmc_mat2_trace(mat2 m); + +CGLM_EXPORT +void +glmc_mat2_scale(mat2 m, float s); + +CGLM_EXPORT +float +glmc_mat2_det(mat2 mat); + +CGLM_EXPORT +void +glmc_mat2_inv(mat2 mat, mat2 dest); + +CGLM_EXPORT +void +glmc_mat2_swap_col(mat2 mat, int col1, int col2); + +CGLM_EXPORT +void +glmc_mat2_swap_row(mat2 mat, int row1, int row2); + +CGLM_EXPORT +float +glmc_mat2_rmc(vec2 r, mat2 m, vec2 c); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_mat2_h */ diff --git a/include/cglm/call/mat3.h b/include/cglm/call/mat3.h new file mode 100644 index 0000000..36dcb27 --- /dev/null +++ b/include/cglm/call/mat3.h @@ -0,0 +1,86 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_mat3_h +#define cglmc_mat3_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +/* DEPRECATED! use _copy, _ucopy versions */ +#define glmc_mat3_dup(mat, dest) glmc_mat3_copy(mat, dest) + +CGLM_EXPORT +void +glmc_mat3_copy(mat3 mat, mat3 dest); + +CGLM_EXPORT +void +glmc_mat3_identity(mat3 mat); + +CGLM_EXPORT +void +glmc_mat3_zero(mat3 mat); + +CGLM_EXPORT +void +glmc_mat3_identity_array(mat3 * __restrict mat, size_t count); + +CGLM_EXPORT +void +glmc_mat3_mul(mat3 m1, mat3 m2, mat3 dest); + +CGLM_EXPORT +void +glmc_mat3_transpose_to(mat3 m, mat3 dest); + +CGLM_EXPORT +void +glmc_mat3_transpose(mat3 m); + +CGLM_EXPORT +void +glmc_mat3_mulv(mat3 m, vec3 v, vec3 dest); + +CGLM_EXPORT +float +glmc_mat3_trace(mat3 m); + +CGLM_EXPORT +void +glmc_mat3_quat(mat3 m, versor dest); + +CGLM_EXPORT +void +glmc_mat3_scale(mat3 m, float s); + +CGLM_EXPORT +float +glmc_mat3_det(mat3 mat); + +CGLM_EXPORT +void +glmc_mat3_inv(mat3 mat, mat3 dest); + +CGLM_EXPORT +void +glmc_mat3_swap_col(mat3 mat, int col1, int col2); + +CGLM_EXPORT +void +glmc_mat3_swap_row(mat3 mat, int row1, int row2); + +CGLM_EXPORT +float +glmc_mat3_rmc(vec3 r, mat3 m, vec3 c); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_mat3_h */ diff --git a/include/cglm/call/mat4.h b/include/cglm/call/mat4.h new file mode 100644 index 0000000..1c71da1 --- /dev/null +++ b/include/cglm/call/mat4.h @@ -0,0 +1,127 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_mat_h +#define cglmc_mat_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +/* DEPRECATED! use _copy, _ucopy versions */ +#define glmc_mat4_udup(mat, dest) glmc_mat4_ucopy(mat, dest) +#define glmc_mat4_dup(mat, dest) glmc_mat4_copy(mat, dest) + +CGLM_EXPORT +void +glmc_mat4_ucopy(mat4 mat, mat4 dest); + +CGLM_EXPORT +void +glmc_mat4_copy(mat4 mat, mat4 dest); + +CGLM_EXPORT +void +glmc_mat4_identity(mat4 mat); + +CGLM_EXPORT +void +glmc_mat4_identity_array(mat4 * __restrict mat, size_t count); + +CGLM_EXPORT +void +glmc_mat4_zero(mat4 mat); + +CGLM_EXPORT +void +glmc_mat4_pick3(mat4 mat, mat3 dest); + +CGLM_EXPORT +void +glmc_mat4_pick3t(mat4 mat, mat3 dest); + +CGLM_EXPORT +void +glmc_mat4_ins3(mat3 mat, mat4 dest); + +CGLM_EXPORT +void +glmc_mat4_mul(mat4 m1, mat4 m2, mat4 dest); + +CGLM_EXPORT +void +glmc_mat4_mulN(mat4 * __restrict matrices[], uint32_t len, mat4 dest); + +CGLM_EXPORT +void +glmc_mat4_mulv(mat4 m, vec4 v, vec4 dest); + +CGLM_EXPORT +void +glmc_mat4_mulv3(mat4 m, vec3 v, float last, vec3 dest); + +CGLM_EXPORT +float +glmc_mat4_trace(mat4 m); + +CGLM_EXPORT +float +glmc_mat4_trace3(mat4 m); + +CGLM_EXPORT +void +glmc_mat4_quat(mat4 m, versor dest); + +CGLM_EXPORT +void +glmc_mat4_transpose_to(mat4 m, mat4 dest); + +CGLM_EXPORT +void +glmc_mat4_transpose(mat4 m); + +CGLM_EXPORT +void +glmc_mat4_scale_p(mat4 m, float s); + +CGLM_EXPORT +void +glmc_mat4_scale(mat4 m, float s); + +CGLM_EXPORT +float +glmc_mat4_det(mat4 mat); + +CGLM_EXPORT +void +glmc_mat4_inv(mat4 mat, mat4 dest); + +CGLM_EXPORT +void +glmc_mat4_inv_precise(mat4 mat, mat4 dest); + +CGLM_EXPORT +void +glmc_mat4_inv_fast(mat4 mat, mat4 dest); + +CGLM_EXPORT +void +glmc_mat4_swap_col(mat4 mat, int col1, int col2); + +CGLM_EXPORT +void +glmc_mat4_swap_row(mat4 mat, int row1, int row2); + +CGLM_EXPORT +float +glmc_mat4_rmc(vec4 r, mat4 m, vec4 c); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_mat_h */ diff --git a/include/cglm/call/plane.h b/include/cglm/call/plane.h new file mode 100644 index 0000000..f991121 --- /dev/null +++ b/include/cglm/call/plane.h @@ -0,0 +1,23 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_plane_h +#define cglmc_plane_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +void +glmc_plane_normalize(vec4 plane); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_plane_h */ diff --git a/include/cglm/call/project.h b/include/cglm/call/project.h new file mode 100644 index 0000000..fcfcf2b --- /dev/null +++ b/include/cglm/call/project.h @@ -0,0 +1,41 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_project_h +#define cglmc_project_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +void +glmc_unprojecti(vec3 pos, mat4 invMat, vec4 vp, vec3 dest); + +CGLM_EXPORT +void +glmc_unproject(vec3 pos, mat4 m, vec4 vp, vec3 dest); + +CGLM_EXPORT +void +glmc_project(vec3 pos, mat4 m, vec4 vp, vec3 dest); + +CGLM_EXPORT +float +glmc_project_z(vec3 pos, mat4 m); + +CGLM_EXPORT +void +glmc_pickmatrix(vec2 center, vec2 size, vec4 vp, mat4 dest); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_project_h */ + + diff --git a/include/cglm/call/quat.h b/include/cglm/call/quat.h new file mode 100644 index 0000000..1a2766d --- /dev/null +++ b/include/cglm/call/quat.h @@ -0,0 +1,167 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_quat_h +#define cglmc_quat_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +void +glmc_quat_identity(versor q); + +CGLM_EXPORT +void +glmc_quat_identity_array(versor * __restrict q, size_t count); + +CGLM_EXPORT +void +glmc_quat_init(versor q, float x, float y, float z, float w); + +CGLM_EXPORT +void +glmc_quat(versor q, float angle, float x, float y, float z); + +CGLM_EXPORT +void +glmc_quatv(versor q, float angle, vec3 axis); + +CGLM_EXPORT +void +glmc_quat_copy(versor q, versor dest); + +CGLM_EXPORT +void +glmc_quat_from_vecs(vec3 a, vec3 b, versor dest); + +CGLM_EXPORT +float +glmc_quat_norm(versor q); + +CGLM_EXPORT +void +glmc_quat_normalize_to(versor q, versor dest); + +CGLM_EXPORT +void +glmc_quat_normalize(versor q); + +CGLM_EXPORT +float +glmc_quat_dot(versor p, versor q); + +CGLM_EXPORT +void +glmc_quat_conjugate(versor q, versor dest); + +CGLM_EXPORT +void +glmc_quat_inv(versor q, versor dest); + +CGLM_EXPORT +void +glmc_quat_add(versor p, versor q, versor dest); + +CGLM_EXPORT +void +glmc_quat_sub(versor p, versor q, versor dest); + +CGLM_EXPORT +float +glmc_quat_real(versor q); + +CGLM_EXPORT +void +glmc_quat_imag(versor q, vec3 dest); + +CGLM_EXPORT +void +glmc_quat_imagn(versor q, vec3 dest); + +CGLM_EXPORT +float +glmc_quat_imaglen(versor q); + +CGLM_EXPORT +float +glmc_quat_angle(versor q); + +CGLM_EXPORT +void +glmc_quat_axis(versor q, vec3 dest); + +CGLM_EXPORT +void +glmc_quat_mul(versor p, versor q, versor dest); + +CGLM_EXPORT +void +glmc_quat_mat4(versor q, mat4 dest); + +CGLM_EXPORT +void +glmc_quat_mat4t(versor q, mat4 dest); + +CGLM_EXPORT +void +glmc_quat_mat3(versor q, mat3 dest); + +CGLM_EXPORT +void +glmc_quat_mat3t(versor q, mat3 dest); + +CGLM_EXPORT +void +glmc_quat_lerp(versor from, versor to, float t, versor dest); + +CGLM_EXPORT +void +glmc_quat_lerpc(versor from, versor to, float t, versor dest); + +CGLM_EXPORT +void +glmc_quat_nlerp(versor q, versor r, float t, versor dest); + +CGLM_EXPORT +void +glmc_quat_slerp(versor q, versor r, float t, versor dest); + +CGLM_EXPORT +void +glmc_quat_look(vec3 eye, versor ori, mat4 dest); + +CGLM_EXPORT +void +glmc_quat_for(vec3 dir, vec3 up, versor dest); + +CGLM_EXPORT +void +glmc_quat_forp(vec3 from, vec3 to, vec3 up, versor dest); + +CGLM_EXPORT +void +glmc_quat_rotatev(versor from, vec3 to, vec3 dest); + +CGLM_EXPORT +void +glmc_quat_rotate(mat4 m, versor q, mat4 dest); + +CGLM_EXPORT +void +glmc_quat_rotate_at(mat4 model, versor q, vec3 pivot); + +CGLM_EXPORT +void +glmc_quat_rotate_atm(mat4 m, versor q, vec3 pivot); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_quat_h */ diff --git a/include/cglm/call/ray.h b/include/cglm/call/ray.h new file mode 100644 index 0000000..1fff055 --- /dev/null +++ b/include/cglm/call/ray.h @@ -0,0 +1,27 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_ray_h +#define cglmc_ray_h +#ifdef __cplusplus +extern "C" { +#endif +#include "../cglm.h" + +CGLM_EXPORT +bool +glmc_ray_triangle(vec3 origin, + vec3 direction, + vec3 v0, + vec3 v1, + vec3 v2, + float *d); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_ray_h */ diff --git a/include/cglm/call/sphere.h b/include/cglm/call/sphere.h new file mode 100644 index 0000000..9b96546 --- /dev/null +++ b/include/cglm/call/sphere.h @@ -0,0 +1,39 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_sphere_h +#define cglmc_sphere_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +float +glmc_sphere_radii(vec4 s); + +CGLM_EXPORT +void +glmc_sphere_transform(vec4 s, mat4 m, vec4 dest); + +CGLM_EXPORT +void +glmc_sphere_merge(vec4 s1, vec4 s2, vec4 dest); + +CGLM_EXPORT +bool +glmc_sphere_sphere(vec4 s1, vec4 s2); + +CGLM_EXPORT +bool +glmc_sphere_point(vec4 s, vec3 point); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_sphere_h */ diff --git a/include/cglm/call/vec2.h b/include/cglm/call/vec2.h new file mode 100644 index 0000000..f3c6a35 --- /dev/null +++ b/include/cglm/call/vec2.h @@ -0,0 +1,171 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_vec2_h +#define cglmc_vec2_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +void +glmc_vec2(float * __restrict v, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_copy(vec2 a, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_zero(vec2 v); + +CGLM_EXPORT +void +glmc_vec2_one(vec2 v); + +CGLM_EXPORT +float +glmc_vec2_dot(vec2 a, vec2 b); + +CGLM_EXPORT +float +glmc_vec2_cross(vec2 a, vec2 b); + +CGLM_EXPORT +float +glmc_vec2_norm2(vec2 v); + +CGLM_EXPORT +float +glmc_vec2_norm(vec2 v); + +CGLM_EXPORT +void +glmc_vec2_add(vec2 a, vec2 b, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_adds(vec2 v, float s, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_sub(vec2 a, vec2 b, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_subs(vec2 v, float s, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_mul(vec2 a, vec2 b, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_scale(vec2 v, float s, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_scale_as(vec2 v, float s, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_div(vec2 a, vec2 b, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_divs(vec2 v, float s, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_addadd(vec2 a, vec2 b, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_subadd(vec2 a, vec2 b, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_muladd(vec2 a, vec2 b, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_muladds(vec2 a, float s, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_maxadd(vec2 a, vec2 b, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_minadd(vec2 a, vec2 b, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_negate_to(vec2 v, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_negate(vec2 v); + +CGLM_EXPORT +void +glmc_vec2_normalize(vec2 v); + +CGLM_EXPORT +void +glmc_vec2_normalize_to(vec2 v, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_rotate(vec2 v, float angle, vec2 dest); + +CGLM_EXPORT +float +glmc_vec2_distance2(vec2 a, vec2 b); + +CGLM_EXPORT +float +glmc_vec2_distance(vec2 a, vec2 b); + +CGLM_EXPORT +void +glmc_vec2_maxv(vec2 a, vec2 b, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_minv(vec2 a, vec2 b, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_clamp(vec2 v, float minval, float maxval); + +CGLM_EXPORT +void +glmc_vec2_abs(vec2 v, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_lerp(vec2 from, vec2 to, float t, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_complex_mul(vec2 a, vec2 b, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_complex_div(vec2 a, vec2 b, vec2 dest); + +CGLM_EXPORT +void +glmc_vec2_complex_conjugate(vec2 a, vec2 dest); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_vec2_h */ diff --git a/include/cglm/call/vec3.h b/include/cglm/call/vec3.h new file mode 100644 index 0000000..69fc0e2 --- /dev/null +++ b/include/cglm/call/vec3.h @@ -0,0 +1,312 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_vec3_h +#define cglmc_vec3_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +/* DEPRECATED! use _copy, _ucopy versions */ +#define glmc_vec_dup(v, dest) glmc_vec3_copy(v, dest) +#define glmc_vec3_flipsign(v) glmc_vec3_negate(v) +#define glmc_vec3_flipsign_to(v, dest) glmc_vec3_negate_to(v, dest) +#define glmc_vec3_inv(v) glmc_vec3_negate(v) +#define glmc_vec3_inv_to(v, dest) glmc_vec3_negate_to(v, dest) + +CGLM_EXPORT +void +glmc_vec3(vec4 v4, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_copy(vec3 a, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_zero(vec3 v); + +CGLM_EXPORT +void +glmc_vec3_one(vec3 v); + +CGLM_EXPORT +float +glmc_vec3_dot(vec3 a, vec3 b); + +CGLM_EXPORT +void +glmc_vec3_cross(vec3 a, vec3 b, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_crossn(vec3 a, vec3 b, vec3 dest); + +CGLM_EXPORT +float +glmc_vec3_norm(vec3 v); + +CGLM_EXPORT +float +glmc_vec3_norm2(vec3 v); + +CGLM_EXPORT +float +glmc_vec3_norm_one(vec3 v); + +CGLM_EXPORT +float +glmc_vec3_norm_inf(vec3 v); + +CGLM_EXPORT +void +glmc_vec3_normalize_to(vec3 v, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_normalize(vec3 v); + +CGLM_EXPORT +void +glmc_vec3_add(vec3 a, vec3 b, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_adds(vec3 v, float s, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_sub(vec3 a, vec3 b, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_subs(vec3 v, float s, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_mul(vec3 a, vec3 b, vec3 d); + +CGLM_EXPORT +void +glmc_vec3_scale(vec3 v, float s, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_scale_as(vec3 v, float s, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_div(vec3 a, vec3 b, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_divs(vec3 a, float s, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_addadd(vec3 a, vec3 b, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_subadd(vec3 a, vec3 b, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_muladd(vec3 a, vec3 b, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_muladds(vec3 a, float s, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_maxadd(vec3 a, vec3 b, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_minadd(vec3 a, vec3 b, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_negate(vec3 v); + +CGLM_EXPORT +void +glmc_vec3_negate_to(vec3 v, vec3 dest); + +CGLM_EXPORT +float +glmc_vec3_angle(vec3 a, vec3 b); + +CGLM_EXPORT +void +glmc_vec3_rotate(vec3 v, float angle, vec3 axis); + +CGLM_EXPORT +void +glmc_vec3_rotate_m4(mat4 m, vec3 v, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_rotate_m3(mat3 m, vec3 v, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_proj(vec3 a, vec3 b, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_center(vec3 a, vec3 b, vec3 dest); + +CGLM_EXPORT +float +glmc_vec3_distance2(vec3 a, vec3 b); + +CGLM_EXPORT +float +glmc_vec3_distance(vec3 a, vec3 b); + +CGLM_EXPORT +void +glmc_vec3_maxv(vec3 a, vec3 b, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_minv(vec3 a, vec3 b, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_clamp(vec3 v, float minVal, float maxVal); + +CGLM_EXPORT +void +glmc_vec3_ortho(vec3 v, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_lerp(vec3 from, vec3 to, float t, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_lerpc(vec3 from, vec3 to, float t, vec3 dest); + +CGLM_INLINE +void +glmc_vec3_mix(vec3 from, vec3 to, float t, vec3 dest) { + glmc_vec3_lerp(from, to, t, dest); +} + +CGLM_INLINE +void +glmc_vec3_mixc(vec3 from, vec3 to, float t, vec3 dest) { + glmc_vec3_lerpc(from, to, t, dest); +} + +CGLM_EXPORT +void +glmc_vec3_step_uni(float edge, vec3 x, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_step(vec3 edge, vec3 x, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_smoothstep_uni(float edge0, float edge1, vec3 x, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_smoothstep(vec3 edge0, vec3 edge1, vec3 x, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_smoothinterp(vec3 from, vec3 to, float t, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_smoothinterpc(vec3 from, vec3 to, float t, vec3 dest); + +/* ext */ + +CGLM_EXPORT +void +glmc_vec3_mulv(vec3 a, vec3 b, vec3 d); + +CGLM_EXPORT +void +glmc_vec3_broadcast(float val, vec3 d); + +CGLM_EXPORT +void +glmc_vec3_fill(vec3 v, float val); + +CGLM_EXPORT +bool +glmc_vec3_eq(vec3 v, float val); + +CGLM_EXPORT +bool +glmc_vec3_eq_eps(vec3 v, float val); + +CGLM_EXPORT +bool +glmc_vec3_eq_all(vec3 v); + +CGLM_EXPORT +bool +glmc_vec3_eqv(vec3 a, vec3 b); + +CGLM_EXPORT +bool +glmc_vec3_eqv_eps(vec3 a, vec3 b); + +CGLM_EXPORT +float +glmc_vec3_max(vec3 v); + +CGLM_EXPORT +float +glmc_vec3_min(vec3 v); + +CGLM_EXPORT +bool +glmc_vec3_isnan(vec3 v); + +CGLM_EXPORT +bool +glmc_vec3_isinf(vec3 v); + +CGLM_EXPORT +bool +glmc_vec3_isvalid(vec3 v); + +CGLM_EXPORT +void +glmc_vec3_sign(vec3 v, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_abs(vec3 v, vec3 dest); + +CGLM_EXPORT +void +glmc_vec3_fract(vec3 v, vec3 dest); + +CGLM_EXPORT +float +glmc_vec3_hadd(vec3 v); + +CGLM_EXPORT +void +glmc_vec3_sqrt(vec3 v, vec3 dest); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_vec3_h */ diff --git a/include/cglm/call/vec4.h b/include/cglm/call/vec4.h new file mode 100644 index 0000000..f56f599 --- /dev/null +++ b/include/cglm/call/vec4.h @@ -0,0 +1,290 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_vec4_h +#define cglmc_vec4_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +/* DEPRECATED! use _copy, _ucopy versions */ +#define glmc_vec4_dup3(v, dest) glmc_vec4_copy3(v, dest) +#define glmc_vec4_dup(v, dest) glmc_vec4_copy(v, dest) +#define glmc_vec4_flipsign(v) glmc_vec4_negate(v) +#define glmc_vec4_flipsign_to(v, dest) glmc_vec4_negate_to(v, dest) +#define glmc_vec4_inv(v) glmc_vec4_negate(v) +#define glmc_vec4_inv_to(v, dest) glmc_vec4_negate_to(v, dest) + +CGLM_EXPORT +void +glmc_vec4(vec3 v3, float last, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_zero(vec4 v); + +CGLM_EXPORT +void +glmc_vec4_one(vec4 v); + +CGLM_EXPORT +void +glmc_vec4_copy3(vec4 v, vec3 dest); + +CGLM_EXPORT +void +glmc_vec4_copy(vec4 v, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_ucopy(vec4 v, vec4 dest); + +CGLM_EXPORT +float +glmc_vec4_dot(vec4 a, vec4 b); + +CGLM_EXPORT +float +glmc_vec4_norm(vec4 v); + +CGLM_EXPORT +float +glmc_vec4_norm2(vec4 v); + +CGLM_EXPORT +float +glmc_vec4_norm_one(vec4 v); + +CGLM_EXPORT +float +glmc_vec4_norm_inf(vec4 v); + +CGLM_EXPORT +void +glmc_vec4_normalize_to(vec4 v, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_normalize(vec4 v); + +CGLM_EXPORT +void +glmc_vec4_add(vec4 a, vec4 b, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_adds(vec4 v, float s, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_sub(vec4 a, vec4 b, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_subs(vec4 v, float s, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_mul(vec4 a, vec4 b, vec4 d); + +CGLM_EXPORT +void +glmc_vec4_scale(vec4 v, float s, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_scale_as(vec4 v, float s, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_div(vec4 a, vec4 b, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_divs(vec4 v, float s, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_addadd(vec4 a, vec4 b, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_subadd(vec4 a, vec4 b, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_muladd(vec4 a, vec4 b, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_muladds(vec4 a, float s, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_maxadd(vec4 a, vec4 b, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_minadd(vec4 a, vec4 b, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_negate(vec4 v); + +CGLM_EXPORT +void +glmc_vec4_negate_to(vec4 v, vec4 dest); + +CGLM_EXPORT +float +glmc_vec4_distance(vec4 a, vec4 b); + +CGLM_EXPORT +float +glmc_vec4_distance2(vec4 a, vec4 b); + +CGLM_EXPORT +void +glmc_vec4_maxv(vec4 a, vec4 b, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_minv(vec4 a, vec4 b, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_clamp(vec4 v, float minVal, float maxVal); + +CGLM_EXPORT +void +glmc_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_lerpc(vec4 from, vec4 to, float t, vec4 dest); + +CGLM_INLINE +void +glmc_vec4_mix(vec4 from, vec4 to, float t, vec4 dest) { + glmc_vec4_lerp(from, to, t, dest); +} + +CGLM_INLINE +void +glmc_vec4_mixc(vec4 from, vec4 to, float t, vec4 dest) { + glmc_vec4_lerpc(from, to, t, dest); +} + +CGLM_EXPORT +void +glmc_vec4_step_uni(float edge, vec4 x, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_step(vec4 edge, vec4 x, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_smoothstep_uni(float edge0, float edge1, vec4 x, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_smoothstep(vec4 edge0, vec4 edge1, vec4 x, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_smoothinterp(vec4 from, vec4 to, float t, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_smoothinterpc(vec4 from, vec4 to, float t, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_cubic(float s, vec4 dest); + +/* ext */ + +CGLM_EXPORT +void +glmc_vec4_mulv(vec4 a, vec4 b, vec4 d); + +CGLM_EXPORT +void +glmc_vec4_broadcast(float val, vec4 d); + +CGLM_EXPORT +void +glmc_vec4_fill(vec4 v, float val); + +CGLM_EXPORT +bool +glmc_vec4_eq(vec4 v, float val); + +CGLM_EXPORT +bool +glmc_vec4_eq_eps(vec4 v, float val); + +CGLM_EXPORT +bool +glmc_vec4_eq_all(vec4 v); + +CGLM_EXPORT +bool +glmc_vec4_eqv(vec4 a, vec4 b); + +CGLM_EXPORT +bool +glmc_vec4_eqv_eps(vec4 a, vec4 b); + +CGLM_EXPORT +float +glmc_vec4_max(vec4 v); + +CGLM_EXPORT +float +glmc_vec4_min(vec4 v); + +CGLM_EXPORT +bool +glmc_vec4_isnan(vec4 v); + +CGLM_EXPORT +bool +glmc_vec4_isinf(vec4 v); + +CGLM_EXPORT +bool +glmc_vec4_isvalid(vec4 v); + +CGLM_EXPORT +void +glmc_vec4_sign(vec4 v, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_abs(vec4 v, vec4 dest); + +CGLM_EXPORT +void +glmc_vec4_fract(vec4 v, vec4 dest); + +CGLM_EXPORT +float +glmc_vec4_hadd(vec4 v); + +CGLM_EXPORT +void +glmc_vec4_sqrt(vec4 v, vec4 dest); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_vec4_h */ + diff --git a/include/cglm/cam.h b/include/cglm/cam.h new file mode 100644 index 0000000..c8cfd42 --- /dev/null +++ b/include/cglm/cam.h @@ -0,0 +1,582 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_frustum(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) + CGLM_INLINE void glm_ortho(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) + CGLM_INLINE void glm_ortho_aabb(vec3 box[2], mat4 dest) + CGLM_INLINE void glm_ortho_aabb_p(vec3 box[2], float padding, mat4 dest) + CGLM_INLINE void glm_ortho_aabb_pz(vec3 box[2], float padding, mat4 dest) + CGLM_INLINE void glm_ortho_default(float aspect, mat4 dest) + CGLM_INLINE void glm_ortho_default_s(float aspect, float size, mat4 dest) + CGLM_INLINE void glm_perspective(float fovy, + float aspect, + float nearZ, + float farZ, + mat4 dest) + CGLM_INLINE void glm_perspective_default(float aspect, mat4 dest) + CGLM_INLINE void glm_perspective_resize(float aspect, mat4 proj) + CGLM_INLINE void glm_lookat(vec3 eye, vec3 center, vec3 up, mat4 dest) + CGLM_INLINE void glm_look(vec3 eye, vec3 dir, vec3 up, mat4 dest) + CGLM_INLINE void glm_look_anyup(vec3 eye, vec3 dir, mat4 dest) + CGLM_INLINE void glm_persp_decomp(mat4 proj, + float *nearZ, float *farZ, + float *top, float *bottom, + float *left, float *right) + CGLM_INLINE void glm_persp_decompv(mat4 proj, float dest[6]) + CGLM_INLINE void glm_persp_decomp_x(mat4 proj, float *left, float *right) + CGLM_INLINE void glm_persp_decomp_y(mat4 proj, float *top, float *bottom) + CGLM_INLINE void glm_persp_decomp_z(mat4 proj, float *nearv, float *farv) + CGLM_INLINE void glm_persp_decomp_far(mat4 proj, float *farZ) + CGLM_INLINE void glm_persp_decomp_near(mat4 proj, float *nearZ) + CGLM_INLINE float glm_persp_fovy(mat4 proj) + CGLM_INLINE float glm_persp_aspect(mat4 proj) + CGLM_INLINE void glm_persp_sizes(mat4 proj, float fovy, vec4 dest) + */ + +#ifndef cglm_cam_h +#define cglm_cam_h + +#include "common.h" +#include "plane.h" + +#include "clipspace/persp.h" + +#ifndef CGLM_CLIPSPACE_INCLUDE_ALL +# if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO +# include "clipspace/ortho_lh_zo.h" +# include "clipspace/persp_lh_zo.h" +# include "clipspace/view_lh_zo.h" +# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO +# include "clipspace/ortho_lh_no.h" +# include "clipspace/persp_lh_no.h" +# include "clipspace/view_lh_no.h" +# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO +# include "clipspace/ortho_rh_zo.h" +# include "clipspace/persp_rh_zo.h" +# include "clipspace/view_rh_zo.h" +# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO +# include "clipspace/ortho_rh_no.h" +# include "clipspace/persp_rh_no.h" +# include "clipspace/view_rh_no.h" +# endif +#else +# include "clipspace/ortho_lh_zo.h" +# include "clipspace/persp_lh_zo.h" +# include "clipspace/ortho_lh_no.h" +# include "clipspace/persp_lh_no.h" +# include "clipspace/ortho_rh_zo.h" +# include "clipspace/persp_rh_zo.h" +# include "clipspace/ortho_rh_no.h" +# include "clipspace/persp_rh_no.h" +# include "clipspace/view_lh_zo.h" +# include "clipspace/view_lh_no.h" +# include "clipspace/view_rh_zo.h" +# include "clipspace/view_rh_no.h" +#endif + +/*! + * @brief set up perspective peprojection matrix + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_frustum(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glm_frustum_lh_zo(left, right, bottom, top, nearZ, farZ, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glm_frustum_lh_no(left, right, bottom, top, nearZ, farZ, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glm_frustum_rh_zo(left, right, bottom, top, nearZ, farZ, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glm_frustum_rh_no(left, right, bottom, top, nearZ, farZ, dest); +#endif +} + +/*! + * @brief set up orthographic projection matrix + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glm_ortho_lh_zo(left, right, bottom, top, nearZ, farZ, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glm_ortho_lh_no(left, right, bottom, top, nearZ, farZ, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glm_ortho_rh_zo(left, right, bottom, top, nearZ, farZ, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glm_ortho_rh_no(left, right, bottom, top, nearZ, farZ, dest); +#endif +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_aabb(vec3 box[2], mat4 dest) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glm_ortho_aabb_lh_zo(box, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glm_ortho_aabb_lh_no(box, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glm_ortho_aabb_rh_zo(box, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glm_ortho_aabb_rh_no(box, dest); +#endif +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_aabb_p(vec3 box[2], float padding, mat4 dest) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glm_ortho_aabb_p_lh_zo(box, padding, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glm_ortho_aabb_p_lh_no(box, padding, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glm_ortho_aabb_p_rh_zo(box, padding, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glm_ortho_aabb_p_rh_no(box, padding, dest); +#endif +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding for near and far + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_aabb_pz(vec3 box[2], float padding, mat4 dest) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glm_ortho_aabb_pz_lh_zo(box, padding, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glm_ortho_aabb_pz_lh_no(box, padding, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glm_ortho_aabb_pz_rh_zo(box, padding, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glm_ortho_aabb_pz_rh_no(box, padding, dest); +#endif +} + +/*! + * @brief set up unit orthographic projection matrix + * + * @param[in] aspect aspect ration ( width / height ) + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_default(float aspect, mat4 dest) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glm_ortho_default_lh_zo(aspect, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glm_ortho_default_lh_no(aspect, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glm_ortho_default_rh_zo(aspect, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glm_ortho_default_rh_no(aspect, dest); +#endif +} + +/*! + * @brief set up orthographic projection matrix with given CUBE size + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] size cube size + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_default_s(float aspect, float size, mat4 dest) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glm_ortho_default_s_lh_zo(aspect, size, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glm_ortho_default_s_lh_no(aspect, size, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glm_ortho_default_s_rh_zo(aspect, size, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glm_ortho_default_s_rh_no(aspect, size, dest); +#endif +} + +/*! + * @brief set up perspective projection matrix + * + * @param[in] fovy field of view angle + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping planes + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_perspective(float fovy, float aspect, float nearZ, float farZ, mat4 dest) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glm_perspective_lh_zo(fovy, aspect, nearZ, farZ, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glm_perspective_lh_no(fovy, aspect, nearZ, farZ, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glm_perspective_rh_zo(fovy, aspect, nearZ, farZ, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glm_perspective_rh_no(fovy, aspect, nearZ, farZ, dest); +#endif +} + +/*! + * @brief extend perspective projection matrix's far distance + * + * this function does not guarantee far >= near, be aware of that! + * + * @param[in, out] proj projection matrix to extend + * @param[in] deltaFar distance from existing far (negative to shink) + */ +CGLM_INLINE +void +glm_persp_move_far(mat4 proj, float deltaFar) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glm_persp_move_far_lh_zo(proj, deltaFar); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glm_persp_move_far_lh_no(proj, deltaFar); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glm_persp_move_far_rh_zo(proj, deltaFar); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glm_persp_move_far_rh_no(proj, deltaFar); +#endif +} + +/*! + * @brief set up perspective projection matrix with default near/far + * and angle values + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_perspective_default(float aspect, mat4 dest) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glm_perspective_default_lh_zo(aspect, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glm_perspective_default_lh_no(aspect, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glm_perspective_default_rh_zo(aspect, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glm_perspective_default_rh_no(aspect, dest); +#endif +} + +/*! + * @brief resize perspective matrix by aspect ratio ( width / height ) + * this makes very easy to resize proj matrix when window /viewport + * reized + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[in, out] proj perspective projection matrix + */ +CGLM_INLINE +void +glm_perspective_resize(float aspect, mat4 proj) { + if (proj[0][0] == 0.0f) + return; + + proj[0][0] = proj[1][1] / aspect; +} + +/*! + * @brief set up view matrix + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] center center vector + * @param[in] up up vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_lookat(vec3 eye, vec3 center, vec3 up, mat4 dest) { +#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_LH_BIT + glm_lookat_lh(eye, center, up, dest); +#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_RH_BIT + glm_lookat_rh(eye, center, up, dest); +#endif +} + +/*! + * @brief set up view matrix + * + * convenient wrapper for lookat: if you only have direction not target self + * then this might be useful. Because you need to get target from direction. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[in] up up vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_look(vec3 eye, vec3 dir, vec3 up, mat4 dest) { +#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_LH_BIT + glm_look_lh(eye, dir, up, dest); +#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_RH_BIT + glm_look_rh(eye, dir, up, dest); +#endif +} + +/*! + * @brief set up view matrix + * + * convenient wrapper for look: if you only have direction and if you don't + * care what UP vector is then this might be useful to create view matrix + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_look_anyup(vec3 eye, vec3 dir, mat4 dest) { +#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_LH_BIT + glm_look_anyup_lh(eye, dir, dest); +#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_RH_BIT + glm_look_anyup_rh(eye, dir, dest); +#endif +} + +/*! + * @brief decomposes frustum values of perspective projection. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + * @param[out] top top + * @param[out] bottom bottom + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glm_persp_decomp(mat4 proj, + float * __restrict nearZ, float * __restrict farZ, + float * __restrict top, float * __restrict bottom, + float * __restrict left, float * __restrict right) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glm_persp_decomp_lh_zo(proj, nearZ, farZ, top, bottom, left, right); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glm_persp_decomp_lh_no(proj, nearZ, farZ, top, bottom, left, right); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glm_persp_decomp_rh_zo(proj, nearZ, farZ, top, bottom, left, right); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glm_persp_decomp_rh_no(proj, nearZ, farZ, top, bottom, left, right); +#endif +} + +/*! + * @brief decomposes frustum values of perspective projection. + * this makes easy to get all values at once + * + * @param[in] proj perspective projection matrix + * @param[out] dest array + */ +CGLM_INLINE +void +glm_persp_decompv(mat4 proj, float dest[6]) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glm_persp_decompv_lh_zo(proj, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glm_persp_decompv_lh_no(proj, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glm_persp_decompv_rh_zo(proj, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glm_persp_decompv_rh_no(proj, dest); +#endif +} + +/*! + * @brief decomposes left and right values of perspective projection. + * x stands for x axis (left / right axis) + * + * @param[in] proj perspective projection matrix + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glm_persp_decomp_x(mat4 proj, + float * __restrict left, + float * __restrict right) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glm_persp_decomp_x_lh_zo(proj, left, right); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glm_persp_decomp_x_lh_no(proj, left, right); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glm_persp_decomp_x_rh_zo(proj, left, right); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glm_persp_decomp_x_rh_no(proj, left, right); +#endif +} + +/*! + * @brief decomposes top and bottom values of perspective projection. + * y stands for y axis (top / botom axis) + * + * @param[in] proj perspective projection matrix + * @param[out] top top + * @param[out] bottom bottom + */ +CGLM_INLINE +void +glm_persp_decomp_y(mat4 proj, + float * __restrict top, + float * __restrict bottom) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glm_persp_decomp_y_lh_zo(proj, top, bottom); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glm_persp_decomp_y_lh_no(proj, top, bottom); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glm_persp_decomp_y_rh_zo(proj, top, bottom); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glm_persp_decomp_y_rh_no(proj, top, bottom); +#endif +} + +/*! + * @brief decomposes near and far values of perspective projection. + * z stands for z axis (near / far axis) + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + */ +CGLM_INLINE +void +glm_persp_decomp_z(mat4 proj, float * __restrict nearZ, float * __restrict farZ) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glm_persp_decomp_z_lh_zo(proj, nearZ, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glm_persp_decomp_z_lh_no(proj, nearZ, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glm_persp_decomp_z_rh_zo(proj, nearZ, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glm_persp_decomp_z_rh_no(proj, nearZ, farZ); +#endif +} + +/*! + * @brief decomposes far value of perspective projection. + * + * @param[in] proj perspective projection matrix + * @param[out] farZ far + */ +CGLM_INLINE +void +glm_persp_decomp_far(mat4 proj, float * __restrict farZ) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glm_persp_decomp_far_lh_zo(proj, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glm_persp_decomp_far_lh_no(proj, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glm_persp_decomp_far_rh_zo(proj, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glm_persp_decomp_far_rh_no(proj, farZ); +#endif +} + +/*! + * @brief decomposes near value of perspective projection. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + */ +CGLM_INLINE +void +glm_persp_decomp_near(mat4 proj, float * __restrict nearZ) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glm_persp_decomp_near_lh_zo(proj, nearZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glm_persp_decomp_near_lh_no(proj, nearZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glm_persp_decomp_near_rh_zo(proj, nearZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glm_persp_decomp_near_rh_no(proj, nearZ); +#endif +} + +/*! + * @brief returns sizes of near and far planes of perspective projection + * + * @param[in] proj perspective projection matrix + * @param[in] fovy fovy (see brief) + * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar] + */ +CGLM_INLINE +void +glm_persp_sizes(mat4 proj, float fovy, vec4 dest) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glm_persp_sizes_lh_zo(proj, fovy, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glm_persp_sizes_lh_no(proj, fovy, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glm_persp_sizes_rh_zo(proj, fovy, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glm_persp_sizes_rh_no(proj, fovy, dest); +#endif +} + +#endif /* cglm_cam_h */ diff --git a/include/cglm/cglm.h b/include/cglm/cglm.h new file mode 100644 index 0000000..1828cb4 --- /dev/null +++ b/include/cglm/cglm.h @@ -0,0 +1,39 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_h +#define cglm_h + +#include "common.h" +#include "vec2.h" +#include "vec3.h" +#include "vec4.h" +#include "ivec2.h" +#include "ivec3.h" +#include "ivec4.h" +#include "mat4.h" +#include "mat3.h" +#include "mat2.h" +#include "affine.h" +#include "cam.h" +#include "frustum.h" +#include "quat.h" +#include "euler.h" +#include "plane.h" +#include "box.h" +#include "color.h" +#include "util.h" +#include "io.h" +#include "project.h" +#include "sphere.h" +#include "ease.h" +#include "curve.h" +#include "bezier.h" +#include "ray.h" +#include "affine2d.h" + +#endif /* cglm_h */ diff --git a/include/cglm/clipspace/ortho_lh_no.h b/include/cglm/clipspace/ortho_lh_no.h new file mode 100644 index 0000000..76c7a94 --- /dev/null +++ b/include/cglm/clipspace/ortho_lh_no.h @@ -0,0 +1,183 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_ortho_lh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) + CGLM_INLINE void glm_ortho_aabb_lh_no(vec3 box[2], mat4 dest) + CGLM_INLINE void glm_ortho_aabb_p_lh_no(vec3 box[2], + float padding, + mat4 dest) + CGLM_INLINE void glm_ortho_aabb_pz_lh_no(vec3 box[2], + float padding, + mat4 dest) + CGLM_INLINE void glm_ortho_default_lh_no(float aspect, + mat4 dest) + CGLM_INLINE void glm_ortho_default_s_lh_no(float aspect, + float size, + mat4 dest) + */ + +#ifndef cglm_ortho_lh_no_h +#define cglm_ortho_lh_no_h + +#include "../common.h" +#include "../plane.h" +#include "../mat4.h" + +/*! + * @brief set up orthographic projection matrix + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_lh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) { + float rl, tb, fn; + + glm_mat4_zero(dest); + + rl = 1.0f / (right - left); + tb = 1.0f / (top - bottom); + fn =-1.0f / (farZ - nearZ); + + dest[0][0] = 2.0f * rl; + dest[1][1] = 2.0f * tb; + dest[2][2] =-2.0f * fn; + dest[3][0] =-(right + left) * rl; + dest[3][1] =-(top + bottom) * tb; + dest[3][2] = (farZ + nearZ) * fn; + dest[3][3] = 1.0f; +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_aabb_lh_no(vec3 box[2], mat4 dest) { + glm_ortho_lh_no(box[0][0], box[1][0], + box[0][1], box[1][1], + -box[1][2], -box[0][2], + dest); +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_aabb_p_lh_no(vec3 box[2], float padding, mat4 dest) { + glm_ortho_lh_no(box[0][0] - padding, box[1][0] + padding, + box[0][1] - padding, box[1][1] + padding, + -(box[1][2] + padding), -(box[0][2] - padding), + dest); +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding for near and far + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_aabb_pz_lh_no(vec3 box[2], float padding, mat4 dest) { + glm_ortho_lh_no(box[0][0], box[1][0], + box[0][1], box[1][1], + -(box[1][2] + padding), -(box[0][2] - padding), + dest); +} + +/*! + * @brief set up unit orthographic projection matrix + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] aspect aspect ration ( width / height ) + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_default_lh_no(float aspect, mat4 dest) { + if (aspect >= 1.0f) { + glm_ortho_lh_no(-aspect, aspect, -1.0f, 1.0f, -100.0f, 100.0f, dest); + return; + } + + aspect = 1.0f / aspect; + + glm_ortho_lh_no(-1.0f, 1.0f, -aspect, aspect, -100.0f, 100.0f, dest); +} + +/*! + * @brief set up orthographic projection matrix with given CUBE size + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] size cube size + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_default_s_lh_no(float aspect, float size, mat4 dest) { + if (aspect >= 1.0f) { + glm_ortho_lh_no(-size * aspect, + size * aspect, + -size, + size, + -size - 100.0f, + size + 100.0f, + dest); + return; + } + + glm_ortho_lh_no(-size, + size, + -size / aspect, + size / aspect, + -size - 100.0f, + size + 100.0f, + dest); +} + +#endif /*cglm_ortho_lh_no_h*/ diff --git a/include/cglm/clipspace/ortho_lh_zo.h b/include/cglm/clipspace/ortho_lh_zo.h new file mode 100644 index 0000000..e45530d --- /dev/null +++ b/include/cglm/clipspace/ortho_lh_zo.h @@ -0,0 +1,177 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_ortho_lh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) + CGLM_INLINE void glm_ortho_aabb_lh_zo(vec3 box[2], mat4 dest) + CGLM_INLINE void glm_ortho_aabb_p_lh_zo(vec3 box[2], + float padding, + mat4 dest) + CGLM_INLINE void glm_ortho_aabb_pz_lh_zo(vec3 box[2], + float padding, + mat4 dest) + CGLM_INLINE void glm_ortho_default_lh_zo(float aspect, + mat4 dest) + CGLM_INLINE void glm_ortho_default_s_lh_zo(float aspect, + float size, + mat4 dest) + */ + +#ifndef cglm_ortho_lh_zo_h +#define cglm_ortho_lh_zo_h + +#include "../common.h" +#include "../plane.h" +#include "../mat4.h" + +/*! + * @brief set up orthographic projection matrix with a left-hand coordinate + * system and a clip-space of [0, 1]. + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_lh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) { + float rl, tb, fn; + + glm_mat4_zero(dest); + + rl = 1.0f / (right - left); + tb = 1.0f / (top - bottom); + fn =-1.0f / (farZ - nearZ); + + dest[0][0] = 2.0f * rl; + dest[1][1] = 2.0f * tb; + dest[2][2] =-fn; + dest[3][0] =-(right + left) * rl; + dest[3][1] =-(top + bottom) * tb; + dest[3][2] = nearZ * fn; + dest[3][3] = 1.0f; +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a left-hand coordinate system and a clip-space of [0, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_aabb_lh_zo(vec3 box[2], mat4 dest) { + glm_ortho_lh_zo(box[0][0], box[1][0], + box[0][1], box[1][1], + -box[1][2], -box[0][2], + dest); +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a left-hand coordinate system and a clip-space of [0, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_aabb_p_lh_zo(vec3 box[2], float padding, mat4 dest) { + glm_ortho_lh_zo(box[0][0] - padding, box[1][0] + padding, + box[0][1] - padding, box[1][1] + padding, + -(box[1][2] + padding), -(box[0][2] - padding), + dest); +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a left-hand coordinate system and a clip-space of [0, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding for near and far + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_aabb_pz_lh_zo(vec3 box[2], float padding, mat4 dest) { + glm_ortho_lh_zo(box[0][0], box[1][0], + box[0][1], box[1][1], + -(box[1][2] + padding), -(box[0][2] - padding), + dest); +} + +/*! + * @brief set up unit orthographic projection matrix + * with a left-hand coordinate system and a clip-space of [0, 1]. + * + * @param[in] aspect aspect ration ( width / height ) + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_default_lh_zo(float aspect, mat4 dest) { + if (aspect >= 1.0f) { + glm_ortho_lh_zo(-aspect, aspect, -1.0f, 1.0f, -100.0f, 100.0f, dest); + return; + } + + aspect = 1.0f / aspect; + + glm_ortho_lh_zo(-1.0f, 1.0f, -aspect, aspect, -100.0f, 100.0f, dest); +} + +/*! + * @brief set up orthographic projection matrix with given CUBE size + * with a left-hand coordinate system and a clip-space of [0, 1]. + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] size cube size + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_default_s_lh_zo(float aspect, float size, mat4 dest) { + if (aspect >= 1.0f) { + glm_ortho_lh_zo(-size * aspect, + size * aspect, + -size, + size, + -size - 100.0f, + size + 100.0f, + dest); + return; + } + + glm_ortho_lh_zo(-size, + size, + -size / aspect, + size / aspect, + -size - 100.0f, + size + 100.0f, + dest); +} + +#endif /*cglm_ortho_lh_zo_h*/ diff --git a/include/cglm/clipspace/ortho_rh_no.h b/include/cglm/clipspace/ortho_rh_no.h new file mode 100644 index 0000000..aa7a906 --- /dev/null +++ b/include/cglm/clipspace/ortho_rh_no.h @@ -0,0 +1,183 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_ortho_rh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) + CGLM_INLINE void glm_ortho_aabb_rh_no(vec3 box[2], mat4 dest) + CGLM_INLINE void glm_ortho_aabb_p_rh_no(vec3 box[2], + float padding, + mat4 dest) + CGLM_INLINE void glm_ortho_aabb_pz_rh_no(vec3 box[2], + float padding, + mat4 dest) + CGLM_INLINE void glm_ortho_default_rh_no(float aspect, + mat4 dest) + CGLM_INLINE void glm_ortho_default_s_rh_no(float aspect, + float size, + mat4 dest) + */ + +#ifndef cglm_ortho_rh_no_h +#define cglm_ortho_rh_no_h + +#include "../common.h" +#include "../plane.h" +#include "../mat4.h" + +/*! + * @brief set up orthographic projection matrix + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_rh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) { + float rl, tb, fn; + + glm_mat4_zero(dest); + + rl = 1.0f / (right - left); + tb = 1.0f / (top - bottom); + fn =-1.0f / (farZ - nearZ); + + dest[0][0] = 2.0f * rl; + dest[1][1] = 2.0f * tb; + dest[2][2] = 2.0f * fn; + dest[3][0] =-(right + left) * rl; + dest[3][1] =-(top + bottom) * tb; + dest[3][2] = (farZ + nearZ) * fn; + dest[3][3] = 1.0f; +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_aabb_rh_no(vec3 box[2], mat4 dest) { + glm_ortho_rh_no(box[0][0], box[1][0], + box[0][1], box[1][1], + -box[1][2], -box[0][2], + dest); +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_aabb_p_rh_no(vec3 box[2], float padding, mat4 dest) { + glm_ortho_rh_no(box[0][0] - padding, box[1][0] + padding, + box[0][1] - padding, box[1][1] + padding, + -(box[1][2] + padding), -(box[0][2] - padding), + dest); +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding for near and far + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_aabb_pz_rh_no(vec3 box[2], float padding, mat4 dest) { + glm_ortho_rh_no(box[0][0], box[1][0], + box[0][1], box[1][1], + -(box[1][2] + padding), -(box[0][2] - padding), + dest); +} + +/*! + * @brief set up unit orthographic projection matrix + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] aspect aspect ration ( width / height ) + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_default_rh_no(float aspect, mat4 dest) { + if (aspect >= 1.0f) { + glm_ortho_rh_no(-aspect, aspect, -1.0f, 1.0f, -100.0f, 100.0f, dest); + return; + } + + aspect = 1.0f / aspect; + + glm_ortho_rh_no(-1.0f, 1.0f, -aspect, aspect, -100.0f, 100.0f, dest); +} + +/*! + * @brief set up orthographic projection matrix with given CUBE size + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] size cube size + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_default_s_rh_no(float aspect, float size, mat4 dest) { + if (aspect >= 1.0f) { + glm_ortho_rh_no(-size * aspect, + size * aspect, + -size, + size, + -size - 100.0f, + size + 100.0f, + dest); + return; + } + + glm_ortho_rh_no(-size, + size, + -size / aspect, + size / aspect, + -size - 100.0f, + size + 100.0f, + dest); +} + +#endif /*cglm_ortho_rh_no_h*/ diff --git a/include/cglm/clipspace/ortho_rh_zo.h b/include/cglm/clipspace/ortho_rh_zo.h new file mode 100644 index 0000000..7a0876c --- /dev/null +++ b/include/cglm/clipspace/ortho_rh_zo.h @@ -0,0 +1,181 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_ortho_rh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) + CGLM_INLINE void glm_ortho_aabb_rh_zo(vec3 box[2], mat4 dest) + CGLM_INLINE void glm_ortho_aabb_p_rh_zo(vec3 box[2], + float padding, + mat4 dest) + CGLM_INLINE void glm_ortho_aabb_pz_rh_zo(vec3 box[2], + float padding, + mat4 dest) + CGLM_INLINE void glm_ortho_default_rh_zo(float aspect, + mat4 dest) + CGLM_INLINE void glm_ortho_default_s_rh_zo(float aspect, + float size, + mat4 dest) + */ + +#ifndef cglm_ortho_rh_zo_h +#define cglm_ortho_rh_zo_h + +#include "../common.h" +#include "../plane.h" +#include "../mat4.h" + +/*! + * @brief set up orthographic projection matrix with a right-hand coordinate + * system and a clip-space of [0, 1]. + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_rh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) { + float rl, tb, fn; + + glm_mat4_zero(dest); + + rl = 1.0f / (right - left); + tb = 1.0f / (top - bottom); + fn =-1.0f / (farZ - nearZ); + + dest[0][0] = 2.0f * rl; + dest[1][1] = 2.0f * tb; + dest[2][2] = fn; + dest[3][0] =-(right + left) * rl; + dest[3][1] =-(top + bottom) * tb; + dest[3][2] = nearZ * fn; + dest[3][3] = 1.0f; +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a right-hand coordinate system and a clip-space with depth + * values from zero to one. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_aabb_rh_zo(vec3 box[2], mat4 dest) { + glm_ortho_rh_zo(box[0][0], box[1][0], + box[0][1], box[1][1], + -box[1][2], -box[0][2], + dest); +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a right-hand coordinate system and a clip-space with depth + * values from zero to one. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_aabb_p_rh_zo(vec3 box[2], float padding, mat4 dest) { + glm_ortho_rh_zo(box[0][0] - padding, box[1][0] + padding, + box[0][1] - padding, box[1][1] + padding, + -(box[1][2] + padding), -(box[0][2] - padding), + dest); +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a right-hand coordinate system and a clip-space with depth + * values from zero to one. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding for near and far + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_aabb_pz_rh_zo(vec3 box[2], float padding, mat4 dest) { + glm_ortho_rh_zo(box[0][0], box[1][0], + box[0][1], box[1][1], + -(box[1][2] + padding), -(box[0][2] - padding), + dest); +} + +/*! + * @brief set up unit orthographic projection matrix with a right-hand + * coordinate system and a clip-space of [0, 1]. + * + * @param[in] aspect aspect ration ( width / height ) + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_default_rh_zo(float aspect, mat4 dest) { + if (aspect >= 1.0f) { + glm_ortho_rh_zo(-aspect, aspect, -1.0f, 1.0f, -100.0f, 100.0f, dest); + return; + } + + aspect = 1.0f / aspect; + + glm_ortho_rh_zo(-1.0f, 1.0f, -aspect, aspect, -100.0f, 100.0f, dest); +} + +/*! + * @brief set up orthographic projection matrix with given CUBE size + * with a right-hand coordinate system and a clip-space with depth + * values from zero to one. + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] size cube size + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_ortho_default_s_rh_zo(float aspect, float size, mat4 dest) { + if (aspect >= 1.0f) { + glm_ortho_rh_zo(-size * aspect, + size * aspect, + -size, + size, + -size - 100.0f, + size + 100.0f, + dest); + return; + } + + glm_ortho_rh_zo(-size, + size, + -size / aspect, + size / aspect, + -size - 100.0f, + size + 100.0f, + dest); +} + +#endif /*cglm_ortho_rh_zo_h*/ diff --git a/include/cglm/clipspace/persp.h b/include/cglm/clipspace/persp.h new file mode 100644 index 0000000..15aa715 --- /dev/null +++ b/include/cglm/clipspace/persp.h @@ -0,0 +1,48 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_persp_decomp_far(mat4 proj, float *farZ) + CGLM_INLINE float glm_persp_fovy(mat4 proj) + CGLM_INLINE float glm_persp_aspect(mat4 proj) + CGLM_INLINE void glm_persp_sizes(mat4 proj, float fovy, vec4 dest) + */ + +#ifndef cglm_persp_h +#define cglm_persp_h + +#include "../common.h" +#include "../plane.h" +#include "../mat4.h" + +/*! + * @brief returns field of view angle along the Y-axis (in radians) + * + * if you need to degrees, use glm_deg to convert it or use this: + * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glm_persp_fovy(mat4 proj) { + return 2.0f * atanf(1.0f / proj[1][1]); +} + +/*! + * @brief returns aspect ratio of perspective projection + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glm_persp_aspect(mat4 proj) { + return proj[1][1] / proj[0][0]; +} + +#endif /* cglm_persp_h */ diff --git a/include/cglm/clipspace/persp_lh_no.h b/include/cglm/clipspace/persp_lh_no.h new file mode 100644 index 0000000..703530e --- /dev/null +++ b/include/cglm/clipspace/persp_lh_no.h @@ -0,0 +1,395 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_frustum_lh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) + CGLM_INLINE void glm_perspective_lh_no(float fovy, + float aspect, + float nearZ, + float farZ, + mat4 dest) + CGLM_INLINE void glm_perspective_default_lh_no(float aspect, mat4 dest) + CGLM_INLINE void glm_perspective_resize_lh_no(float aspect, mat4 proj) + CGLM_INLINE void glm_persp_move_far_lh_no(mat4 proj, + float deltaFar) + CGLM_INLINE void glm_persp_decomp_lh_no(mat4 proj, + float * __restrict nearZ, + float * __restrict farZ, + float * __restrict top, + float * __restrict bottom, + float * __restrict left, + float * __restrict right) + CGLM_INLINE void glm_persp_decompv_lh_no(mat4 proj, + float dest[6]) + CGLM_INLINE void glm_persp_decomp_x_lh_no(mat4 proj, + float * __restrict left, + float * __restrict right) + CGLM_INLINE void glm_persp_decomp_y_lh_no(mat4 proj, + float * __restrict top, + float * __restrict bottom) + CGLM_INLINE void glm_persp_decomp_z_lh_no(mat4 proj, + float * __restrict nearZ, + float * __restrict farZ) + CGLM_INLINE void glm_persp_decomp_far_lh_no(mat4 proj, float * __restrict farZ) + CGLM_INLINE void glm_persp_decomp_near_lh_no(mat4 proj, float * __restrict nearZ) + CGLM_INLINE void glm_persp_sizes_lh_no(mat4 proj, float fovy, vec4 dest) + */ + +#ifndef cglm_persp_lh_no_h +#define cglm_persp_lh_no_h + +#include "../common.h" +#include "persp.h" + +/*! + * @brief set up perspective peprojection matrix + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_frustum_lh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) { + float rl, tb, fn, nv; + + glm_mat4_zero(dest); + + rl = 1.0f / (right - left); + tb = 1.0f / (top - bottom); + fn =-1.0f / (farZ - nearZ); + nv = 2.0f * nearZ; + + dest[0][0] = nv * rl; + dest[1][1] = nv * tb; + dest[2][0] = (right + left) * rl; + dest[2][1] = (top + bottom) * tb; + dest[2][2] =-(farZ + nearZ) * fn; + dest[2][3] = 1.0f; + dest[3][2] = farZ * nv * fn; +} + +/*! + * @brief set up perspective projection matrix + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] fovy field of view angle + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping planes + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_perspective_lh_no(float fovy, + float aspect, + float nearZ, + float farZ, + mat4 dest) { + float f, fn; + + glm_mat4_zero(dest); + + f = 1.0f / tanf(fovy * 0.5f); + fn = 1.0f / (nearZ - farZ); + + dest[0][0] = f / aspect; + dest[1][1] = f; + dest[2][2] =-(nearZ + farZ) * fn; + dest[2][3] = 1.0f; + dest[3][2] = 2.0f * nearZ * farZ * fn; + +} + +/*! + * @brief set up perspective projection matrix with default near/far + * and angle values with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_perspective_default_lh_no(float aspect, mat4 dest) { + glm_perspective_lh_no(GLM_PI_4f, aspect, 0.01f, 100.0f, dest); +} + +/*! + * @brief resize perspective matrix by aspect ratio ( width / height ) + * this makes very easy to resize proj matrix when window /viewport + * resized with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[in, out] proj perspective projection matrix + */ +CGLM_INLINE +void +glm_perspective_resize_lh_no(float aspect, mat4 proj) { + if (proj[0][0] == 0.0f) + return; + + proj[0][0] = proj[1][1] / aspect; +} + +/*! + * @brief extend perspective projection matrix's far distance + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * this function does not guarantee far >= near, be aware of that! + * + * @param[in, out] proj projection matrix to extend + * @param[in] deltaFar distance from existing far (negative to shink) + */ +CGLM_INLINE +void +glm_persp_move_far_lh_no(mat4 proj, float deltaFar) { + float fn, farZ, nearZ, p22, p32; + + p22 = -proj[2][2]; + p32 = proj[3][2]; + + nearZ = p32 / (p22 - 1.0f); + farZ = p32 / (p22 + 1.0f) + deltaFar; + fn = 1.0f / (nearZ - farZ); + + proj[2][2] = -(farZ + nearZ) * fn; + proj[3][2] = 2.0f * nearZ * farZ * fn; +} + +/*! + * @brief decomposes frustum values of perspective projection + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + * @param[out] top top + * @param[out] bottom bottom + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glm_persp_decomp_lh_no(mat4 proj, + float * __restrict nearZ, float * __restrict farZ, + float * __restrict top, float * __restrict bottom, + float * __restrict left, float * __restrict right) { + float m00, m11, m20, m21, m22, m32, n, f; + float n_m11, n_m00; + + m00 = proj[0][0]; + m11 = proj[1][1]; + m20 = proj[2][0]; + m21 = proj[2][1]; + m22 =-proj[2][2]; + m32 = proj[3][2]; + + n = m32 / (m22 - 1.0f); + f = m32 / (m22 + 1.0f); + + n_m11 = n / m11; + n_m00 = n / m00; + + *nearZ = n; + *farZ = f; + *bottom = n_m11 * (m21 - 1.0f); + *top = n_m11 * (m21 + 1.0f); + *left = n_m00 * (m20 - 1.0f); + *right = n_m00 * (m20 + 1.0f); +} + +/*! + * @brief decomposes frustum values of perspective projection + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * this makes easy to get all values at once + * + * @param[in] proj perspective projection matrix + * @param[out] dest array + */ +CGLM_INLINE +void +glm_persp_decompv_lh_no(mat4 proj, float dest[6]) { + glm_persp_decomp_lh_no(proj, &dest[0], &dest[1], &dest[2], + &dest[3], &dest[4], &dest[5]); +} + +/*! + * @brief decomposes left and right values of perspective projection + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * x stands for x axis (left / right axis) + * + * @param[in] proj perspective projection matrix + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glm_persp_decomp_x_lh_no(mat4 proj, + float * __restrict left, + float * __restrict right) { + float nearZ, m20, m00, m22; + + m00 = proj[0][0]; + m20 = proj[2][0]; + m22 =-proj[2][2]; + + nearZ = proj[3][2] / (m22 - 1.0f); + *left = nearZ * (m20 - 1.0f) / m00; + *right = nearZ * (m20 + 1.0f) / m00; +} + +/*! + * @brief decomposes top and bottom values of perspective projection + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * y stands for y axis (top / botom axis) + * + * @param[in] proj perspective projection matrix + * @param[out] top top + * @param[out] bottom bottom + */ +CGLM_INLINE +void +glm_persp_decomp_y_lh_no(mat4 proj, + float * __restrict top, + float * __restrict bottom) { + float nearZ, m21, m11, m22; + + m21 = proj[2][1]; + m11 = proj[1][1]; + m22 =-proj[2][2]; + + nearZ = proj[3][2] / (m22 - 1.0f); + *bottom = nearZ * (m21 - 1.0f) / m11; + *top = nearZ * (m21 + 1.0f) / m11; +} + +/*! + * @brief decomposes near and far values of perspective projection + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * z stands for z axis (near / far axis) + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + */ +CGLM_INLINE +void +glm_persp_decomp_z_lh_no(mat4 proj, + float * __restrict nearZ, + float * __restrict farZ) { + float m32, m22; + + m32 = proj[3][2]; + m22 =-proj[2][2]; + + *nearZ = m32 / (m22 - 1.0f); + *farZ = m32 / (m22 + 1.0f); +} + +/*! + * @brief decomposes far value of perspective projection + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] farZ far + */ +CGLM_INLINE +void +glm_persp_decomp_far_lh_no(mat4 proj, float * __restrict farZ) { + *farZ = proj[3][2] / (-proj[2][2] + 1.0f); +} + +/*! + * @brief decomposes near value of perspective projection + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + */ +CGLM_INLINE +void +glm_persp_decomp_near_lh_no(mat4 proj, float * __restrict nearZ) { + *nearZ = proj[3][2] / (-proj[2][2] - 1.0f); +} + +/*! + * @brief returns sizes of near and far planes of perspective projection + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + * @param[in] fovy fovy (see brief) + * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar] + */ +CGLM_INLINE +void +glm_persp_sizes_lh_no(mat4 proj, float fovy, vec4 dest) { + float t, a, nearZ, farZ; + + t = 2.0f * tanf(fovy * 0.5f); + a = glm_persp_aspect(proj); + + glm_persp_decomp_z_lh_no(proj, &nearZ, &farZ); + + dest[1] = t * nearZ; + dest[3] = t * farZ; + dest[0] = a * dest[1]; + dest[2] = a * dest[3]; +} + +/*! + * @brief returns field of view angle along the Y-axis (in radians) + * with a left-hand coordinate system and a clip-space of [-1, 1]. + * + * if you need to degrees, use glm_deg to convert it or use this: + * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glm_persp_fovy_lh_no(mat4 proj) { + return glm_persp_fovy(proj); +} + +/*! + * @brief returns aspect ratio of perspective projection + * with a left-hand coordinate system and a clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glm_persp_aspect_lh_no(mat4 proj) { + return glm_persp_aspect(proj); +} + +#endif /*cglm_cam_lh_no_h*/ diff --git a/include/cglm/clipspace/persp_lh_zo.h b/include/cglm/clipspace/persp_lh_zo.h new file mode 100644 index 0000000..de89643 --- /dev/null +++ b/include/cglm/clipspace/persp_lh_zo.h @@ -0,0 +1,387 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_frustum_lh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) + CGLM_INLINE void glm_perspective_lh_zo(float fovy, + float aspect, + float nearZ, + float farZ, + mat4 dest) + CGLM_INLINE void glm_perspective_default_lh_zo(float aspect, mat4 dest) + CGLM_INLINE void glm_perspective_resize_lh_zo(float aspect, mat4 proj) + CGLM_INLINE void glm_persp_move_far_lh_zo(mat4 proj, + float deltaFar) + CGLM_INLINE void glm_persp_decomp_lh_zo(mat4 proj, + float * __restrict nearZ, + float * __restrict farZ, + float * __restrict top, + float * __restrict bottom, + float * __restrict left, + float * __restrict right) + CGLM_INLINE void glm_persp_decompv_lh_zo(mat4 proj, + float dest[6]) + CGLM_INLINE void glm_persp_decomp_x_lh_zo(mat4 proj, + float * __restrict left, + float * __restrict right) + CGLM_INLINE void glm_persp_decomp_y_lh_zo(mat4 proj, + float * __restrict top, + float * __restrict bottom) + CGLM_INLINE void glm_persp_decomp_z_lh_zo(mat4 proj, + float * __restrict nearZ, + float * __restrict farZ) + CGLM_INLINE void glm_persp_decomp_far_lh_zo(mat4 proj, float * __restrict farZ) + CGLM_INLINE void glm_persp_decomp_near_lh_zo(mat4 proj, float * __restrict nearZ) + CGLM_INLINE void glm_persp_sizes_lh_zo(mat4 proj, float fovy, vec4 dest) + */ + +#ifndef cglm_persp_lh_zo_h +#define cglm_persp_lh_zo_h + +#include "../common.h" +#include "persp.h" + +/*! + * @brief set up perspective peprojection matrix with a left-hand coordinate + * system and a clip-space of [0, 1]. + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_frustum_lh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) { + float rl, tb, fn, nv; + + glm_mat4_zero(dest); + + rl = 1.0f / (right - left); + tb = 1.0f / (top - bottom); + fn =-1.0f / (farZ - nearZ); + nv = 2.0f * nearZ; + + dest[0][0] = nv * rl; + dest[1][1] = nv * tb; + dest[2][0] = (right + left) * rl; + dest[2][1] = (top + bottom) * tb; + dest[2][2] =-farZ * fn; + dest[2][3] = 1.0f; + dest[3][2] = farZ * nearZ * fn; +} + +/*! + * @brief set up perspective projection matrix with a left-hand coordinate + * system and a clip-space of [0, 1]. + * + * @param[in] fovy field of view angle + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping planes + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_perspective_lh_zo(float fovy, + float aspect, + float nearZ, + float farZ, + mat4 dest) { + float f, fn; + + glm_mat4_zero(dest); + + f = 1.0f / tanf(fovy * 0.5f); + fn = 1.0f / (nearZ - farZ); + + dest[0][0] = f / aspect; + dest[1][1] = f; + dest[2][2] =-farZ * fn; + dest[2][3] = 1.0f; + dest[3][2] = nearZ * farZ * fn; +} + +/*! + * @brief extend perspective projection matrix's far distance with a + * left-hand coordinate system and a clip-space with depth values + * from zero to one. + * + * this function does not guarantee far >= near, be aware of that! + * + * @param[in, out] proj projection matrix to extend + * @param[in] deltaFar distance from existing far (negative to shink) + */ +CGLM_INLINE +void +glm_persp_move_far_lh_zo(mat4 proj, float deltaFar) { + float fn, farZ, nearZ, p22, p32; + + p22 = -proj[2][2]; + p32 = proj[3][2]; + + nearZ = p32 / p22; + farZ = p32 / (p22 + 1.0f) + deltaFar; + fn = 1.0f / (nearZ - farZ); + + proj[2][2] = -farZ * fn; + proj[3][2] = nearZ * farZ * fn; +} + +/*! + * @brief set up perspective projection matrix with default near/far + * and angle values with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_perspective_default_lh_zo(float aspect, mat4 dest) { + glm_perspective_lh_zo(GLM_PI_4f, aspect, 0.01f, 100.0f, dest); +} + +/*! + * @brief resize perspective matrix by aspect ratio ( width / height ) + * this makes very easy to resize proj matrix when window /viewport + * reized + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[in, out] proj perspective projection matrix + */ +CGLM_INLINE +void +glm_perspective_resize_lh_zo(float aspect, mat4 proj) { + if (proj[0][0] == 0.0f) + return; + + proj[0][0] = proj[1][1] / aspect; +} + +/*! + * @brief decomposes frustum values of perspective projection + * with angle values with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + * @param[out] top top + * @param[out] bottom bottom + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glm_persp_decomp_lh_zo(mat4 proj, + float * __restrict nearZ, float * __restrict farZ, + float * __restrict top, float * __restrict bottom, + float * __restrict left, float * __restrict right) { + float m00, m11, m20, m21, m22, m32, n, f; + float n_m11, n_m00; + + m00 = proj[0][0]; + m11 = proj[1][1]; + m20 = proj[2][0]; + m21 = proj[2][1]; + m22 =-proj[2][2]; + m32 = proj[3][2]; + + n = m32 / m22; + f = m32 / (m22 + 1.0f); + + n_m11 = n / m11; + n_m00 = n / m00; + + *nearZ = n; + *farZ = f; + *bottom = n_m11 * (m21 - 1.0f); + *top = n_m11 * (m21 + 1.0f); + *left = n_m00 * (m20 - 1.0f); + *right = n_m00 * (m20 + 1.0f); +} + +/*! + * @brief decomposes frustum values of perspective projection + * with angle values with a left-hand coordinate system and a + * clip-space of [0, 1]. + * this makes easy to get all values at once + * + * @param[in] proj perspective projection matrix + * @param[out] dest array + */ +CGLM_INLINE +void +glm_persp_decompv_lh_zo(mat4 proj, float dest[6]) { + glm_persp_decomp_lh_zo(proj, &dest[0], &dest[1], &dest[2], + &dest[3], &dest[4], &dest[5]); +} + +/*! + * @brief decomposes left and right values of perspective projection (ZO). + * x stands for x axis (left / right axis) + * + * @param[in] proj perspective projection matrix + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glm_persp_decomp_x_lh_zo(mat4 proj, + float * __restrict left, + float * __restrict right) { + float nearZ, m20, m00; + + m00 = proj[0][0]; + m20 = proj[2][0]; + + nearZ = proj[3][2] / (proj[3][3]); + *left = nearZ * (m20 - 1.0f) / m00; + *right = nearZ * (m20 + 1.0f) / m00; +} + +/*! + * @brief decomposes top and bottom values of perspective projection + * with angle values with a left-hand coordinate system and a + * clip-space of [0, 1]. + * y stands for y axis (top / bottom axis) + * + * @param[in] proj perspective projection matrix + * @param[out] top top + * @param[out] bottom bottom + */ +CGLM_INLINE +void +glm_persp_decomp_y_lh_zo(mat4 proj, + float * __restrict top, + float * __restrict bottom) { + float nearZ, m21, m11; + + m21 = proj[2][1]; + m11 = proj[1][1]; + + nearZ = proj[3][2] / (proj[3][3]); + *bottom = nearZ * (m21 - 1) / m11; + *top = nearZ * (m21 + 1) / m11; +} + +/*! + * @brief decomposes near and far values of perspective projection + * with angle values with a left-hand coordinate system and a + * clip-space of [0, 1]. + * z stands for z axis (near / far axis) + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + */ +CGLM_INLINE +void +glm_persp_decomp_z_lh_zo(mat4 proj, + float * __restrict nearZ, + float * __restrict farZ) { + float m32, m22; + + m32 = proj[3][2]; + m22 = -proj[2][2]; + + *nearZ = m32 / m22; + *farZ = m32 / (m22 + 1.0f); +} + +/*! + * @brief decomposes far value of perspective projection + * with angle values with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] farZ far + */ +CGLM_INLINE +void +glm_persp_decomp_far_lh_zo(mat4 proj, float * __restrict farZ) { + *farZ = proj[3][2] / (-proj[2][2] + 1.0f); +} + +/*! + * @brief decomposes near value of perspective projection + * with angle values with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + */ +CGLM_INLINE +void +glm_persp_decomp_near_lh_zo(mat4 proj, float * __restrict nearZ) { + *nearZ = proj[3][2] / -proj[2][2]; +} + +/*! + * @brief returns sizes of near and far planes of perspective projection + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + * @param[in] fovy fovy (see brief) + * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar] + */ +CGLM_INLINE +void +glm_persp_sizes_lh_zo(mat4 proj, float fovy, vec4 dest) { + float t, a, nearZ, farZ; + + t = 2.0f * tanf(fovy * 0.5f); + a = glm_persp_aspect(proj); + + glm_persp_decomp_z_lh_zo(proj, &nearZ, &farZ); + + dest[1] = t * nearZ; + dest[3] = t * farZ; + dest[0] = a * dest[1]; + dest[2] = a * dest[3]; +} + +/*! + * @brief returns field of view angle along the Y-axis (in radians) + * with a left-hand coordinate system and a clip-space of [0, 1]. + * + * if you need to degrees, use glm_deg to convert it or use this: + * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glm_persp_fovy_lh_zo(mat4 proj) { + return glm_persp_fovy(proj); +} + +/*! + * @brief returns aspect ratio of perspective projection + * with a left-hand coordinate system and a clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glm_persp_aspect_lh_zo(mat4 proj) { + return glm_persp_aspect(proj); +} + +#endif /*cglm_persp_lh_zo_h*/ diff --git a/include/cglm/clipspace/persp_rh_no.h b/include/cglm/clipspace/persp_rh_no.h new file mode 100644 index 0000000..021b7d8 --- /dev/null +++ b/include/cglm/clipspace/persp_rh_no.h @@ -0,0 +1,395 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_frustum_rh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) + CGLM_INLINE void glm_perspective_rh_no(float fovy, + float aspect, + float nearZ, + float farZ, + mat4 dest) + CGLM_INLINE void glm_perspective_default_rh_no(float aspect, mat4 dest) + CGLM_INLINE void glm_perspective_resize_rh_no(float aspect, mat4 proj) + CGLM_INLINE void glm_persp_move_far_rh_no(mat4 proj, + float deltaFar) + CGLM_INLINE void glm_persp_decomp_rh_no(mat4 proj, + float * __restrict nearZ, + float * __restrict farZ, + float * __restrict top, + float * __restrict bottom, + float * __restrict left, + float * __restrict right) + CGLM_INLINE void glm_persp_decompv_rh_no(mat4 proj, + float dest[6]) + CGLM_INLINE void glm_persp_decomp_x_rh_no(mat4 proj, + float * __restrict left, + float * __restrict right) + CGLM_INLINE void glm_persp_decomp_y_rh_no(mat4 proj, + float * __restrict top, + float * __restrict bottom) + CGLM_INLINE void glm_persp_decomp_z_rh_no(mat4 proj, + float * __restrict nearZ, + float * __restrict farZ) + CGLM_INLINE void glm_persp_decomp_far_rh_no(mat4 proj, float * __restrict farZ) + CGLM_INLINE void glm_persp_decomp_near_rh_no(mat4 proj, float * __restrict nearZ) + CGLM_INLINE void glm_persp_sizes_rh_no(mat4 proj, float fovy, vec4 dest) + */ + +#ifndef cglm_persp_rh_no_h +#define cglm_persp_rh_no_h + +#include "../common.h" +#include "persp.h" + +/*! + * @brief set up perspective peprojection matrix + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_frustum_rh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) { + float rl, tb, fn, nv; + + glm_mat4_zero(dest); + + rl = 1.0f / (right - left); + tb = 1.0f / (top - bottom); + fn =-1.0f / (farZ - nearZ); + nv = 2.0f * nearZ; + + dest[0][0] = nv * rl; + dest[1][1] = nv * tb; + dest[2][0] = (right + left) * rl; + dest[2][1] = (top + bottom) * tb; + dest[2][2] = (farZ + nearZ) * fn; + dest[2][3] =-1.0f; + dest[3][2] = farZ * nv * fn; +} + +/*! + * @brief set up perspective projection matrix + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] fovy field of view angle + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping planes + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_perspective_rh_no(float fovy, + float aspect, + float nearZ, + float farZ, + mat4 dest) { + float f, fn; + + glm_mat4_zero(dest); + + f = 1.0f / tanf(fovy * 0.5f); + fn = 1.0f / (nearZ - farZ); + + dest[0][0] = f / aspect; + dest[1][1] = f; + dest[2][2] = (nearZ + farZ) * fn; + dest[2][3] =-1.0f; + dest[3][2] = 2.0f * nearZ * farZ * fn; + +} + +/*! + * @brief set up perspective projection matrix with default near/far + * and angle values with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_perspective_default_rh_no(float aspect, mat4 dest) { + glm_perspective_rh_no(GLM_PI_4f, aspect, 0.01f, 100.0f, dest); +} + +/*! + * @brief resize perspective matrix by aspect ratio ( width / height ) + * this makes very easy to resize proj matrix when window /viewport + * resized with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[in, out] proj perspective projection matrix + */ +CGLM_INLINE +void +glm_perspective_resize_rh_no(float aspect, mat4 proj) { + if (proj[0][0] == 0.0f) + return; + + proj[0][0] = proj[1][1] / aspect; +} + +/*! + * @brief extend perspective projection matrix's far distance + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * this function does not guarantee far >= near, be aware of that! + * + * @param[in, out] proj projection matrix to extend + * @param[in] deltaFar distance from existing far (negative to shink) + */ +CGLM_INLINE +void +glm_persp_move_far_rh_no(mat4 proj, float deltaFar) { + float fn, farZ, nearZ, p22, p32; + + p22 = proj[2][2]; + p32 = proj[3][2]; + + nearZ = p32 / (p22 - 1.0f); + farZ = p32 / (p22 + 1.0f) + deltaFar; + fn = 1.0f / (nearZ - farZ); + + proj[2][2] = (farZ + nearZ) * fn; + proj[3][2] = 2.0f * nearZ * farZ * fn; +} + +/*! + * @brief decomposes frustum values of perspective projection + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + * @param[out] top top + * @param[out] bottom bottom + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glm_persp_decomp_rh_no(mat4 proj, + float * __restrict nearZ, float * __restrict farZ, + float * __restrict top, float * __restrict bottom, + float * __restrict left, float * __restrict right) { + float m00, m11, m20, m21, m22, m32, n, f; + float n_m11, n_m00; + + m00 = proj[0][0]; + m11 = proj[1][1]; + m20 = proj[2][0]; + m21 = proj[2][1]; + m22 = proj[2][2]; + m32 = proj[3][2]; + + n = m32 / (m22 - 1.0f); + f = m32 / (m22 + 1.0f); + + n_m11 = n / m11; + n_m00 = n / m00; + + *nearZ = n; + *farZ = f; + *bottom = n_m11 * (m21 - 1.0f); + *top = n_m11 * (m21 + 1.0f); + *left = n_m00 * (m20 - 1.0f); + *right = n_m00 * (m20 + 1.0f); +} + +/*! + * @brief decomposes frustum values of perspective projection + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * this makes easy to get all values at once + * + * @param[in] proj perspective projection matrix + * @param[out] dest array + */ +CGLM_INLINE +void +glm_persp_decompv_rh_no(mat4 proj, float dest[6]) { + glm_persp_decomp_rh_no(proj, &dest[0], &dest[1], &dest[2], + &dest[3], &dest[4], &dest[5]); +} + +/*! + * @brief decomposes left and right values of perspective projection + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * x stands for x axis (left / right axis) + * + * @param[in] proj perspective projection matrix + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glm_persp_decomp_x_rh_no(mat4 proj, + float * __restrict left, + float * __restrict right) { + float nearZ, m20, m00, m22; + + m00 = proj[0][0]; + m20 = proj[2][0]; + m22 = proj[2][2]; + + nearZ = proj[3][2] / (m22 - 1.0f); + *left = nearZ * (m20 - 1.0f) / m00; + *right = nearZ * (m20 + 1.0f) / m00; +} + +/*! + * @brief decomposes top and bottom values of perspective projection + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * y stands for y axis (top / botom axis) + * + * @param[in] proj perspective projection matrix + * @param[out] top top + * @param[out] bottom bottom + */ +CGLM_INLINE +void +glm_persp_decomp_y_rh_no(mat4 proj, + float * __restrict top, + float * __restrict bottom) { + float nearZ, m21, m11, m22; + + m21 = proj[2][1]; + m11 = proj[1][1]; + m22 = proj[2][2]; + + nearZ = proj[3][2] / (m22 - 1.0f); + *bottom = nearZ * (m21 - 1.0f) / m11; + *top = nearZ * (m21 + 1.0f) / m11; +} + +/*! + * @brief decomposes near and far values of perspective projection + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * z stands for z axis (near / far axis) + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + */ +CGLM_INLINE +void +glm_persp_decomp_z_rh_no(mat4 proj, + float * __restrict nearZ, + float * __restrict farZ) { + float m32, m22; + + m32 = proj[3][2]; + m22 = proj[2][2]; + + *nearZ = m32 / (m22 - 1.0f); + *farZ = m32 / (m22 + 1.0f); +} + +/*! + * @brief decomposes far value of perspective projection + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] farZ far + */ +CGLM_INLINE +void +glm_persp_decomp_far_rh_no(mat4 proj, float * __restrict farZ) { + *farZ = proj[3][2] / (proj[2][2] + 1.0f); +} + +/*! + * @brief decomposes near value of perspective projection + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + */ +CGLM_INLINE +void +glm_persp_decomp_near_rh_no(mat4 proj, float * __restrict nearZ) { + *nearZ = proj[3][2] / (proj[2][2] - 1.0f); +} + +/*! + * @brief returns sizes of near and far planes of perspective projection + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + * @param[in] fovy fovy (see brief) + * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar] + */ +CGLM_INLINE +void +glm_persp_sizes_rh_no(mat4 proj, float fovy, vec4 dest) { + float t, a, nearZ, farZ; + + t = 2.0f * tanf(fovy * 0.5f); + a = glm_persp_aspect(proj); + + glm_persp_decomp_z_rh_no(proj, &nearZ, &farZ); + + dest[1] = t * nearZ; + dest[3] = t * farZ; + dest[0] = a * dest[1]; + dest[2] = a * dest[3]; +} + +/*! + * @brief returns field of view angle along the Y-axis (in radians) + * with a right-hand coordinate system and a clip-space of [-1, 1]. + * + * if you need to degrees, use glm_deg to convert it or use this: + * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glm_persp_fovy_rh_no(mat4 proj) { + return glm_persp_fovy(proj); +} + +/*! + * @brief returns aspect ratio of perspective projection + * with a right-hand coordinate system and a clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glm_persp_aspect_rh_no(mat4 proj) { + return glm_persp_aspect(proj); +} + +#endif /*cglm_cam_rh_no_h*/ diff --git a/include/cglm/clipspace/persp_rh_zo.h b/include/cglm/clipspace/persp_rh_zo.h new file mode 100644 index 0000000..ce632b3 --- /dev/null +++ b/include/cglm/clipspace/persp_rh_zo.h @@ -0,0 +1,389 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_frustum_rh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) + CGLM_INLINE void glm_perspective_rh_zo(float fovy, + float aspect, + float nearZ, + float farZ, + mat4 dest) + CGLM_INLINE void glm_perspective_default_rh_zo(float aspect, mat4 dest) + CGLM_INLINE void glm_perspective_resize_rh_zo(float aspect, mat4 proj) + CGLM_INLINE void glm_persp_move_far_rh_zo(mat4 proj, + float deltaFar) + CGLM_INLINE void glm_persp_decomp_rh_zo(mat4 proj, + float * __restrict nearZ, + float * __restrict farZ, + float * __restrict top, + float * __restrict bottom, + float * __restrict left, + float * __restrict right) + CGLM_INLINE void glm_persp_decompv_rh_zo(mat4 proj, + float dest[6]) + CGLM_INLINE void glm_persp_decomp_x_rh_zo(mat4 proj, + float * __restrict left, + float * __restrict right) + CGLM_INLINE void glm_persp_decomp_y_rh_zo(mat4 proj, + float * __restrict top, + float * __restrict bottom) + CGLM_INLINE void glm_persp_decomp_z_rh_zo(mat4 proj, + float * __restrict nearZ, + float * __restrict farZ) + CGLM_INLINE void glm_persp_decomp_far_rh_zo(mat4 proj, float * __restrict farZ) + CGLM_INLINE void glm_persp_decomp_near_rh_zo(mat4 proj, float * __restrict nearZ) + CGLM_INLINE void glm_persp_sizes_rh_zo(mat4 proj, float fovy, vec4 dest) + */ + +#ifndef cglm_persp_rh_zo_h +#define cglm_persp_rh_zo_h + +#include "../common.h" +#include "persp.h" + +/*! + * @brief set up perspective peprojection matrix with a right-hand coordinate + * system and a clip-space of [0, 1]. + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_frustum_rh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ, + mat4 dest) { + float rl, tb, fn, nv; + + glm_mat4_zero(dest); + + rl = 1.0f / (right - left); + tb = 1.0f / (top - bottom); + fn =-1.0f / (farZ - nearZ); + nv = 2.0f * nearZ; + + dest[0][0] = nv * rl; + dest[1][1] = nv * tb; + dest[2][0] = (right + left) * rl; + dest[2][1] = (top + bottom) * tb; + dest[2][2] = farZ * fn; + dest[2][3] =-1.0f; + dest[3][2] = farZ * nearZ * fn; +} + +/*! + * @brief set up perspective projection matrix with a right-hand coordinate + * system and a clip-space of [0, 1]. + * + * @param[in] fovy field of view angle + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping planes + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_perspective_rh_zo(float fovy, + float aspect, + float nearZ, + float farZ, + mat4 dest) { + float f, fn; + + glm_mat4_zero(dest); + + f = 1.0f / tanf(fovy * 0.5f); + fn = 1.0f / (nearZ - farZ); + + dest[0][0] = f / aspect; + dest[1][1] = f; + dest[2][2] = farZ * fn; + dest[2][3] =-1.0f; + dest[3][2] = nearZ * farZ * fn; +} + +/*! + * @brief set up perspective projection matrix with default near/far + * and angle values with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_perspective_default_rh_zo(float aspect, mat4 dest) { + glm_perspective_rh_zo(GLM_PI_4f, aspect, 0.01f, 100.0f, dest); +} + +/*! + * @brief resize perspective matrix by aspect ratio ( width / height ) + * this makes very easy to resize proj matrix when window /viewport + * resized with a right-hand coordinate system and a clip-space of + * [0, 1]. + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[in, out] proj perspective projection matrix + */ +CGLM_INLINE +void +glm_perspective_resize_rh_zo(float aspect, mat4 proj) { + if (proj[0][0] == 0.0f) + return; + + proj[0][0] = proj[1][1] / aspect; +} + +/*! + * @brief extend perspective projection matrix's far distance with a + * right-hand coordinate system and a clip-space of [0, 1]. + * + * this function does not guarantee far >= near, be aware of that! + * + * @param[in, out] proj projection matrix to extend + * @param[in] deltaFar distance from existing far (negative to shink) + */ +CGLM_INLINE +void +glm_persp_move_far_rh_zo(mat4 proj, float deltaFar) { + float fn, farZ, nearZ, p22, p32; + + p22 = proj[2][2]; + p32 = proj[3][2]; + + nearZ = p32 / p22; + farZ = p32 / (p22 + 1.0f) + deltaFar; + fn = 1.0f / (nearZ - farZ); + + proj[2][2] = farZ * fn; + proj[3][2] = nearZ * farZ * fn; +} + +/*! + * @brief decomposes frustum values of perspective projection + * with angle values with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + * @param[out] top top + * @param[out] bottom bottom + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glm_persp_decomp_rh_zo(mat4 proj, + float * __restrict nearZ, float * __restrict farZ, + float * __restrict top, float * __restrict bottom, + float * __restrict left, float * __restrict right) { + float m00, m11, m20, m21, m22, m32, n, f; + float n_m11, n_m00; + + m00 = proj[0][0]; + m11 = proj[1][1]; + m20 = proj[2][0]; + m21 = proj[2][1]; + m22 = proj[2][2]; + m32 = proj[3][2]; + + n = m32 / m22; + f = m32 / (m22 + 1.0f); + + n_m11 = n / m11; + n_m00 = n / m00; + + *nearZ = n; + *farZ = f; + *bottom = n_m11 * (m21 - 1.0f); + *top = n_m11 * (m21 + 1.0f); + *left = n_m00 * (m20 - 1.0f); + *right = n_m00 * (m20 + 1.0f); +} + +/*! + * @brief decomposes frustum values of perspective projection + * with angle values with a right-hand coordinate system and a + * clip-space of [0, 1]. + * this makes easy to get all values at once + * + * @param[in] proj perspective projection matrix + * @param[out] dest array + */ +CGLM_INLINE +void +glm_persp_decompv_rh_zo(mat4 proj, float dest[6]) { + glm_persp_decomp_rh_zo(proj, &dest[0], &dest[1], &dest[2], + &dest[3], &dest[4], &dest[5]); +} + +/*! + * @brief decomposes left and right values of perspective projection (ZO). + * x stands for x axis (left / right axis) + * + * @param[in] proj perspective projection matrix + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glm_persp_decomp_x_rh_zo(mat4 proj, + float * __restrict left, + float * __restrict right) { + float nearZ, m20, m00, m22; + + m00 = proj[0][0]; + m20 = proj[2][0]; + m22 = proj[2][2]; + + nearZ = proj[3][2] / m22; + *left = nearZ * (m20 - 1.0f) / m00; + *right = nearZ * (m20 + 1.0f) / m00; +} + +/*! + * @brief decomposes top and bottom values of perspective projection + * with angle values with a right-hand coordinate system and a + * clip-space of [0, 1]. + * y stands for y axis (top / bottom axis) + * + * @param[in] proj perspective projection matrix + * @param[out] top top + * @param[out] bottom bottom + */ +CGLM_INLINE +void +glm_persp_decomp_y_rh_zo(mat4 proj, + float * __restrict top, + float * __restrict bottom) { + float nearZ, m21, m11, m22; + + m21 = proj[2][1]; + m11 = proj[1][1]; + m22 = proj[2][2]; + + nearZ = proj[3][2] / m22; + *bottom = nearZ * (m21 - 1) / m11; + *top = nearZ * (m21 + 1) / m11; +} + +/*! + * @brief decomposes near and far values of perspective projection + * with angle values with a right-hand coordinate system and a + * clip-space of [0, 1]. + * z stands for z axis (near / far axis) + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + */ +CGLM_INLINE +void +glm_persp_decomp_z_rh_zo(mat4 proj, + float * __restrict nearZ, + float * __restrict farZ) { + float m32, m22; + + m32 = proj[3][2]; + m22 = proj[2][2]; + + *nearZ = m32 / m22; + *farZ = m32 / (m22 + 1.0f); +} + +/*! + * @brief decomposes far value of perspective projection + * with angle values with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] farZ far + */ +CGLM_INLINE +void +glm_persp_decomp_far_rh_zo(mat4 proj, float * __restrict farZ) { + *farZ = proj[3][2] / (proj[2][2] + 1.0f); +} + +/*! + * @brief decomposes near value of perspective projection + * with angle values with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + */ +CGLM_INLINE +void +glm_persp_decomp_near_rh_zo(mat4 proj, float * __restrict nearZ) { + *nearZ = proj[3][2] / proj[2][2]; +} + +/*! + * @brief returns sizes of near and far planes of perspective projection + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + * @param[in] fovy fovy (see brief) + * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar] + */ +CGLM_INLINE +void +glm_persp_sizes_rh_zo(mat4 proj, float fovy, vec4 dest) { + float t, a, nearZ, farZ; + + t = 2.0f * tanf(fovy * 0.5f); + a = glm_persp_aspect(proj); + + glm_persp_decomp_z_rh_zo(proj, &nearZ, &farZ); + + dest[1] = t * nearZ; + dest[3] = t * farZ; + dest[0] = a * dest[1]; + dest[2] = a * dest[3]; +} + +/*! + * @brief returns field of view angle along the Y-axis (in radians) + * with a right-hand coordinate system and a clip-space of [0, 1]. + * + * if you need to degrees, use glm_deg to convert it or use this: + * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glm_persp_fovy_rh_zo(mat4 proj) { + return glm_persp_fovy(proj); +} + +/*! + * @brief returns aspect ratio of perspective projection + * with a right-hand coordinate system and a clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glm_persp_aspect_rh_zo(mat4 proj) { + return glm_persp_aspect(proj); +} + +#endif /*cglm_persp_rh_zo_h*/ diff --git a/include/cglm/clipspace/project_no.h b/include/cglm/clipspace/project_no.h new file mode 100644 index 0000000..71fbc52 --- /dev/null +++ b/include/cglm/clipspace/project_no.h @@ -0,0 +1,109 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_project_no_h +#define cglm_project_no_h + +#include "../common.h" +#include "../vec3.h" +#include "../vec4.h" +#include "../mat4.h" + +/*! + * @brief maps the specified viewport coordinates into specified space [1] + * the matrix should contain projection matrix. + * + * if you don't have ( and don't want to have ) an inverse matrix then use + * glm_unproject version. You may use existing inverse of matrix in somewhere + * else, this is why glm_unprojecti exists to save save inversion cost + * + * [1] space: + * 1- if m = invProj: View Space + * 2- if m = invViewProj: World Space + * 3- if m = invMVP: Object Space + * + * You probably want to map the coordinates into object space + * so use invMVP as m + * + * Computing viewProj: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * glm_mat4_inv(viewProj, invMVP); + * + * @param[in] pos point/position in viewport coordinates + * @param[in] invMat matrix (see brief) + * @param[in] vp viewport as [x, y, width, height] + * @param[out] dest unprojected coordinates + */ +CGLM_INLINE +void +glm_unprojecti_no(vec3 pos, mat4 invMat, vec4 vp, vec3 dest) { + vec4 v; + + v[0] = 2.0f * (pos[0] - vp[0]) / vp[2] - 1.0f; + v[1] = 2.0f * (pos[1] - vp[1]) / vp[3] - 1.0f; + v[2] = 2.0f * pos[2] - 1.0f; + v[3] = 1.0f; + + glm_mat4_mulv(invMat, v, v); + glm_vec4_scale(v, 1.0f / v[3], v); + glm_vec3(v, dest); +} + +/*! + * @brief map object coordinates to window coordinates + * + * Computing MVP: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * + * @param[in] pos object coordinates + * @param[in] m MVP matrix + * @param[in] vp viewport as [x, y, width, height] + * @param[out] dest projected coordinates + */ +CGLM_INLINE +void +glm_project_no(vec3 pos, mat4 m, vec4 vp, vec3 dest) { + CGLM_ALIGN(16) vec4 pos4; + + glm_vec4(pos, 1.0f, pos4); + + glm_mat4_mulv(m, pos4, pos4); + glm_vec4_scale(pos4, 1.0f / pos4[3], pos4); /* pos = pos / pos.w */ + glm_vec4_scale(pos4, 0.5f, pos4); + glm_vec4_adds(pos4, 0.5f, pos4); + + dest[0] = pos4[0] * vp[2] + vp[0]; + dest[1] = pos4[1] * vp[3] + vp[1]; + dest[2] = pos4[2]; +} + +/*! + * @brief map object's z coordinate to window coordinates + * + * Computing MVP: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * + * @param[in] v object coordinates + * @param[in] m MVP matrix + * + * @returns projected z coordinate + */ +CGLM_INLINE +float +glm_project_z_no(vec3 v, mat4 m) { + float z, w; + + z = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2]; + w = m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3]; + + return 0.5f * (z / w) + 0.5f; +} + +#endif /* cglm_project_no_h */ diff --git a/include/cglm/clipspace/project_zo.h b/include/cglm/clipspace/project_zo.h new file mode 100644 index 0000000..dc32078 --- /dev/null +++ b/include/cglm/clipspace/project_zo.h @@ -0,0 +1,111 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_project_zo_h +#define cglm_project_zo_h + +#include "../common.h" +#include "../vec3.h" +#include "../vec4.h" +#include "../mat4.h" + +/*! + * @brief maps the specified viewport coordinates into specified space [1] + * the matrix should contain projection matrix. + * + * if you don't have ( and don't want to have ) an inverse matrix then use + * glm_unproject version. You may use existing inverse of matrix in somewhere + * else, this is why glm_unprojecti exists to save save inversion cost + * + * [1] space: + * 1- if m = invProj: View Space + * 2- if m = invViewProj: World Space + * 3- if m = invMVP: Object Space + * + * You probably want to map the coordinates into object space + * so use invMVP as m + * + * Computing viewProj: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * glm_mat4_inv(viewProj, invMVP); + * + * @param[in] pos point/position in viewport coordinates + * @param[in] invMat matrix (see brief) + * @param[in] vp viewport as [x, y, width, height] + * @param[out] dest unprojected coordinates + */ +CGLM_INLINE +void +glm_unprojecti_zo(vec3 pos, mat4 invMat, vec4 vp, vec3 dest) { + vec4 v; + + v[0] = 2.0f * (pos[0] - vp[0]) / vp[2] - 1.0f; + v[1] = 2.0f * (pos[1] - vp[1]) / vp[3] - 1.0f; + v[2] = pos[2]; + v[3] = 1.0f; + + glm_mat4_mulv(invMat, v, v); + glm_vec4_scale(v, 1.0f / v[3], v); + glm_vec3(v, dest); +} + +/*! + * @brief map object coordinates to window coordinates + * + * Computing MVP: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * + * @param[in] pos object coordinates + * @param[in] m MVP matrix + * @param[in] vp viewport as [x, y, width, height] + * @param[out] dest projected coordinates + */ +CGLM_INLINE +void +glm_project_zo(vec3 pos, mat4 m, vec4 vp, vec3 dest) { + CGLM_ALIGN(16) vec4 pos4; + + glm_vec4(pos, 1.0f, pos4); + + glm_mat4_mulv(m, pos4, pos4); + glm_vec4_scale(pos4, 1.0f / pos4[3], pos4); /* pos = pos / pos.w */ + + dest[2] = pos4[2]; + + glm_vec4_scale(pos4, 0.5f, pos4); + glm_vec4_adds(pos4, 0.5f, pos4); + + dest[0] = pos4[0] * vp[2] + vp[0]; + dest[1] = pos4[1] * vp[3] + vp[1]; +} + +/*! + * @brief map object's z coordinate to window coordinates + * + * Computing MVP: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * + * @param[in] v object coordinates + * @param[in] m MVP matrix + * + * @returns projected z coordinate + */ +CGLM_INLINE +float +glm_project_z_zo(vec3 v, mat4 m) { + float z, w; + + z = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2]; + w = m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3]; + + return z / w; +} + +#endif /* cglm_project_zo_h */ diff --git a/include/cglm/clipspace/view_lh.h b/include/cglm/clipspace/view_lh.h new file mode 100644 index 0000000..5667694 --- /dev/null +++ b/include/cglm/clipspace/view_lh.h @@ -0,0 +1,99 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_lookat_lh(vec3 eye, vec3 center, vec3 up, mat4 dest) + CGLM_INLINE void glm_look_lh(vec3 eye, vec3 dir, vec3 up, mat4 dest) + CGLM_INLINE void glm_look_anyup_lh(vec3 eye, vec3 dir, mat4 dest) + */ + +#ifndef cglm_view_lh_h +#define cglm_view_lh_h + +#include "../common.h" +#include "../plane.h" + +/*! + * @brief set up view matrix (LH) + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] center center vector + * @param[in] up up vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_lookat_lh(vec3 eye, vec3 center, vec3 up, mat4 dest) { + CGLM_ALIGN(8) vec3 f, u, s; + + glm_vec3_sub(center, eye, f); + glm_vec3_normalize(f); + + glm_vec3_crossn(up, f, s); + glm_vec3_cross(f, s, u); + + dest[0][0] = s[0]; + dest[0][1] = u[0]; + dest[0][2] = f[0]; + dest[1][0] = s[1]; + dest[1][1] = u[1]; + dest[1][2] = f[1]; + dest[2][0] = s[2]; + dest[2][1] = u[2]; + dest[2][2] = f[2]; + dest[3][0] =-glm_vec3_dot(s, eye); + dest[3][1] =-glm_vec3_dot(u, eye); + dest[3][2] =-glm_vec3_dot(f, eye); + dest[0][3] = dest[1][3] = dest[2][3] = 0.0f; + dest[3][3] = 1.0f; +} + +/*! + * @brief set up view matrix with left handed coordinate system + * + * convenient wrapper for lookat: if you only have direction not target self + * then this might be useful. Because you need to get target from direction. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[in] up up vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_look_lh(vec3 eye, vec3 dir, vec3 up, mat4 dest) { + CGLM_ALIGN(8) vec3 target; + glm_vec3_add(eye, dir, target); + glm_lookat_lh(eye, target, up, dest); +} + +/*! + * @brief set up view matrix with left handed coordinate system + * + * convenient wrapper for look: if you only have direction and if you don't + * care what UP vector is then this might be useful to create view matrix + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_look_anyup_lh(vec3 eye, vec3 dir, mat4 dest) { + CGLM_ALIGN(8) vec3 up; + glm_vec3_ortho(dir, up); + glm_look_lh(eye, dir, up, dest); +} + +#endif /*cglm_view_lh_h*/ diff --git a/include/cglm/clipspace/view_lh_no.h b/include/cglm/clipspace/view_lh_no.h new file mode 100644 index 0000000..454d903 --- /dev/null +++ b/include/cglm/clipspace/view_lh_no.h @@ -0,0 +1,74 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_lookat_lh_no(vec3 eye, vec3 center, vec3 up, mat4 dest) + CGLM_INLINE void glm_look_lh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest) + CGLM_INLINE void glm_look_anyup_lh_no(vec3 eye, vec3 dir, mat4 dest) + */ + +#ifndef cglm_view_lh_no_h +#define cglm_view_lh_no_h + +#include "../common.h" +#include "view_lh.h" + +/*! + * @brief set up view matrix with left handed coordinate system. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] center center vector + * @param[in] up up vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_lookat_lh_no(vec3 eye, vec3 center, vec3 up, mat4 dest) { + glm_lookat_lh(eye, center, up, dest); +} + +/*! + * @brief set up view matrix with left handed coordinate system. + * + * convenient wrapper for lookat: if you only have direction not target self + * then this might be useful. Because you need to get target from direction. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[in] up up vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_look_lh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest) { + glm_look_lh(eye, dir, up, dest); +} + +/*! + * @brief set up view matrix with left handed coordinate system. + * + * convenient wrapper for look: if you only have direction and if you don't + * care what UP vector is then this might be useful to create view matrix + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_look_anyup_lh_no(vec3 eye, vec3 dir, mat4 dest) { + glm_look_anyup_lh(eye, dir, dest); +} + +#endif /*cglm_view_lh_no_h*/ diff --git a/include/cglm/clipspace/view_lh_zo.h b/include/cglm/clipspace/view_lh_zo.h new file mode 100644 index 0000000..6b0c4d1 --- /dev/null +++ b/include/cglm/clipspace/view_lh_zo.h @@ -0,0 +1,74 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_lookat_lh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest) + CGLM_INLINE void glm_look_lh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest) + CGLM_INLINE void glm_look_anyup_lh_zo(vec3 eye, vec3 dir, mat4 dest) + */ + +#ifndef cglm_view_lh_zo_h +#define cglm_view_lh_zo_h + +#include "../common.h" +#include "view_lh.h" + +/*! + * @brief set up view matrix with left handed coordinate system. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] center center vector + * @param[in] up up vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_lookat_lh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest) { + glm_lookat_lh(eye, center, up, dest); +} + +/*! + * @brief set up view matrix with left handed coordinate system. + * + * convenient wrapper for lookat: if you only have direction not target self + * then this might be useful. Because you need to get target from direction. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[in] up up vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_look_lh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest) { + glm_look_lh(eye, dir, up, dest); +} + +/*! + * @brief set up view matrix with left handed coordinate system. + * + * convenient wrapper for look: if you only have direction and if you don't + * care what UP vector is then this might be useful to create view matrix + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_look_anyup_lh_zo(vec3 eye, vec3 dir, mat4 dest) { + glm_look_anyup_lh(eye, dir, dest); +} + +#endif /*cglm_view_lh_zo_h*/ diff --git a/include/cglm/clipspace/view_rh.h b/include/cglm/clipspace/view_rh.h new file mode 100644 index 0000000..51ec916 --- /dev/null +++ b/include/cglm/clipspace/view_rh.h @@ -0,0 +1,99 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_lookat_rh(vec3 eye, vec3 center, vec3 up, mat4 dest) + CGLM_INLINE void glm_look_rh(vec3 eye, vec3 dir, vec3 up, mat4 dest) + CGLM_INLINE void glm_look_anyup_rh(vec3 eye, vec3 dir, mat4 dest) + */ + +#ifndef cglm_view_rh_h +#define cglm_view_rh_h + +#include "../common.h" +#include "../plane.h" + +/*! + * @brief set up view matrix with right handed coordinate system. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] center center vector + * @param[in] up up vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_lookat_rh(vec3 eye, vec3 center, vec3 up, mat4 dest) { + CGLM_ALIGN(8) vec3 f, u, s; + + glm_vec3_sub(center, eye, f); + glm_vec3_normalize(f); + + glm_vec3_crossn(f, up, s); + glm_vec3_cross(s, f, u); + + dest[0][0] = s[0]; + dest[0][1] = u[0]; + dest[0][2] =-f[0]; + dest[1][0] = s[1]; + dest[1][1] = u[1]; + dest[1][2] =-f[1]; + dest[2][0] = s[2]; + dest[2][1] = u[2]; + dest[2][2] =-f[2]; + dest[3][0] =-glm_vec3_dot(s, eye); + dest[3][1] =-glm_vec3_dot(u, eye); + dest[3][2] = glm_vec3_dot(f, eye); + dest[0][3] = dest[1][3] = dest[2][3] = 0.0f; + dest[3][3] = 1.0f; +} + +/*! + * @brief set up view matrix with right handed coordinate system. + * + * convenient wrapper for lookat: if you only have direction not target self + * then this might be useful. Because you need to get target from direction. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[in] up up vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_look_rh(vec3 eye, vec3 dir, vec3 up, mat4 dest) { + CGLM_ALIGN(8) vec3 target; + glm_vec3_add(eye, dir, target); + glm_lookat_rh(eye, target, up, dest); +} + +/*! + * @brief set up view matrix with right handed coordinate system. + * + * convenient wrapper for look: if you only have direction and if you don't + * care what UP vector is then this might be useful to create view matrix + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_look_anyup_rh(vec3 eye, vec3 dir, mat4 dest) { + CGLM_ALIGN(8) vec3 up; + glm_vec3_ortho(dir, up); + glm_look_rh(eye, dir, up, dest); +} + +#endif /*cglm_view_rh_h*/ diff --git a/include/cglm/clipspace/view_rh_no.h b/include/cglm/clipspace/view_rh_no.h new file mode 100644 index 0000000..ca36d30 --- /dev/null +++ b/include/cglm/clipspace/view_rh_no.h @@ -0,0 +1,74 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_lookat_rh_no(vec3 eye, vec3 center, vec3 up, mat4 dest) + CGLM_INLINE void glm_look_rh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest) + CGLM_INLINE void glm_look_anyup_rh_no(vec3 eye, vec3 dir, mat4 dest) + */ + +#ifndef cglm_view_rh_no_h +#define cglm_view_rh_no_h + +#include "../common.h" +#include "view_rh.h" + +/*! + * @brief set up view matrix with right handed coordinate system. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] center center vector + * @param[in] up up vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_lookat_rh_no(vec3 eye, vec3 center, vec3 up, mat4 dest) { + glm_lookat_rh(eye, center, up, dest); +} + +/*! + * @brief set up view matrix with right handed coordinate system. + * + * convenient wrapper for lookat: if you only have direction not target self + * then this might be useful. Because you need to get target from direction. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[in] up up vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_look_rh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest) { + glm_look_rh(eye, dir, up, dest); +} + +/*! + * @brief set up view matrix with right handed coordinate system. + * + * convenient wrapper for look: if you only have direction and if you don't + * care what UP vector is then this might be useful to create view matrix + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_look_anyup_rh_no(vec3 eye, vec3 dir, mat4 dest) { + glm_look_anyup_rh(eye, dir, dest); +} + +#endif /*cglm_view_rh_no_h*/ diff --git a/include/cglm/clipspace/view_rh_zo.h b/include/cglm/clipspace/view_rh_zo.h new file mode 100644 index 0000000..1ad5c91 --- /dev/null +++ b/include/cglm/clipspace/view_rh_zo.h @@ -0,0 +1,74 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_lookat_rh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest) + CGLM_INLINE void glm_look_rh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest) + CGLM_INLINE void glm_look_anyup_rh_zo(vec3 eye, vec3 dir, mat4 dest) + */ + +#ifndef cglm_view_rh_zo_h +#define cglm_view_rh_zo_h + +#include "../common.h" +#include "view_rh.h" + +/*! + * @brief set up view matrix with right handed coordinate system. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] center center vector + * @param[in] up up vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_lookat_rh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest) { + glm_lookat_rh(eye, center, up, dest); +} + +/*! + * @brief set up view matrix with right handed coordinate system. + * + * convenient wrapper for lookat: if you only have direction not target self + * then this might be useful. Because you need to get target from direction. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[in] up up vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_look_rh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest) { + glm_look_rh(eye, dir, up, dest); +} + +/*! + * @brief set up view matrix with right handed coordinate system. + * + * convenient wrapper for look: if you only have direction and if you don't + * care what UP vector is then this might be useful to create view matrix + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_look_anyup_rh_zo(vec3 eye, vec3 dir, mat4 dest) { + glm_look_anyup_rh(eye, dir, dest); +} + +#endif /*cglm_view_rh_zo_h*/ diff --git a/include/cglm/color.h b/include/cglm/color.h new file mode 100644 index 0000000..69566ad --- /dev/null +++ b/include/cglm/color.h @@ -0,0 +1,26 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_color_h +#define cglm_color_h + +#include "common.h" +#include "vec3.h" + +/*! + * @brief averages the color channels into one value + * + * @param[in] rgb RGB color + */ +CGLM_INLINE +float +glm_luminance(vec3 rgb) { + vec3 l = {0.212671f, 0.715160f, 0.072169f}; + return glm_dot(rgb, l); +} + +#endif /* cglm_color_h */ diff --git a/include/cglm/common.h b/include/cglm/common.h new file mode 100644 index 0000000..e31f0ce --- /dev/null +++ b/include/cglm/common.h @@ -0,0 +1,85 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_common_h +#define cglm_common_h + +#ifndef _USE_MATH_DEFINES +# define _USE_MATH_DEFINES /* for windows */ +#endif + +#ifndef _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS /* for windows */ +#endif + +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +# ifdef CGLM_STATIC +# define CGLM_EXPORT +# elif defined(CGLM_EXPORTS) +# define CGLM_EXPORT __declspec(dllexport) +# else +# define CGLM_EXPORT __declspec(dllimport) +# endif +# define CGLM_INLINE __forceinline +#else +# define CGLM_EXPORT __attribute__((visibility("default"))) +# define CGLM_INLINE static inline __attribute((always_inline)) +#endif + +#define GLM_SHUFFLE4(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w)) +#define GLM_SHUFFLE3(z, y, x) (((z) << 4) | ((y) << 2) | (x)) + +#include "types.h" +#include "simd/intrin.h" + +#ifndef CGLM_USE_DEFAULT_EPSILON +# ifndef GLM_FLT_EPSILON +# define GLM_FLT_EPSILON 1e-5f +# endif +#else +# define GLM_FLT_EPSILON FLT_EPSILON +#endif + +/* + * Clip control: define CGLM_FORCE_DEPTH_ZERO_TO_ONE before including + * CGLM to use a clip space between 0 to 1. + * Coordinate system: define CGLM_FORCE_LEFT_HANDED before including + * CGLM to use the left handed coordinate system by default. + */ + +#define CGLM_CLIP_CONTROL_ZO_BIT (1 << 0) /* ZERO_TO_ONE */ +#define CGLM_CLIP_CONTROL_NO_BIT (1 << 1) /* NEGATIVE_ONE_TO_ONE */ +#define CGLM_CLIP_CONTROL_LH_BIT (1 << 2) /* LEFT_HANDED, For DirectX, Metal, Vulkan */ +#define CGLM_CLIP_CONTROL_RH_BIT (1 << 3) /* RIGHT_HANDED, For OpenGL, default in GLM */ + +#define CGLM_CLIP_CONTROL_LH_ZO (CGLM_CLIP_CONTROL_LH_BIT | CGLM_CLIP_CONTROL_ZO_BIT) +#define CGLM_CLIP_CONTROL_LH_NO (CGLM_CLIP_CONTROL_LH_BIT | CGLM_CLIP_CONTROL_NO_BIT) +#define CGLM_CLIP_CONTROL_RH_ZO (CGLM_CLIP_CONTROL_RH_BIT | CGLM_CLIP_CONTROL_ZO_BIT) +#define CGLM_CLIP_CONTROL_RH_NO (CGLM_CLIP_CONTROL_RH_BIT | CGLM_CLIP_CONTROL_NO_BIT) + +#ifdef CGLM_FORCE_DEPTH_ZERO_TO_ONE +# ifdef CGLM_FORCE_LEFT_HANDED +# define CGLM_CONFIG_CLIP_CONTROL CGLM_CLIP_CONTROL_LH_ZO +# else +# define CGLM_CONFIG_CLIP_CONTROL CGLM_CLIP_CONTROL_RH_ZO +# endif +#else +# ifdef CGLM_FORCE_LEFT_HANDED +# define CGLM_CONFIG_CLIP_CONTROL CGLM_CLIP_CONTROL_LH_NO +# else +# define CGLM_CONFIG_CLIP_CONTROL CGLM_CLIP_CONTROL_RH_NO +# endif +#endif + +#endif /* cglm_common_h */ diff --git a/include/cglm/curve.h b/include/cglm/curve.h new file mode 100644 index 0000000..5033be5 --- /dev/null +++ b/include/cglm/curve.h @@ -0,0 +1,40 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_curve_h +#define cglm_curve_h + +#include "common.h" +#include "vec4.h" +#include "mat4.h" + +/*! + * @brief helper function to calculate S*M*C multiplication for curves + * + * This function does not encourage you to use SMC, + * instead it is a helper if you use SMC. + * + * if you want to specify S as vector then use more generic glm_mat4_rmc() func. + * + * Example usage: + * B(s) = glm_smc(s, GLM_BEZIER_MAT, (vec4){p0, c0, c1, p1}) + * + * @param[in] s parameter between 0 and 1 (this will be [s3, s2, s, 1]) + * @param[in] m basis matrix + * @param[in] c position/control vector + * + * @return B(s) + */ +CGLM_INLINE +float +glm_smc(float s, mat4 m, vec4 c) { + vec4 vs; + glm_vec4_cubic(s, vs); + return glm_mat4_rmc(vs, m, c); +} + +#endif /* cglm_curve_h */ diff --git a/include/cglm/ease.h b/include/cglm/ease.h new file mode 100644 index 0000000..b40b75e --- /dev/null +++ b/include/cglm/ease.h @@ -0,0 +1,317 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_ease_h +#define cglm_ease_h + +#include "common.h" + +CGLM_INLINE +float +glm_ease_linear(float t) { + return t; +} + +CGLM_INLINE +float +glm_ease_sine_in(float t) { + return sinf((t - 1.0f) * GLM_PI_2f) + 1.0f; +} + +CGLM_INLINE +float +glm_ease_sine_out(float t) { + return sinf(t * GLM_PI_2f); +} + +CGLM_INLINE +float +glm_ease_sine_inout(float t) { + return 0.5f * (1.0f - cosf(t * GLM_PIf)); +} + +CGLM_INLINE +float +glm_ease_quad_in(float t) { + return t * t; +} + +CGLM_INLINE +float +glm_ease_quad_out(float t) { + return -(t * (t - 2.0f)); +} + +CGLM_INLINE +float +glm_ease_quad_inout(float t) { + float tt; + + tt = t * t; + if (t < 0.5f) + return 2.0f * tt; + + return (-2.0f * tt) + (4.0f * t) - 1.0f; +} + +CGLM_INLINE +float +glm_ease_cubic_in(float t) { + return t * t * t; +} + +CGLM_INLINE +float +glm_ease_cubic_out(float t) { + float f; + f = t - 1.0f; + return f * f * f + 1.0f; +} + +CGLM_INLINE +float +glm_ease_cubic_inout(float t) { + float f; + + if (t < 0.5f) + return 4.0f * t * t * t; + + f = 2.0f * t - 2.0f; + + return 0.5f * f * f * f + 1.0f; +} + +CGLM_INLINE +float +glm_ease_quart_in(float t) { + float f; + f = t * t; + return f * f; +} + +CGLM_INLINE +float +glm_ease_quart_out(float t) { + float f; + + f = t - 1.0f; + + return f * f * f * (1.0f - t) + 1.0f; +} + +CGLM_INLINE +float +glm_ease_quart_inout(float t) { + float f, g; + + if (t < 0.5f) { + f = t * t; + return 8.0f * f * f; + } + + f = t - 1.0f; + g = f * f; + + return -8.0f * g * g + 1.0f; +} + +CGLM_INLINE +float +glm_ease_quint_in(float t) { + float f; + f = t * t; + return f * f * t; +} + +CGLM_INLINE +float +glm_ease_quint_out(float t) { + float f, g; + + f = t - 1.0f; + g = f * f; + + return g * g * f + 1.0f; +} + +CGLM_INLINE +float +glm_ease_quint_inout(float t) { + float f, g; + + if (t < 0.5f) { + f = t * t; + return 16.0f * f * f * t; + } + + f = 2.0f * t - 2.0f; + g = f * f; + + return 0.5f * g * g * f + 1.0f; +} + +CGLM_INLINE +float +glm_ease_exp_in(float t) { + if (t == 0.0f) + return t; + + return powf(2.0f, 10.0f * (t - 1.0f)); +} + +CGLM_INLINE +float +glm_ease_exp_out(float t) { + if (t == 1.0f) + return t; + + return 1.0f - powf(2.0f, -10.0f * t); +} + +CGLM_INLINE +float +glm_ease_exp_inout(float t) { + if (t == 0.0f || t == 1.0f) + return t; + + if (t < 0.5f) + return 0.5f * powf(2.0f, (20.0f * t) - 10.0f); + + return -0.5f * powf(2.0f, (-20.0f * t) + 10.0f) + 1.0f; +} + +CGLM_INLINE +float +glm_ease_circ_in(float t) { + return 1.0f - sqrtf(1.0f - (t * t)); +} + +CGLM_INLINE +float +glm_ease_circ_out(float t) { + return sqrtf((2.0f - t) * t); +} + +CGLM_INLINE +float +glm_ease_circ_inout(float t) { + if (t < 0.5f) + return 0.5f * (1.0f - sqrtf(1.0f - 4.0f * (t * t))); + + return 0.5f * (sqrtf(-((2.0f * t) - 3.0f) * ((2.0f * t) - 1.0f)) + 1.0f); +} + +CGLM_INLINE +float +glm_ease_back_in(float t) { + float o, z; + + o = 1.70158f; + z = ((o + 1.0f) * t) - o; + + return t * t * z; +} + +CGLM_INLINE +float +glm_ease_back_out(float t) { + float o, z, n; + + o = 1.70158f; + n = t - 1.0f; + z = (o + 1.0f) * n + o; + + return n * n * z + 1.0f; +} + +CGLM_INLINE +float +glm_ease_back_inout(float t) { + float o, z, n, m, s, x; + + o = 1.70158f; + s = o * 1.525f; + x = 0.5; + n = t / 0.5f; + + if (n < 1.0f) { + z = (s + 1) * n - s; + m = n * n * z; + return x * m; + } + + n -= 2.0f; + z = (s + 1.0f) * n + s; + m = (n * n * z) + 2; + + return x * m; +} + +CGLM_INLINE +float +glm_ease_elast_in(float t) { + return sinf(13.0f * GLM_PI_2f * t) * powf(2.0f, 10.0f * (t - 1.0f)); +} + +CGLM_INLINE +float +glm_ease_elast_out(float t) { + return sinf(-13.0f * GLM_PI_2f * (t + 1.0f)) * powf(2.0f, -10.0f * t) + 1.0f; +} + +CGLM_INLINE +float +glm_ease_elast_inout(float t) { + float a; + + a = 2.0f * t; + + if (t < 0.5f) + return 0.5f * sinf(13.0f * GLM_PI_2f * a) + * powf(2.0f, 10.0f * (a - 1.0f)); + + return 0.5f * (sinf(-13.0f * GLM_PI_2f * a) + * powf(2.0f, -10.0f * (a - 1.0f)) + 2.0f); +} + +CGLM_INLINE +float +glm_ease_bounce_out(float t) { + float tt; + + tt = t * t; + + if (t < (4.0f / 11.0f)) + return (121.0f * tt) / 16.0f; + + if (t < 8.0f / 11.0f) + return ((363.0f / 40.0f) * tt) - ((99.0f / 10.0f) * t) + (17.0f / 5.0f); + + if (t < (9.0f / 10.0f)) + return (4356.0f / 361.0f) * tt + - (35442.0f / 1805.0f) * t + + (16061.0f / 1805.0f); + + return ((54.0f / 5.0f) * tt) - ((513.0f / 25.0f) * t) + (268.0f / 25.0f); +} + +CGLM_INLINE +float +glm_ease_bounce_in(float t) { + return 1.0f - glm_ease_bounce_out(1.0f - t); +} + +CGLM_INLINE +float +glm_ease_bounce_inout(float t) { + if (t < 0.5f) + return 0.5f * (1.0f - glm_ease_bounce_out(t * 2.0f)); + + return 0.5f * glm_ease_bounce_out(t * 2.0f - 1.0f) + 0.5f; +} + +#endif /* cglm_ease_h */ diff --git a/include/cglm/euler.h b/include/cglm/euler.h new file mode 100644 index 0000000..725a205 --- /dev/null +++ b/include/cglm/euler.h @@ -0,0 +1,451 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + NOTE: + angles must be passed as [X-Angle, Y-Angle, Z-angle] order + For instance you don't pass angles as [Z-Angle, X-Angle, Y-angle] to + glm_euler_zxy funciton, All RELATED functions accept angles same order + which is [X, Y, Z]. + */ + +/* + Types: + enum glm_euler_seq + + Functions: + CGLM_INLINE glm_euler_seq glm_euler_order(int newOrder[3]); + CGLM_INLINE void glm_euler_angles(mat4 m, vec3 dest); + CGLM_INLINE void glm_euler(vec3 angles, mat4 dest); + CGLM_INLINE void glm_euler_xyz(vec3 angles, mat4 dest); + CGLM_INLINE void glm_euler_zyx(vec3 angles, mat4 dest); + CGLM_INLINE void glm_euler_zxy(vec3 angles, mat4 dest); + CGLM_INLINE void glm_euler_xzy(vec3 angles, mat4 dest); + CGLM_INLINE void glm_euler_yzx(vec3 angles, mat4 dest); + CGLM_INLINE void glm_euler_yxz(vec3 angles, mat4 dest); + CGLM_INLINE void glm_euler_by_order(vec3 angles, + glm_euler_seq ord, + mat4 dest); + */ + +#ifndef cglm_euler_h +#define cglm_euler_h + +#include "common.h" + +/*! + * if you have axis order like vec3 orderVec = [0, 1, 2] or [0, 2, 1]... + * vector then you can convert it to this enum by doing this: + * @code + * glm_euler_seq order; + * order = orderVec[0] | orderVec[1] << 2 | orderVec[2] << 4; + * @endcode + * you may need to explicit cast if required + */ +typedef enum glm_euler_seq { + GLM_EULER_XYZ = 0 << 0 | 1 << 2 | 2 << 4, + GLM_EULER_XZY = 0 << 0 | 2 << 2 | 1 << 4, + GLM_EULER_YZX = 1 << 0 | 2 << 2 | 0 << 4, + GLM_EULER_YXZ = 1 << 0 | 0 << 2 | 2 << 4, + GLM_EULER_ZXY = 2 << 0 | 0 << 2 | 1 << 4, + GLM_EULER_ZYX = 2 << 0 | 1 << 2 | 0 << 4 +} glm_euler_seq; + +CGLM_INLINE +glm_euler_seq +glm_euler_order(int ord[3]) { + return (glm_euler_seq)(ord[0] << 0 | ord[1] << 2 | ord[2] << 4); +} + +/*! + * @brief extract euler angles (in radians) using xyz order + * + * @param[in] m affine transform + * @param[out] dest angles vector [x, y, z] + */ +CGLM_INLINE +void +glm_euler_angles(mat4 m, vec3 dest) { + float m00, m01, m10, m11, m20, m21, m22; + float thetaX, thetaY, thetaZ; + + m00 = m[0][0]; m10 = m[1][0]; m20 = m[2][0]; + m01 = m[0][1]; m11 = m[1][1]; m21 = m[2][1]; + m22 = m[2][2]; + + if (m20 < 1.0f) { + if (m20 > -1.0f) { + thetaY = asinf(m20); + thetaX = atan2f(-m21, m22); + thetaZ = atan2f(-m10, m00); + } else { /* m20 == -1 */ + /* Not a unique solution */ + thetaY = -GLM_PI_2f; + thetaX = -atan2f(m01, m11); + thetaZ = 0.0f; + } + } else { /* m20 == +1 */ + thetaY = GLM_PI_2f; + thetaX = atan2f(m01, m11); + thetaZ = 0.0f; + } + + dest[0] = thetaX; + dest[1] = thetaY; + dest[2] = thetaZ; +} + +/*! + * @brief build rotation matrix from euler angles + * + * @param[in] angles angles as vector [Xangle, Yangle, Zangle] + * @param[out] dest rotation matrix + */ +CGLM_INLINE +void +glm_euler_xyz(vec3 angles, mat4 dest) { + float cx, cy, cz, + sx, sy, sz, czsx, cxcz, sysz; + + sx = sinf(angles[0]); cx = cosf(angles[0]); + sy = sinf(angles[1]); cy = cosf(angles[1]); + sz = sinf(angles[2]); cz = cosf(angles[2]); + + czsx = cz * sx; + cxcz = cx * cz; + sysz = sy * sz; + + dest[0][0] = cy * cz; + dest[0][1] = czsx * sy + cx * sz; + dest[0][2] = -cxcz * sy + sx * sz; + dest[1][0] = -cy * sz; + dest[1][1] = cxcz - sx * sysz; + dest[1][2] = czsx + cx * sysz; + dest[2][0] = sy; + dest[2][1] = -cy * sx; + dest[2][2] = cx * cy; + dest[0][3] = 0.0f; + dest[1][3] = 0.0f; + dest[2][3] = 0.0f; + dest[3][0] = 0.0f; + dest[3][1] = 0.0f; + dest[3][2] = 0.0f; + dest[3][3] = 1.0f; +} + +/*! + * @brief build rotation matrix from euler angles + * + * @param[in] angles angles as vector [Xangle, Yangle, Zangle] + * @param[out] dest rotation matrix + */ +CGLM_INLINE +void +glm_euler(vec3 angles, mat4 dest) { + glm_euler_xyz(angles, dest); +} + +/*! + * @brief build rotation matrix from euler angles + * + * @param[in] angles angles as vector [Xangle, Yangle, Zangle] + * @param[out] dest rotation matrix + */ +CGLM_INLINE +void +glm_euler_xzy(vec3 angles, mat4 dest) { + float cx, cy, cz, + sx, sy, sz, sxsy, cysx, cxsy, cxcy; + + sx = sinf(angles[0]); cx = cosf(angles[0]); + sy = sinf(angles[1]); cy = cosf(angles[1]); + sz = sinf(angles[2]); cz = cosf(angles[2]); + + sxsy = sx * sy; + cysx = cy * sx; + cxsy = cx * sy; + cxcy = cx * cy; + + dest[0][0] = cy * cz; + dest[0][1] = sxsy + cxcy * sz; + dest[0][2] = -cxsy + cysx * sz; + dest[1][0] = -sz; + dest[1][1] = cx * cz; + dest[1][2] = cz * sx; + dest[2][0] = cz * sy; + dest[2][1] = -cysx + cxsy * sz; + dest[2][2] = cxcy + sxsy * sz; + dest[0][3] = 0.0f; + dest[1][3] = 0.0f; + dest[2][3] = 0.0f; + dest[3][0] = 0.0f; + dest[3][1] = 0.0f; + dest[3][2] = 0.0f; + dest[3][3] = 1.0f; +} + + +/*! + * @brief build rotation matrix from euler angles + * + * @param[in] angles angles as vector [Xangle, Yangle, Zangle] + * @param[out] dest rotation matrix + */ +CGLM_INLINE +void +glm_euler_yxz(vec3 angles, mat4 dest) { + float cx, cy, cz, + sx, sy, sz, cycz, sysz, czsy, cysz; + + sx = sinf(angles[0]); cx = cosf(angles[0]); + sy = sinf(angles[1]); cy = cosf(angles[1]); + sz = sinf(angles[2]); cz = cosf(angles[2]); + + cycz = cy * cz; + sysz = sy * sz; + czsy = cz * sy; + cysz = cy * sz; + + dest[0][0] = cycz + sx * sysz; + dest[0][1] = cx * sz; + dest[0][2] = -czsy + cysz * sx; + dest[1][0] = -cysz + czsy * sx; + dest[1][1] = cx * cz; + dest[1][2] = cycz * sx + sysz; + dest[2][0] = cx * sy; + dest[2][1] = -sx; + dest[2][2] = cx * cy; + dest[0][3] = 0.0f; + dest[1][3] = 0.0f; + dest[2][3] = 0.0f; + dest[3][0] = 0.0f; + dest[3][1] = 0.0f; + dest[3][2] = 0.0f; + dest[3][3] = 1.0f; +} + +/*! + * @brief build rotation matrix from euler angles + * + * @param[in] angles angles as vector [Xangle, Yangle, Zangle] + * @param[out] dest rotation matrix + */ +CGLM_INLINE +void +glm_euler_yzx(vec3 angles, mat4 dest) { + float cx, cy, cz, + sx, sy, sz, sxsy, cxcy, cysx, cxsy; + + sx = sinf(angles[0]); cx = cosf(angles[0]); + sy = sinf(angles[1]); cy = cosf(angles[1]); + sz = sinf(angles[2]); cz = cosf(angles[2]); + + sxsy = sx * sy; + cxcy = cx * cy; + cysx = cy * sx; + cxsy = cx * sy; + + dest[0][0] = cy * cz; + dest[0][1] = sz; + dest[0][2] = -cz * sy; + dest[1][0] = sxsy - cxcy * sz; + dest[1][1] = cx * cz; + dest[1][2] = cysx + cxsy * sz; + dest[2][0] = cxsy + cysx * sz; + dest[2][1] = -cz * sx; + dest[2][2] = cxcy - sxsy * sz; + dest[0][3] = 0.0f; + dest[1][3] = 0.0f; + dest[2][3] = 0.0f; + dest[3][0] = 0.0f; + dest[3][1] = 0.0f; + dest[3][2] = 0.0f; + dest[3][3] = 1.0f; +} + +/*! + * @brief build rotation matrix from euler angles + * + * @param[in] angles angles as vector [Xangle, Yangle, Zangle] + * @param[out] dest rotation matrix + */ +CGLM_INLINE +void +glm_euler_zxy(vec3 angles, mat4 dest) { + float cx, cy, cz, + sx, sy, sz, cycz, sxsy, cysz; + + sx = sinf(angles[0]); cx = cosf(angles[0]); + sy = sinf(angles[1]); cy = cosf(angles[1]); + sz = sinf(angles[2]); cz = cosf(angles[2]); + + cycz = cy * cz; + sxsy = sx * sy; + cysz = cy * sz; + + dest[0][0] = cycz - sxsy * sz; + dest[0][1] = cz * sxsy + cysz; + dest[0][2] = -cx * sy; + dest[1][0] = -cx * sz; + dest[1][1] = cx * cz; + dest[1][2] = sx; + dest[2][0] = cz * sy + cysz * sx; + dest[2][1] = -cycz * sx + sy * sz; + dest[2][2] = cx * cy; + dest[0][3] = 0.0f; + dest[1][3] = 0.0f; + dest[2][3] = 0.0f; + dest[3][0] = 0.0f; + dest[3][1] = 0.0f; + dest[3][2] = 0.0f; + dest[3][3] = 1.0f; +} + +/*! + * @brief build rotation matrix from euler angles + * + * @param[in] angles angles as vector [Xangle, Yangle, Zangle] + * @param[out] dest rotation matrix + */ +CGLM_INLINE +void +glm_euler_zyx(vec3 angles, mat4 dest) { + float cx, cy, cz, + sx, sy, sz, czsx, cxcz, sysz; + + sx = sinf(angles[0]); cx = cosf(angles[0]); + sy = sinf(angles[1]); cy = cosf(angles[1]); + sz = sinf(angles[2]); cz = cosf(angles[2]); + + czsx = cz * sx; + cxcz = cx * cz; + sysz = sy * sz; + + dest[0][0] = cy * cz; + dest[0][1] = cy * sz; + dest[0][2] = -sy; + dest[1][0] = czsx * sy - cx * sz; + dest[1][1] = cxcz + sx * sysz; + dest[1][2] = cy * sx; + dest[2][0] = cxcz * sy + sx * sz; + dest[2][1] = -czsx + cx * sysz; + dest[2][2] = cx * cy; + dest[0][3] = 0.0f; + dest[1][3] = 0.0f; + dest[2][3] = 0.0f; + dest[3][0] = 0.0f; + dest[3][1] = 0.0f; + dest[3][2] = 0.0f; + dest[3][3] = 1.0f; +} + +/*! + * @brief build rotation matrix from euler angles + * + * @param[in] angles angles as vector [Xangle, Yangle, Zangle] + * @param[in] ord euler order + * @param[out] dest rotation matrix + */ +CGLM_INLINE +void +glm_euler_by_order(vec3 angles, glm_euler_seq ord, mat4 dest) { + float cx, cy, cz, + sx, sy, sz; + + float cycz, cysz, cysx, cxcy, + czsy, cxcz, czsx, cxsz, + sysz; + + sx = sinf(angles[0]); cx = cosf(angles[0]); + sy = sinf(angles[1]); cy = cosf(angles[1]); + sz = sinf(angles[2]); cz = cosf(angles[2]); + + cycz = cy * cz; cysz = cy * sz; + cysx = cy * sx; cxcy = cx * cy; + czsy = cz * sy; cxcz = cx * cz; + czsx = cz * sx; cxsz = cx * sz; + sysz = sy * sz; + + switch (ord) { + case GLM_EULER_XZY: + dest[0][0] = cycz; + dest[0][1] = sx * sy + cx * cysz; + dest[0][2] = -cx * sy + cysx * sz; + dest[1][0] = -sz; + dest[1][1] = cxcz; + dest[1][2] = czsx; + dest[2][0] = czsy; + dest[2][1] = -cysx + cx * sysz; + dest[2][2] = cxcy + sx * sysz; + break; + case GLM_EULER_XYZ: + dest[0][0] = cycz; + dest[0][1] = czsx * sy + cxsz; + dest[0][2] = -cx * czsy + sx * sz; + dest[1][0] = -cysz; + dest[1][1] = cxcz - sx * sysz; + dest[1][2] = czsx + cx * sysz; + dest[2][0] = sy; + dest[2][1] = -cysx; + dest[2][2] = cxcy; + break; + case GLM_EULER_YXZ: + dest[0][0] = cycz + sx * sysz; + dest[0][1] = cxsz; + dest[0][2] = -czsy + cysx * sz; + dest[1][0] = czsx * sy - cysz; + dest[1][1] = cxcz; + dest[1][2] = cycz * sx + sysz; + dest[2][0] = cx * sy; + dest[2][1] = -sx; + dest[2][2] = cxcy; + break; + case GLM_EULER_YZX: + dest[0][0] = cycz; + dest[0][1] = sz; + dest[0][2] = -czsy; + dest[1][0] = sx * sy - cx * cysz; + dest[1][1] = cxcz; + dest[1][2] = cysx + cx * sysz; + dest[2][0] = cx * sy + cysx * sz; + dest[2][1] = -czsx; + dest[2][2] = cxcy - sx * sysz; + break; + case GLM_EULER_ZXY: + dest[0][0] = cycz - sx * sysz; + dest[0][1] = czsx * sy + cysz; + dest[0][2] = -cx * sy; + dest[1][0] = -cxsz; + dest[1][1] = cxcz; + dest[1][2] = sx; + dest[2][0] = czsy + cysx * sz; + dest[2][1] = -cycz * sx + sysz; + dest[2][2] = cxcy; + break; + case GLM_EULER_ZYX: + dest[0][0] = cycz; + dest[0][1] = cysz; + dest[0][2] = -sy; + dest[1][0] = czsx * sy - cxsz; + dest[1][1] = cxcz + sx * sysz; + dest[1][2] = cysx; + dest[2][0] = cx * czsy + sx * sz; + dest[2][1] = -czsx + cx * sysz; + dest[2][2] = cxcy; + break; + } + + dest[0][3] = 0.0f; + dest[1][3] = 0.0f; + dest[2][3] = 0.0f; + dest[3][0] = 0.0f; + dest[3][1] = 0.0f; + dest[3][2] = 0.0f; + dest[3][3] = 1.0f; +} + +#endif /* cglm_euler_h */ diff --git a/include/cglm/frustum.h b/include/cglm/frustum.h new file mode 100644 index 0000000..5aa3c17 --- /dev/null +++ b/include/cglm/frustum.h @@ -0,0 +1,255 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_frustum_h +#define cglm_frustum_h + +#include "common.h" +#include "plane.h" +#include "vec3.h" +#include "vec4.h" +#include "mat4.h" + +#define GLM_LBN 0 /* left bottom near */ +#define GLM_LTN 1 /* left top near */ +#define GLM_RTN 2 /* right top near */ +#define GLM_RBN 3 /* right bottom near */ + +#define GLM_LBF 4 /* left bottom far */ +#define GLM_LTF 5 /* left top far */ +#define GLM_RTF 6 /* right top far */ +#define GLM_RBF 7 /* right bottom far */ + +#define GLM_LEFT 0 +#define GLM_RIGHT 1 +#define GLM_BOTTOM 2 +#define GLM_TOP 3 +#define GLM_NEAR 4 +#define GLM_FAR 5 + +/* you can override clip space coords + but you have to provide all with same name + e.g.: define GLM_CSCOORD_LBN {0.0f, 0.0f, 1.0f, 1.0f} */ +#ifndef GLM_CUSTOM_CLIPSPACE + +/* near */ +#define GLM_CSCOORD_LBN {-1.0f, -1.0f, -1.0f, 1.0f} +#define GLM_CSCOORD_LTN {-1.0f, 1.0f, -1.0f, 1.0f} +#define GLM_CSCOORD_RTN { 1.0f, 1.0f, -1.0f, 1.0f} +#define GLM_CSCOORD_RBN { 1.0f, -1.0f, -1.0f, 1.0f} + +/* far */ +#define GLM_CSCOORD_LBF {-1.0f, -1.0f, 1.0f, 1.0f} +#define GLM_CSCOORD_LTF {-1.0f, 1.0f, 1.0f, 1.0f} +#define GLM_CSCOORD_RTF { 1.0f, 1.0f, 1.0f, 1.0f} +#define GLM_CSCOORD_RBF { 1.0f, -1.0f, 1.0f, 1.0f} + +#endif + +/*! + * @brief extracts view frustum planes + * + * planes' space: + * 1- if m = proj: View Space + * 2- if m = viewProj: World Space + * 3- if m = MVP: Object Space + * + * You probably want to extract planes in world space so use viewProj as m + * Computing viewProj: + * glm_mat4_mul(proj, view, viewProj); + * + * Exracted planes order: [left, right, bottom, top, near, far] + * + * @param[in] m matrix (see brief) + * @param[out] dest extracted view frustum planes (see brief) + */ +CGLM_INLINE +void +glm_frustum_planes(mat4 m, vec4 dest[6]) { + mat4 t; + + glm_mat4_transpose_to(m, t); + + glm_vec4_add(t[3], t[0], dest[0]); /* left */ + glm_vec4_sub(t[3], t[0], dest[1]); /* right */ + glm_vec4_add(t[3], t[1], dest[2]); /* bottom */ + glm_vec4_sub(t[3], t[1], dest[3]); /* top */ + glm_vec4_add(t[3], t[2], dest[4]); /* near */ + glm_vec4_sub(t[3], t[2], dest[5]); /* far */ + + glm_plane_normalize(dest[0]); + glm_plane_normalize(dest[1]); + glm_plane_normalize(dest[2]); + glm_plane_normalize(dest[3]); + glm_plane_normalize(dest[4]); + glm_plane_normalize(dest[5]); +} + +/*! + * @brief extracts view frustum corners using clip-space coordinates + * + * corners' space: + * 1- if m = invViewProj: World Space + * 2- if m = invMVP: Object Space + * + * You probably want to extract corners in world space so use invViewProj + * Computing invViewProj: + * glm_mat4_mul(proj, view, viewProj); + * ... + * glm_mat4_inv(viewProj, invViewProj); + * + * if you have a near coord at i index, you can get it's far coord by i + 4 + * + * Find center coordinates: + * for (j = 0; j < 4; j++) { + * glm_vec3_center(corners[i], corners[i + 4], centerCorners[i]); + * } + * + * @param[in] invMat matrix (see brief) + * @param[out] dest exracted view frustum corners (see brief) + */ +CGLM_INLINE +void +glm_frustum_corners(mat4 invMat, vec4 dest[8]) { + vec4 c[8]; + + /* indexOf(nearCoord) = indexOf(farCoord) + 4 */ + vec4 csCoords[8] = { + GLM_CSCOORD_LBN, + GLM_CSCOORD_LTN, + GLM_CSCOORD_RTN, + GLM_CSCOORD_RBN, + + GLM_CSCOORD_LBF, + GLM_CSCOORD_LTF, + GLM_CSCOORD_RTF, + GLM_CSCOORD_RBF + }; + + glm_mat4_mulv(invMat, csCoords[0], c[0]); + glm_mat4_mulv(invMat, csCoords[1], c[1]); + glm_mat4_mulv(invMat, csCoords[2], c[2]); + glm_mat4_mulv(invMat, csCoords[3], c[3]); + glm_mat4_mulv(invMat, csCoords[4], c[4]); + glm_mat4_mulv(invMat, csCoords[5], c[5]); + glm_mat4_mulv(invMat, csCoords[6], c[6]); + glm_mat4_mulv(invMat, csCoords[7], c[7]); + + glm_vec4_scale(c[0], 1.0f / c[0][3], dest[0]); + glm_vec4_scale(c[1], 1.0f / c[1][3], dest[1]); + glm_vec4_scale(c[2], 1.0f / c[2][3], dest[2]); + glm_vec4_scale(c[3], 1.0f / c[3][3], dest[3]); + glm_vec4_scale(c[4], 1.0f / c[4][3], dest[4]); + glm_vec4_scale(c[5], 1.0f / c[5][3], dest[5]); + glm_vec4_scale(c[6], 1.0f / c[6][3], dest[6]); + glm_vec4_scale(c[7], 1.0f / c[7][3], dest[7]); +} + +/*! + * @brief finds center of view frustum + * + * @param[in] corners view frustum corners + * @param[out] dest view frustum center + */ +CGLM_INLINE +void +glm_frustum_center(vec4 corners[8], vec4 dest) { + vec4 center; + + glm_vec4_copy(corners[0], center); + + glm_vec4_add(corners[1], center, center); + glm_vec4_add(corners[2], center, center); + glm_vec4_add(corners[3], center, center); + glm_vec4_add(corners[4], center, center); + glm_vec4_add(corners[5], center, center); + glm_vec4_add(corners[6], center, center); + glm_vec4_add(corners[7], center, center); + + glm_vec4_scale(center, 0.125f, dest); +} + +/*! + * @brief finds bounding box of frustum relative to given matrix e.g. view mat + * + * @param[in] corners view frustum corners + * @param[in] m matrix to convert existing conners + * @param[out] box bounding box as array [min, max] + */ +CGLM_INLINE +void +glm_frustum_box(vec4 corners[8], mat4 m, vec3 box[2]) { + vec4 v; + vec3 min, max; + int i; + + glm_vec3_broadcast(FLT_MAX, min); + glm_vec3_broadcast(-FLT_MAX, max); + + for (i = 0; i < 8; i++) { + glm_mat4_mulv(m, corners[i], v); + + min[0] = glm_min(min[0], v[0]); + min[1] = glm_min(min[1], v[1]); + min[2] = glm_min(min[2], v[2]); + + max[0] = glm_max(max[0], v[0]); + max[1] = glm_max(max[1], v[1]); + max[2] = glm_max(max[2], v[2]); + } + + glm_vec3_copy(min, box[0]); + glm_vec3_copy(max, box[1]); +} + +/*! + * @brief finds planes corners which is between near and far planes (parallel) + * + * this will be helpful if you want to split a frustum e.g. CSM/PSSM. This will + * find planes' corners but you will need to one more plane. + * Actually you have it, it is near, far or created previously with this func ;) + * + * @param[in] corners view frustum corners + * @param[in] splitDist split distance + * @param[in] farDist far distance (zFar) + * @param[out] planeCorners plane corners [LB, LT, RT, RB] + */ +CGLM_INLINE +void +glm_frustum_corners_at(vec4 corners[8], + float splitDist, + float farDist, + vec4 planeCorners[4]) { + vec4 corner; + float dist, sc; + + /* because distance and scale is same for all */ + dist = glm_vec3_distance(corners[GLM_RTF], corners[GLM_RTN]); + sc = dist * (splitDist / farDist); + + /* left bottom */ + glm_vec4_sub(corners[GLM_LBF], corners[GLM_LBN], corner); + glm_vec4_scale_as(corner, sc, corner); + glm_vec4_add(corners[GLM_LBN], corner, planeCorners[0]); + + /* left top */ + glm_vec4_sub(corners[GLM_LTF], corners[GLM_LTN], corner); + glm_vec4_scale_as(corner, sc, corner); + glm_vec4_add(corners[GLM_LTN], corner, planeCorners[1]); + + /* right top */ + glm_vec4_sub(corners[GLM_RTF], corners[GLM_RTN], corner); + glm_vec4_scale_as(corner, sc, corner); + glm_vec4_add(corners[GLM_RTN], corner, planeCorners[2]); + + /* right bottom */ + glm_vec4_sub(corners[GLM_RBF], corners[GLM_RBN], corner); + glm_vec4_scale_as(corner, sc, corner); + glm_vec4_add(corners[GLM_RBN], corner, planeCorners[3]); +} + +#endif /* cglm_frustum_h */ diff --git a/include/cglm/io.h b/include/cglm/io.h new file mode 100644 index 0000000..3381cff --- /dev/null +++ b/include/cglm/io.h @@ -0,0 +1,345 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_mat4_print(mat4 matrix, FILE *ostream); + CGLM_INLINE void glm_mat3_print(mat3 matrix, FILE *ostream); + CGLM_INLINE void glm_vec4_print(vec4 vec, FILE *ostream); + CGLM_INLINE void glm_vec3_print(vec3 vec, FILE *ostream); + CGLM_INLINE void glm_ivec3_print(ivec3 vec, FILE *ostream); + CGLM_INLINE void glm_versor_print(versor vec, FILE *ostream); + */ + +/* + cglm tried to enable print functions in debug mode and disable them in + release/production mode to eliminate printing costs. + + if you need to force enable then define CGLM_DEFINE_PRINTS macro not DEBUG one + + Print functions are enabled if: + + - DEBUG or _DEBUG macro is defined (mostly defined automatically in debugging) + - CGLM_DEFINE_PRINTS macro is defined including release/production + which makes enabled printing always + - glmc_ calls for io are always prints + + */ + +/* DEPRECATED: CGLM_NO_PRINTS_NOOP (use CGLM_DEFINE_PRINTS) */ + +#ifndef cglm_io_h +#define cglm_io_h +#if defined(DEBUG) || defined(_DEBUG) \ + || defined(CGLM_DEFINE_PRINTS) || defined(CGLM_LIB_SRC) \ + || defined(CGLM_NO_PRINTS_NOOP) + +#include "common.h" +#include "util.h" + +#include +#include + +#ifndef CGLM_PRINT_PRECISION +# define CGLM_PRINT_PRECISION 5 +#endif + +#ifndef CGLM_PRINT_MAX_TO_SHORT +# define CGLM_PRINT_MAX_TO_SHORT 1e5f +#endif + +#ifndef CGLM_PRINT_COLOR +# define CGLM_PRINT_COLOR "\033[36m" +#endif + +#ifndef CGLM_PRINT_COLOR_RESET +# define CGLM_PRINT_COLOR_RESET "\033[0m" +#endif + +CGLM_INLINE +void +glm_mat4_print(mat4 matrix, + FILE * __restrict ostream) { + char buff[16]; + int i, j, cw[4], cwi; + +#define m 4 +#define n 4 + + fprintf(ostream, "Matrix (float%dx%d): " CGLM_PRINT_COLOR "\n" , m, n); + + cw[0] = cw[1] = cw[2] = cw[3] = 0; + + for (i = 0; i < m; i++) { + for (j = 0; j < n; j++) { + if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT) + cwi = sprintf(buff, "% .*f", CGLM_PRINT_PRECISION, (double)matrix[i][j]); + else + cwi = sprintf(buff, "% g", (double)matrix[i][j]); + cw[i] = GLM_MAX(cw[i], cwi); + } + } + + for (i = 0; i < m; i++) { + fprintf(ostream, " |"); + + for (j = 0; j < n; j++) + if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT) + fprintf(ostream, " % *.*f", cw[j], CGLM_PRINT_PRECISION, (double)matrix[j][i]); + else + fprintf(ostream, " % *g", cw[j], (double)matrix[j][i]); + + fprintf(ostream, " |\n"); + } + + fprintf(ostream, CGLM_PRINT_COLOR_RESET "\n"); + +#undef m +#undef n +} + + +CGLM_INLINE +void +glm_mat3_print(mat3 matrix, + FILE * __restrict ostream) { + char buff[16]; + int i, j, cw[4], cwi; + +#define m 3 +#define n 3 + + fprintf(ostream, "Matrix (float%dx%d): " CGLM_PRINT_COLOR "\n", m, n); + + cw[0] = cw[1] = cw[2] = 0; + + for (i = 0; i < m; i++) { + for (j = 0; j < n; j++) { + if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT) + cwi = sprintf(buff, "% .*f", CGLM_PRINT_PRECISION, (double)matrix[i][j]); + else + cwi = sprintf(buff, "% g", (double)matrix[i][j]); + cw[i] = GLM_MAX(cw[i], cwi); + } + } + + for (i = 0; i < m; i++) { + fprintf(ostream, " |"); + + for (j = 0; j < n; j++) + if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT) + fprintf(ostream, " % *.*f", cw[j], CGLM_PRINT_PRECISION, (double)matrix[j][i]); + else + fprintf(ostream, " % *g", cw[j], (double)matrix[j][i]); + + fprintf(ostream, " |\n"); + } + + fprintf(ostream, CGLM_PRINT_COLOR_RESET "\n"); + +#undef m +#undef n +} + +CGLM_INLINE +void +glm_mat2_print(mat2 matrix, + FILE * __restrict ostream) { + char buff[16]; + int i, j, cw[4], cwi; + +#define m 2 +#define n 2 + + fprintf(ostream, "Matrix (float%dx%d): " CGLM_PRINT_COLOR "\n", m, n); + + cw[0] = cw[1] = 0; + + for (i = 0; i < m; i++) { + for (j = 0; j < n; j++) { + if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT) + cwi = sprintf(buff, "% .*f", CGLM_PRINT_PRECISION, (double)matrix[i][j]); + else + cwi = sprintf(buff, "% g", (double)matrix[i][j]); + cw[i] = GLM_MAX(cw[i], cwi); + } + } + + for (i = 0; i < m; i++) { + fprintf(ostream, " |"); + + for (j = 0; j < n; j++) + if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT) + fprintf(ostream, " % *.*f", cw[j], CGLM_PRINT_PRECISION, (double)matrix[j][i]); + else + fprintf(ostream, " % *g", cw[j], (double)matrix[j][i]); + + fprintf(ostream, " |\n"); + } + + fprintf(ostream, CGLM_PRINT_COLOR_RESET "\n"); + +#undef m +#undef n +} + +CGLM_INLINE +void +glm_vec4_print(vec4 vec, + FILE * __restrict ostream) { + int i; + +#define m 4 + + fprintf(ostream, "Vector (float%d): " CGLM_PRINT_COLOR "\n (", m); + + for (i = 0; i < m; i++) { + if (vec[i] < CGLM_PRINT_MAX_TO_SHORT) + fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)vec[i]); + else + fprintf(ostream, " % g", (double)vec[i]); + } + + fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); + +#undef m +} + +CGLM_INLINE +void +glm_vec3_print(vec3 vec, + FILE * __restrict ostream) { + int i; + +#define m 3 + + fprintf(ostream, "Vector (float%d): " CGLM_PRINT_COLOR "\n (", m); + + for (i = 0; i < m; i++) { + if (vec[i] < CGLM_PRINT_MAX_TO_SHORT) + fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)vec[i]); + else + fprintf(ostream, " % g", (double)vec[i]); + } + + fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); + +#undef m +} + +CGLM_INLINE +void +glm_ivec3_print(ivec3 vec, + FILE * __restrict ostream) { + int i; + +#define m 3 + + fprintf(ostream, "Vector (int%d): " CGLM_PRINT_COLOR "\n (", m); + + for (i = 0; i < m; i++) + fprintf(ostream, " % d", vec[i]); + + fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); + +#undef m +} + +CGLM_INLINE +void +glm_vec2_print(vec2 vec, + FILE * __restrict ostream) { + int i; + +#define m 2 + + fprintf(ostream, "Vector (float%d): " CGLM_PRINT_COLOR "\n (", m); + + for (i = 0; i < m; i++) { + if (vec[i] < CGLM_PRINT_MAX_TO_SHORT) + fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)vec[i]); + else + fprintf(ostream, " % g", (double)vec[i]); + } + + fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); + +#undef m +} + +CGLM_INLINE +void +glm_versor_print(versor vec, + FILE * __restrict ostream) { + int i; + +#define m 4 + + fprintf(ostream, "Quaternion (float%d): " CGLM_PRINT_COLOR "\n (", m); + + for (i = 0; i < m; i++) { + if (vec[i] < CGLM_PRINT_MAX_TO_SHORT) + fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)vec[i]); + else + fprintf(ostream, " % g", (double)vec[i]); + } + + + fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); + +#undef m +} + +CGLM_INLINE +void +glm_aabb_print(vec3 bbox[2], + const char * __restrict tag, + FILE * __restrict ostream) { + int i, j; + +#define m 3 + + fprintf(ostream, "AABB (%s): " CGLM_PRINT_COLOR "\n", tag ? tag: "float"); + + for (i = 0; i < 2; i++) { + fprintf(ostream, " ("); + + for (j = 0; j < m; j++) { + if (bbox[i][j] < CGLM_PRINT_MAX_TO_SHORT) + fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)bbox[i][j]); + else + fprintf(ostream, " % g", (double)bbox[i][j]); + } + + fprintf(ostream, " )\n"); + } + + fprintf(ostream, CGLM_PRINT_COLOR_RESET "\n"); + +#undef m +} + +#else + +#include "common.h" + +#include +#include + +/* NOOP: Remove print from DEBUG */ +#define glm_mat4_print(v, s) (void)v; (void)s; +#define glm_mat3_print(v, s) (void)v; (void)s; +#define glm_mat2_print(v, s) (void)v; (void)s; +#define glm_vec4_print(v, s) (void)v; (void)s; +#define glm_vec3_print(v, s) (void)v; (void)s; +#define glm_ivec3_print(v, s) (void)v; (void)s; +#define glm_vec2_print(v, s) (void)v; (void)s; +#define glm_versor_print(v, s) (void)v; (void)s; +#define glm_aabb_print(v, t, s) (void)v; (void)t; (void)s; + +#endif +#endif /* cglm_io_h */ diff --git a/include/cglm/ivec2.h b/include/cglm/ivec2.h new file mode 100644 index 0000000..d6c7484 --- /dev/null +++ b/include/cglm/ivec2.h @@ -0,0 +1,256 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* +FUNCTIONS: + CGLM_INLINE void glm_ivec2(int * __restrict v, ivec2 dest) + CGLM_INLINE void glm_ivec2_copy(ivec2 a, ivec2 dest) + CGLM_INLINE void glm_ivec2_zero(ivec2 v) + CGLM_INLINE void glm_ivec2_one(ivec2 v) + CGLM_INLINE void glm_ivec2_add(ivec2 a, ivec2 b, ivec2 dest) + CGLM_INLINE void glm_ivec2_adds(ivec2 v, int s, ivec2 dest) + CGLM_INLINE void glm_ivec2_sub(ivec2 a, ivec2 b, ivec2 dest) + CGLM_INLINE void glm_ivec2_subs(ivec2 v, int s, ivec2 dest) + CGLM_INLINE void glm_ivec2_mul(ivec2 a, ivec2 b, ivec2 dest) + CGLM_INLINE void glm_ivec2_scale(ivec2 v, int s, ivec2 dest) + CGLM_INLINE int glm_ivec2_distance2(ivec2 a, ivec2 b) + CGLM_INLINE float glm_ivec2_distance(ivec2 a, ivec2 b) + CGLM_INLINE void glm_ivec2_maxv(ivec2 a, ivec2 b, ivec2 dest) + CGLM_INLINE void glm_ivec2_minv(ivec2 a, ivec2 b, ivec2 dest) + CGLM_INLINE void glm_ivec2_clamp(ivec2 v, int minVal, int maxVal) + CGLM_INLINE void glm_ivec2_abs(ivec2 v, ivec2 dest) + */ + +#ifndef cglm_ivec2_h +#define cglm_ivec2_h + +#include "common.h" + +/*! + * @brief init ivec2 using vec3 or vec4 + * + * @param[in] v vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec2(int * __restrict v, ivec2 dest) { + dest[0] = v[0]; + dest[1] = v[1]; +} + +/*! + * @brief copy all members of [a] to [dest] + * + * @param[in] a source vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec2_copy(ivec2 a, ivec2 dest) { + dest[0] = a[0]; + dest[1] = a[1]; +} + +/*! + * @brief set all members of [v] to zero + * + * @param[out] v vector + */ +CGLM_INLINE +void +glm_ivec2_zero(ivec2 v) { + v[0] = v[1] = 0; +} + +/*! + * @brief set all members of [v] to one + * + * @param[out] v vector + */ +CGLM_INLINE +void +glm_ivec2_one(ivec2 v) { + v[0] = v[1] = 1; +} + +/*! + * @brief add vector [a] to vector [b] and store result in [dest] + * + * @param[in] a first vector + * @param[in] b second vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec2_add(ivec2 a, ivec2 b, ivec2 dest) { + dest[0] = a[0] + b[0]; + dest[1] = a[1] + b[1]; +} + +/*! + * @brief add scalar s to vector [v] and store result in [dest] + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec2_adds(ivec2 v, int s, ivec2 dest) { + dest[0] = v[0] + s; + dest[1] = v[1] + s; +} + +/*! + * @brief subtract vector [b] from vector [a] and store result in [dest] + * + * @param[in] a first vector + * @param[in] b second vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec2_sub(ivec2 a, ivec2 b, ivec2 dest) { + dest[0] = a[0] - b[0]; + dest[1] = a[1] - b[1]; +} + +/*! + * @brief subtract scalar s from vector [v] and store result in [dest] + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec2_subs(ivec2 v, int s, ivec2 dest) { + dest[0] = v[0] - s; + dest[1] = v[1] - s; +} + +/*! + * @brief multiply vector [a] with vector [b] and store result in [dest] + * + * @param[in] a frist vector + * @param[in] b second vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec2_mul(ivec2 a, ivec2 b, ivec2 dest) { + dest[0] = a[0] * b[0]; + dest[1] = a[1] * b[1]; +} + +/*! + * @brief multiply vector [a] with scalar s and store result in [dest] + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec2_scale(ivec2 v, int s, ivec2 dest) { + dest[0] = v[0] * s; + dest[1] = v[1] * s; +} + +/*! + * @brief squared distance between two vectors + * + * @param[in] a first vector + * @param[in] b second vector + * @return returns squared distance (distance * distance) + */ +CGLM_INLINE +int +glm_ivec2_distance2(ivec2 a, ivec2 b) { + int xd, yd; + xd = a[0] - b[0]; + yd = a[1] - b[1]; + return xd * xd + yd * yd; +} + +/*! + * @brief distance between two vectors + * + * @param[in] a first vector + * @param[in] b second vector + * @return returns distance + */ +CGLM_INLINE +float +glm_ivec2_distance(ivec2 a, ivec2 b) { + return sqrtf((float)glm_ivec2_distance2(a, b)); +} + +/*! + * @brief set each member of dest to greater of vector a and b + * + * @param[in] a first vector + * @param[in] b second vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec2_maxv(ivec2 a, ivec2 b, ivec2 dest) { + dest[0] = a[0] > b[0] ? a[0] : b[0]; + dest[1] = a[1] > b[1] ? a[1] : b[1]; +} + +/*! + * @brief set each member of dest to lesser of vector a and b + * + * @param[in] a first vector + * @param[in] b second vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec2_minv(ivec2 a, ivec2 b, ivec2 dest) { + dest[0] = a[0] < b[0] ? a[0] : b[0]; + dest[1] = a[1] < b[1] ? a[1] : b[1]; +} + +/*! + * @brief clamp each member of [v] between minVal and maxVal (inclusive) + * + * @param[in, out] v vector + * @param[in] minVal minimum value + * @param[in] maxVal maximum value + */ +CGLM_INLINE +void +glm_ivec2_clamp(ivec2 v, int minVal, int maxVal) { + if (v[0] < minVal) + v[0] = minVal; + else if(v[0] > maxVal) + v[0] = maxVal; + + if (v[1] < minVal) + v[1] = minVal; + else if(v[1] > maxVal) + v[1] = maxVal; +} + +/*! + * @brief absolute value of v + * + * @param[in] v vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec2_abs(ivec2 v, ivec2 dest) { + dest[0] = abs(v[0]); + dest[1] = abs(v[1]); +} + +#endif /* cglm_ivec2_h */ diff --git a/include/cglm/ivec3.h b/include/cglm/ivec3.h new file mode 100644 index 0000000..0dfb57a --- /dev/null +++ b/include/cglm/ivec3.h @@ -0,0 +1,273 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* +FUNCTIONS: + CGLM_INLINE void glm_ivec3(ivec4 v4, ivec3 dest) + CGLM_INLINE void glm_ivec3_copy(ivec3 a, ivec3 dest) + CGLM_INLINE void glm_ivec3_zero(ivec3 v) + CGLM_INLINE void glm_ivec3_one(ivec3 v) + CGLM_INLINE void glm_ivec3_add(ivec3 a, ivec3 b, ivec3 dest) + CGLM_INLINE void glm_ivec3_adds(ivec3 v, int s, ivec3 dest) + CGLM_INLINE void glm_ivec3_sub(ivec3 a, ivec3 b, ivec3 dest) + CGLM_INLINE void glm_ivec3_subs(ivec3 v, int s, ivec3 dest) + CGLM_INLINE void glm_ivec3_mul(ivec3 a, ivec3 b, ivec3 dest) + CGLM_INLINE void glm_ivec3_scale(ivec3 v, int s, ivec3 dest) + CGLM_INLINE int glm_ivec3_distance2(ivec3 a, ivec3 b) + CGLM_INLINE float glm_ivec3_distance(ivec3 a, ivec3 b) + CGLM_INLINE void glm_ivec3_maxv(ivec3 a, ivec3 b, ivec3 dest) + CGLM_INLINE void glm_ivec3_minv(ivec3 a, ivec3 b, ivec3 dest) + CGLM_INLINE void glm_ivec3_clamp(ivec3 v, int minVal, int maxVal) + CGLM_INLINE void glm_ivec3_abs(ivec3 v, ivec3 dest) + */ + +#ifndef cglm_ivec3_h +#define cglm_ivec3_h + +#include "common.h" + +/*! + * @brief init ivec3 using ivec4 + * + * @param[in] v4 vector4 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec3(ivec4 v4, ivec3 dest) { + dest[0] = v4[0]; + dest[1] = v4[1]; + dest[2] = v4[2]; +} + +/*! + * @brief copy all members of [a] to [dest] + * + * @param[in] a source vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec3_copy(ivec3 a, ivec3 dest) { + dest[0] = a[0]; + dest[1] = a[1]; + dest[2] = a[2]; +} + +/*! + * @brief set all members of [v] to zero + * + * @param[out] v vector + */ +CGLM_INLINE +void +glm_ivec3_zero(ivec3 v) { + v[0] = v[1] = v[2] = 0; +} + +/*! + * @brief set all members of [v] to one + * + * @param[out] v vector + */ +CGLM_INLINE +void +glm_ivec3_one(ivec3 v) { + v[0] = v[1] = v[2] = 1; +} + +/*! + * @brief add vector [a] to vector [b] and store result in [dest] + * + * @param[in] a first vector + * @param[in] b second vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec3_add(ivec3 a, ivec3 b, ivec3 dest) { + dest[0] = a[0] + b[0]; + dest[1] = a[1] + b[1]; + dest[2] = a[2] + b[2]; +} + +/*! + * @brief add scalar s to vector [v] and store result in [dest] + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec3_adds(ivec3 v, int s, ivec3 dest) { + dest[0] = v[0] + s; + dest[1] = v[1] + s; + dest[2] = v[2] + s; +} + +/*! + * @brief subtract vector [b] from vector [a] and store result in [dest] + * + * @param[in] a first vector + * @param[in] b second vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec3_sub(ivec3 a, ivec3 b, ivec3 dest) { + dest[0] = a[0] - b[0]; + dest[1] = a[1] - b[1]; + dest[2] = a[2] - b[2]; +} + +/*! + * @brief subtract scalar s from vector [v] and store result in [dest] + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec3_subs(ivec3 v, int s, ivec3 dest) { + dest[0] = v[0] - s; + dest[1] = v[1] - s; + dest[2] = v[2] - s; +} + +/*! + * @brief multiply vector [a] with vector [b] and store result in [dest] + * + * @param[in] a frist vector + * @param[in] b second vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec3_mul(ivec3 a, ivec3 b, ivec3 dest) { + dest[0] = a[0] * b[0]; + dest[1] = a[1] * b[1]; + dest[2] = a[2] * b[2]; +} + +/*! + * @brief multiply vector [a] with scalar s and store result in [dest] + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec3_scale(ivec3 v, int s, ivec3 dest) { + dest[0] = v[0] * s; + dest[1] = v[1] * s; + dest[2] = v[2] * s; +} + +/*! + * @brief squared distance between two vectors + * + * @param[in] a first vector + * @param[in] b second vector + * @return returns squared distance (distance * distance) + */ +CGLM_INLINE +int +glm_ivec3_distance2(ivec3 a, ivec3 b) { + int xd, yd, zd; + xd = a[0] - b[0]; + yd = a[1] - b[1]; + zd = a[2] - b[2]; + return xd * xd + yd * yd + zd * zd; +} + +/*! + * @brief distance between two vectors + * + * @param[in] a first vector + * @param[in] b second vector + * @return returns distance + */ +CGLM_INLINE +float +glm_ivec3_distance(ivec3 a, ivec3 b) { + return sqrtf((float)glm_ivec3_distance2(a, b)); +} + +/*! + * @brief set each member of dest to greater of vector a and b + * + * @param[in] a first vector + * @param[in] b second vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec3_maxv(ivec3 a, ivec3 b, ivec3 dest) { + dest[0] = a[0] > b[0] ? a[0] : b[0]; + dest[1] = a[1] > b[1] ? a[1] : b[1]; + dest[2] = a[2] > b[2] ? a[2] : b[2]; +} + +/*! + * @brief set each member of dest to lesser of vector a and b + * + * @param[in] a first vector + * @param[in] b second vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec3_minv(ivec3 a, ivec3 b, ivec3 dest) { + dest[0] = a[0] < b[0] ? a[0] : b[0]; + dest[1] = a[1] < b[1] ? a[1] : b[1]; + dest[2] = a[2] < b[2] ? a[2] : b[2]; +} + +/*! + * @brief clamp each member of [v] between minVal and maxVal (inclusive) + * + * @param[in, out] v vector + * @param[in] minVal minimum value + * @param[in] maxVal maximum value + */ +CGLM_INLINE +void +glm_ivec3_clamp(ivec3 v, int minVal, int maxVal) { + if (v[0] < minVal) + v[0] = minVal; + else if(v[0] > maxVal) + v[0] = maxVal; + + if (v[1] < minVal) + v[1] = minVal; + else if(v[1] > maxVal) + v[1] = maxVal; + + if (v[2] < minVal) + v[2] = minVal; + else if(v[2] > maxVal) + v[2] = maxVal; +} + +/*! + * @brief absolute value of v + * + * @param[in] v vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec3_abs(ivec3 v, ivec3 dest) { + dest[0] = abs(v[0]); + dest[1] = abs(v[1]); + dest[2] = abs(v[2]); +} + +#endif /* cglm_ivec3_h */ diff --git a/include/cglm/ivec4.h b/include/cglm/ivec4.h new file mode 100644 index 0000000..6706036 --- /dev/null +++ b/include/cglm/ivec4.h @@ -0,0 +1,291 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* +FUNCTIONS: + CGLM_INLINE void glm_ivec4(ivec3 v3, int last, ivec4 dest) + CGLM_INLINE void glm_ivec4_copy(ivec4 a, ivec4 dest) + CGLM_INLINE void glm_ivec4_zero(ivec4 v) + CGLM_INLINE void glm_ivec4_one(ivec4 v) + CGLM_INLINE void glm_ivec4_add(ivec4 a, ivec4 b, ivec4 dest) + CGLM_INLINE void glm_ivec4_adds(ivec4 v, int s, ivec4 dest) + CGLM_INLINE void glm_ivec4_sub(ivec4 a, ivec4 b, ivec4 dest) + CGLM_INLINE void glm_ivec4_subs(ivec4 v, int s, ivec4 dest) + CGLM_INLINE void glm_ivec4_mul(ivec4 a, ivec4 b, ivec4 dest) + CGLM_INLINE void glm_ivec4_scale(ivec4 v, int s, ivec4 dest) + CGLM_INLINE int glm_ivec4_distance2(ivec4 a, ivec4 b) + CGLM_INLINE float glm_ivec4_distance(ivec4 a, ivec4 b) + CGLM_INLINE void glm_ivec4_maxv(ivec4 a, ivec4 b, ivec4 dest) + CGLM_INLINE void glm_ivec4_minv(ivec4 a, ivec4 b, ivec4 dest) + CGLM_INLINE void glm_ivec4_clamp(ivec4 v, int minVal, int maxVal) + CGLM_INLINE void glm_ivec4_abs(ivec4 v, ivec4 dest) + */ + +#ifndef cglm_ivec4_h +#define cglm_ivec4_h + +#include "common.h" + +/*! + * @brief init ivec4 using ivec3 + * + * @param[in] v3 vector3 + * @param[in] last last item + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec4(ivec3 v3, int last, ivec4 dest) { + dest[0] = v3[0]; + dest[1] = v3[1]; + dest[2] = v3[2]; + dest[3] = last; +} + +/*! + * @brief copy all members of [a] to [dest] + * + * @param[in] a source vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec4_copy(ivec4 a, ivec4 dest) { + dest[0] = a[0]; + dest[1] = a[1]; + dest[2] = a[2]; + dest[3] = a[3]; +} + +/*! + * @brief set all members of [v] to zero + * + * @param[out] v vector + */ +CGLM_INLINE +void +glm_ivec4_zero(ivec4 v) { + v[0] = v[1] = v[2] = v[3] = 0; +} + +/*! + * @brief set all members of [v] to one + * + * @param[out] v vector + */ +CGLM_INLINE +void +glm_ivec4_one(ivec4 v) { + v[0] = v[1] = v[2] = v[3] = 1; +} + +/*! + * @brief add vector [a] to vector [b] and store result in [dest] + * + * @param[in] a first vector + * @param[in] b second vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec4_add(ivec4 a, ivec4 b, ivec4 dest) { + dest[0] = a[0] + b[0]; + dest[1] = a[1] + b[1]; + dest[2] = a[2] + b[2]; + dest[3] = a[3] + b[3]; +} + +/*! + * @brief add scalar s to vector [v] and store result in [dest] + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec4_adds(ivec4 v, int s, ivec4 dest) { + dest[0] = v[0] + s; + dest[1] = v[1] + s; + dest[2] = v[2] + s; + dest[3] = v[3] + s; +} + +/*! + * @brief subtract vector [b] from vector [a] and store result in [dest] + * + * @param[in] a first vector + * @param[in] b second vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec4_sub(ivec4 a, ivec4 b, ivec4 dest) { + dest[0] = a[0] - b[0]; + dest[1] = a[1] - b[1]; + dest[2] = a[2] - b[2]; + dest[3] = a[3] - b[3]; +} + +/*! + * @brief subtract scalar s from vector [v] and store result in [dest] + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec4_subs(ivec4 v, int s, ivec4 dest) { + dest[0] = v[0] - s; + dest[1] = v[1] - s; + dest[2] = v[2] - s; + dest[3] = v[3] - s; +} + +/*! + * @brief multiply vector [a] with vector [b] and store result in [dest] + * + * @param[in] a frist vector + * @param[in] b second vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec4_mul(ivec4 a, ivec4 b, ivec4 dest) { + dest[0] = a[0] * b[0]; + dest[1] = a[1] * b[1]; + dest[2] = a[2] * b[2]; + dest[3] = a[3] * b[3]; +} + +/*! + * @brief multiply vector [a] with scalar s and store result in [dest] + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec4_scale(ivec4 v, int s, ivec4 dest) { + dest[0] = v[0] * s; + dest[1] = v[1] * s; + dest[2] = v[2] * s; + dest[3] = v[3] * s; +} + +/*! + * @brief squared distance between two vectors + * + * @param[in] a first vector + * @param[in] b second vector + * @return returns squared distance (distance * distance) + */ +CGLM_INLINE +int +glm_ivec4_distance2(ivec4 a, ivec4 b) { + int xd, yd, zd, wd; + xd = a[0] - b[0]; + yd = a[1] - b[1]; + zd = a[2] - b[2]; + wd = a[3] - b[3]; + return xd * xd + yd * yd + zd * zd + wd * wd; +} + +/*! + * @brief distance between two vectors + * + * @param[in] a first vector + * @param[in] b second vector + * @return returns distance + */ +CGLM_INLINE +float +glm_ivec4_distance(ivec4 a, ivec4 b) { + return sqrtf((float)glm_ivec4_distance2(a, b)); +} + +/*! + * @brief set each member of dest to greater of vector a and b + * + * @param[in] a first vector + * @param[in] b second vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec4_maxv(ivec4 a, ivec4 b, ivec4 dest) { + dest[0] = a[0] > b[0] ? a[0] : b[0]; + dest[1] = a[1] > b[1] ? a[1] : b[1]; + dest[2] = a[2] > b[2] ? a[2] : b[2]; + dest[3] = a[3] > b[3] ? a[3] : b[3]; +} + +/*! + * @brief set each member of dest to lesser of vector a and b + * + * @param[in] a first vector + * @param[in] b second vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec4_minv(ivec4 a, ivec4 b, ivec4 dest) { + dest[0] = a[0] < b[0] ? a[0] : b[0]; + dest[1] = a[1] < b[1] ? a[1] : b[1]; + dest[2] = a[2] < b[2] ? a[2] : b[2]; + dest[3] = a[3] < b[3] ? a[3] : b[3]; +} + +/*! + * @brief clamp each member of [v] between minVal and maxVal (inclusive) + * + * @param[in, out] v vector + * @param[in] minVal minimum value + * @param[in] maxVal maximum value + */ +CGLM_INLINE +void +glm_ivec4_clamp(ivec4 v, int minVal, int maxVal) { + if (v[0] < minVal) + v[0] = minVal; + else if(v[0] > maxVal) + v[0] = maxVal; + + if (v[1] < minVal) + v[1] = minVal; + else if(v[1] > maxVal) + v[1] = maxVal; + + if (v[2] < minVal) + v[2] = minVal; + else if(v[2] > maxVal) + v[2] = maxVal; + + if (v[3] < minVal) + v[3] = minVal; + else if(v[3] > maxVal) + v[3] = maxVal; +} + +/*! + * @brief absolute value of v + * + * @param[in] v vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_ivec4_abs(ivec4 v, ivec4 dest) { + dest[0] = abs(v[0]); + dest[1] = abs(v[1]); + dest[2] = abs(v[2]); + dest[3] = abs(v[3]); +} + +#endif /* cglm_ivec4_h */ diff --git a/include/cglm/mat2.h b/include/cglm/mat2.h new file mode 100644 index 0000000..871d6bd --- /dev/null +++ b/include/cglm/mat2.h @@ -0,0 +1,337 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Macros: + GLM_MAT2_IDENTITY_INIT + GLM_MAT2_ZERO_INIT + GLM_MAT2_IDENTITY + GLM_MAT2_ZERO + + Functions: + CGLM_INLINE void glm_mat2_copy(mat2 mat, mat2 dest) + CGLM_INLINE void glm_mat2_identity(mat2 mat) + CGLM_INLINE void glm_mat2_identity_array(mat2 * restrict mat, size_t count) + CGLM_INLINE void glm_mat2_zero(mat2 mat) + CGLM_INLINE void glm_mat2_mul(mat2 m1, mat2 m2, mat2 dest) + CGLM_INLINE void glm_mat2_transpose_to(mat2 m, mat2 dest) + CGLM_INLINE void glm_mat2_transpose(mat2 m) + CGLM_INLINE void glm_mat2_mulv(mat2 m, vec2 v, vec2 dest) + CGLM_INLINE float glm_mat2_trace(mat2 m) + CGLM_INLINE void glm_mat2_scale(mat2 m, float s) + CGLM_INLINE float glm_mat2_det(mat2 mat) + CGLM_INLINE void glm_mat2_inv(mat2 mat, mat2 dest) + CGLM_INLINE void glm_mat2_swap_col(mat2 mat, int col1, int col2) + CGLM_INLINE void glm_mat2_swap_row(mat2 mat, int row1, int row2) + CGLM_INLINE float glm_mat2_rmc(vec2 r, mat2 m, vec2 c) + */ + +#ifndef cglm_mat2_h +#define cglm_mat2_h + +#include "common.h" +#include "vec2.h" + +#ifdef CGLM_SSE_FP +# include "simd/sse2/mat2.h" +#endif + +#ifdef CGLM_NEON_FP +# include "simd/neon/mat2.h" +#endif + +#define GLM_MAT2_IDENTITY_INIT {{1.0f, 0.0f}, {0.0f, 1.0f}} +#define GLM_MAT2_ZERO_INIT {{0.0f, 0.0f}, {0.0f, 0.0f}} + +/* for C only */ +#define GLM_MAT2_IDENTITY ((mat2)GLM_MAT2_IDENTITY_INIT) +#define GLM_MAT2_ZERO ((mat2)GLM_MAT2_ZERO_INIT) + +/*! + * @brief copy all members of [mat] to [dest] + * + * @param[in] mat source + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_mat2_copy(mat2 mat, mat2 dest) { + glm_vec4_ucopy(mat[0], dest[0]); +} + +/*! + * @brief make given matrix identity. It is identical with below, + * but it is more easy to do that with this func especially for members + * e.g. glm_mat2_identity(aStruct->aMatrix); + * + * @code + * glm_mat2_copy(GLM_MAT2_IDENTITY, mat); // C only + * + * // or + * mat2 mat = GLM_MAT2_IDENTITY_INIT; + * @endcode + * + * @param[in, out] mat destination + */ +CGLM_INLINE +void +glm_mat2_identity(mat2 mat) { + CGLM_ALIGN_MAT mat2 t = GLM_MAT2_IDENTITY_INIT; + glm_mat2_copy(t, mat); +} + +/*! + * @brief make given matrix array's each element identity matrix + * + * @param[in, out] mat matrix array (must be aligned (16) + * if alignment is not disabled) + * + * @param[in] count count of matrices + */ +CGLM_INLINE +void +glm_mat2_identity_array(mat2 * __restrict mat, size_t count) { + CGLM_ALIGN_MAT mat2 t = GLM_MAT2_IDENTITY_INIT; + size_t i; + + for (i = 0; i < count; i++) { + glm_mat2_copy(t, mat[i]); + } +} + +/*! + * @brief make given matrix zero. + * + * @param[in, out] mat matrix + */ +CGLM_INLINE +void +glm_mat2_zero(mat2 mat) { + CGLM_ALIGN_MAT mat2 t = GLM_MAT2_ZERO_INIT; + glm_mat2_copy(t, mat); +} + +/*! + * @brief multiply m1 and m2 to dest + * + * m1, m2 and dest matrices can be same matrix, it is possible to write this: + * + * @code + * mat2 m = GLM_MAT2_IDENTITY_INIT; + * glm_mat2_mul(m, m, m); + * @endcode + * + * @param[in] m1 left matrix + * @param[in] m2 right matrix + * @param[out] dest destination matrix + */ +CGLM_INLINE +void +glm_mat2_mul(mat2 m1, mat2 m2, mat2 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glm_mat2_mul_sse2(m1, m2, dest); +#elif defined(CGLM_NEON_FP) + glm_mat2_mul_neon(m1, m2, dest); +#else + float a00 = m1[0][0], a01 = m1[0][1], + a10 = m1[1][0], a11 = m1[1][1], + b00 = m2[0][0], b01 = m2[0][1], + b10 = m2[1][0], b11 = m2[1][1]; + + dest[0][0] = a00 * b00 + a10 * b01; + dest[0][1] = a01 * b00 + a11 * b01; + dest[1][0] = a00 * b10 + a10 * b11; + dest[1][1] = a01 * b10 + a11 * b11; +#endif +} + +/*! + * @brief transpose mat2 and store in dest + * + * source matrix will not be transposed unless dest is m + * + * @param[in] m matrix + * @param[out] dest result + */ +CGLM_INLINE +void +glm_mat2_transpose_to(mat2 m, mat2 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glm_mat2_transp_sse2(m, dest); +#else + dest[0][0] = m[0][0]; + dest[0][1] = m[1][0]; + dest[1][0] = m[0][1]; + dest[1][1] = m[1][1]; +#endif +} + +/*! + * @brief tranpose mat2 and store result in same matrix + * + * @param[in, out] m source and dest + */ +CGLM_INLINE +void +glm_mat2_transpose(mat2 m) { + float tmp; + tmp = m[0][1]; + m[0][1] = m[1][0]; + m[1][0] = tmp; +} + +/*! + * @brief multiply mat2 with vec2 (column vector) and store in dest vector + * + * @param[in] m mat2 (left) + * @param[in] v vec2 (right, column vector) + * @param[out] dest vec2 (result, column vector) + */ +CGLM_INLINE +void +glm_mat2_mulv(mat2 m, vec2 v, vec2 dest) { + dest[0] = m[0][0] * v[0] + m[1][0] * v[1]; + dest[1] = m[0][1] * v[0] + m[1][1] * v[1]; +} + +/*! + * @brief trace of matrix + * + * sum of the elements on the main diagonal from upper left to the lower right + * + * @param[in] m matrix + */ +CGLM_INLINE +float +glm_mat2_trace(mat2 m) { + return m[0][0] + m[1][1]; +} + +/*! + * @brief scale (multiply with scalar) matrix + * + * multiply matrix with scalar + * + * @param[in, out] m matrix + * @param[in] s scalar + */ +CGLM_INLINE +void +glm_mat2_scale(mat2 m, float s) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(m[0], _mm_mul_ps(_mm_loadu_ps(m[0]), _mm_set1_ps(s))); +#elif defined(CGLM_NEON_FP) + vst1q_f32(m[0], vmulq_f32(vld1q_f32(m[0]), vdupq_n_f32(s))); +#else + m[0][0] = m[0][0] * s; + m[0][1] = m[0][1] * s; + m[1][0] = m[1][0] * s; + m[1][1] = m[1][1] * s; +#endif +} + +/*! + * @brief mat2 determinant + * + * @param[in] mat matrix + * + * @return determinant + */ +CGLM_INLINE +float +glm_mat2_det(mat2 mat) { + return mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1]; +} + +/*! + * @brief inverse mat2 and store in dest + * + * @param[in] mat matrix + * @param[out] dest inverse matrix + */ +CGLM_INLINE +void +glm_mat2_inv(mat2 mat, mat2 dest) { + float det; + float a = mat[0][0], b = mat[0][1], + c = mat[1][0], d = mat[1][1]; + + det = 1.0f / (a * d - b * c); + + dest[0][0] = d * det; + dest[0][1] = -b * det; + dest[1][0] = -c * det; + dest[1][1] = a * det; +} + +/*! + * @brief swap two matrix columns + * + * @param[in,out] mat matrix + * @param[in] col1 col1 + * @param[in] col2 col2 + */ +CGLM_INLINE +void +glm_mat2_swap_col(mat2 mat, int col1, int col2) { + float a, b; + + a = mat[col1][0]; + b = mat[col1][1]; + + mat[col1][0] = mat[col2][0]; + mat[col1][1] = mat[col2][1]; + + mat[col2][0] = a; + mat[col2][1] = b; +} + +/*! + * @brief swap two matrix rows + * + * @param[in,out] mat matrix + * @param[in] row1 row1 + * @param[in] row2 row2 + */ +CGLM_INLINE +void +glm_mat2_swap_row(mat2 mat, int row1, int row2) { + float a, b; + + a = mat[0][row1]; + b = mat[1][row1]; + + mat[0][row1] = mat[0][row2]; + mat[1][row1] = mat[1][row2]; + + mat[0][row2] = a; + mat[1][row2] = b; +} + +/*! + * @brief helper for R (row vector) * M (matrix) * C (column vector) + * + * rmc stands for Row * Matrix * Column + * + * the result is scalar because R * M = Matrix1x2 (row vector), + * then Matrix1x2 * Vec2 (column vector) = Matrix1x1 (Scalar) + * + * @param[in] r row vector or matrix1x2 + * @param[in] m matrix2x2 + * @param[in] c column vector or matrix2x1 + * + * @return scalar value e.g. Matrix1x1 + */ +CGLM_INLINE +float +glm_mat2_rmc(vec2 r, mat2 m, vec2 c) { + vec2 tmp; + glm_mat2_mulv(m, c, tmp); + return glm_vec2_dot(r, tmp); +} + +#endif /* cglm_mat2_h */ diff --git a/include/cglm/mat3.h b/include/cglm/mat3.h new file mode 100644 index 0000000..0b29f97 --- /dev/null +++ b/include/cglm/mat3.h @@ -0,0 +1,424 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Macros: + GLM_MAT3_IDENTITY_INIT + GLM_MAT3_ZERO_INIT + GLM_MAT3_IDENTITY + GLM_MAT3_ZERO + glm_mat3_dup(mat, dest) + + Functions: + CGLM_INLINE void glm_mat3_copy(mat3 mat, mat3 dest); + CGLM_INLINE void glm_mat3_identity(mat3 mat); + CGLM_INLINE void glm_mat3_identity_array(mat3 * restrict mat, size_t count); + CGLM_INLINE void glm_mat3_zero(mat3 mat); + CGLM_INLINE void glm_mat3_mul(mat3 m1, mat3 m2, mat3 dest); + CGLM_INLINE void glm_mat3_transpose_to(mat3 m, mat3 dest); + CGLM_INLINE void glm_mat3_transpose(mat3 m); + CGLM_INLINE void glm_mat3_mulv(mat3 m, vec3 v, vec3 dest); + CGLM_INLINE float glm_mat3_trace(mat3 m); + CGLM_INLINE void glm_mat3_quat(mat3 m, versor dest); + CGLM_INLINE void glm_mat3_scale(mat3 m, float s); + CGLM_INLINE float glm_mat3_det(mat3 mat); + CGLM_INLINE void glm_mat3_inv(mat3 mat, mat3 dest); + CGLM_INLINE void glm_mat3_swap_col(mat3 mat, int col1, int col2); + CGLM_INLINE void glm_mat3_swap_row(mat3 mat, int row1, int row2); + CGLM_INLINE float glm_mat3_rmc(vec3 r, mat3 m, vec3 c); + */ + +#ifndef cglm_mat3_h +#define cglm_mat3_h + +#include "common.h" +#include "vec3.h" + +#ifdef CGLM_SSE_FP +# include "simd/sse2/mat3.h" +#endif + +#define GLM_MAT3_IDENTITY_INIT {{1.0f, 0.0f, 0.0f}, \ + {0.0f, 1.0f, 0.0f}, \ + {0.0f, 0.0f, 1.0f}} +#define GLM_MAT3_ZERO_INIT {{0.0f, 0.0f, 0.0f}, \ + {0.0f, 0.0f, 0.0f}, \ + {0.0f, 0.0f, 0.0f}} + + +/* for C only */ +#define GLM_MAT3_IDENTITY ((mat3)GLM_MAT3_IDENTITY_INIT) +#define GLM_MAT3_ZERO ((mat3)GLM_MAT3_ZERO_INIT) + +/* DEPRECATED! use _copy, _ucopy versions */ +#define glm_mat3_dup(mat, dest) glm_mat3_copy(mat, dest) + +/*! + * @brief copy all members of [mat] to [dest] + * + * @param[in] mat source + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_mat3_copy(mat3 mat, mat3 dest) { + dest[0][0] = mat[0][0]; + dest[0][1] = mat[0][1]; + dest[0][2] = mat[0][2]; + + dest[1][0] = mat[1][0]; + dest[1][1] = mat[1][1]; + dest[1][2] = mat[1][2]; + + dest[2][0] = mat[2][0]; + dest[2][1] = mat[2][1]; + dest[2][2] = mat[2][2]; +} + +/*! + * @brief make given matrix identity. It is identical with below, + * but it is more easy to do that with this func especially for members + * e.g. glm_mat3_identity(aStruct->aMatrix); + * + * @code + * glm_mat3_copy(GLM_MAT3_IDENTITY, mat); // C only + * + * // or + * mat3 mat = GLM_MAT3_IDENTITY_INIT; + * @endcode + * + * @param[in, out] mat destination + */ +CGLM_INLINE +void +glm_mat3_identity(mat3 mat) { + CGLM_ALIGN_MAT mat3 t = GLM_MAT3_IDENTITY_INIT; + glm_mat3_copy(t, mat); +} + +/*! + * @brief make given matrix array's each element identity matrix + * + * @param[in, out] mat matrix array (must be aligned (16/32) + * if alignment is not disabled) + * + * @param[in] count count of matrices + */ +CGLM_INLINE +void +glm_mat3_identity_array(mat3 * __restrict mat, size_t count) { + CGLM_ALIGN_MAT mat3 t = GLM_MAT3_IDENTITY_INIT; + size_t i; + + for (i = 0; i < count; i++) { + glm_mat3_copy(t, mat[i]); + } +} + +/*! + * @brief make given matrix zero. + * + * @param[in, out] mat matrix + */ +CGLM_INLINE +void +glm_mat3_zero(mat3 mat) { + CGLM_ALIGN_MAT mat3 t = GLM_MAT3_ZERO_INIT; + glm_mat3_copy(t, mat); +} + +/*! + * @brief multiply m1 and m2 to dest + * + * m1, m2 and dest matrices can be same matrix, it is possible to write this: + * + * @code + * mat3 m = GLM_MAT3_IDENTITY_INIT; + * glm_mat3_mul(m, m, m); + * @endcode + * + * @param[in] m1 left matrix + * @param[in] m2 right matrix + * @param[out] dest destination matrix + */ +CGLM_INLINE +void +glm_mat3_mul(mat3 m1, mat3 m2, mat3 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glm_mat3_mul_sse2(m1, m2, dest); +#else + float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], + a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], + a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], + + b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], + b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], + b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2]; + + dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02; + dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02; + dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02; + dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12; + dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12; + dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12; + dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22; + dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22; + dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22; +#endif +} + +/*! + * @brief transpose mat3 and store in dest + * + * source matrix will not be transposed unless dest is m + * + * @param[in] m matrix + * @param[out] dest result + */ +CGLM_INLINE +void +glm_mat3_transpose_to(mat3 m, mat3 dest) { + dest[0][0] = m[0][0]; + dest[0][1] = m[1][0]; + dest[0][2] = m[2][0]; + dest[1][0] = m[0][1]; + dest[1][1] = m[1][1]; + dest[1][2] = m[2][1]; + dest[2][0] = m[0][2]; + dest[2][1] = m[1][2]; + dest[2][2] = m[2][2]; +} + +/*! + * @brief tranpose mat3 and store result in same matrix + * + * @param[in, out] m source and dest + */ +CGLM_INLINE +void +glm_mat3_transpose(mat3 m) { + CGLM_ALIGN_MAT mat3 tmp; + + tmp[0][1] = m[1][0]; + tmp[0][2] = m[2][0]; + tmp[1][0] = m[0][1]; + tmp[1][2] = m[2][1]; + tmp[2][0] = m[0][2]; + tmp[2][1] = m[1][2]; + + m[0][1] = tmp[0][1]; + m[0][2] = tmp[0][2]; + m[1][0] = tmp[1][0]; + m[1][2] = tmp[1][2]; + m[2][0] = tmp[2][0]; + m[2][1] = tmp[2][1]; +} + +/*! + * @brief multiply mat3 with vec3 (column vector) and store in dest vector + * + * @param[in] m mat3 (left) + * @param[in] v vec3 (right, column vector) + * @param[out] dest vec3 (result, column vector) + */ +CGLM_INLINE +void +glm_mat3_mulv(mat3 m, vec3 v, vec3 dest) { + vec3 res; + res[0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2]; + res[1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2]; + res[2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2]; + glm_vec3_copy(res, dest); +} + +/*! + * @brief trace of matrix + * + * sum of the elements on the main diagonal from upper left to the lower right + * + * @param[in] m matrix + */ +CGLM_INLINE +float +glm_mat3_trace(mat3 m) { + return m[0][0] + m[1][1] + m[2][2]; +} + +/*! + * @brief convert mat3 to quaternion + * + * @param[in] m rotation matrix + * @param[out] dest destination quaternion + */ +CGLM_INLINE +void +glm_mat3_quat(mat3 m, versor dest) { + float trace, r, rinv; + + /* it seems using like m12 instead of m[1][2] causes extra instructions */ + + trace = m[0][0] + m[1][1] + m[2][2]; + if (trace >= 0.0f) { + r = sqrtf(1.0f + trace); + rinv = 0.5f / r; + + dest[0] = rinv * (m[1][2] - m[2][1]); + dest[1] = rinv * (m[2][0] - m[0][2]); + dest[2] = rinv * (m[0][1] - m[1][0]); + dest[3] = r * 0.5f; + } else if (m[0][0] >= m[1][1] && m[0][0] >= m[2][2]) { + r = sqrtf(1.0f - m[1][1] - m[2][2] + m[0][0]); + rinv = 0.5f / r; + + dest[0] = r * 0.5f; + dest[1] = rinv * (m[0][1] + m[1][0]); + dest[2] = rinv * (m[0][2] + m[2][0]); + dest[3] = rinv * (m[1][2] - m[2][1]); + } else if (m[1][1] >= m[2][2]) { + r = sqrtf(1.0f - m[0][0] - m[2][2] + m[1][1]); + rinv = 0.5f / r; + + dest[0] = rinv * (m[0][1] + m[1][0]); + dest[1] = r * 0.5f; + dest[2] = rinv * (m[1][2] + m[2][1]); + dest[3] = rinv * (m[2][0] - m[0][2]); + } else { + r = sqrtf(1.0f - m[0][0] - m[1][1] + m[2][2]); + rinv = 0.5f / r; + + dest[0] = rinv * (m[0][2] + m[2][0]); + dest[1] = rinv * (m[1][2] + m[2][1]); + dest[2] = r * 0.5f; + dest[3] = rinv * (m[0][1] - m[1][0]); + } +} + +/*! + * @brief scale (multiply with scalar) matrix + * + * multiply matrix with scalar + * + * @param[in, out] m matrix + * @param[in] s scalar + */ +CGLM_INLINE +void +glm_mat3_scale(mat3 m, float s) { + m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; + m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; + m[2][0] *= s; m[2][1] *= s; m[2][2] *= s; +} + +/*! + * @brief mat3 determinant + * + * @param[in] mat matrix + * + * @return determinant + */ +CGLM_INLINE +float +glm_mat3_det(mat3 mat) { + float a = mat[0][0], b = mat[0][1], c = mat[0][2], + d = mat[1][0], e = mat[1][1], f = mat[1][2], + g = mat[2][0], h = mat[2][1], i = mat[2][2]; + + return a * (e * i - h * f) - d * (b * i - c * h) + g * (b * f - c * e); +} + +/*! + * @brief inverse mat3 and store in dest + * + * @param[in] mat matrix + * @param[out] dest inverse matrix + */ +CGLM_INLINE +void +glm_mat3_inv(mat3 mat, mat3 dest) { + float det; + float a = mat[0][0], b = mat[0][1], c = mat[0][2], + d = mat[1][0], e = mat[1][1], f = mat[1][2], + g = mat[2][0], h = mat[2][1], i = mat[2][2]; + + dest[0][0] = e * i - f * h; + dest[0][1] = -(b * i - h * c); + dest[0][2] = b * f - e * c; + dest[1][0] = -(d * i - g * f); + dest[1][1] = a * i - c * g; + dest[1][2] = -(a * f - d * c); + dest[2][0] = d * h - g * e; + dest[2][1] = -(a * h - g * b); + dest[2][2] = a * e - b * d; + + det = 1.0f / (a * dest[0][0] + b * dest[1][0] + c * dest[2][0]); + + glm_mat3_scale(dest, det); +} + +/*! + * @brief swap two matrix columns + * + * @param[in,out] mat matrix + * @param[in] col1 col1 + * @param[in] col2 col2 + */ +CGLM_INLINE +void +glm_mat3_swap_col(mat3 mat, int col1, int col2) { + vec3 tmp; + glm_vec3_copy(mat[col1], tmp); + glm_vec3_copy(mat[col2], mat[col1]); + glm_vec3_copy(tmp, mat[col2]); +} + +/*! + * @brief swap two matrix rows + * + * @param[in,out] mat matrix + * @param[in] row1 row1 + * @param[in] row2 row2 + */ +CGLM_INLINE +void +glm_mat3_swap_row(mat3 mat, int row1, int row2) { + vec3 tmp; + tmp[0] = mat[0][row1]; + tmp[1] = mat[1][row1]; + tmp[2] = mat[2][row1]; + + mat[0][row1] = mat[0][row2]; + mat[1][row1] = mat[1][row2]; + mat[2][row1] = mat[2][row2]; + + mat[0][row2] = tmp[0]; + mat[1][row2] = tmp[1]; + mat[2][row2] = tmp[2]; +} + +/*! + * @brief helper for R (row vector) * M (matrix) * C (column vector) + * + * rmc stands for Row * Matrix * Column + * + * the result is scalar because R * M = Matrix1x3 (row vector), + * then Matrix1x3 * Vec3 (column vector) = Matrix1x1 (Scalar) + * + * @param[in] r row vector or matrix1x3 + * @param[in] m matrix3x3 + * @param[in] c column vector or matrix3x1 + * + * @return scalar value e.g. Matrix1x1 + */ +CGLM_INLINE +float +glm_mat3_rmc(vec3 r, mat3 m, vec3 c) { + vec3 tmp; + glm_mat3_mulv(m, c, tmp); + return glm_vec3_dot(r, tmp); +} + +#endif /* cglm_mat3_h */ diff --git a/include/cglm/mat4.h b/include/cglm/mat4.h new file mode 100644 index 0000000..04cfece --- /dev/null +++ b/include/cglm/mat4.h @@ -0,0 +1,754 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/*! + * Most of functions in this header are optimized manually with SIMD + * if available. You dont need to call/incude SIMD headers manually + */ + +/* + Macros: + GLM_MAT4_IDENTITY_INIT + GLM_MAT4_ZERO_INIT + GLM_MAT4_IDENTITY + GLM_MAT4_ZERO + + Functions: + CGLM_INLINE void glm_mat4_ucopy(mat4 mat, mat4 dest); + CGLM_INLINE void glm_mat4_copy(mat4 mat, mat4 dest); + CGLM_INLINE void glm_mat4_identity(mat4 mat); + CGLM_INLINE void glm_mat4_identity_array(mat4 * restrict mat, size_t count); + CGLM_INLINE void glm_mat4_zero(mat4 mat); + CGLM_INLINE void glm_mat4_pick3(mat4 mat, mat3 dest); + CGLM_INLINE void glm_mat4_pick3t(mat4 mat, mat3 dest); + CGLM_INLINE void glm_mat4_ins3(mat3 mat, mat4 dest); + CGLM_INLINE void glm_mat4_mul(mat4 m1, mat4 m2, mat4 dest); + CGLM_INLINE void glm_mat4_mulN(mat4 *matrices[], int len, mat4 dest); + CGLM_INLINE void glm_mat4_mulv(mat4 m, vec4 v, vec4 dest); + CGLM_INLINE void glm_mat4_mulv3(mat4 m, vec3 v, vec3 dest); + CGLM_INLINE float glm_mat4_trace(mat4 m); + CGLM_INLINE float glm_mat4_trace3(mat4 m); + CGLM_INLINE void glm_mat4_quat(mat4 m, versor dest) ; + CGLM_INLINE void glm_mat4_transpose_to(mat4 m, mat4 dest); + CGLM_INLINE void glm_mat4_transpose(mat4 m); + CGLM_INLINE void glm_mat4_scale_p(mat4 m, float s); + CGLM_INLINE void glm_mat4_scale(mat4 m, float s); + CGLM_INLINE float glm_mat4_det(mat4 mat); + CGLM_INLINE void glm_mat4_inv(mat4 mat, mat4 dest); + CGLM_INLINE void glm_mat4_inv_fast(mat4 mat, mat4 dest); + CGLM_INLINE void glm_mat4_swap_col(mat4 mat, int col1, int col2); + CGLM_INLINE void glm_mat4_swap_row(mat4 mat, int row1, int row2); + CGLM_INLINE float glm_mat4_rmc(vec4 r, mat4 m, vec4 c); + */ + +#ifndef cglm_mat_h +#define cglm_mat_h + +#include "common.h" +#include "vec4.h" +#include "vec3.h" + +#ifdef CGLM_SSE_FP +# include "simd/sse2/mat4.h" +#endif + +#ifdef CGLM_AVX_FP +# include "simd/avx/mat4.h" +#endif + +#ifdef CGLM_NEON_FP +# include "simd/neon/mat4.h" +#endif + +#ifdef DEBUG +# include +#endif + +#define GLM_MAT4_IDENTITY_INIT {{1.0f, 0.0f, 0.0f, 0.0f}, \ + {0.0f, 1.0f, 0.0f, 0.0f}, \ + {0.0f, 0.0f, 1.0f, 0.0f}, \ + {0.0f, 0.0f, 0.0f, 1.0f}} + +#define GLM_MAT4_ZERO_INIT {{0.0f, 0.0f, 0.0f, 0.0f}, \ + {0.0f, 0.0f, 0.0f, 0.0f}, \ + {0.0f, 0.0f, 0.0f, 0.0f}, \ + {0.0f, 0.0f, 0.0f, 0.0f}} + +/* for C only */ +#define GLM_MAT4_IDENTITY ((mat4)GLM_MAT4_IDENTITY_INIT) +#define GLM_MAT4_ZERO ((mat4)GLM_MAT4_ZERO_INIT) + +/* DEPRECATED! use _copy, _ucopy versions */ +#define glm_mat4_udup(mat, dest) glm_mat4_ucopy(mat, dest) +#define glm_mat4_dup(mat, dest) glm_mat4_copy(mat, dest) + +/* DEPRECATED! default is precise now. */ +#define glm_mat4_inv_precise(mat, dest) glm_mat4_inv(mat, dest) + +/*! + * @brief copy all members of [mat] to [dest] + * + * matrix may not be aligned, u stands for unaligned, this may be useful when + * copying a matrix from external source e.g. asset importer... + * + * @param[in] mat source + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_mat4_ucopy(mat4 mat, mat4 dest) { + dest[0][0] = mat[0][0]; dest[1][0] = mat[1][0]; + dest[0][1] = mat[0][1]; dest[1][1] = mat[1][1]; + dest[0][2] = mat[0][2]; dest[1][2] = mat[1][2]; + dest[0][3] = mat[0][3]; dest[1][3] = mat[1][3]; + + dest[2][0] = mat[2][0]; dest[3][0] = mat[3][0]; + dest[2][1] = mat[2][1]; dest[3][1] = mat[3][1]; + dest[2][2] = mat[2][2]; dest[3][2] = mat[3][2]; + dest[2][3] = mat[2][3]; dest[3][3] = mat[3][3]; +} + +/*! + * @brief copy all members of [mat] to [dest] + * + * @param[in] mat source + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_mat4_copy(mat4 mat, mat4 dest) { +#ifdef __AVX__ + glmm_store256(dest[0], glmm_load256(mat[0])); + glmm_store256(dest[2], glmm_load256(mat[2])); +#elif defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(dest[0], glmm_load(mat[0])); + glmm_store(dest[1], glmm_load(mat[1])); + glmm_store(dest[2], glmm_load(mat[2])); + glmm_store(dest[3], glmm_load(mat[3])); +#elif defined(CGLM_NEON_FP) + vst1q_f32(dest[0], vld1q_f32(mat[0])); + vst1q_f32(dest[1], vld1q_f32(mat[1])); + vst1q_f32(dest[2], vld1q_f32(mat[2])); + vst1q_f32(dest[3], vld1q_f32(mat[3])); +#else + glm_mat4_ucopy(mat, dest); +#endif +} + +/*! + * @brief make given matrix identity. It is identical with below, + * but it is more easy to do that with this func especially for members + * e.g. glm_mat4_identity(aStruct->aMatrix); + * + * @code + * glm_mat4_copy(GLM_MAT4_IDENTITY, mat); // C only + * + * // or + * mat4 mat = GLM_MAT4_IDENTITY_INIT; + * @endcode + * + * @param[in, out] mat destination + */ +CGLM_INLINE +void +glm_mat4_identity(mat4 mat) { + CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; + glm_mat4_copy(t, mat); +} + +/*! + * @brief make given matrix array's each element identity matrix + * + * @param[in, out] mat matrix array (must be aligned (16/32) + * if alignment is not disabled) + * + * @param[in] count count of matrices + */ +CGLM_INLINE +void +glm_mat4_identity_array(mat4 * __restrict mat, size_t count) { + CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; + size_t i; + + for (i = 0; i < count; i++) { + glm_mat4_copy(t, mat[i]); + } +} + +/*! + * @brief make given matrix zero. + * + * @param[in, out] mat matrix + */ +CGLM_INLINE +void +glm_mat4_zero(mat4 mat) { +#ifdef __AVX__ + __m256 y0; + y0 = _mm256_setzero_ps(); + glmm_store256(mat[0], y0); + glmm_store256(mat[2], y0); +#elif defined( __SSE__ ) || defined( __SSE2__ ) + glmm_128 x0; + x0 = _mm_setzero_ps(); + glmm_store(mat[0], x0); + glmm_store(mat[1], x0); + glmm_store(mat[2], x0); + glmm_store(mat[3], x0); +#elif defined(CGLM_NEON_FP) + glmm_128 x0; + x0 = vdupq_n_f32(0.0f); + vst1q_f32(mat[0], x0); + vst1q_f32(mat[1], x0); + vst1q_f32(mat[2], x0); + vst1q_f32(mat[3], x0); +#else + CGLM_ALIGN_MAT mat4 t = GLM_MAT4_ZERO_INIT; + glm_mat4_copy(t, mat); +#endif +} + +/*! + * @brief copy upper-left of mat4 to mat3 + * + * @param[in] mat source + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_mat4_pick3(mat4 mat, mat3 dest) { + dest[0][0] = mat[0][0]; + dest[0][1] = mat[0][1]; + dest[0][2] = mat[0][2]; + + dest[1][0] = mat[1][0]; + dest[1][1] = mat[1][1]; + dest[1][2] = mat[1][2]; + + dest[2][0] = mat[2][0]; + dest[2][1] = mat[2][1]; + dest[2][2] = mat[2][2]; +} + +/*! + * @brief copy upper-left of mat4 to mat3 (transposed) + * + * the postfix t stands for transpose + * + * @param[in] mat source + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_mat4_pick3t(mat4 mat, mat3 dest) { + dest[0][0] = mat[0][0]; + dest[0][1] = mat[1][0]; + dest[0][2] = mat[2][0]; + + dest[1][0] = mat[0][1]; + dest[1][1] = mat[1][1]; + dest[1][2] = mat[2][1]; + + dest[2][0] = mat[0][2]; + dest[2][1] = mat[1][2]; + dest[2][2] = mat[2][2]; +} + +/*! + * @brief copy mat3 to mat4's upper-left + * + * @param[in] mat source + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_mat4_ins3(mat3 mat, mat4 dest) { + dest[0][0] = mat[0][0]; + dest[0][1] = mat[0][1]; + dest[0][2] = mat[0][2]; + + dest[1][0] = mat[1][0]; + dest[1][1] = mat[1][1]; + dest[1][2] = mat[1][2]; + + dest[2][0] = mat[2][0]; + dest[2][1] = mat[2][1]; + dest[2][2] = mat[2][2]; +} + +/*! + * @brief multiply m1 and m2 to dest + * + * m1, m2 and dest matrices can be same matrix, it is possible to write this: + * + * @code + * mat4 m = GLM_MAT4_IDENTITY_INIT; + * glm_mat4_mul(m, m, m); + * @endcode + * + * @param[in] m1 left matrix + * @param[in] m2 right matrix + * @param[out] dest destination matrix + */ +CGLM_INLINE +void +glm_mat4_mul(mat4 m1, mat4 m2, mat4 dest) { +#ifdef __AVX__ + glm_mat4_mul_avx(m1, m2, dest); +#elif defined( __SSE__ ) || defined( __SSE2__ ) + glm_mat4_mul_sse2(m1, m2, dest); +#elif defined(CGLM_NEON_FP) + glm_mat4_mul_neon(m1, m2, dest); +#else + float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3], + a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3], + a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], a23 = m1[2][3], + a30 = m1[3][0], a31 = m1[3][1], a32 = m1[3][2], a33 = m1[3][3], + + b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], b03 = m2[0][3], + b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], b13 = m2[1][3], + b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2], b23 = m2[2][3], + b30 = m2[3][0], b31 = m2[3][1], b32 = m2[3][2], b33 = m2[3][3]; + + dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03; + dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03; + dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03; + dest[0][3] = a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03; + dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13; + dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13; + dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13; + dest[1][3] = a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13; + dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23; + dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23; + dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23; + dest[2][3] = a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23; + dest[3][0] = a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33; + dest[3][1] = a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33; + dest[3][2] = a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33; + dest[3][3] = a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33; +#endif +} + +/*! + * @brief mupliply N mat4 matrices and store result in dest + * + * this function lets you multiply multiple (more than two or more...) matrices + *

multiplication will be done in loop, this may reduce instructions + * size but if len is too small then compiler may unroll whole loop, + * usage: + * @code + * mat m1, m2, m3, m4, res; + * + * glm_mat4_mulN((mat4 *[]){&m1, &m2, &m3, &m4}, 4, res); + * @endcode + * + * @warning matrices parameter is pointer array not mat4 array! + * + * @param[in] matrices mat4 * array + * @param[in] len matrices count + * @param[out] dest result + */ +CGLM_INLINE +void +glm_mat4_mulN(mat4 * __restrict matrices[], uint32_t len, mat4 dest) { + uint32_t i; + +#ifdef DEBUG + assert(len > 1 && "there must be least 2 matrices to go!"); +#endif + + glm_mat4_mul(*matrices[0], *matrices[1], dest); + + for (i = 2; i < len; i++) + glm_mat4_mul(dest, *matrices[i], dest); +} + +/*! + * @brief multiply mat4 with vec4 (column vector) and store in dest vector + * + * @param[in] m mat4 (left) + * @param[in] v vec4 (right, column vector) + * @param[out] dest vec4 (result, column vector) + */ +CGLM_INLINE +void +glm_mat4_mulv(mat4 m, vec4 v, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glm_mat4_mulv_sse2(m, v, dest); +#elif defined(CGLM_NEON_FP) + glm_mat4_mulv_neon(m, v, dest); +#else + vec4 res; + res[0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0] * v[3]; + res[1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1] * v[3]; + res[2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2] * v[3]; + res[3] = m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3] * v[3]; + glm_vec4_copy(res, dest); +#endif +} + +/*! + * @brief trace of matrix + * + * sum of the elements on the main diagonal from upper left to the lower right + * + * @param[in] m matrix + */ +CGLM_INLINE +float +glm_mat4_trace(mat4 m) { + return m[0][0] + m[1][1] + m[2][2] + m[3][3]; +} + +/*! + * @brief trace of matrix (rotation part) + * + * sum of the elements on the main diagonal from upper left to the lower right + * + * @param[in] m matrix + */ +CGLM_INLINE +float +glm_mat4_trace3(mat4 m) { + return m[0][0] + m[1][1] + m[2][2]; +} + +/*! + * @brief convert mat4's rotation part to quaternion + * + * @param[in] m affine matrix + * @param[out] dest destination quaternion + */ +CGLM_INLINE +void +glm_mat4_quat(mat4 m, versor dest) { + float trace, r, rinv; + + /* it seems using like m12 instead of m[1][2] causes extra instructions */ + + trace = m[0][0] + m[1][1] + m[2][2]; + if (trace >= 0.0f) { + r = sqrtf(1.0f + trace); + rinv = 0.5f / r; + + dest[0] = rinv * (m[1][2] - m[2][1]); + dest[1] = rinv * (m[2][0] - m[0][2]); + dest[2] = rinv * (m[0][1] - m[1][0]); + dest[3] = r * 0.5f; + } else if (m[0][0] >= m[1][1] && m[0][0] >= m[2][2]) { + r = sqrtf(1.0f - m[1][1] - m[2][2] + m[0][0]); + rinv = 0.5f / r; + + dest[0] = r * 0.5f; + dest[1] = rinv * (m[0][1] + m[1][0]); + dest[2] = rinv * (m[0][2] + m[2][0]); + dest[3] = rinv * (m[1][2] - m[2][1]); + } else if (m[1][1] >= m[2][2]) { + r = sqrtf(1.0f - m[0][0] - m[2][2] + m[1][1]); + rinv = 0.5f / r; + + dest[0] = rinv * (m[0][1] + m[1][0]); + dest[1] = r * 0.5f; + dest[2] = rinv * (m[1][2] + m[2][1]); + dest[3] = rinv * (m[2][0] - m[0][2]); + } else { + r = sqrtf(1.0f - m[0][0] - m[1][1] + m[2][2]); + rinv = 0.5f / r; + + dest[0] = rinv * (m[0][2] + m[2][0]); + dest[1] = rinv * (m[1][2] + m[2][1]); + dest[2] = r * 0.5f; + dest[3] = rinv * (m[0][1] - m[1][0]); + } +} + +/*! + * @brief multiply vector with mat4 + * + * actually the result is vec4, after multiplication the last component + * is trimmed. if you need it don't use this func. + * + * @param[in] m mat4(affine transform) + * @param[in] v vec3 + * @param[in] last 4th item to make it vec4 + * @param[out] dest result vector (vec3) + */ +CGLM_INLINE +void +glm_mat4_mulv3(mat4 m, vec3 v, float last, vec3 dest) { + vec4 res; + glm_vec4(v, last, res); + glm_mat4_mulv(m, res, res); + glm_vec3(res, dest); +} + +/*! + * @brief transpose mat4 and store in dest + * + * source matrix will not be transposed unless dest is m + * + * @param[in] m matrix + * @param[out] dest result + */ +CGLM_INLINE +void +glm_mat4_transpose_to(mat4 m, mat4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glm_mat4_transp_sse2(m, dest); +#elif defined(CGLM_NEON_FP) + glm_mat4_transp_neon(m, dest); +#else + dest[0][0] = m[0][0]; dest[1][0] = m[0][1]; + dest[0][1] = m[1][0]; dest[1][1] = m[1][1]; + dest[0][2] = m[2][0]; dest[1][2] = m[2][1]; + dest[0][3] = m[3][0]; dest[1][3] = m[3][1]; + dest[2][0] = m[0][2]; dest[3][0] = m[0][3]; + dest[2][1] = m[1][2]; dest[3][1] = m[1][3]; + dest[2][2] = m[2][2]; dest[3][2] = m[2][3]; + dest[2][3] = m[3][2]; dest[3][3] = m[3][3]; +#endif +} + +/*! + * @brief tranpose mat4 and store result in same matrix + * + * @param[in, out] m source and dest + */ +CGLM_INLINE +void +glm_mat4_transpose(mat4 m) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glm_mat4_transp_sse2(m, m); +#elif defined(CGLM_NEON_FP) + glm_mat4_transp_neon(m, m); +#else + mat4 d; + glm_mat4_transpose_to(m, d); + glm_mat4_ucopy(d, m); +#endif +} + +/*! + * @brief scale (multiply with scalar) matrix without simd optimization + * + * multiply matrix with scalar + * + * @param[in, out] m matrix + * @param[in] s scalar + */ +CGLM_INLINE +void +glm_mat4_scale_p(mat4 m, float s) { + m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; m[0][3] *= s; + m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; m[1][3] *= s; + m[2][0] *= s; m[2][1] *= s; m[2][2] *= s; m[2][3] *= s; + m[3][0] *= s; m[3][1] *= s; m[3][2] *= s; m[3][3] *= s; +} + +/*! + * @brief scale (multiply with scalar) matrix + * + * multiply matrix with scalar + * + * @param[in, out] m matrix + * @param[in] s scalar + */ +CGLM_INLINE +void +glm_mat4_scale(mat4 m, float s) { +#ifdef __AVX__ + glm_mat4_scale_avx(m, s); +#elif defined( __SSE__ ) || defined( __SSE2__ ) + glm_mat4_scale_sse2(m, s); +#elif defined(CGLM_NEON_FP) + glm_mat4_scale_neon(m, s); +#else + glm_mat4_scale_p(m, s); +#endif +} + +/*! + * @brief mat4 determinant + * + * @param[in] mat matrix + * + * @return determinant + */ +CGLM_INLINE +float +glm_mat4_det(mat4 mat) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + return glm_mat4_det_sse2(mat); +#elif defined(CGLM_NEON_FP) + return glm_mat4_det_neon(mat); +#else + /* [square] det(A) = det(At) */ + float t[6]; + float a = mat[0][0], b = mat[0][1], c = mat[0][2], d = mat[0][3], + e = mat[1][0], f = mat[1][1], g = mat[1][2], h = mat[1][3], + i = mat[2][0], j = mat[2][1], k = mat[2][2], l = mat[2][3], + m = mat[3][0], n = mat[3][1], o = mat[3][2], p = mat[3][3]; + + t[0] = k * p - o * l; + t[1] = j * p - n * l; + t[2] = j * o - n * k; + t[3] = i * p - m * l; + t[4] = i * o - m * k; + t[5] = i * n - m * j; + + return a * (f * t[0] - g * t[1] + h * t[2]) + - b * (e * t[0] - g * t[3] + h * t[4]) + + c * (e * t[1] - f * t[3] + h * t[5]) + - d * (e * t[2] - f * t[4] + g * t[5]); +#endif +} + +/*! + * @brief inverse mat4 and store in dest + * + * @param[in] mat matrix + * @param[out] dest inverse matrix + */ +CGLM_INLINE +void +glm_mat4_inv(mat4 mat, mat4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glm_mat4_inv_sse2(mat, dest); +#elif defined(CGLM_NEON_FP) + glm_mat4_inv_neon(mat, dest); +#else + float t[6]; + float det; + float a = mat[0][0], b = mat[0][1], c = mat[0][2], d = mat[0][3], + e = mat[1][0], f = mat[1][1], g = mat[1][2], h = mat[1][3], + i = mat[2][0], j = mat[2][1], k = mat[2][2], l = mat[2][3], + m = mat[3][0], n = mat[3][1], o = mat[3][2], p = mat[3][3]; + + t[0] = k * p - o * l; t[1] = j * p - n * l; t[2] = j * o - n * k; + t[3] = i * p - m * l; t[4] = i * o - m * k; t[5] = i * n - m * j; + + dest[0][0] = f * t[0] - g * t[1] + h * t[2]; + dest[1][0] =-(e * t[0] - g * t[3] + h * t[4]); + dest[2][0] = e * t[1] - f * t[3] + h * t[5]; + dest[3][0] =-(e * t[2] - f * t[4] + g * t[5]); + + dest[0][1] =-(b * t[0] - c * t[1] + d * t[2]); + dest[1][1] = a * t[0] - c * t[3] + d * t[4]; + dest[2][1] =-(a * t[1] - b * t[3] + d * t[5]); + dest[3][1] = a * t[2] - b * t[4] + c * t[5]; + + t[0] = g * p - o * h; t[1] = f * p - n * h; t[2] = f * o - n * g; + t[3] = e * p - m * h; t[4] = e * o - m * g; t[5] = e * n - m * f; + + dest[0][2] = b * t[0] - c * t[1] + d * t[2]; + dest[1][2] =-(a * t[0] - c * t[3] + d * t[4]); + dest[2][2] = a * t[1] - b * t[3] + d * t[5]; + dest[3][2] =-(a * t[2] - b * t[4] + c * t[5]); + + t[0] = g * l - k * h; t[1] = f * l - j * h; t[2] = f * k - j * g; + t[3] = e * l - i * h; t[4] = e * k - i * g; t[5] = e * j - i * f; + + dest[0][3] =-(b * t[0] - c * t[1] + d * t[2]); + dest[1][3] = a * t[0] - c * t[3] + d * t[4]; + dest[2][3] =-(a * t[1] - b * t[3] + d * t[5]); + dest[3][3] = a * t[2] - b * t[4] + c * t[5]; + + det = 1.0f / (a * dest[0][0] + b * dest[1][0] + + c * dest[2][0] + d * dest[3][0]); + + glm_mat4_scale_p(dest, det); +#endif +} + +/*! + * @brief inverse mat4 and store in dest + * + * this func uses reciprocal approximation without extra corrections + * e.g Newton-Raphson. this should work faster than normal, + * to get more precise use glm_mat4_inv version. + * + * NOTE: You will lose precision, glm_mat4_inv is more accurate + * + * @param[in] mat matrix + * @param[out] dest inverse matrix + */ +CGLM_INLINE +void +glm_mat4_inv_fast(mat4 mat, mat4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glm_mat4_inv_fast_sse2(mat, dest); +#else + glm_mat4_inv(mat, dest); +#endif +} + +/*! + * @brief swap two matrix columns + * + * @param[in,out] mat matrix + * @param[in] col1 col1 + * @param[in] col2 col2 + */ +CGLM_INLINE +void +glm_mat4_swap_col(mat4 mat, int col1, int col2) { + CGLM_ALIGN(16) vec4 tmp; + glm_vec4_copy(mat[col1], tmp); + glm_vec4_copy(mat[col2], mat[col1]); + glm_vec4_copy(tmp, mat[col2]); +} + +/*! + * @brief swap two matrix rows + * + * @param[in,out] mat matrix + * @param[in] row1 row1 + * @param[in] row2 row2 + */ +CGLM_INLINE +void +glm_mat4_swap_row(mat4 mat, int row1, int row2) { + CGLM_ALIGN(16) vec4 tmp; + tmp[0] = mat[0][row1]; + tmp[1] = mat[1][row1]; + tmp[2] = mat[2][row1]; + tmp[3] = mat[3][row1]; + + mat[0][row1] = mat[0][row2]; + mat[1][row1] = mat[1][row2]; + mat[2][row1] = mat[2][row2]; + mat[3][row1] = mat[3][row2]; + + mat[0][row2] = tmp[0]; + mat[1][row2] = tmp[1]; + mat[2][row2] = tmp[2]; + mat[3][row2] = tmp[3]; +} + +/*! + * @brief helper for R (row vector) * M (matrix) * C (column vector) + * + * rmc stands for Row * Matrix * Column + * + * the result is scalar because R * M = Matrix1x4 (row vector), + * then Matrix1x4 * Vec4 (column vector) = Matrix1x1 (Scalar) + * + * @param[in] r row vector or matrix1x4 + * @param[in] m matrix4x4 + * @param[in] c column vector or matrix4x1 + * + * @return scalar value e.g. B(s) + */ +CGLM_INLINE +float +glm_mat4_rmc(vec4 r, mat4 m, vec4 c) { + vec4 tmp; + glm_mat4_mulv(m, c, tmp); + return glm_vec4_dot(r, tmp); +} + +#endif /* cglm_mat_h */ diff --git a/include/cglm/plane.h b/include/cglm/plane.h new file mode 100644 index 0000000..0504373 --- /dev/null +++ b/include/cglm/plane.h @@ -0,0 +1,44 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_plane_h +#define cglm_plane_h + +#include "common.h" +#include "vec3.h" +#include "vec4.h" + +/* + Plane equation: Ax + By + Cz + D = 0; + + It stored in vec4 as [A, B, C, D]. (A, B, C) is normal and D is distance +*/ + +/* + Functions: + CGLM_INLINE void glm_plane_normalize(vec4 plane); + */ + +/*! + * @brief normalizes a plane + * + * @param[in, out] plane plane to normalize + */ +CGLM_INLINE +void +glm_plane_normalize(vec4 plane) { + float norm; + + if ((norm = glm_vec3_norm(plane)) == 0.0f) { + glm_vec4_zero(plane); + return; + } + + glm_vec4_scale(plane, 1.0f / norm, plane); +} + +#endif /* cglm_plane_h */ diff --git a/include/cglm/project.h b/include/cglm/project.h new file mode 100644 index 0000000..1d0a4e5 --- /dev/null +++ b/include/cglm/project.h @@ -0,0 +1,172 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_project_h +#define cglm_project_h + +#include "common.h" +#include "vec3.h" +#include "vec4.h" +#include "mat4.h" + +#ifndef CGLM_CLIPSPACE_INCLUDE_ALL +# if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT +# include "clipspace/project_zo.h" +# elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT +# include "clipspace/project_no.h" +# endif +#else +# include "clipspace/project_zo.h" +# include "clipspace/project_no.h" +#endif + +/*! + * @brief maps the specified viewport coordinates into specified space [1] + * the matrix should contain projection matrix. + * + * if you don't have ( and don't want to have ) an inverse matrix then use + * glm_unproject version. You may use existing inverse of matrix in somewhere + * else, this is why glm_unprojecti exists to save save inversion cost + * + * [1] space: + * 1- if m = invProj: View Space + * 2- if m = invViewProj: World Space + * 3- if m = invMVP: Object Space + * + * You probably want to map the coordinates into object space + * so use invMVP as m + * + * Computing viewProj: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * glm_mat4_inv(viewProj, invMVP); + * + * @param[in] pos point/position in viewport coordinates + * @param[in] invMat matrix (see brief) + * @param[in] vp viewport as [x, y, width, height] + * @param[out] dest unprojected coordinates + */ +CGLM_INLINE +void +glm_unprojecti(vec3 pos, mat4 invMat, vec4 vp, vec3 dest) { +#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT + glm_unprojecti_zo(pos, invMat, vp, dest); +#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT + glm_unprojecti_no(pos, invMat, vp, dest); +#endif +} + +/*! + * @brief maps the specified viewport coordinates into specified space [1] + * the matrix should contain projection matrix. + * + * this is same as glm_unprojecti except this function get inverse matrix for + * you. + * + * [1] space: + * 1- if m = proj: View Space + * 2- if m = viewProj: World Space + * 3- if m = MVP: Object Space + * + * You probably want to map the coordinates into object space + * so use MVP as m + * + * Computing viewProj and MVP: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * + * @param[in] pos point/position in viewport coordinates + * @param[in] m matrix (see brief) + * @param[in] vp viewport as [x, y, width, height] + * @param[out] dest unprojected coordinates + */ +CGLM_INLINE +void +glm_unproject(vec3 pos, mat4 m, vec4 vp, vec3 dest) { + mat4 inv; + glm_mat4_inv(m, inv); + glm_unprojecti(pos, inv, vp, dest); +} + +/*! + * @brief map object coordinates to window coordinates + * + * Computing MVP: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * + * @param[in] pos object coordinates + * @param[in] m MVP matrix + * @param[in] vp viewport as [x, y, width, height] + * @param[out] dest projected coordinates + */ +CGLM_INLINE +void +glm_project(vec3 pos, mat4 m, vec4 vp, vec3 dest) { +#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT + glm_project_zo(pos, m, vp, dest); +#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT + glm_project_no(pos, m, vp, dest); +#endif +} + +/*! + * @brief map object's z coordinate to window coordinates + * + * Computing MVP: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * + * @param[in] v object coordinates + * @param[in] m MVP matrix + * + * @returns projected z coordinate + */ +CGLM_INLINE +float +glm_project_z(vec3 v, mat4 m) { +#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT + return glm_project_z_zo(v, m); +#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT + return glm_project_z_no(v, m); +#endif +} + +/*! + * @brief define a picking region + * + * @param[in] center center [x, y] of a picking region in window coordinates + * @param[in] size size [width, height] of the picking region in window coordinates + * @param[in] vp viewport as [x, y, width, height] + * @param[out] dest projected coordinates + */ +CGLM_INLINE +void +glm_pickmatrix(vec2 center, vec2 size, vec4 vp, mat4 dest) { + mat4 res; + vec3 v; + + if (size[0] <= 0.0f || size[1] <= 0.0f) + return; + + /* Translate and scale the picked region to the entire window */ + v[0] = (vp[2] - 2.0f * (center[0] - vp[0])) / size[0]; + v[1] = (vp[3] - 2.0f * (center[1] - vp[1])) / size[1]; + v[2] = 0.0f; + + glm_translate_make(res, v); + + v[0] = vp[2] / size[0]; + v[1] = vp[3] / size[1]; + v[2] = 1.0f; + + glm_scale(res, v); + + glm_mat4_copy(res, dest); +} + +#endif /* cglm_project_h */ diff --git a/include/cglm/quat.h b/include/cglm/quat.h new file mode 100644 index 0000000..c76fa03 --- /dev/null +++ b/include/cglm/quat.h @@ -0,0 +1,867 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Macros: + GLM_QUAT_IDENTITY_INIT + GLM_QUAT_IDENTITY + + Functions: + CGLM_INLINE void glm_quat_identity(versor q); + CGLM_INLINE void glm_quat_init(versor q, float x, float y, float z, float w); + CGLM_INLINE void glm_quat(versor q, float angle, float x, float y, float z); + CGLM_INLINE void glm_quatv(versor q, float angle, vec3 axis); + CGLM_INLINE void glm_quat_copy(versor q, versor dest); + CGLM_INLINE void glm_quat_from_vecs(vec3 a, vec3 b, versor dest); + CGLM_INLINE float glm_quat_norm(versor q); + CGLM_INLINE void glm_quat_normalize(versor q); + CGLM_INLINE void glm_quat_normalize_to(versor q, versor dest); + CGLM_INLINE float glm_quat_dot(versor p, versor q); + CGLM_INLINE void glm_quat_conjugate(versor q, versor dest); + CGLM_INLINE void glm_quat_inv(versor q, versor dest); + CGLM_INLINE void glm_quat_add(versor p, versor q, versor dest); + CGLM_INLINE void glm_quat_sub(versor p, versor q, versor dest); + CGLM_INLINE float glm_quat_real(versor q); + CGLM_INLINE void glm_quat_imag(versor q, vec3 dest); + CGLM_INLINE void glm_quat_imagn(versor q, vec3 dest); + CGLM_INLINE float glm_quat_imaglen(versor q); + CGLM_INLINE float glm_quat_angle(versor q); + CGLM_INLINE void glm_quat_axis(versor q, vec3 dest); + CGLM_INLINE void glm_quat_mul(versor p, versor q, versor dest); + CGLM_INLINE void glm_quat_mat4(versor q, mat4 dest); + CGLM_INLINE void glm_quat_mat4t(versor q, mat4 dest); + CGLM_INLINE void glm_quat_mat3(versor q, mat3 dest); + CGLM_INLINE void glm_quat_mat3t(versor q, mat3 dest); + CGLM_INLINE void glm_quat_lerp(versor from, versor to, float t, versor dest); + CGLM_INLINE void glm_quat_lerpc(versor from, versor to, float t, versor dest); + CGLM_INLINE void glm_quat_slerp(versor q, versor r, float t, versor dest); + CGLM_INLINE void glm_quat_nlerp(versor q, versor r, float t, versor dest); + CGLM_INLINE void glm_quat_look(vec3 eye, versor ori, mat4 dest); + CGLM_INLINE void glm_quat_for(vec3 dir, vec3 fwd, vec3 up, versor dest); + CGLM_INLINE void glm_quat_forp(vec3 from, + vec3 to, + vec3 fwd, + vec3 up, + versor dest); + CGLM_INLINE void glm_quat_rotatev(versor q, vec3 v, vec3 dest); + CGLM_INLINE void glm_quat_rotate(mat4 m, versor q, mat4 dest); + */ + +#ifndef cglm_quat_h +#define cglm_quat_h + +#include "common.h" +#include "vec3.h" +#include "vec4.h" +#include "mat4.h" +#include "mat3.h" +#include "affine-mat.h" +#include "affine.h" + +#ifdef CGLM_SSE_FP +# include "simd/sse2/quat.h" +#endif + +#ifdef CGLM_NEON_FP +# include "simd/neon/quat.h" +#endif + +CGLM_INLINE void glm_quat_normalize(versor q); + +/* + * IMPORTANT: + * ---------------------------------------------------------------------------- + * cglm stores quat as [x, y, z, w] since v0.3.6 + * + * it was [w, x, y, z] before v0.3.6 it has been changed to [x, y, z, w] + * with v0.3.6 version. + * ---------------------------------------------------------------------------- + */ + +#define GLM_QUAT_IDENTITY_INIT {0.0f, 0.0f, 0.0f, 1.0f} +#define GLM_QUAT_IDENTITY ((versor)GLM_QUAT_IDENTITY_INIT) + +/*! + * @brief makes given quat to identity + * + * @param[in, out] q quaternion + */ +CGLM_INLINE +void +glm_quat_identity(versor q) { + CGLM_ALIGN(16) versor v = GLM_QUAT_IDENTITY_INIT; + glm_vec4_copy(v, q); +} + +/*! + * @brief make given quaternion array's each element identity quaternion + * + * @param[in, out] q quat array (must be aligned (16) + * if alignment is not disabled) + * + * @param[in] count count of quaternions + */ +CGLM_INLINE +void +glm_quat_identity_array(versor * __restrict q, size_t count) { + CGLM_ALIGN(16) versor v = GLM_QUAT_IDENTITY_INIT; + size_t i; + + for (i = 0; i < count; i++) { + glm_vec4_copy(v, q[i]); + } +} + +/*! + * @brief inits quaterion with raw values + * + * @param[out] q quaternion + * @param[in] x x + * @param[in] y y + * @param[in] z z + * @param[in] w w (real part) + */ +CGLM_INLINE +void +glm_quat_init(versor q, float x, float y, float z, float w) { + q[0] = x; + q[1] = y; + q[2] = z; + q[3] = w; +} + +/*! + * @brief creates NEW quaternion with axis vector + * + * @param[out] q quaternion + * @param[in] angle angle (radians) + * @param[in] axis axis + */ +CGLM_INLINE +void +glm_quatv(versor q, float angle, vec3 axis) { + CGLM_ALIGN(8) vec3 k; + float a, c, s; + + a = angle * 0.5f; + c = cosf(a); + s = sinf(a); + + glm_normalize_to(axis, k); + + q[0] = s * k[0]; + q[1] = s * k[1]; + q[2] = s * k[2]; + q[3] = c; +} + +/*! + * @brief creates NEW quaternion with individual axis components + * + * @param[out] q quaternion + * @param[in] angle angle (radians) + * @param[in] x axis.x + * @param[in] y axis.y + * @param[in] z axis.z + */ +CGLM_INLINE +void +glm_quat(versor q, float angle, float x, float y, float z) { + CGLM_ALIGN(8) vec3 axis = {x, y, z}; + glm_quatv(q, angle, axis); +} + +/*! + * @brief copy quaternion to another one + * + * @param[in] q quaternion + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_quat_copy(versor q, versor dest) { + glm_vec4_copy(q, dest); +} + +/*! + * @brief compute quaternion rotating vector A to vector B + * + * @param[in] a vec3 (must have unit length) + * @param[in] b vec3 (must have unit length) + * @param[out] dest quaternion (of unit length) + */ +CGLM_INLINE +void +glm_quat_from_vecs(vec3 a, vec3 b, versor dest) { + CGLM_ALIGN(8) vec3 axis; + float cos_theta; + float cos_half_theta; + + cos_theta = glm_vec3_dot(a, b); + if (cos_theta >= 1.f - GLM_FLT_EPSILON) { /* a ∥ b */ + glm_quat_identity(dest); + return; + } + if (cos_theta < -1.f + GLM_FLT_EPSILON) { /* angle(a, b) = π */ + glm_vec3_ortho(a, axis); + cos_half_theta = 0.f; /* cos π/2 */ + } else { + glm_vec3_cross(a, b, axis); + cos_half_theta = 1.0f + cos_theta; /* cos 0 + cos θ */ + } + + glm_quat_init(dest, axis[0], axis[1], axis[2], cos_half_theta); + glm_quat_normalize(dest); +} + +/*! + * @brief returns norm (magnitude) of quaternion + * + * @param[in] q quaternion + */ +CGLM_INLINE +float +glm_quat_norm(versor q) { + return glm_vec4_norm(q); +} + +/*! + * @brief normalize quaternion and store result in dest + * + * @param[in] q quaternion to normalze + * @param[out] dest destination quaternion + */ +CGLM_INLINE +void +glm_quat_normalize_to(versor q, versor dest) { +#if defined( __SSE2__ ) || defined( __SSE2__ ) + __m128 xdot, x0; + float dot; + + x0 = glmm_load(q); + xdot = glmm_vdot(x0, x0); + dot = _mm_cvtss_f32(xdot); + + if (dot <= 0.0f) { + glm_quat_identity(dest); + return; + } + + glmm_store(dest, _mm_div_ps(x0, _mm_sqrt_ps(xdot))); +#else + float dot; + + dot = glm_vec4_norm2(q); + + if (dot <= 0.0f) { + glm_quat_identity(dest); + return; + } + + glm_vec4_scale(q, 1.0f / sqrtf(dot), dest); +#endif +} + +/*! + * @brief normalize quaternion + * + * @param[in, out] q quaternion + */ +CGLM_INLINE +void +glm_quat_normalize(versor q) { + glm_quat_normalize_to(q, q); +} + +/*! + * @brief dot product of two quaternion + * + * @param[in] p quaternion 1 + * @param[in] q quaternion 2 + */ +CGLM_INLINE +float +glm_quat_dot(versor p, versor q) { + return glm_vec4_dot(p, q); +} + +/*! + * @brief conjugate of quaternion + * + * @param[in] q quaternion + * @param[out] dest conjugate + */ +CGLM_INLINE +void +glm_quat_conjugate(versor q, versor dest) { + glm_vec4_negate_to(q, dest); + dest[3] = -dest[3]; +} + +/*! + * @brief inverse of non-zero quaternion + * + * @param[in] q quaternion + * @param[out] dest inverse quaternion + */ +CGLM_INLINE +void +glm_quat_inv(versor q, versor dest) { + CGLM_ALIGN(16) versor conj; + glm_quat_conjugate(q, conj); + glm_vec4_scale(conj, 1.0f / glm_vec4_norm2(q), dest); +} + +/*! + * @brief add (componentwise) two quaternions and store result in dest + * + * @param[in] p quaternion 1 + * @param[in] q quaternion 2 + * @param[out] dest result quaternion + */ +CGLM_INLINE +void +glm_quat_add(versor p, versor q, versor dest) { + glm_vec4_add(p, q, dest); +} + +/*! + * @brief subtract (componentwise) two quaternions and store result in dest + * + * @param[in] p quaternion 1 + * @param[in] q quaternion 2 + * @param[out] dest result quaternion + */ +CGLM_INLINE +void +glm_quat_sub(versor p, versor q, versor dest) { + glm_vec4_sub(p, q, dest); +} + +/*! + * @brief returns real part of quaternion + * + * @param[in] q quaternion + */ +CGLM_INLINE +float +glm_quat_real(versor q) { + return q[3]; +} + +/*! + * @brief returns imaginary part of quaternion + * + * @param[in] q quaternion + * @param[out] dest imag + */ +CGLM_INLINE +void +glm_quat_imag(versor q, vec3 dest) { + dest[0] = q[0]; + dest[1] = q[1]; + dest[2] = q[2]; +} + +/*! + * @brief returns normalized imaginary part of quaternion + * + * @param[in] q quaternion + */ +CGLM_INLINE +void +glm_quat_imagn(versor q, vec3 dest) { + glm_normalize_to(q, dest); +} + +/*! + * @brief returns length of imaginary part of quaternion + * + * @param[in] q quaternion + */ +CGLM_INLINE +float +glm_quat_imaglen(versor q) { + return glm_vec3_norm(q); +} + +/*! + * @brief returns angle of quaternion + * + * @param[in] q quaternion + */ +CGLM_INLINE +float +glm_quat_angle(versor q) { + /* + sin(theta / 2) = length(x*x + y*y + z*z) + cos(theta / 2) = w + theta = 2 * atan(sin(theta / 2) / cos(theta / 2)) + */ + return 2.0f * atan2f(glm_quat_imaglen(q), glm_quat_real(q)); +} + +/*! + * @brief axis of quaternion + * + * @param[in] q quaternion + * @param[out] dest axis of quaternion + */ +CGLM_INLINE +void +glm_quat_axis(versor q, vec3 dest) { + glm_quat_imagn(q, dest); +} + +/*! + * @brief multiplies two quaternion and stores result in dest + * this is also called Hamilton Product + * + * According to WikiPedia: + * The product of two rotation quaternions [clarification needed] will be + * equivalent to the rotation q followed by the rotation p + * + * @param[in] p quaternion 1 + * @param[in] q quaternion 2 + * @param[out] dest result quaternion + */ +CGLM_INLINE +void +glm_quat_mul(versor p, versor q, versor dest) { + /* + + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i + + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j + + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k + a1 a2 − b1 b2 − c1 c2 − d1 d2 + */ +#if defined( __SSE__ ) || defined( __SSE2__ ) + glm_quat_mul_sse2(p, q, dest); +#elif defined(CGLM_NEON_FP) + glm_quat_mul_neon(p, q, dest); +#else + dest[0] = p[3] * q[0] + p[0] * q[3] + p[1] * q[2] - p[2] * q[1]; + dest[1] = p[3] * q[1] - p[0] * q[2] + p[1] * q[3] + p[2] * q[0]; + dest[2] = p[3] * q[2] + p[0] * q[1] - p[1] * q[0] + p[2] * q[3]; + dest[3] = p[3] * q[3] - p[0] * q[0] - p[1] * q[1] - p[2] * q[2]; +#endif +} + +/*! + * @brief convert quaternion to mat4 + * + * @param[in] q quaternion + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_quat_mat4(versor q, mat4 dest) { + float w, x, y, z, + xx, yy, zz, + xy, yz, xz, + wx, wy, wz, norm, s; + + norm = glm_quat_norm(q); + s = norm > 0.0f ? 2.0f / norm : 0.0f; + + x = q[0]; + y = q[1]; + z = q[2]; + w = q[3]; + + xx = s * x * x; xy = s * x * y; wx = s * w * x; + yy = s * y * y; yz = s * y * z; wy = s * w * y; + zz = s * z * z; xz = s * x * z; wz = s * w * z; + + dest[0][0] = 1.0f - yy - zz; + dest[1][1] = 1.0f - xx - zz; + dest[2][2] = 1.0f - xx - yy; + + dest[0][1] = xy + wz; + dest[1][2] = yz + wx; + dest[2][0] = xz + wy; + + dest[1][0] = xy - wz; + dest[2][1] = yz - wx; + dest[0][2] = xz - wy; + + dest[0][3] = 0.0f; + dest[1][3] = 0.0f; + dest[2][3] = 0.0f; + dest[3][0] = 0.0f; + dest[3][1] = 0.0f; + dest[3][2] = 0.0f; + dest[3][3] = 1.0f; +} + +/*! + * @brief convert quaternion to mat4 (transposed) + * + * @param[in] q quaternion + * @param[out] dest result matrix as transposed + */ +CGLM_INLINE +void +glm_quat_mat4t(versor q, mat4 dest) { + float w, x, y, z, + xx, yy, zz, + xy, yz, xz, + wx, wy, wz, norm, s; + + norm = glm_quat_norm(q); + s = norm > 0.0f ? 2.0f / norm : 0.0f; + + x = q[0]; + y = q[1]; + z = q[2]; + w = q[3]; + + xx = s * x * x; xy = s * x * y; wx = s * w * x; + yy = s * y * y; yz = s * y * z; wy = s * w * y; + zz = s * z * z; xz = s * x * z; wz = s * w * z; + + dest[0][0] = 1.0f - yy - zz; + dest[1][1] = 1.0f - xx - zz; + dest[2][2] = 1.0f - xx - yy; + + dest[1][0] = xy + wz; + dest[2][1] = yz + wx; + dest[0][2] = xz + wy; + + dest[0][1] = xy - wz; + dest[1][2] = yz - wx; + dest[2][0] = xz - wy; + + dest[0][3] = 0.0f; + dest[1][3] = 0.0f; + dest[2][3] = 0.0f; + dest[3][0] = 0.0f; + dest[3][1] = 0.0f; + dest[3][2] = 0.0f; + dest[3][3] = 1.0f; +} + +/*! + * @brief convert quaternion to mat3 + * + * @param[in] q quaternion + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_quat_mat3(versor q, mat3 dest) { + float w, x, y, z, + xx, yy, zz, + xy, yz, xz, + wx, wy, wz, norm, s; + + norm = glm_quat_norm(q); + s = norm > 0.0f ? 2.0f / norm : 0.0f; + + x = q[0]; + y = q[1]; + z = q[2]; + w = q[3]; + + xx = s * x * x; xy = s * x * y; wx = s * w * x; + yy = s * y * y; yz = s * y * z; wy = s * w * y; + zz = s * z * z; xz = s * x * z; wz = s * w * z; + + dest[0][0] = 1.0f - yy - zz; + dest[1][1] = 1.0f - xx - zz; + dest[2][2] = 1.0f - xx - yy; + + dest[0][1] = xy + wz; + dest[1][2] = yz + wx; + dest[2][0] = xz + wy; + + dest[1][0] = xy - wz; + dest[2][1] = yz - wx; + dest[0][2] = xz - wy; +} + +/*! + * @brief convert quaternion to mat3 (transposed) + * + * @param[in] q quaternion + * @param[out] dest result matrix + */ +CGLM_INLINE +void +glm_quat_mat3t(versor q, mat3 dest) { + float w, x, y, z, + xx, yy, zz, + xy, yz, xz, + wx, wy, wz, norm, s; + + norm = glm_quat_norm(q); + s = norm > 0.0f ? 2.0f / norm : 0.0f; + + x = q[0]; + y = q[1]; + z = q[2]; + w = q[3]; + + xx = s * x * x; xy = s * x * y; wx = s * w * x; + yy = s * y * y; yz = s * y * z; wy = s * w * y; + zz = s * z * z; xz = s * x * z; wz = s * w * z; + + dest[0][0] = 1.0f - yy - zz; + dest[1][1] = 1.0f - xx - zz; + dest[2][2] = 1.0f - xx - yy; + + dest[1][0] = xy + wz; + dest[2][1] = yz + wx; + dest[0][2] = xz + wy; + + dest[0][1] = xy - wz; + dest[1][2] = yz - wx; + dest[2][0] = xz - wy; +} + +/*! + * @brief interpolates between two quaternions + * using linear interpolation (LERP) + * + * @param[in] from from + * @param[in] to to + * @param[in] t interpolant (amount) + * @param[out] dest result quaternion + */ +CGLM_INLINE +void +glm_quat_lerp(versor from, versor to, float t, versor dest) { + glm_vec4_lerp(from, to, t, dest); +} + +/*! + * @brief interpolates between two quaternions + * using linear interpolation (LERP) + * + * @param[in] from from + * @param[in] to to + * @param[in] t interpolant (amount) clamped between 0 and 1 + * @param[out] dest result quaternion + */ +CGLM_INLINE +void +glm_quat_lerpc(versor from, versor to, float t, versor dest) { + glm_vec4_lerpc(from, to, t, dest); +} + +/*! + * @brief interpolates between two quaternions + * taking the shortest rotation path using + * normalized linear interpolation (NLERP) + * + * @param[in] from from + * @param[in] to to + * @param[in] t interpolant (amount) + * @param[out] dest result quaternion + */ +CGLM_INLINE +void +glm_quat_nlerp(versor from, versor to, float t, versor dest) { + versor target; + float dot; + + dot = glm_vec4_dot(from, to); + + glm_vec4_scale(to, (dot >= 0) ? 1.0f : -1.0f, target); + glm_quat_lerp(from, target, t, dest); + glm_quat_normalize(dest); +} + +/*! + * @brief interpolates between two quaternions + * using spherical linear interpolation (SLERP) + * + * @param[in] from from + * @param[in] to to + * @param[in] t amout + * @param[out] dest result quaternion + */ +CGLM_INLINE +void +glm_quat_slerp(versor from, versor to, float t, versor dest) { + CGLM_ALIGN(16) vec4 q1, q2; + float cosTheta, sinTheta, angle; + + cosTheta = glm_quat_dot(from, to); + glm_quat_copy(from, q1); + + if (fabsf(cosTheta) >= 1.0f) { + glm_quat_copy(q1, dest); + return; + } + + if (cosTheta < 0.0f) { + glm_vec4_negate(q1); + cosTheta = -cosTheta; + } + + sinTheta = sqrtf(1.0f - cosTheta * cosTheta); + + /* LERP to avoid zero division */ + if (fabsf(sinTheta) < 0.001f) { + glm_quat_lerp(from, to, t, dest); + return; + } + + /* SLERP */ + angle = acosf(cosTheta); + glm_vec4_scale(q1, sinf((1.0f - t) * angle), q1); + glm_vec4_scale(to, sinf(t * angle), q2); + + glm_vec4_add(q1, q2, q1); + glm_vec4_scale(q1, 1.0f / sinTheta, dest); +} + +/*! + * @brief creates view matrix using quaternion as camera orientation + * + * @param[in] eye eye + * @param[in] ori orientation in world space as quaternion + * @param[out] dest view matrix + */ +CGLM_INLINE +void +glm_quat_look(vec3 eye, versor ori, mat4 dest) { + /* orientation */ + glm_quat_mat4t(ori, dest); + + /* translate */ + glm_mat4_mulv3(dest, eye, 1.0f, dest[3]); + glm_vec3_negate(dest[3]); +} + +/*! + * @brief creates look rotation quaternion + * + * @param[in] dir direction to look + * @param[in] up up vector + * @param[out] dest destination quaternion + */ +CGLM_INLINE +void +glm_quat_for(vec3 dir, vec3 up, versor dest) { + CGLM_ALIGN_MAT mat3 m; + + glm_vec3_normalize_to(dir, m[2]); + + /* No need to negate in LH, but we use RH here */ + glm_vec3_negate(m[2]); + + glm_vec3_crossn(up, m[2], m[0]); + glm_vec3_cross(m[2], m[0], m[1]); + + glm_mat3_quat(m, dest); +} + +/*! + * @brief creates look rotation quaternion using source and + * destination positions p suffix stands for position + * + * @param[in] from source point + * @param[in] to destination point + * @param[in] up up vector + * @param[out] dest destination quaternion + */ +CGLM_INLINE +void +glm_quat_forp(vec3 from, vec3 to, vec3 up, versor dest) { + CGLM_ALIGN(8) vec3 dir; + glm_vec3_sub(to, from, dir); + glm_quat_for(dir, up, dest); +} + +/*! + * @brief rotate vector using using quaternion + * + * @param[in] q quaternion + * @param[in] v vector to rotate + * @param[out] dest rotated vector + */ +CGLM_INLINE +void +glm_quat_rotatev(versor q, vec3 v, vec3 dest) { + CGLM_ALIGN(16) versor p; + CGLM_ALIGN(8) vec3 u, v1, v2; + float s; + + glm_quat_normalize_to(q, p); + glm_quat_imag(p, u); + s = glm_quat_real(p); + + glm_vec3_scale(u, 2.0f * glm_vec3_dot(u, v), v1); + glm_vec3_scale(v, s * s - glm_vec3_dot(u, u), v2); + glm_vec3_add(v1, v2, v1); + + glm_vec3_cross(u, v, v2); + glm_vec3_scale(v2, 2.0f * s, v2); + + glm_vec3_add(v1, v2, dest); +} + +/*! + * @brief rotate existing transform matrix using quaternion + * + * @param[in] m existing transform matrix + * @param[in] q quaternion + * @param[out] dest rotated matrix/transform + */ +CGLM_INLINE +void +glm_quat_rotate(mat4 m, versor q, mat4 dest) { + CGLM_ALIGN_MAT mat4 rot; + glm_quat_mat4(q, rot); + glm_mul_rot(m, rot, dest); +} + +/*! + * @brief rotate existing transform matrix using quaternion at pivot point + * + * @param[in, out] m existing transform matrix + * @param[in] q quaternion + * @param[out] pivot pivot + */ +CGLM_INLINE +void +glm_quat_rotate_at(mat4 m, versor q, vec3 pivot) { + CGLM_ALIGN(8) vec3 pivotInv; + + glm_vec3_negate_to(pivot, pivotInv); + + glm_translate(m, pivot); + glm_quat_rotate(m, q, m); + glm_translate(m, pivotInv); +} + +/*! + * @brief rotate NEW transform matrix using quaternion at pivot point + * + * this creates rotation matrix, it assumes you don't have a matrix + * + * this should work faster than glm_quat_rotate_at because it reduces + * one glm_translate. + * + * @param[out] m existing transform matrix + * @param[in] q quaternion + * @param[in] pivot pivot + */ +CGLM_INLINE +void +glm_quat_rotate_atm(mat4 m, versor q, vec3 pivot) { + CGLM_ALIGN(8) vec3 pivotInv; + + glm_vec3_negate_to(pivot, pivotInv); + + glm_translate_make(m, pivot); + glm_quat_rotate(m, q, m); + glm_translate(m, pivotInv); +} + +#endif /* cglm_quat_h */ diff --git a/include/cglm/ray.h b/include/cglm/ray.h new file mode 100644 index 0000000..ced1ad6 --- /dev/null +++ b/include/cglm/ray.h @@ -0,0 +1,77 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE bool glm_line_triangle_intersect(vec3 origin, + vec3 direction, + vec3 v0, + vec3 v1, + vec3 v2, + float *d); +*/ + +#ifndef cglm_ray_h +#define cglm_ray_h + +#include "vec3.h" + +/*! + * @brief Möller–Trumbore ray-triangle intersection algorithm + * + * @param[in] origin origin of ray + * @param[in] direction direction of ray + * @param[in] v0 first vertex of triangle + * @param[in] v1 second vertex of triangle + * @param[in] v2 third vertex of triangle + * @param[in, out] d distance to intersection + * @return whether there is intersection + */ + +CGLM_INLINE +bool +glm_ray_triangle(vec3 origin, + vec3 direction, + vec3 v0, + vec3 v1, + vec3 v2, + float *d) { + vec3 edge1, edge2, p, t, q; + float det, inv_det, u, v, dist; + const float epsilon = 0.000001f; + + glm_vec3_sub(v1, v0, edge1); + glm_vec3_sub(v2, v0, edge2); + glm_vec3_cross(direction, edge2, p); + + det = glm_vec3_dot(edge1, p); + if (det > -epsilon && det < epsilon) + return false; + + inv_det = 1.0f / det; + + glm_vec3_sub(origin, v0, t); + + u = inv_det * glm_vec3_dot(t, p); + if (u < 0.0f || u > 1.0f) + return false; + + glm_vec3_cross(t, edge1, q); + + v = inv_det * glm_vec3_dot(direction, q); + if (v < 0.0f || u + v > 1.0f) + return false; + + dist = inv_det * glm_vec3_dot(edge2, q); + + if (d) + *d = dist; + + return dist > epsilon; +} + +#endif diff --git a/include/cglm/simd/arm.h b/include/cglm/simd/arm.h new file mode 100644 index 0000000..50cec46 --- /dev/null +++ b/include/cglm/simd/arm.h @@ -0,0 +1,173 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_simd_arm_h +#define cglm_simd_arm_h +#include "intrin.h" +#ifdef CGLM_SIMD_ARM + +#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || defined(__aarch64__) +# define CGLM_ARM64 1 +#endif + +#define glmm_load(p) vld1q_f32(p) +#define glmm_store(p, a) vst1q_f32(p, a) + +#define glmm_set1(x) vdupq_n_f32(x) +#define glmm_128 float32x4_t + +#define glmm_splat_x(x) vdupq_lane_f32(vget_low_f32(x), 0) +#define glmm_splat_y(x) vdupq_lane_f32(vget_low_f32(x), 1) +#define glmm_splat_z(x) vdupq_lane_f32(vget_high_f32(x), 0) +#define glmm_splat_w(x) vdupq_lane_f32(vget_high_f32(x), 1) + +#define glmm_xor(a, b) \ + vreinterpretq_f32_s32(veorq_s32(vreinterpretq_s32_f32(a), \ + vreinterpretq_s32_f32(b))) + +#define glmm_swplane(v) vextq_f32(v, v, 2) +#define glmm_low(x) vget_low_f32(x) +#define glmm_high(x) vget_high_f32(x) + +#define glmm_combine_ll(x, y) vcombine_f32(vget_low_f32(x), vget_low_f32(y)) +#define glmm_combine_hl(x, y) vcombine_f32(vget_high_f32(x), vget_low_f32(y)) +#define glmm_combine_lh(x, y) vcombine_f32(vget_low_f32(x), vget_high_f32(y)) +#define glmm_combine_hh(x, y) vcombine_f32(vget_high_f32(x), vget_high_f32(y)) + +static inline +float32x4_t +glmm_abs(float32x4_t v) { + return vabsq_f32(v); +} + +static inline +float32x4_t +glmm_vhadd(float32x4_t v) { + return vaddq_f32(vaddq_f32(glmm_splat_x(v), glmm_splat_y(v)), + vaddq_f32(glmm_splat_z(v), glmm_splat_w(v))); + /* + this seems slower: + v = vaddq_f32(v, vrev64q_f32(v)); + return vaddq_f32(v, vcombine_f32(vget_high_f32(v), vget_low_f32(v))); + */ +} + +static inline +float +glmm_hadd(float32x4_t v) { +#if CGLM_ARM64 + return vaddvq_f32(v); +#else + v = vaddq_f32(v, vrev64q_f32(v)); + v = vaddq_f32(v, vcombine_f32(vget_high_f32(v), vget_low_f32(v))); + return vgetq_lane_f32(v, 0); +#endif +} + +static inline +float +glmm_hmin(float32x4_t v) { + float32x2_t t; + t = vpmin_f32(vget_low_f32(v), vget_high_f32(v)); + t = vpmin_f32(t, t); + return vget_lane_f32(t, 0); +} + +static inline +float +glmm_hmax(float32x4_t v) { + float32x2_t t; + t = vpmax_f32(vget_low_f32(v), vget_high_f32(v)); + t = vpmax_f32(t, t); + return vget_lane_f32(t, 0); +} + +static inline +float +glmm_dot(float32x4_t a, float32x4_t b) { + return glmm_hadd(vmulq_f32(a, b)); +} + +static inline +float +glmm_norm(float32x4_t a) { + return sqrtf(glmm_dot(a, a)); +} + +static inline +float +glmm_norm2(float32x4_t a) { + return glmm_dot(a, a); +} + +static inline +float +glmm_norm_one(float32x4_t a) { + return glmm_hadd(glmm_abs(a)); +} + +static inline +float +glmm_norm_inf(float32x4_t a) { + return glmm_hmax(glmm_abs(a)); +} + +static inline +float32x4_t +glmm_div(float32x4_t a, float32x4_t b) { +#if CGLM_ARM64 + return vdivq_f32(a, b); +#else + /* 2 iterations of Newton-Raphson refinement of reciprocal */ + float32x4_t r0, r1; + r0 = vrecpeq_f32(b); + r1 = vrecpsq_f32(r0, b); + r0 = vmulq_f32(r1, r0); + r1 = vrecpsq_f32(r0, b); + r0 = vmulq_f32(r1, r0); + return vmulq_f32(a, r0); +#endif +} + +static inline +float32x4_t +glmm_fmadd(float32x4_t a, float32x4_t b, float32x4_t c) { +#if CGLM_ARM64 + return vfmaq_f32(c, a, b); /* why vfmaq_f32 is slower than vmlaq_f32 ??? */ +#else + return vmlaq_f32(c, a, b); +#endif +} + +static inline +float32x4_t +glmm_fnmadd(float32x4_t a, float32x4_t b, float32x4_t c) { +#if CGLM_ARM64 + return vfmsq_f32(c, a, b); +#else + return vmlsq_f32(c, a, b); +#endif +} + +static inline +float32x4_t +glmm_fmsub(float32x4_t a, float32x4_t b, float32x4_t c) { +#if CGLM_ARM64 + return vfmsq_f32(c, a, b); +#else + return vmlsq_f32(c, a, b); +#endif +} + +static inline +float32x4_t +glmm_fnmsub(float32x4_t a, float32x4_t b, float32x4_t c) { + return vsubq_f32(vdupq_n_f32(0.0f), glmm_fmadd(a, b, c)); +} + +#endif +#endif /* cglm_simd_arm_h */ diff --git a/include/cglm/simd/avx/affine.h b/include/cglm/simd/avx/affine.h new file mode 100644 index 0000000..b02ff0c --- /dev/null +++ b/include/cglm/simd/avx/affine.h @@ -0,0 +1,66 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_affine_mat_avx_h +#define cglm_affine_mat_avx_h +#ifdef __AVX__ + +#include "../../common.h" +#include "../intrin.h" + +#include + +CGLM_INLINE +void +glm_mul_avx(mat4 m1, mat4 m2, mat4 dest) { + /* D = R * L (Column-Major) */ + + __m256 y0, y1, y2, y3, y4, y5, y6, y7, y8, y9; + + y0 = glmm_load256(m2[0]); /* h g f e d c b a */ + y1 = glmm_load256(m2[2]); /* p o n m l k j i */ + + y2 = glmm_load256(m1[0]); /* h g f e d c b a */ + y3 = glmm_load256(m1[2]); /* p o n m l k j i */ + + /* 0x03: 0b00000011 */ + y4 = _mm256_permute2f128_ps(y2, y2, 0x03); /* d c b a h g f e */ + y5 = _mm256_permute2f128_ps(y3, y3, 0x03); /* l k j i p o n m */ + + /* f f f f a a a a */ + /* h h h h c c c c */ + /* e e e e b b b b */ + /* g g g g d d d d */ + y6 = _mm256_permutevar_ps(y0, _mm256_set_epi32(1, 1, 1, 1, 0, 0, 0, 0)); + y7 = _mm256_permutevar_ps(y0, _mm256_set_epi32(3, 3, 3, 3, 2, 2, 2, 2)); + y8 = _mm256_permutevar_ps(y0, _mm256_set_epi32(0, 0, 0, 0, 1, 1, 1, 1)); + y9 = _mm256_permutevar_ps(y0, _mm256_set_epi32(2, 2, 2, 2, 3, 3, 3, 3)); + + glmm_store256(dest[0], + _mm256_add_ps(_mm256_add_ps(_mm256_mul_ps(y2, y6), + _mm256_mul_ps(y3, y7)), + _mm256_add_ps(_mm256_mul_ps(y4, y8), + _mm256_mul_ps(y5, y9)))); + + /* n n n n i i i i */ + /* p p p p k k k k */ + /* m m m m j j j j */ + /* o o o o l l l l */ + y6 = _mm256_permutevar_ps(y1, _mm256_set_epi32(1, 1, 1, 1, 0, 0, 0, 0)); + y7 = _mm256_permutevar_ps(y1, _mm256_set_epi32(3, 3, 3, 3, 2, 2, 2, 2)); + y8 = _mm256_permutevar_ps(y1, _mm256_set_epi32(0, 0, 0, 0, 1, 1, 1, 1)); + y9 = _mm256_permutevar_ps(y1, _mm256_set_epi32(2, 2, 2, 2, 3, 3, 3, 3)); + + glmm_store256(dest[2], + _mm256_add_ps(_mm256_add_ps(_mm256_mul_ps(y2, y6), + _mm256_mul_ps(y3, y7)), + _mm256_add_ps(_mm256_mul_ps(y4, y8), + _mm256_mul_ps(y5, y9)))); +} + +#endif +#endif /* cglm_affine_mat_avx_h */ diff --git a/include/cglm/simd/avx/mat4.h b/include/cglm/simd/avx/mat4.h new file mode 100644 index 0000000..e8c36c8 --- /dev/null +++ b/include/cglm/simd/avx/mat4.h @@ -0,0 +1,76 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_mat_simd_avx_h +#define cglm_mat_simd_avx_h +#ifdef __AVX__ + +#include "../../common.h" +#include "../intrin.h" + +#include + +CGLM_INLINE +void +glm_mat4_scale_avx(mat4 m, float s) { + __m256 y0; + y0 = _mm256_set1_ps(s); + + glmm_store256(m[0], _mm256_mul_ps(y0, glmm_load256(m[0]))); + glmm_store256(m[2], _mm256_mul_ps(y0, glmm_load256(m[2]))); +} + +CGLM_INLINE +void +glm_mat4_mul_avx(mat4 m1, mat4 m2, mat4 dest) { + /* D = R * L (Column-Major) */ + + __m256 y0, y1, y2, y3, y4, y5, y6, y7, y8, y9; + + y0 = glmm_load256(m2[0]); /* h g f e d c b a */ + y1 = glmm_load256(m2[2]); /* p o n m l k j i */ + + y2 = glmm_load256(m1[0]); /* h g f e d c b a */ + y3 = glmm_load256(m1[2]); /* p o n m l k j i */ + + /* 0x03: 0b00000011 */ + y4 = _mm256_permute2f128_ps(y2, y2, 0x03); /* d c b a h g f e */ + y5 = _mm256_permute2f128_ps(y3, y3, 0x03); /* l k j i p o n m */ + + /* f f f f a a a a */ + /* h h h h c c c c */ + /* e e e e b b b b */ + /* g g g g d d d d */ + y6 = _mm256_permutevar_ps(y0, _mm256_set_epi32(1, 1, 1, 1, 0, 0, 0, 0)); + y7 = _mm256_permutevar_ps(y0, _mm256_set_epi32(3, 3, 3, 3, 2, 2, 2, 2)); + y8 = _mm256_permutevar_ps(y0, _mm256_set_epi32(0, 0, 0, 0, 1, 1, 1, 1)); + y9 = _mm256_permutevar_ps(y0, _mm256_set_epi32(2, 2, 2, 2, 3, 3, 3, 3)); + + glmm_store256(dest[0], + _mm256_add_ps(_mm256_add_ps(_mm256_mul_ps(y2, y6), + _mm256_mul_ps(y3, y7)), + _mm256_add_ps(_mm256_mul_ps(y4, y8), + _mm256_mul_ps(y5, y9)))); + + /* n n n n i i i i */ + /* p p p p k k k k */ + /* m m m m j j j j */ + /* o o o o l l l l */ + y6 = _mm256_permutevar_ps(y1, _mm256_set_epi32(1, 1, 1, 1, 0, 0, 0, 0)); + y7 = _mm256_permutevar_ps(y1, _mm256_set_epi32(3, 3, 3, 3, 2, 2, 2, 2)); + y8 = _mm256_permutevar_ps(y1, _mm256_set_epi32(0, 0, 0, 0, 1, 1, 1, 1)); + y9 = _mm256_permutevar_ps(y1, _mm256_set_epi32(2, 2, 2, 2, 3, 3, 3, 3)); + + glmm_store256(dest[2], + _mm256_add_ps(_mm256_add_ps(_mm256_mul_ps(y2, y6), + _mm256_mul_ps(y3, y7)), + _mm256_add_ps(_mm256_mul_ps(y4, y8), + _mm256_mul_ps(y5, y9)))); +} + +#endif +#endif /* cglm_mat_simd_avx_h */ diff --git a/include/cglm/simd/intrin.h b/include/cglm/simd/intrin.h new file mode 100644 index 0000000..a6ca5b0 --- /dev/null +++ b/include/cglm/simd/intrin.h @@ -0,0 +1,90 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_intrin_h +#define cglm_intrin_h + +#if defined( _MSC_VER ) +# if (defined(_M_AMD64) || defined(_M_X64)) || _M_IX86_FP == 2 +# ifndef __SSE2__ +# define __SSE2__ +# endif +# elif _M_IX86_FP == 1 +# ifndef __SSE__ +# define __SSE__ +# endif +# endif +/* do not use alignment for older visual studio versions */ +# if _MSC_VER < 1913 /* Visual Studio 2017 version 15.6 */ +# define CGLM_ALL_UNALIGNED +# endif +#endif + +#if defined( __SSE__ ) || defined( __SSE2__ ) +# include +# include +# define CGLM_SSE_FP 1 +# ifndef CGLM_SIMD_x86 +# define CGLM_SIMD_x86 +# endif +#endif + +#if defined(__SSE3__) +# include +# ifndef CGLM_SIMD_x86 +# define CGLM_SIMD_x86 +# endif +#endif + +#if defined(__SSE4_1__) +# include +# ifndef CGLM_SIMD_x86 +# define CGLM_SIMD_x86 +# endif +#endif + +#if defined(__SSE4_2__) +# include +# ifndef CGLM_SIMD_x86 +# define CGLM_SIMD_x86 +# endif +#endif + +#ifdef __AVX__ +# include +# define CGLM_AVX_FP 1 +# ifndef CGLM_SIMD_x86 +# define CGLM_SIMD_x86 +# endif +#endif + +/* ARM Neon */ +#if defined(__ARM_NEON) +# include +# if defined(__ARM_NEON_FP) +# define CGLM_NEON_FP 1 +# ifndef CGLM_SIMD_ARM +# define CGLM_SIMD_ARM +# endif +# endif +#endif + +#if defined(CGLM_SIMD_x86) || defined(CGLM_NEON_FP) +# ifndef CGLM_SIMD +# define CGLM_SIMD +# endif +#endif + +#if defined(CGLM_SIMD_x86) +# include "x86.h" +#endif + +#if defined(CGLM_SIMD_ARM) +# include "arm.h" +#endif + +#endif /* cglm_intrin_h */ diff --git a/include/cglm/simd/neon/affine.h b/include/cglm/simd/neon/affine.h new file mode 100644 index 0000000..da0a350 --- /dev/null +++ b/include/cglm/simd/neon/affine.h @@ -0,0 +1,121 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_affine_neon_h +#define cglm_affine_neon_h +#if defined(__ARM_NEON_FP) + +#include "../../common.h" +#include "../intrin.h" + +CGLM_INLINE +void +glm_mul_neon(mat4 m1, mat4 m2, mat4 dest) { + /* D = R * L (Column-Major) */ + + glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3; + + l = glmm_load(m1[0]); + r0 = glmm_load(m2[0]); + r1 = glmm_load(m2[1]); + r2 = glmm_load(m2[2]); + r3 = glmm_load(m2[3]); + + v0 = vmulq_f32(glmm_splat_x(r0), l); + v1 = vmulq_f32(glmm_splat_x(r1), l); + v2 = vmulq_f32(glmm_splat_x(r2), l); + v3 = vmulq_f32(glmm_splat_x(r3), l); + + l = glmm_load(m1[1]); + v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); + v3 = glmm_fmadd(glmm_splat_y(r3), l, v3); + + l = glmm_load(m1[2]); + v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); + v3 = glmm_fmadd(glmm_splat_z(r3), l, v3); + + v3 = glmm_fmadd(glmm_splat_w(r3), glmm_load(m1[3]), v3); + + glmm_store(dest[0], v0); + glmm_store(dest[1], v1); + glmm_store(dest[2], v2); + glmm_store(dest[3], v3); +} + +CGLM_INLINE +void +glm_mul_rot_neon(mat4 m1, mat4 m2, mat4 dest) { + /* D = R * L (Column-Major) */ + + glmm_128 l, r0, r1, r2, v0, v1, v2; + + l = glmm_load(m1[0]); + r0 = glmm_load(m2[0]); + r1 = glmm_load(m2[1]); + r2 = glmm_load(m2[2]); + + v0 = vmulq_f32(glmm_splat_x(r0), l); + v1 = vmulq_f32(glmm_splat_x(r1), l); + v2 = vmulq_f32(glmm_splat_x(r2), l); + + l = glmm_load(m1[1]); + v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); + + l = glmm_load(m1[2]); + v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); + + glmm_store(dest[0], v0); + glmm_store(dest[1], v1); + glmm_store(dest[2], v2); + glmm_store(dest[3], glmm_load(m1[3])); +} + +CGLM_INLINE +void +glm_inv_tr_neon(mat4 mat) { + float32x4x4_t vmat; + glmm_128 r0, r1, r2, x0; + + vmat = vld4q_f32(mat[0]); + r0 = vmat.val[0]; + r1 = vmat.val[1]; + r2 = vmat.val[2]; + + x0 = glmm_fmadd(r0, glmm_splat_w(r0), + glmm_fmadd(r1, glmm_splat_w(r1), + vmulq_f32(r2, glmm_splat_w(r2)))); + x0 = vnegq_f32(x0); + + glmm_store(mat[0], r0); + glmm_store(mat[1], r1); + glmm_store(mat[2], r2); + glmm_store(mat[3], x0); + + mat[0][3] = 0.0f; + mat[1][3] = 0.0f; + mat[2][3] = 0.0f; + mat[3][3] = 1.0f; + + /* TODO: ? + zo = vget_high_f32(r3); + vst1_lane_f32(&mat[0][3], zo, 0); + vst1_lane_f32(&mat[1][3], zo, 0); + vst1_lane_f32(&mat[2][3], zo, 0); + vst1_lane_f32(&mat[3][3], zo, 1); + */ +} + +#endif +#endif /* cglm_affine_neon_h */ diff --git a/include/cglm/simd/neon/mat2.h b/include/cglm/simd/neon/mat2.h new file mode 100644 index 0000000..471ebea --- /dev/null +++ b/include/cglm/simd/neon/mat2.h @@ -0,0 +1,44 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_mat2_neon_h +#define cglm_mat2_neon_h +#if defined(__ARM_NEON_FP) + +#include "../../common.h" +#include "../intrin.h" + +CGLM_INLINE +void +glm_mat2_mul_neon(mat2 m1, mat2 m2, mat2 dest) { + float32x4x2_t a1; + glmm_128 x0, x1, x2; + float32x2_t dc, ba; + + x1 = glmm_load(m1[0]); /* d c b a */ + x2 = glmm_load(m2[0]); /* h g f e */ + + dc = vget_high_f32(x1); + ba = vget_low_f32(x1); + + /* g g e e, h h f f */ + a1 = vtrnq_f32(x2, x2); + + /* + dest[0][0] = a * e + c * f; + dest[0][1] = b * e + d * f; + dest[1][0] = a * g + c * h; + dest[1][1] = b * g + d * h; + */ + x0 = glmm_fmadd(vcombine_f32(ba, ba), a1.val[0], + vmulq_f32(vcombine_f32(dc, dc), a1.val[1])); + + glmm_store(dest[0], x0); +} + +#endif +#endif /* cglm_mat2_neon_h */ diff --git a/include/cglm/simd/neon/mat4.h b/include/cglm/simd/neon/mat4.h new file mode 100644 index 0000000..5b9f014 --- /dev/null +++ b/include/cglm/simd/neon/mat4.h @@ -0,0 +1,317 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_mat4_neon_h +#define cglm_mat4_neon_h +#if defined(__ARM_NEON_FP) + +#include "../../common.h" +#include "../intrin.h" + +CGLM_INLINE +void +glm_mat4_scale_neon(mat4 m, float s) { + float32x4_t v0; + + v0 = vdupq_n_f32(s); + + vst1q_f32(m[0], vmulq_f32(vld1q_f32(m[0]), v0)); + vst1q_f32(m[1], vmulq_f32(vld1q_f32(m[1]), v0)); + vst1q_f32(m[2], vmulq_f32(vld1q_f32(m[2]), v0)); + vst1q_f32(m[3], vmulq_f32(vld1q_f32(m[3]), v0)); +} + +CGLM_INLINE +void +glm_mat4_transp_neon(mat4 m, mat4 dest) { + float32x4x4_t vmat; + + vmat = vld4q_f32(m[0]); + + vst1q_f32(dest[0], vmat.val[0]); + vst1q_f32(dest[1], vmat.val[1]); + vst1q_f32(dest[2], vmat.val[2]); + vst1q_f32(dest[3], vmat.val[3]); +} + +CGLM_INLINE +void +glm_mat4_mul_neon(mat4 m1, mat4 m2, mat4 dest) { + /* D = R * L (Column-Major) */ + + glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3; + + l = glmm_load(m1[0]); + r0 = glmm_load(m2[0]); + r1 = glmm_load(m2[1]); + r2 = glmm_load(m2[2]); + r3 = glmm_load(m2[3]); + + v0 = vmulq_f32(glmm_splat_x(r0), l); + v1 = vmulq_f32(glmm_splat_x(r1), l); + v2 = vmulq_f32(glmm_splat_x(r2), l); + v3 = vmulq_f32(glmm_splat_x(r3), l); + + l = glmm_load(m1[1]); + v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); + v3 = glmm_fmadd(glmm_splat_y(r3), l, v3); + + l = glmm_load(m1[2]); + v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); + v3 = glmm_fmadd(glmm_splat_z(r3), l, v3); + + l = glmm_load(m1[3]); + v0 = glmm_fmadd(glmm_splat_w(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_w(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_w(r2), l, v2); + v3 = glmm_fmadd(glmm_splat_w(r3), l, v3); + + glmm_store(dest[0], v0); + glmm_store(dest[1], v1); + glmm_store(dest[2], v2); + glmm_store(dest[3], v3); +} + +CGLM_INLINE +void +glm_mat4_mulv_neon(mat4 m, vec4 v, vec4 dest) { + float32x4_t l0, l1, l2, l3; + float32x2_t vlo, vhi; + + l0 = vld1q_f32(m[0]); + l1 = vld1q_f32(m[1]); + l2 = vld1q_f32(m[2]); + l3 = vld1q_f32(m[3]); + + vlo = vld1_f32(&v[0]); + vhi = vld1_f32(&v[2]); + + l0 = vmulq_lane_f32(l0, vlo, 0); + l0 = vmlaq_lane_f32(l0, l1, vlo, 1); + l0 = vmlaq_lane_f32(l0, l2, vhi, 0); + l0 = vmlaq_lane_f32(l0, l3, vhi, 1); + + vst1q_f32(dest, l0); +} + +CGLM_INLINE +float +glm_mat4_det_neon(mat4 mat) { + float32x4_t r0, r1, r2, r3, x0, x1, x2; + float32x2_t ij, op, mn, kl, nn, mm, jj, ii, gh, ef, t12, t34; + float32x4x2_t a1; + float32x4_t x3 = { 0.f, -0.f, 0.f, -0.f }; + + /* 127 <- 0, [square] det(A) = det(At) */ + r0 = glmm_load(mat[0]); /* d c b a */ + r1 = vrev64q_f32(glmm_load(mat[1])); /* g h e f */ + r2 = vrev64q_f32(glmm_load(mat[2])); /* l k i j */ + r3 = vrev64q_f32(glmm_load(mat[3])); /* o p m n */ + + gh = vget_high_f32(r1); + ef = vget_low_f32(r1); + kl = vget_high_f32(r2); + ij = vget_low_f32(r2); + op = vget_high_f32(r3); + mn = vget_low_f32(r3); + mm = vdup_lane_f32(mn, 1); + nn = vdup_lane_f32(mn, 0); + ii = vdup_lane_f32(ij, 1); + jj = vdup_lane_f32(ij, 0); + + /* + t[1] = j * p - n * l; + t[2] = j * o - n * k; + t[3] = i * p - m * l; + t[4] = i * o - m * k; + */ + x0 = glmm_fnmadd(vcombine_f32(kl, kl), vcombine_f32(nn, mm), + vmulq_f32(vcombine_f32(op, op), vcombine_f32(jj, ii))); + + t12 = vget_low_f32(x0); + t34 = vget_high_f32(x0); + + /* 1 3 1 3 2 4 2 4 */ + a1 = vuzpq_f32(x0, x0); + + /* + t[0] = k * p - o * l; + t[0] = k * p - o * l; + t[5] = i * n - m * j; + t[5] = i * n - m * j; + */ + x1 = glmm_fnmadd(vcombine_f32(vdup_lane_f32(kl, 0), jj), + vcombine_f32(vdup_lane_f32(op, 1), mm), + vmulq_f32(vcombine_f32(vdup_lane_f32(op, 0), nn), + vcombine_f32(vdup_lane_f32(kl, 1), ii))); + + /* + a * (f * t[0] - g * t[1] + h * t[2]) + - b * (e * t[0] - g * t[3] + h * t[4]) + + c * (e * t[1] - f * t[3] + h * t[5]) + - d * (e * t[2] - f * t[4] + g * t[5]) + */ + x2 = glmm_fnmadd(vcombine_f32(vdup_lane_f32(gh, 1), vdup_lane_f32(ef, 0)), + vcombine_f32(vget_low_f32(a1.val[0]), t34), + vmulq_f32(vcombine_f32(ef, vdup_lane_f32(ef, 1)), + vcombine_f32(vget_low_f32(x1), t12))); + + x2 = glmm_fmadd(vcombine_f32(vdup_lane_f32(gh, 0), gh), + vcombine_f32(vget_low_f32(a1.val[1]), vget_high_f32(x1)), x2); + + x2 = glmm_xor(x2, x3); + + return glmm_hadd(vmulq_f32(x2, r0)); +} + +CGLM_INLINE +void +glm_mat4_inv_neon(mat4 mat, mat4 dest) { + float32x4_t r0, r1, r2, r3, + v0, v1, v2, v3, + t0, t1, t2, t3, t4, t5, + x0, x1, x2, x3, x4, x5, x6, x7, x8; + float32x4x2_t a1; + float32x2_t lp, ko, hg, jn, im, fe, ae, bf, cg, dh; + float32x4_t x9 = { -0.f, 0.f, -0.f, 0.f }; + + x8 = vrev64q_f32(x9); + + /* 127 <- 0 */ + r0 = glmm_load(mat[0]); /* d c b a */ + r1 = glmm_load(mat[1]); /* h g f e */ + r2 = glmm_load(mat[2]); /* l k j i */ + r3 = glmm_load(mat[3]); /* p o n m */ + + /* l p k o, j n i m */ + a1 = vzipq_f32(r3, r2); + + jn = vget_high_f32(a1.val[0]); + im = vget_low_f32(a1.val[0]); + lp = vget_high_f32(a1.val[1]); + ko = vget_low_f32(a1.val[1]); + hg = vget_high_f32(r1); + + x1 = vcombine_f32(vdup_lane_f32(lp, 0), lp); /* l p p p */ + x2 = vcombine_f32(vdup_lane_f32(ko, 0), ko); /* k o o o */ + x0 = vcombine_f32(vdup_lane_f32(lp, 1), vdup_lane_f32(hg, 1)); /* h h l l */ + x3 = vcombine_f32(vdup_lane_f32(ko, 1), vdup_lane_f32(hg, 0)); /* g g k k */ + + /* t1[0] = k * p - o * l; + t1[0] = k * p - o * l; + t2[0] = g * p - o * h; + t3[0] = g * l - k * h; */ + t0 = glmm_fnmadd(x2, x0, vmulq_f32(x3, x1)); + + fe = vget_low_f32(r1); + x4 = vcombine_f32(vdup_lane_f32(jn, 0), jn); /* j n n n */ + x5 = vcombine_f32(vdup_lane_f32(jn, 1), vdup_lane_f32(fe, 1)); /* f f j j */ + + /* t1[1] = j * p - n * l; + t1[1] = j * p - n * l; + t2[1] = f * p - n * h; + t3[1] = f * l - j * h; */ + t1 = glmm_fnmadd(x4, x0, vmulq_f32(x5, x1)); + + /* t1[2] = j * o - n * k + t1[2] = j * o - n * k; + t2[2] = f * o - n * g; + t3[2] = f * k - j * g; */ + t2 = glmm_fnmadd(x4, x3, vmulq_f32(x5, x2)); + + x6 = vcombine_f32(vdup_lane_f32(im, 1), vdup_lane_f32(fe, 0)); /* e e i i */ + x7 = vcombine_f32(vdup_lane_f32(im, 0), im); /* i m m m */ + + /* t1[3] = i * p - m * l; + t1[3] = i * p - m * l; + t2[3] = e * p - m * h; + t3[3] = e * l - i * h; */ + t3 = glmm_fnmadd(x7, x0, vmulq_f32(x6, x1)); + + /* t1[4] = i * o - m * k; + t1[4] = i * o - m * k; + t2[4] = e * o - m * g; + t3[4] = e * k - i * g; */ + t4 = glmm_fnmadd(x7, x3, vmulq_f32(x6, x2)); + + /* t1[5] = i * n - m * j; + t1[5] = i * n - m * j; + t2[5] = e * n - m * f; + t3[5] = e * j - i * f; */ + t5 = glmm_fnmadd(x7, x5, vmulq_f32(x6, x4)); + + /* h d f b, g c e a */ + a1 = vtrnq_f32(r0, r1); + + x4 = vrev64q_f32(a1.val[0]); /* c g a e */ + x5 = vrev64q_f32(a1.val[1]); /* d h b f */ + + ae = vget_low_f32(x4); + cg = vget_high_f32(x4); + bf = vget_low_f32(x5); + dh = vget_high_f32(x5); + + x0 = vcombine_f32(ae, vdup_lane_f32(ae, 1)); /* a a a e */ + x1 = vcombine_f32(bf, vdup_lane_f32(bf, 1)); /* b b b f */ + x2 = vcombine_f32(cg, vdup_lane_f32(cg, 1)); /* c c c g */ + x3 = vcombine_f32(dh, vdup_lane_f32(dh, 1)); /* d d d h */ + + /* + dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2]; + dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]); + dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2]; + dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */ + v0 = glmm_xor(glmm_fmadd(x3, t2, glmm_fnmadd(x2, t1, vmulq_f32(x1, t0))), x8); + + /* + dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5]; + dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]); + dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5]; + dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/ + v2 = glmm_xor(glmm_fmadd(x3, t5, glmm_fnmadd(x1, t3, vmulq_f32(x0, t1))), x8); + + /* + dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]); + dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4]; + dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]); + dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */ + v1 = glmm_xor(glmm_fmadd(x3, t4, glmm_fnmadd(x2, t3, vmulq_f32(x0, t0))), x9); + + /* + dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]); + dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5]; + dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]); + dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */ + v3 = glmm_xor(glmm_fmadd(x2, t5, glmm_fnmadd(x1, t4, vmulq_f32(x0, t2))), x9); + + /* determinant */ + x0 = vcombine_f32(vget_low_f32(vzipq_f32(v0, v1).val[0]), + vget_low_f32(vzipq_f32(v2, v3).val[0])); + + /* + x0 = glmm_div(glmm_set1(1.0f), glmm_vhadd(vmulq_f32(x0, r0))); + + glmm_store(dest[0], vmulq_f32(v0, x0)); + glmm_store(dest[1], vmulq_f32(v1, x0)); + glmm_store(dest[2], vmulq_f32(v2, x0)); + glmm_store(dest[3], vmulq_f32(v3, x0)); + */ + + x0 = glmm_vhadd(vmulq_f32(x0, r0)); + + glmm_store(dest[0], glmm_div(v0, x0)); + glmm_store(dest[1], glmm_div(v1, x0)); + glmm_store(dest[2], glmm_div(v2, x0)); + glmm_store(dest[3], glmm_div(v3, x0)); +} + +#endif +#endif /* cglm_mat4_neon_h */ diff --git a/include/cglm/simd/neon/quat.h b/include/cglm/simd/neon/quat.h new file mode 100644 index 0000000..f6b9e99 --- /dev/null +++ b/include/cglm/simd/neon/quat.h @@ -0,0 +1,56 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_quat_neon_h +#define cglm_quat_neon_h +#if defined(__ARM_NEON_FP) + +#include "../../common.h" +#include "../intrin.h" + +CGLM_INLINE +void +glm_quat_mul_neon(versor p, versor q, versor dest) { + /* + + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i + + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j + + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k + a1 a2 − b1 b2 − c1 c2 − d1 d2 + */ + + glmm_128 xp, xq, xqr, r, x, y, z, s2, s3; + glmm_128 s1 = {-0.f, 0.f, 0.f, -0.f}; + float32x2_t qh, ql; + + xp = glmm_load(p); /* 3 2 1 0 */ + xq = glmm_load(q); + + r = vmulq_f32(glmm_splat_w(xp), xq); + x = glmm_splat_x(xp); + y = glmm_splat_y(xp); + z = glmm_splat_z(xp); + + ql = vget_high_f32(s1); + s3 = vcombine_f32(ql, ql); + s2 = vzipq_f32(s3, s3).val[0]; + + xqr = vrev64q_f32(xq); + qh = vget_high_f32(xqr); + ql = vget_low_f32(xqr); + + r = glmm_fmadd(glmm_xor(x, s3), vcombine_f32(qh, ql), r); + + r = glmm_fmadd(glmm_xor(y, s2), vcombine_f32(vget_high_f32(xq), + vget_low_f32(xq)), r); + + r = glmm_fmadd(glmm_xor(z, s1), vcombine_f32(ql, qh), r); + + glmm_store(dest, r); +} + +#endif +#endif /* cglm_quat_neon_h */ diff --git a/include/cglm/simd/sse2/affine.h b/include/cglm/simd/sse2/affine.h new file mode 100644 index 0000000..99edaa0 --- /dev/null +++ b/include/cglm/simd/sse2/affine.h @@ -0,0 +1,115 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_affine_mat_sse2_h +#define cglm_affine_mat_sse2_h +#if defined( __SSE__ ) || defined( __SSE2__ ) + +#include "../../common.h" +#include "../intrin.h" + +CGLM_INLINE +void +glm_mul_sse2(mat4 m1, mat4 m2, mat4 dest) { + /* D = R * L (Column-Major) */ + glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3; + + l = glmm_load(m1[0]); + r0 = glmm_load(m2[0]); + r1 = glmm_load(m2[1]); + r2 = glmm_load(m2[2]); + r3 = glmm_load(m2[3]); + + v0 = _mm_mul_ps(glmm_splat_x(r0), l); + v1 = _mm_mul_ps(glmm_splat_x(r1), l); + v2 = _mm_mul_ps(glmm_splat_x(r2), l); + v3 = _mm_mul_ps(glmm_splat_x(r3), l); + + l = glmm_load(m1[1]); + v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); + v3 = glmm_fmadd(glmm_splat_y(r3), l, v3); + + l = glmm_load(m1[2]); + v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); + v3 = glmm_fmadd(glmm_splat_z(r3), l, v3); + + l = glmm_load(m1[3]); + v3 = glmm_fmadd(glmm_splat_w(r3), l, v3); + + glmm_store(dest[0], v0); + glmm_store(dest[1], v1); + glmm_store(dest[2], v2); + glmm_store(dest[3], v3); +} + +CGLM_INLINE +void +glm_mul_rot_sse2(mat4 m1, mat4 m2, mat4 dest) { + /* D = R * L (Column-Major) */ + + glmm_128 l, r0, r1, r2, v0, v1, v2; + + l = glmm_load(m1[0]); + r0 = glmm_load(m2[0]); + r1 = glmm_load(m2[1]); + r2 = glmm_load(m2[2]); + + v0 = _mm_mul_ps(glmm_splat_x(r0), l); + v1 = _mm_mul_ps(glmm_splat_x(r1), l); + v2 = _mm_mul_ps(glmm_splat_x(r2), l); + + l = glmm_load(m1[1]); + v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); + + l = glmm_load(m1[2]); + v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); + + glmm_store(dest[0], v0); + glmm_store(dest[1], v1); + glmm_store(dest[2], v2); + glmm_store(dest[3], glmm_load(m1[3])); +} + +CGLM_INLINE +void +glm_inv_tr_sse2(mat4 mat) { + __m128 r0, r1, r2, r3, x0, x1, x2, x3, x4, x5; + + r0 = glmm_load(mat[0]); + r1 = glmm_load(mat[1]); + r2 = glmm_load(mat[2]); + r3 = glmm_load(mat[3]); + x1 = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f); + + _MM_TRANSPOSE4_PS(r0, r1, r2, x1); + + x2 = glmm_shuff1(r3, 0, 0, 0, 0); + x3 = glmm_shuff1(r3, 1, 1, 1, 1); + x4 = glmm_shuff1(r3, 2, 2, 2, 2); + x5 = _mm_set1_ps(-0.f); + + x0 = glmm_fmadd(r0, x2, glmm_fmadd(r1, x3, _mm_mul_ps(r2, x4))); + x0 = _mm_xor_ps(x0, x5); + + x0 = _mm_add_ps(x0, x1); + + glmm_store(mat[0], r0); + glmm_store(mat[1], r1); + glmm_store(mat[2], r2); + glmm_store(mat[3], x0); +} + +#endif +#endif /* cglm_affine_mat_sse2_h */ diff --git a/include/cglm/simd/sse2/mat2.h b/include/cglm/simd/sse2/mat2.h new file mode 100644 index 0000000..31b3a29 --- /dev/null +++ b/include/cglm/simd/sse2/mat2.h @@ -0,0 +1,48 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_mat2_sse_h +#define cglm_mat2_sse_h +#if defined( __SSE__ ) || defined( __SSE2__ ) + +#include "../../common.h" +#include "../intrin.h" + +CGLM_INLINE +void +glm_mat2_mul_sse2(mat2 m1, mat2 m2, mat2 dest) { + __m128 x0, x1, x2, x3, x4; + + x1 = glmm_load(m1[0]); /* d c b a */ + x2 = glmm_load(m2[0]); /* h g f e */ + + x3 = glmm_shuff1(x2, 2, 2, 0, 0); + x4 = glmm_shuff1(x2, 3, 3, 1, 1); + x0 = _mm_movelh_ps(x1, x1); + x2 = _mm_movehl_ps(x1, x1); + + /* + dest[0][0] = a * e + c * f; + dest[0][1] = b * e + d * f; + dest[1][0] = a * g + c * h; + dest[1][1] = b * g + d * h; + */ + x0 = glmm_fmadd(x0, x3, _mm_mul_ps(x2, x4)); + + glmm_store(dest[0], x0); +} + +CGLM_INLINE +void +glm_mat2_transp_sse2(mat2 m, mat2 dest) { + /* d c b a */ + /* d b c a */ + glmm_store(dest[0], glmm_shuff1(glmm_load(m[0]), 3, 1, 2, 0)); +} + +#endif +#endif /* cglm_mat2_sse_h */ diff --git a/include/cglm/simd/sse2/mat3.h b/include/cglm/simd/sse2/mat3.h new file mode 100644 index 0000000..f07320c --- /dev/null +++ b/include/cglm/simd/sse2/mat3.h @@ -0,0 +1,76 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_mat3_sse_h +#define cglm_mat3_sse_h +#if defined( __SSE__ ) || defined( __SSE2__ ) + +#include "../../common.h" +#include "../intrin.h" + +CGLM_INLINE +void +glm_mat3_mul_sse2(mat3 m1, mat3 m2, mat3 dest) { + __m128 l0, l1, l2, r0, r1, r2, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; + + l0 = _mm_loadu_ps(m1[0]); + l1 = _mm_loadu_ps(&m1[1][1]); + + r0 = _mm_loadu_ps(m2[0]); + r1 = _mm_loadu_ps(&m2[1][1]); + + x8 = glmm_shuff1(l0, 0, 2, 1, 0); /* a00 a02 a01 a00 */ + x1 = glmm_shuff1(r0, 3, 0, 0, 0); /* b10 b00 b00 b00 */ + x2 = _mm_shuffle_ps(l0, l1, _MM_SHUFFLE(1, 0, 3, 3)); /* a12 a11 a10 a10 */ + x3 = _mm_shuffle_ps(r0, r1, _MM_SHUFFLE(2, 0, 3, 1)); /* b20 b11 b10 b01 */ + x0 = _mm_mul_ps(x8, x1); + + x6 = glmm_shuff1(l0, 1, 0, 2, 1); /* a01 a00 a02 a01 */ + x7 = glmm_shuff1(x3, 3, 3, 1, 1); /* b20 b20 b10 b10 */ + l2 = _mm_load_ss(&m1[2][2]); + r2 = _mm_load_ss(&m2[2][2]); + x1 = _mm_mul_ps(x6, x7); + l2 = glmm_shuff1(l2, 0, 0, 1, 0); /* a22 a22 0.f a22 */ + r2 = glmm_shuff1(r2, 0, 0, 1, 0); /* b22 b22 0.f b22 */ + + x4 = glmm_shuff1(x2, 0, 3, 2, 0); /* a10 a12 a11 a10 */ + x5 = glmm_shuff1(x2, 2, 0, 3, 2); /* a11 a10 a12 a11 */ + x6 = glmm_shuff1(x3, 2, 0, 0, 0); /* b11 b01 b01 b01 */ + x2 = glmm_shuff1(r1, 3, 3, 0, 0); /* b21 b21 b11 b11 */ + + x8 = _mm_unpackhi_ps(x8, x4); /* a10 a00 a12 a02 */ + x9 = _mm_unpackhi_ps(x7, x2); /* b21 b20 b21 b20 */ + + x0 = glmm_fmadd(x4, x6, x0); + x1 = glmm_fmadd(x5, x2, x1); + + x2 = _mm_movehl_ps(l2, l1); /* a22 a22 a21 a20 */ + x3 = glmm_shuff1(x2, 0, 2, 1, 0); /* a20 a22 a21 a20 */ + x2 = glmm_shuff1(x2, 1, 0, 2, 1); /* a21 a20 a22 a21 */ + x4 = _mm_shuffle_ps(r0, r1, _MM_SHUFFLE(1, 1, 2, 2)); /* b12 b12 b02 b02 */ + + x5 = glmm_shuff1(x4, 3, 0, 0, 0); /* b12 b02 b02 b02 */ + x4 = _mm_movehl_ps(r2, x4); /* b22 b22 b12 b12 */ + x0 = glmm_fmadd(x3, x5, x0); + x1 = glmm_fmadd(x2, x4, x1); + + /* + Dot Product : dest[2][2] = a02 * b20 + + a12 * b21 + + a22 * b22 + + 0 * 00 */ + x2 = _mm_movelh_ps(x8, l2); /* 0.f a22 a12 a02 */ + x3 = _mm_movelh_ps(x9, r2); /* 0.f b22 b21 b20 */ + x2 = glmm_vdots(x2, x3); + + _mm_storeu_ps(&dest[0][0], x0); + _mm_storeu_ps(&dest[1][1], x1); + _mm_store_ss (&dest[2][2], x2); +} + +#endif +#endif /* cglm_mat3_sse_h */ diff --git a/include/cglm/simd/sse2/mat4.h b/include/cglm/simd/sse2/mat4.h new file mode 100644 index 0000000..5c78499 --- /dev/null +++ b/include/cglm/simd/sse2/mat4.h @@ -0,0 +1,434 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_mat_sse_h +#define cglm_mat_sse_h +#if defined( __SSE__ ) || defined( __SSE2__ ) + +#include "../../common.h" +#include "../intrin.h" + +#define glm_mat4_inv_precise_sse2(mat, dest) glm_mat4_inv_sse2(mat, dest) + +CGLM_INLINE +void +glm_mat4_scale_sse2(mat4 m, float s) { + __m128 x0; + x0 = _mm_set1_ps(s); + + glmm_store(m[0], _mm_mul_ps(glmm_load(m[0]), x0)); + glmm_store(m[1], _mm_mul_ps(glmm_load(m[1]), x0)); + glmm_store(m[2], _mm_mul_ps(glmm_load(m[2]), x0)); + glmm_store(m[3], _mm_mul_ps(glmm_load(m[3]), x0)); +} + +CGLM_INLINE +void +glm_mat4_transp_sse2(mat4 m, mat4 dest) { + __m128 r0, r1, r2, r3; + + r0 = glmm_load(m[0]); + r1 = glmm_load(m[1]); + r2 = glmm_load(m[2]); + r3 = glmm_load(m[3]); + + _MM_TRANSPOSE4_PS(r0, r1, r2, r3); + + glmm_store(dest[0], r0); + glmm_store(dest[1], r1); + glmm_store(dest[2], r2); + glmm_store(dest[3], r3); +} + +CGLM_INLINE +void +glm_mat4_mul_sse2(mat4 m1, mat4 m2, mat4 dest) { + /* D = R * L (Column-Major) */ + + glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3; + + l = glmm_load(m1[0]); + r0 = glmm_load(m2[0]); + r1 = glmm_load(m2[1]); + r2 = glmm_load(m2[2]); + r3 = glmm_load(m2[3]); + + v0 = _mm_mul_ps(glmm_splat_x(r0), l); + v1 = _mm_mul_ps(glmm_splat_x(r1), l); + v2 = _mm_mul_ps(glmm_splat_x(r2), l); + v3 = _mm_mul_ps(glmm_splat_x(r3), l); + + l = glmm_load(m1[1]); + v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); + v3 = glmm_fmadd(glmm_splat_y(r3), l, v3); + + l = glmm_load(m1[2]); + v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); + v3 = glmm_fmadd(glmm_splat_z(r3), l, v3); + + l = glmm_load(m1[3]); + v0 = glmm_fmadd(glmm_splat_w(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_w(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_w(r2), l, v2); + v3 = glmm_fmadd(glmm_splat_w(r3), l, v3); + + glmm_store(dest[0], v0); + glmm_store(dest[1], v1); + glmm_store(dest[2], v2); + glmm_store(dest[3], v3); +} + +CGLM_INLINE +void +glm_mat4_mulv_sse2(mat4 m, vec4 v, vec4 dest) { + __m128 x0, x1, m0, m1, m2, m3, v0, v1, v2, v3; + + m0 = glmm_load(m[0]); + m1 = glmm_load(m[1]); + m2 = glmm_load(m[2]); + m3 = glmm_load(m[3]); + + x0 = glmm_load(v); + v0 = glmm_splat_x(x0); + v1 = glmm_splat_y(x0); + v2 = glmm_splat_z(x0); + v3 = glmm_splat_w(x0); + + x1 = _mm_mul_ps(m3, v3); + x1 = glmm_fmadd(m2, v2, x1); + x1 = glmm_fmadd(m1, v1, x1); + x1 = glmm_fmadd(m0, v0, x1); + + glmm_store(dest, x1); +} + +CGLM_INLINE +float +glm_mat4_det_sse2(mat4 mat) { + __m128 r0, r1, r2, r3, x0, x1, x2; + + /* 127 <- 0, [square] det(A) = det(At) */ + r0 = glmm_load(mat[0]); /* d c b a */ + r1 = glmm_load(mat[1]); /* h g f e */ + r2 = glmm_load(mat[2]); /* l k j i */ + r3 = glmm_load(mat[3]); /* p o n m */ + + /* + t[1] = j * p - n * l; + t[2] = j * o - n * k; + t[3] = i * p - m * l; + t[4] = i * o - m * k; + */ + x0 = glmm_fnmadd(glmm_shuff1(r3, 0, 0, 1, 1), glmm_shuff1(r2, 2, 3, 2, 3), + _mm_mul_ps(glmm_shuff1(r2, 0, 0, 1, 1), + glmm_shuff1(r3, 2, 3, 2, 3))); + /* + t[0] = k * p - o * l; + t[0] = k * p - o * l; + t[5] = i * n - m * j; + t[5] = i * n - m * j; + */ + x1 = glmm_fnmadd(glmm_shuff1(r3, 0, 0, 2, 2), glmm_shuff1(r2, 1, 1, 3, 3), + _mm_mul_ps(glmm_shuff1(r2, 0, 0, 2, 2), + glmm_shuff1(r3, 1, 1, 3, 3))); + + /* + a * (f * t[0] - g * t[1] + h * t[2]) + - b * (e * t[0] - g * t[3] + h * t[4]) + + c * (e * t[1] - f * t[3] + h * t[5]) + - d * (e * t[2] - f * t[4] + g * t[5]) + */ + x2 = glmm_fnmadd(glmm_shuff1(r1, 1, 1, 2, 2), glmm_shuff1(x0, 3, 2, 2, 0), + _mm_mul_ps(glmm_shuff1(r1, 0, 0, 0, 1), + _mm_shuffle_ps(x1, x0, _MM_SHUFFLE(1, 0, 0, 0)))); + x2 = glmm_fmadd(glmm_shuff1(r1, 2, 3, 3, 3), + _mm_shuffle_ps(x0, x1, _MM_SHUFFLE(2, 2, 3, 1)), + x2); + + x2 = _mm_xor_ps(x2, _mm_set_ps(-0.f, 0.f, -0.f, 0.f)); + + return glmm_hadd(_mm_mul_ps(x2, r0)); +} + +CGLM_INLINE +void +glm_mat4_inv_fast_sse2(mat4 mat, mat4 dest) { + __m128 r0, r1, r2, r3, + v0, v1, v2, v3, + t0, t1, t2, t3, t4, t5, + x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; + + x8 = _mm_set_ps(-0.f, 0.f, -0.f, 0.f); + x9 = glmm_shuff1(x8, 2, 1, 2, 1); + + /* 127 <- 0 */ + r0 = glmm_load(mat[0]); /* d c b a */ + r1 = glmm_load(mat[1]); /* h g f e */ + r2 = glmm_load(mat[2]); /* l k j i */ + r3 = glmm_load(mat[3]); /* p o n m */ + + x0 = _mm_movehl_ps(r3, r2); /* p o l k */ + x3 = _mm_movelh_ps(r2, r3); /* n m j i */ + x1 = glmm_shuff1(x0, 1, 3, 3 ,3); /* l p p p */ + x2 = glmm_shuff1(x0, 0, 2, 2, 2); /* k o o o */ + x4 = glmm_shuff1(x3, 1, 3, 3, 3); /* j n n n */ + x7 = glmm_shuff1(x3, 0, 2, 2, 2); /* i m m m */ + + x6 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(0, 0, 0, 0)); /* e e i i */ + x5 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(1, 1, 1, 1)); /* f f j j */ + x3 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(2, 2, 2, 2)); /* g g k k */ + x0 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(3, 3, 3, 3)); /* h h l l */ + + t0 = _mm_mul_ps(x3, x1); + t1 = _mm_mul_ps(x5, x1); + t2 = _mm_mul_ps(x5, x2); + t3 = _mm_mul_ps(x6, x1); + t4 = _mm_mul_ps(x6, x2); + t5 = _mm_mul_ps(x6, x4); + + /* t1[0] = k * p - o * l; + t1[0] = k * p - o * l; + t2[0] = g * p - o * h; + t3[0] = g * l - k * h; */ + t0 = glmm_fnmadd(x2, x0, t0); + + /* t1[1] = j * p - n * l; + t1[1] = j * p - n * l; + t2[1] = f * p - n * h; + t3[1] = f * l - j * h; */ + t1 = glmm_fnmadd(x4, x0, t1); + + /* t1[2] = j * o - n * k + t1[2] = j * o - n * k; + t2[2] = f * o - n * g; + t3[2] = f * k - j * g; */ + t2 = glmm_fnmadd(x4, x3, t2); + + /* t1[3] = i * p - m * l; + t1[3] = i * p - m * l; + t2[3] = e * p - m * h; + t3[3] = e * l - i * h; */ + t3 = glmm_fnmadd(x7, x0, t3); + + /* t1[4] = i * o - m * k; + t1[4] = i * o - m * k; + t2[4] = e * o - m * g; + t3[4] = e * k - i * g; */ + t4 = glmm_fnmadd(x7, x3, t4); + + /* t1[5] = i * n - m * j; + t1[5] = i * n - m * j; + t2[5] = e * n - m * f; + t3[5] = e * j - i * f; */ + t5 = glmm_fnmadd(x7, x5, t5); + + x4 = _mm_movelh_ps(r0, r1); /* f e b a */ + x5 = _mm_movehl_ps(r1, r0); /* h g d c */ + + x0 = glmm_shuff1(x4, 0, 0, 0, 2); /* a a a e */ + x1 = glmm_shuff1(x4, 1, 1, 1, 3); /* b b b f */ + x2 = glmm_shuff1(x5, 0, 0, 0, 2); /* c c c g */ + x3 = glmm_shuff1(x5, 1, 1, 1, 3); /* d d d h */ + + v2 = _mm_mul_ps(x0, t1); + v1 = _mm_mul_ps(x0, t0); + v3 = _mm_mul_ps(x0, t2); + v0 = _mm_mul_ps(x1, t0); + + v2 = glmm_fnmadd(x1, t3, v2); + v3 = glmm_fnmadd(x1, t4, v3); + v0 = glmm_fnmadd(x2, t1, v0); + v1 = glmm_fnmadd(x2, t3, v1); + + v3 = glmm_fmadd(x2, t5, v3); + v0 = glmm_fmadd(x3, t2, v0); + v2 = glmm_fmadd(x3, t5, v2); + v1 = glmm_fmadd(x3, t4, v1); + + /* + dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2]; + dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]); + dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2]; + dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */ + v0 = _mm_xor_ps(v0, x8); + + /* + dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5]; + dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]); + dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5]; + dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/ + v2 = _mm_xor_ps(v2, x8); + + /* + dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]); + dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4]; + dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]); + dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */ + v1 = _mm_xor_ps(v1, x9); + + /* + dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]); + dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5]; + dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]); + dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */ + v3 = _mm_xor_ps(v3, x9); + + /* determinant */ + x0 = _mm_shuffle_ps(v0, v1, _MM_SHUFFLE(0, 0, 0, 0)); + x1 = _mm_shuffle_ps(v2, v3, _MM_SHUFFLE(0, 0, 0, 0)); + x0 = _mm_shuffle_ps(x0, x1, _MM_SHUFFLE(2, 0, 2, 0)); + + x0 = _mm_rcp_ps(glmm_vhadd(_mm_mul_ps(x0, r0))); + + glmm_store(dest[0], _mm_mul_ps(v0, x0)); + glmm_store(dest[1], _mm_mul_ps(v1, x0)); + glmm_store(dest[2], _mm_mul_ps(v2, x0)); + glmm_store(dest[3], _mm_mul_ps(v3, x0)); +} + +CGLM_INLINE +void +glm_mat4_inv_sse2(mat4 mat, mat4 dest) { + __m128 r0, r1, r2, r3, + v0, v1, v2, v3, + t0, t1, t2, t3, t4, t5, + x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; + + x8 = _mm_set_ps(-0.f, 0.f, -0.f, 0.f); + x9 = glmm_shuff1(x8, 2, 1, 2, 1); + + /* 127 <- 0 */ + r0 = glmm_load(mat[0]); /* d c b a */ + r1 = glmm_load(mat[1]); /* h g f e */ + r2 = glmm_load(mat[2]); /* l k j i */ + r3 = glmm_load(mat[3]); /* p o n m */ + + x0 = _mm_movehl_ps(r3, r2); /* p o l k */ + x3 = _mm_movelh_ps(r2, r3); /* n m j i */ + x1 = glmm_shuff1(x0, 1, 3, 3 ,3); /* l p p p */ + x2 = glmm_shuff1(x0, 0, 2, 2, 2); /* k o o o */ + x4 = glmm_shuff1(x3, 1, 3, 3, 3); /* j n n n */ + x7 = glmm_shuff1(x3, 0, 2, 2, 2); /* i m m m */ + + x6 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(0, 0, 0, 0)); /* e e i i */ + x5 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(1, 1, 1, 1)); /* f f j j */ + x3 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(2, 2, 2, 2)); /* g g k k */ + x0 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(3, 3, 3, 3)); /* h h l l */ + + t0 = _mm_mul_ps(x3, x1); + t1 = _mm_mul_ps(x5, x1); + t2 = _mm_mul_ps(x5, x2); + t3 = _mm_mul_ps(x6, x1); + t4 = _mm_mul_ps(x6, x2); + t5 = _mm_mul_ps(x6, x4); + + /* t1[0] = k * p - o * l; + t1[0] = k * p - o * l; + t2[0] = g * p - o * h; + t3[0] = g * l - k * h; */ + t0 = glmm_fnmadd(x2, x0, t0); + + /* t1[1] = j * p - n * l; + t1[1] = j * p - n * l; + t2[1] = f * p - n * h; + t3[1] = f * l - j * h; */ + t1 = glmm_fnmadd(x4, x0, t1); + + /* t1[2] = j * o - n * k + t1[2] = j * o - n * k; + t2[2] = f * o - n * g; + t3[2] = f * k - j * g; */ + t2 = glmm_fnmadd(x4, x3, t2); + + /* t1[3] = i * p - m * l; + t1[3] = i * p - m * l; + t2[3] = e * p - m * h; + t3[3] = e * l - i * h; */ + t3 = glmm_fnmadd(x7, x0, t3); + + /* t1[4] = i * o - m * k; + t1[4] = i * o - m * k; + t2[4] = e * o - m * g; + t3[4] = e * k - i * g; */ + t4 = glmm_fnmadd(x7, x3, t4); + + /* t1[5] = i * n - m * j; + t1[5] = i * n - m * j; + t2[5] = e * n - m * f; + t3[5] = e * j - i * f; */ + t5 = glmm_fnmadd(x7, x5, t5); + + x4 = _mm_movelh_ps(r0, r1); /* f e b a */ + x5 = _mm_movehl_ps(r1, r0); /* h g d c */ + + x0 = glmm_shuff1(x4, 0, 0, 0, 2); /* a a a e */ + x1 = glmm_shuff1(x4, 1, 1, 1, 3); /* b b b f */ + x2 = glmm_shuff1(x5, 0, 0, 0, 2); /* c c c g */ + x3 = glmm_shuff1(x5, 1, 1, 1, 3); /* d d d h */ + + v2 = _mm_mul_ps(x0, t1); + v1 = _mm_mul_ps(x0, t0); + v3 = _mm_mul_ps(x0, t2); + v0 = _mm_mul_ps(x1, t0); + + v2 = glmm_fnmadd(x1, t3, v2); + v3 = glmm_fnmadd(x1, t4, v3); + v0 = glmm_fnmadd(x2, t1, v0); + v1 = glmm_fnmadd(x2, t3, v1); + + v3 = glmm_fmadd(x2, t5, v3); + v0 = glmm_fmadd(x3, t2, v0); + v2 = glmm_fmadd(x3, t5, v2); + v1 = glmm_fmadd(x3, t4, v1); + + /* + dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2]; + dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]); + dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2]; + dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */ + v0 = _mm_xor_ps(v0, x8); + + /* + dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5]; + dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]); + dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5]; + dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/ + v2 = _mm_xor_ps(v2, x8); + + /* + dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]); + dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4]; + dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]); + dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */ + v1 = _mm_xor_ps(v1, x9); + + /* + dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]); + dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5]; + dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]); + dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */ + v3 = _mm_xor_ps(v3, x9); + + /* determinant */ + x0 = _mm_shuffle_ps(v0, v1, _MM_SHUFFLE(0, 0, 0, 0)); + x1 = _mm_shuffle_ps(v2, v3, _MM_SHUFFLE(0, 0, 0, 0)); + x0 = _mm_shuffle_ps(x0, x1, _MM_SHUFFLE(2, 0, 2, 0)); + + x0 = _mm_div_ps(_mm_set1_ps(1.0f), glmm_vhadd(_mm_mul_ps(x0, r0))); + + glmm_store(dest[0], _mm_mul_ps(v0, x0)); + glmm_store(dest[1], _mm_mul_ps(v1, x0)); + glmm_store(dest[2], _mm_mul_ps(v2, x0)); + glmm_store(dest[3], _mm_mul_ps(v3, x0)); +} + +#endif +#endif /* cglm_mat_sse_h */ diff --git a/include/cglm/simd/sse2/quat.h b/include/cglm/simd/sse2/quat.h new file mode 100644 index 0000000..94850cc --- /dev/null +++ b/include/cglm/simd/sse2/quat.h @@ -0,0 +1,54 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_quat_simd_h +#define cglm_quat_simd_h +#if defined( __SSE__ ) || defined( __SSE2__ ) + +#include "../../common.h" +#include "../intrin.h" + +CGLM_INLINE +void +glm_quat_mul_sse2(versor p, versor q, versor dest) { + /* + + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i + + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j + + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k + a1 a2 − b1 b2 − c1 c2 − d1 d2 + */ + + __m128 xp, xq, x1, x2, x3, r, x, y, z; + + xp = glmm_load(p); /* 3 2 1 0 */ + xq = glmm_load(q); + x1 = _mm_set_ps(-0.f, 0.f, -0.f, 0.f); /* TODO: _mm_set1_ss() + shuff ? */ + r = _mm_mul_ps(glmm_splat_w(xp), xq); + + x2 = _mm_unpackhi_ps(x1, x1); + x3 = glmm_shuff1(x1, 3, 2, 0, 1); + x = glmm_splat_x(xp); + y = glmm_splat_y(xp); + z = glmm_splat_z(xp); + + x = _mm_xor_ps(x, x1); + y = _mm_xor_ps(y, x2); + z = _mm_xor_ps(z, x3); + + x1 = glmm_shuff1(xq, 0, 1, 2, 3); + x2 = glmm_shuff1(xq, 1, 0, 3, 2); + x3 = glmm_shuff1(xq, 2, 3, 0, 1); + + r = glmm_fmadd(x, x1, r); + r = glmm_fmadd(y, x2, r); + r = glmm_fmadd(z, x3, r); + + glmm_store(dest, r); +} + +#endif +#endif /* cglm_quat_simd_h */ diff --git a/include/cglm/simd/x86.h b/include/cglm/simd/x86.h new file mode 100644 index 0000000..dbbd0f8 --- /dev/null +++ b/include/cglm/simd/x86.h @@ -0,0 +1,307 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_simd_x86_h +#define cglm_simd_x86_h +#include "intrin.h" +#ifdef CGLM_SIMD_x86 + +#ifdef CGLM_ALL_UNALIGNED +# define glmm_load(p) _mm_loadu_ps(p) +# define glmm_store(p, a) _mm_storeu_ps(p, a) +#else +# define glmm_load(p) _mm_load_ps(p) +# define glmm_store(p, a) _mm_store_ps(p, a) +#endif + +#define glmm_set1(x) _mm_set1_ps(x) +#define glmm_128 __m128 + +#ifdef CGLM_USE_INT_DOMAIN +# define glmm_shuff1(xmm, z, y, x, w) \ + _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(xmm), \ + _MM_SHUFFLE(z, y, x, w))) +#else +# define glmm_shuff1(xmm, z, y, x, w) \ + _mm_shuffle_ps(xmm, xmm, _MM_SHUFFLE(z, y, x, w)) +#endif + +#define glmm_splat(x, lane) glmm_shuff1(x, lane, lane, lane, lane) + +#define glmm_splat_x(x) glmm_splat(x, 0) +#define glmm_splat_y(x) glmm_splat(x, 1) +#define glmm_splat_z(x) glmm_splat(x, 2) +#define glmm_splat_w(x) glmm_splat(x, 3) + +/* glmm_shuff1x() is DEPRECATED!, use glmm_splat() */ +#define glmm_shuff1x(xmm, x) glmm_shuff1(xmm, x, x, x, x) + +#define glmm_shuff2(a, b, z0, y0, x0, w0, z1, y1, x1, w1) \ + glmm_shuff1(_mm_shuffle_ps(a, b, _MM_SHUFFLE(z0, y0, x0, w0)), \ + z1, y1, x1, w1) + +#ifdef __AVX__ +# ifdef CGLM_ALL_UNALIGNED +# define glmm_load256(p) _mm256_loadu_ps(p) +# define glmm_store256(p, a) _mm256_storeu_ps(p, a) +# else +# define glmm_load256(p) _mm256_load_ps(p) +# define glmm_store256(p, a) _mm256_store_ps(p, a) +# endif +#endif + +static inline +__m128 +glmm_abs(__m128 x) { + return _mm_andnot_ps(_mm_set1_ps(-0.0f), x); +} + +static inline +__m128 +glmm_vhadd(__m128 v) { + __m128 x0; + x0 = _mm_add_ps(v, glmm_shuff1(v, 0, 1, 2, 3)); + x0 = _mm_add_ps(x0, glmm_shuff1(x0, 1, 0, 0, 1)); + return x0; +} + +static inline +__m128 +glmm_vhadds(__m128 v) { +#if defined(__SSE3__) + __m128 shuf, sums; + shuf = _mm_movehdup_ps(v); + sums = _mm_add_ps(v, shuf); + shuf = _mm_movehl_ps(shuf, sums); + sums = _mm_add_ss(sums, shuf); + return sums; +#else + __m128 shuf, sums; + shuf = glmm_shuff1(v, 2, 3, 0, 1); + sums = _mm_add_ps(v, shuf); + shuf = _mm_movehl_ps(shuf, sums); + sums = _mm_add_ss(sums, shuf); + return sums; +#endif +} + +static inline +float +glmm_hadd(__m128 v) { + return _mm_cvtss_f32(glmm_vhadds(v)); +} + +static inline +__m128 +glmm_vhmin(__m128 v) { + __m128 x0, x1, x2; + x0 = _mm_movehl_ps(v, v); /* [2, 3, 2, 3] */ + x1 = _mm_min_ps(x0, v); /* [0|2, 1|3, 2|2, 3|3] */ + x2 = glmm_splat(x1, 1); /* [1|3, 1|3, 1|3, 1|3] */ + return _mm_min_ss(x1, x2); +} + +static inline +float +glmm_hmin(__m128 v) { + return _mm_cvtss_f32(glmm_vhmin(v)); +} + +static inline +__m128 +glmm_vhmax(__m128 v) { + __m128 x0, x1, x2; + x0 = _mm_movehl_ps(v, v); /* [2, 3, 2, 3] */ + x1 = _mm_max_ps(x0, v); /* [0|2, 1|3, 2|2, 3|3] */ + x2 = glmm_splat(x1, 1); /* [1|3, 1|3, 1|3, 1|3] */ + return _mm_max_ss(x1, x2); +} + +static inline +float +glmm_hmax(__m128 v) { + return _mm_cvtss_f32(glmm_vhmax(v)); +} + +static inline +__m128 +glmm_vdots(__m128 a, __m128 b) { +#if (defined(__SSE4_1__) || defined(__SSE4_2__)) && defined(CGLM_SSE4_DOT) + return _mm_dp_ps(a, b, 0xFF); +#elif defined(__SSE3__) && defined(CGLM_SSE3_DOT) + __m128 x0, x1; + x0 = _mm_mul_ps(a, b); + x1 = _mm_hadd_ps(x0, x0); + return _mm_hadd_ps(x1, x1); +#else + return glmm_vhadds(_mm_mul_ps(a, b)); +#endif +} + +static inline +__m128 +glmm_vdot(__m128 a, __m128 b) { +#if (defined(__SSE4_1__) || defined(__SSE4_2__)) && defined(CGLM_SSE4_DOT) + return _mm_dp_ps(a, b, 0xFF); +#elif defined(__SSE3__) && defined(CGLM_SSE3_DOT) + __m128 x0, x1; + x0 = _mm_mul_ps(a, b); + x1 = _mm_hadd_ps(x0, x0); + return _mm_hadd_ps(x1, x1); +#else + __m128 x0; + x0 = _mm_mul_ps(a, b); + x0 = _mm_add_ps(x0, glmm_shuff1(x0, 1, 0, 3, 2)); + return _mm_add_ps(x0, glmm_shuff1(x0, 0, 1, 0, 1)); +#endif +} + +static inline +float +glmm_dot(__m128 a, __m128 b) { + return _mm_cvtss_f32(glmm_vdots(a, b)); +} + +static inline +float +glmm_norm(__m128 a) { + return _mm_cvtss_f32(_mm_sqrt_ss(glmm_vhadds(_mm_mul_ps(a, a)))); +} + +static inline +float +glmm_norm2(__m128 a) { + return _mm_cvtss_f32(glmm_vhadds(_mm_mul_ps(a, a))); +} + +static inline +float +glmm_norm_one(__m128 a) { + return _mm_cvtss_f32(glmm_vhadds(glmm_abs(a))); +} + +static inline +float +glmm_norm_inf(__m128 a) { + return _mm_cvtss_f32(glmm_vhmax(glmm_abs(a))); +} + +static inline +__m128 +glmm_load3(float v[3]) { + __m128i xy; + __m128 z; + + xy = _mm_loadl_epi64(CGLM_CASTPTR_ASSUME_ALIGNED(v, const __m128i)); + z = _mm_load_ss(&v[2]); + + return _mm_movelh_ps(_mm_castsi128_ps(xy), z); +} + +static inline +void +glmm_store3(float v[3], __m128 vx) { + _mm_storel_pi(CGLM_CASTPTR_ASSUME_ALIGNED(v, __m64), vx); + _mm_store_ss(&v[2], glmm_shuff1(vx, 2, 2, 2, 2)); +} + +static inline +__m128 +glmm_div(__m128 a, __m128 b) { + return _mm_div_ps(a, b); +} + +/* enable FMA macro for MSVC? */ +#if defined(_MSC_VER) && !defined(__FMA__) && defined(__AVX2__) +# define __FMA__ 1 +#endif + +static inline +__m128 +glmm_fmadd(__m128 a, __m128 b, __m128 c) { +#ifdef __FMA__ + return _mm_fmadd_ps(a, b, c); +#else + return _mm_add_ps(c, _mm_mul_ps(a, b)); +#endif +} + +static inline +__m128 +glmm_fnmadd(__m128 a, __m128 b, __m128 c) { +#ifdef __FMA__ + return _mm_fnmadd_ps(a, b, c); +#else + return _mm_sub_ps(c, _mm_mul_ps(a, b)); +#endif +} + +static inline +__m128 +glmm_fmsub(__m128 a, __m128 b, __m128 c) { +#ifdef __FMA__ + return _mm_fmsub_ps(a, b, c); +#else + return _mm_sub_ps(_mm_mul_ps(a, b), c); +#endif +} + +static inline +__m128 +glmm_fnmsub(__m128 a, __m128 b, __m128 c) { +#ifdef __FMA__ + return _mm_fnmsub_ps(a, b, c); +#else + return _mm_xor_ps(_mm_add_ps(_mm_mul_ps(a, b), c), _mm_set1_ps(-0.0f)); +#endif +} + +#if defined(__AVX__) +static inline +__m256 +glmm256_fmadd(__m256 a, __m256 b, __m256 c) { +#ifdef __FMA__ + return _mm256_fmadd_ps(a, b, c); +#else + return _mm256_add_ps(c, _mm256_mul_ps(a, b)); +#endif +} + +static inline +__m256 +glmm256_fnmadd(__m256 a, __m256 b, __m256 c) { +#ifdef __FMA__ + return _mm256_fnmadd_ps(a, b, c); +#else + return _mm256_sub_ps(c, _mm256_mul_ps(a, b)); +#endif +} + +static inline +__m256 +glmm256_fmsub(__m256 a, __m256 b, __m256 c) { +#ifdef __FMA__ + return _mm256_fmsub_ps(a, b, c); +#else + return _mm256_sub_ps(_mm256_mul_ps(a, b), c); +#endif +} + +static inline +__m256 +glmm256_fnmsub(__m256 a, __m256 b, __m256 c) { +#ifdef __FMA__ + return _mm256_fmsub_ps(a, b, c); +#else + return _mm256_xor_ps(_mm256_sub_ps(_mm256_mul_ps(a, b), c), + _mm256_set1_ps(-0.0f)); +#endif +} +#endif + +#endif +#endif /* cglm_simd_x86_h */ diff --git a/include/cglm/sphere.h b/include/cglm/sphere.h new file mode 100644 index 0000000..334b83a --- /dev/null +++ b/include/cglm/sphere.h @@ -0,0 +1,99 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_sphere_h +#define cglm_sphere_h + +#include "common.h" +#include "mat4.h" + +/* + Sphere Representation in cglm: [center.x, center.y, center.z, radii] + + You could use this representation or you can convert it to vec4 before call + any function + */ + +/*! + * @brief helper for getting sphere radius + * + * @param[in] s sphere + * + * @return returns radii + */ +CGLM_INLINE +float +glm_sphere_radii(vec4 s) { + return s[3]; +} + +/*! + * @brief apply transform to sphere, it is just wrapper for glm_mat4_mulv3 + * + * @param[in] s sphere + * @param[in] m transform matrix + * @param[out] dest transformed sphere + */ +CGLM_INLINE +void +glm_sphere_transform(vec4 s, mat4 m, vec4 dest) { + glm_mat4_mulv3(m, s, 1.0f, dest); + dest[3] = s[3]; +} + +/*! + * @brief merges two spheres and creates a new one + * + * two sphere must be in same space, for instance if one in world space then + * the other must be in world space too, not in local space. + * + * @param[in] s1 sphere 1 + * @param[in] s2 sphere 2 + * @param[out] dest merged/extended sphere + */ +CGLM_INLINE +void +glm_sphere_merge(vec4 s1, vec4 s2, vec4 dest) { + float dist, radii; + + dist = glm_vec3_distance(s1, s2); + radii = dist + s1[3] + s2[3]; + + radii = glm_max(radii, s1[3]); + radii = glm_max(radii, s2[3]); + + glm_vec3_center(s1, s2, dest); + dest[3] = radii; +} + +/*! + * @brief check if two sphere intersects + * + * @param[in] s1 sphere + * @param[in] s2 other sphere + */ +CGLM_INLINE +bool +glm_sphere_sphere(vec4 s1, vec4 s2) { + return glm_vec3_distance2(s1, s2) <= glm_pow2(s1[3] + s2[3]); +} + +/*! + * @brief check if sphere intersects with point + * + * @param[in] s sphere + * @param[in] point point + */ +CGLM_INLINE +bool +glm_sphere_point(vec4 s, vec3 point) { + float rr; + rr = s[3] * s[3]; + return glm_vec3_distance2(point, s) <= rr; +} + +#endif /* cglm_sphere_h */ diff --git a/include/cglm/struct.h b/include/cglm/struct.h new file mode 100644 index 0000000..871525a --- /dev/null +++ b/include/cglm/struct.h @@ -0,0 +1,39 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_structs_h +#define cglm_structs_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "cglm.h" +#include "types-struct.h" +#include "struct/vec2.h" +#include "struct/vec3.h" +#include "struct/vec4.h" +#include "struct/mat2.h" +#include "struct/mat3.h" +#include "struct/mat4.h" +#include "struct/affine.h" +#include "struct/frustum.h" +#include "struct/plane.h" +#include "struct/box.h" +#include "struct/color.h" +#include "struct/io.h" +#include "struct/cam.h" +#include "struct/quat.h" +#include "struct/euler.h" +#include "struct/project.h" +#include "struct/sphere.h" +#include "struct/curve.h" +#include "struct/affine2d.h" + +#ifdef __cplusplus +} +#endif +#endif /* cglm_structs_h */ diff --git a/include/cglm/struct/affine-post.h b/include/cglm/struct/affine-post.h new file mode 100644 index 0000000..5b6a93a --- /dev/null +++ b/include/cglm/struct/affine-post.h @@ -0,0 +1,184 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE mat4s glms_translated(mat4s m, vec3s v); + CGLM_INLINE mat4s glms_translated_x(mat4s m, float x); + CGLM_INLINE mat4s glms_translated_y(mat4s m, float y); + CGLM_INLINE mat4s glms_translated_z(mat4s m, float z); + CGLM_INLINE mat4s glms_rotated_x(mat4s m, float angle); + CGLM_INLINE mat4s glms_rotated_y(mat4s m, float angle); + CGLM_INLINE mat4s glms_rotated_z(mat4s m, float angle); + CGLM_INLINE mat4s glms_rotated(mat4s m, float angle, vec3s axis); + CGLM_INLINE mat4s glms_rotated_at(mat4s m, vec3s pivot, float angle, vec3s axis); + CGLM_INLINE mat4s glms_spinned(mat4s m, float angle, vec3s axis); + */ + +#ifndef cglms_affines_post_h +#define cglms_affines_post_h + +#include "../common.h" +#include "../types-struct.h" +#include "../affine.h" +#include "vec3.h" +#include "vec4.h" +#include "mat4.h" + +/*! + * @brief translate existing transform matrix by v vector + * and stores result in same matrix + * + * @param[in] m affine transfrom + * @param[in] v translate vector [x, y, z] + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_translated(mat4s m, vec3s v) { + glm_translated(m.raw, v.raw); + return m; +} + +/*! + * @brief translate existing transform matrix by x factor + * + * @param[in] m affine transfrom + * @param[in] x x factor + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_translated_x(mat4s m, float x) { + glm_translated_x(m.raw, x); + return m; +} + +/*! + * @brief translate existing transform matrix by y factor + * + * @param[in] m affine transfrom + * @param[in] y y factor + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_translated_y(mat4s m, float y) { + glm_translated_y(m.raw, y); + return m; +} + +/*! + * @brief translate existing transform matrix by z factor + * + * @param[in] m affine transfrom + * @param[in] z z factor + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_translated_z(mat4s m, float z) { + glm_translated_z(m.raw, z); + return m; +} + +/*! + * @brief rotate existing transform matrix around X axis by angle + * and store result in dest + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @returns rotated matrix + */ +CGLM_INLINE +mat4s +glms_rotated_x(mat4s m, float angle) { + mat4s r; + glm_rotated_x(m.raw, angle, r.raw); + return r; +} + +/*! + * @brief rotate existing transform matrix around Y axis by angle + * and store result in dest + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @returns rotated matrix + */ +CGLM_INLINE +mat4s +glms_rotated_y(mat4s m, float angle) { + mat4s r; + glm_rotated_y(m.raw, angle, r.raw); + return r; +} + +/*! + * @brief rotate existing transform matrix around Z axis by angle + * and store result in dest + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @returns rotated matrix + */ +CGLM_INLINE +mat4s +glms_rotated_z(mat4s m, float angle) { + mat4s r; + glm_rotated_z(m.raw, angle, r.raw); + return r; +} + +/*! + * @brief rotate existing transform matrix around given axis by angle + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @param[in] axis axis + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_rotated(mat4s m, float angle, vec3s axis) { + glm_rotated(m.raw, angle, axis.raw); + return m; +} + +/*! + * @brief rotate existing transform + * around given axis by angle at given pivot point (rotation center) + * + * @param[in] m affine transfrom + * @param[in] pivot rotation center + * @param[in] angle angle (radians) + * @param[in] axis axis + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_rotated_at(mat4s m, vec3s pivot, float angle, vec3s axis) { + glm_rotated_at(m.raw, pivot.raw, angle, axis.raw); + return m; +} + +/*! + * @brief rotate existing transform matrix around given axis by angle around self (doesn't affected by position) + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @param[in] axis axis + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_spinned(mat4s m, float angle, vec3s axis) { + glm_spinned(m.raw, angle, axis.raw); + return m; +} + +#endif /* cglms_affines_post_h */ diff --git a/include/cglm/struct/affine-pre.h b/include/cglm/struct/affine-pre.h new file mode 100644 index 0000000..f55dc29 --- /dev/null +++ b/include/cglm/struct/affine-pre.h @@ -0,0 +1,184 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE mat4s glms_translate(mat4s m, vec3s v); + CGLM_INLINE mat4s glms_translate_x(mat4s m, float x); + CGLM_INLINE mat4s glms_translate_y(mat4s m, float y); + CGLM_INLINE mat4s glms_translate_z(mat4s m, float z); + CGLM_INLINE mat4s glms_rotate_x(mat4s m, float angle); + CGLM_INLINE mat4s glms_rotate_y(mat4s m, float angle); + CGLM_INLINE mat4s glms_rotate_z(mat4s m, float angle); + CGLM_INLINE mat4s glms_rotate(mat4s m, float angle, vec3s axis); + CGLM_INLINE mat4s glms_rotate_at(mat4s m, vec3s pivot, float angle, vec3s axis); + CGLM_INLINE mat4s glms_spin(mat4s m, float angle, vec3s axis); + */ + +#ifndef cglms_affines_pre_h +#define cglms_affines_pre_h + +#include "../common.h" +#include "../types-struct.h" +#include "../affine.h" +#include "vec3.h" +#include "vec4.h" +#include "mat4.h" + +/*! + * @brief translate existing transform matrix by v vector + * and stores result in same matrix + * + * @param[in] m affine transfrom + * @param[in] v translate vector [x, y, z] + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_translate(mat4s m, vec3s v) { + glm_translate(m.raw, v.raw); + return m; +} + +/*! + * @brief translate existing transform matrix by x factor + * + * @param[in] m affine transfrom + * @param[in] x x factor + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_translate_x(mat4s m, float x) { + glm_translate_x(m.raw, x); + return m; +} + +/*! + * @brief translate existing transform matrix by y factor + * + * @param[in] m affine transfrom + * @param[in] y y factor + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_translate_y(mat4s m, float y) { + glm_translate_y(m.raw, y); + return m; +} + +/*! + * @brief translate existing transform matrix by z factor + * + * @param[in] m affine transfrom + * @param[in] z z factor + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_translate_z(mat4s m, float z) { + glm_translate_z(m.raw, z); + return m; +} + +/*! + * @brief rotate existing transform matrix around X axis by angle + * and store result in dest + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @returns rotated matrix + */ +CGLM_INLINE +mat4s +glms_rotate_x(mat4s m, float angle) { + mat4s r; + glm_rotate_x(m.raw, angle, r.raw); + return r; +} + +/*! + * @brief rotate existing transform matrix around Y axis by angle + * and store result in dest + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @returns rotated matrix + */ +CGLM_INLINE +mat4s +glms_rotate_y(mat4s m, float angle) { + mat4s r; + glm_rotate_y(m.raw, angle, r.raw); + return r; +} + +/*! + * @brief rotate existing transform matrix around Z axis by angle + * and store result in dest + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @returns rotated matrix + */ +CGLM_INLINE +mat4s +glms_rotate_z(mat4s m, float angle) { + mat4s r; + glm_rotate_z(m.raw, angle, r.raw); + return r; +} + +/*! + * @brief rotate existing transform matrix around given axis by angle + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @param[in] axis axis + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_rotate(mat4s m, float angle, vec3s axis) { + glm_rotate(m.raw, angle, axis.raw); + return m; +} + +/*! + * @brief rotate existing transform + * around given axis by angle at given pivot point (rotation center) + * + * @param[in] m affine transfrom + * @param[in] pivot rotation center + * @param[in] angle angle (radians) + * @param[in] axis axis + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_rotate_at(mat4s m, vec3s pivot, float angle, vec3s axis) { + glm_rotate_at(m.raw, pivot.raw, angle, axis.raw); + return m; +} + +/*! + * @brief rotate existing transform matrix around given axis by angle around self (doesn't affected by position) + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @param[in] axis axis + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_spin(mat4s m, float angle, vec3s axis) { + glm_spin(m.raw, angle, axis.raw); + return m; +} + +#endif /* cglms_affines_pre_h */ diff --git a/include/cglm/struct/affine.h b/include/cglm/struct/affine.h new file mode 100644 index 0000000..64e56d0 --- /dev/null +++ b/include/cglm/struct/affine.h @@ -0,0 +1,200 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE mat4s glms_translate(mat4s m, vec3s v); + CGLM_INLINE mat4s glms_translate_x(mat4s m, float x); + CGLM_INLINE mat4s glms_translate_y(mat4s m, float y); + CGLM_INLINE mat4s glms_translate_z(mat4s m, float z); + CGLM_INLINE mat4s glms_translate_make(vec3s v); + CGLM_INLINE mat4s glms_scale_to(mat4s m, vec3s v); + CGLM_INLINE mat4s glms_scale_make(vec3s v); + CGLM_INLINE mat4s glms_scale(mat4s m, vec3s v); + CGLM_INLINE mat4s glms_scale_uni(mat4s m, float s); + CGLM_INLINE mat4s glms_rotate_x(mat4s m, float angle); + CGLM_INLINE mat4s glms_rotate_y(mat4s m, float angle); + CGLM_INLINE mat4s glms_rotate_z(mat4s m, float angle); + CGLM_INLINE mat4s glms_rotate_make(float angle, vec3s axis); + CGLM_INLINE mat4s glms_rotate(mat4s m, float angle, vec3s axis); + CGLM_INLINE mat4s glms_rotate_at(mat4s m, vec3s pivot, float angle, vec3s axis); + CGLM_INLINE mat4s glms_rotate_atm(mat4s m, vec3s pivot, float angle, vec3s axis); + CGLM_INLINE mat4s glms_spin(mat4s m, float angle, vec3s axis); + CGLM_INLINE vec3s glms_decompose_scalev(mat4s m); + CGLM_INLINE bool glms_uniscaled(mat4s m); + CGLM_INLINE void glms_decompose_rs(mat4s m, mat4s * r, vec3s * s); + CGLM_INLINE void glms_decompose(mat4s m, vec4s t, mat4s * r, vec3s * s); + */ + +#ifndef cglms_affines_h +#define cglms_affines_h + +#include "../common.h" +#include "../types-struct.h" +#include "../affine.h" +#include "vec3.h" +#include "vec4.h" +#include "mat4.h" + +/*! + * @brief creates NEW translate transform matrix by v vector + * + * @param[in] v translate vector [x, y, z] + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_translate_make(vec3s v) { + mat4s m; + glm_translate_make(m.raw, v.raw); + return m; +} + +/*! + * @brief creates NEW scale matrix by v vector + * + * @param[in] v scale vector [x, y, z] + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_scale_make(vec3s v) { + mat4s m; + glm_scale_make(m.raw, v.raw); + return m; +} + +/*! + * @brief scales existing transform matrix by v vector + * and stores result in same matrix + * + * @param[in] m affine transfrom + * @param[in] v scale vector [x, y, z] + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_scale(mat4s m, vec3s v) { + mat4s r; + glm_scale_to(m.raw, v.raw, r.raw); + return r; +} + +/*! + * @brief applies uniform scale to existing transform matrix v = [s, s, s] + * and stores result in same matrix + * + * @param[in] m affine transfrom + * @param[in] s scale factor + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_scale_uni(mat4s m, float s) { + glm_scale_uni(m.raw, s); + return m; +} + +/*! + * @brief creates NEW rotation matrix by angle and axis + * + * axis will be normalized so you don't need to normalize it + * + * @param[in] angle angle (radians) + * @param[in] axis axis + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_rotate_make(float angle, vec3s axis) { + mat4s m; + glm_rotate_make(m.raw, angle, axis.raw); + return m; +} + +/*! + * @brief creates NEW rotation matrix by angle and axis at given point + * + * this creates rotation matrix, it assumes you don't have a matrix + * + * this should work faster than glm_rotate_at because it reduces + * one glm_translate. + * + * @param[in] m affine transfrom + * @param[in] pivot rotation center + * @param[in] angle angle (radians) + * @param[in] axis axis + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_rotate_atm(mat4s m, vec3s pivot, float angle, vec3s axis) { + glm_rotate_atm(m.raw, pivot.raw, angle, axis.raw); + return m; +} + +/*! + * @brief decompose scale vector + * + * @param[in] m affine transform + * @returns scale vector (Sx, Sy, Sz) + */ +CGLM_INLINE +vec3s +glms_decompose_scalev(mat4s m) { + vec3s r; + glm_decompose_scalev(m.raw, r.raw); + return r; +} + +/*! + * @brief returns true if matrix is uniform scaled. This is helpful for + * creating normal matrix. + * + * @param[in] m m + * + * @return boolean + */ +CGLM_INLINE +bool +glms_uniscaled(mat4s m) { + return glm_uniscaled(m.raw); +} + +/*! + * @brief decompose rotation matrix (mat4) and scale vector [Sx, Sy, Sz] + * DON'T pass projected matrix here + * + * @param[in] m affine transform + * @param[out] r rotation matrix + * @param[out] s scale matrix + */ +CGLM_INLINE +void +glms_decompose_rs(mat4s m, mat4s * __restrict r, vec3s * __restrict s) { + glm_decompose_rs(m.raw, r->raw, s->raw); +} + +/*! + * @brief decompose affine transform, TODO: extract shear factors. + * DON'T pass projected matrix here + * + * @param[in] m affine transfrom + * @param[out] t translation vector + * @param[out] r rotation matrix (mat4) + * @param[out] s scaling vector [X, Y, Z] + */ +CGLM_INLINE +void +glms_decompose(mat4s m, vec4s * __restrict t, mat4s * __restrict r, vec3s * __restrict s) { + glm_decompose(m.raw, t->raw, r->raw, s->raw); +} + +#include "affine-pre.h" +#include "affine-post.h" + +#endif /* cglms_affines_h */ diff --git a/include/cglm/struct/affine2d.h b/include/cglm/struct/affine2d.h new file mode 100644 index 0000000..412bd47 --- /dev/null +++ b/include/cglm/struct/affine2d.h @@ -0,0 +1,177 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE mat3s glms_translate2d(mat3 m, vec2 v) + CGLM_INLINE mat3s glms_translate2d_x(mat3s m, float x) + CGLM_INLINE mat3s glms_translate2d_y(mat3s m, float y) + CGLM_INLINE mat3s glms_translate2d_make(vec2s v) + CGLM_INLINE mat3s glms_scale2d_make(vec2s v) + CGLM_INLINE mat3s glms_scale2d(mat3s m, vec2s v) + CGLM_INLINE mat3s glms_scale2d_uni(mat3s m, float s) + CGLM_INLINE mat3s glms_rotate2d_make(float angle) + CGLM_INLINE mat3s glms_rotate2d(mat3s m, float angle) + CGLM_INLINE mat3s glms_rotate2d_to(mat3s m, float angle) + */ + +#ifndef cglms_affine2ds_h +#define cglms_affine2ds_h + +#include "../common.h" +#include "../types-struct.h" +#include "../affine2d.h" +#include "vec3.h" +#include "mat3.h" + +/*! + * @brief translate existing 2d transform matrix by v vector + * and stores result in same matrix + * + * @param[in] m affine transfrom + * @param[in] v translate vector [x, y] + * @returns affine transfrom + */ +CGLM_INLINE +mat3s +glms_translate2d(mat3s m, vec2s v) { + glm_translate2d(m.raw, v.raw); + return m; +} + +/*! + * @brief translate existing 2d transform matrix by x factor + * + * @param[in] m affine transfrom + * @param[in] x x factor + * @returns affine transfrom + */ +CGLM_INLINE +mat3s +glms_translate2d_x(mat3s m, float x) { + glm_translate2d_x(m.raw, x); + return m; +} + +/*! + * @brief translate existing 2d transform matrix by y factor + * + * @param[in] m affine transfrom + * @param[in] y y factor + * @returns affine transfrom + */ +CGLM_INLINE +mat3s +glms_translate2d_y(mat3s m, float y) { + glm_translate2d_y(m.raw, y); + return m; +} + +/*! + * @brief creates NEW translate 2d transform matrix by v vector + * + * @param[in] v translate vector [x, y] + * @returns affine transfrom + */ +CGLM_INLINE +mat3s +glms_translate2d_make(vec2s v) { + mat3s m; + glm_translate2d_make(m.raw, v.raw); + return m; +} + +/*! + * @brief creates NEW 2d scale matrix by v vector + * + * @param[in] v scale vector [x, y] + * @returns affine transfrom + */ +CGLM_INLINE +mat3s +glms_scale2d_make(vec2s v) { + mat3s m; + glm_scale2d_make(m.raw, v.raw); + return m; +} + +/*! + * @brief scales existing 2d transform matrix by v vector + * and stores result in same matrix + * + * @param[in] m affine transfrom + * @param[in] v scale vector [x, y, z] + * @returns affine transfrom + */ +CGLM_INLINE +mat3s +glms_scale2d(mat3s m, vec2s v) { + mat3s r; + glm_scale2d_to(m.raw, v.raw, r.raw); + return r; +} + +/*! + * @brief applies uniform scale to existing 2d transform matrix v = [s, s, s] + * and stores result in same matrix + * + * @param[in] m affine transfrom + * @param[in] s scale factor + * @returns affine transfrom + */ +CGLM_INLINE +mat3s +glms_scale2d_uni(mat3s m, float s) { + glm_scale2d_uni(m.raw, s); + return m; +} + +/*! + * @brief creates NEW 2d rotation matrix by angle and axis + * + * axis will be normalized so you don't need to normalize it + * + * @param[in] angle angle (radians) + * @returns affine transfrom + */ +CGLM_INLINE +mat3s +glms_rotate2d_make(float angle) { + mat3s m; + glm_rotate2d_make(m.raw, angle); + return m; +} + +/*! + * @brief rotate existing 2d transform matrix around given axis by angle + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @returns affine transfrom + */ +CGLM_INLINE +mat3s +glms_rotate2d(mat3s m, float angle) { + glm_rotate2d(m.raw, angle); + return m; +} + +/*! + * @brief rotate existing 2d transform matrix around given axis by angle + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @returns affine transfrom + */ +CGLM_INLINE +mat3s +glms_rotate2d_to(mat3s m, float angle) { + glm_rotate2d(m.raw, angle); + return m; +} + +#endif /* cglms_affine2ds_h */ diff --git a/include/cglm/struct/box.h b/include/cglm/struct/box.h new file mode 100644 index 0000000..a55884f --- /dev/null +++ b/include/cglm/struct/box.h @@ -0,0 +1,256 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglms_boxs_h +#define cglms_boxs_h + +#include "../common.h" +#include "../types-struct.h" +#include "../box.h" +#include "vec3.h" +#include "vec4.h" +#include "mat4.h" + +/*! + * @brief apply transform to Axis-Aligned Bounding Box + * + * @param[in] box bounding box + * @param[in] m transform matrix + * @param[out] dest transformed bounding box + */ +CGLM_INLINE +void +glms_aabb_transform(vec3s box[2], mat4s m, vec3s dest[2]) { + vec3 rawBox[2]; + vec3 rawDest[2]; + + glms_vec3_unpack(rawBox, box, 2); + glm_aabb_transform(rawBox, m.raw, rawDest); + glms_vec3_pack(dest, rawDest, 2); +} + +/*! + * @brief merges two AABB bounding box and creates new one + * + * two box must be in same space, if one of box is in different space then + * you should consider to convert it's space by glm_box_space + * + * @param[in] box1 bounding box 1 + * @param[in] box2 bounding box 2 + * @param[out] dest merged bounding box + */ +CGLM_INLINE +void +glms_aabb_merge(vec3s box1[2], vec3s box2[2], vec3s dest[2]) { + vec3 rawBox1[2]; + vec3 rawBox2[2]; + vec3 rawDest[2]; + + glms_vec3_unpack(rawBox1, box1, 2); + glms_vec3_unpack(rawBox2, box2, 2); + glm_aabb_merge(rawBox1, rawBox2, rawDest); + glms_vec3_pack(dest, rawDest, 2); +} + +/*! + * @brief crops a bounding box with another one. + * + * this could be useful for gettng a bbox which fits with view frustum and + * object bounding boxes. In this case you crop view frustum box with objects + * box + * + * @param[in] box bounding box 1 + * @param[in] cropBox crop box + * @param[out] dest cropped bounding box + */ +CGLM_INLINE +void +glms_aabb_crop(vec3s box[2], vec3s cropBox[2], vec3s dest[2]) { + vec3 rawBox[2]; + vec3 rawCropBox[2]; + vec3 rawDest[2]; + + glms_vec3_unpack(rawBox, box, 2); + glms_vec3_unpack(rawCropBox, cropBox, 2); + glm_aabb_crop(rawBox, rawCropBox, rawDest); + glms_vec3_pack(dest, rawDest, 2); +} + +/*! + * @brief crops a bounding box with another one. + * + * this could be useful for gettng a bbox which fits with view frustum and + * object bounding boxes. In this case you crop view frustum box with objects + * box + * + * @param[in] box bounding box + * @param[in] cropBox crop box + * @param[in] clampBox miniumum box + * @param[out] dest cropped bounding box + */ +CGLM_INLINE +void +glms_aabb_crop_until(vec3s box[2], + vec3s cropBox[2], + vec3s clampBox[2], + vec3s dest[2]) { + glms_aabb_crop(box, cropBox, dest); + glms_aabb_merge(clampBox, dest, dest); +} + +/*! + * @brief check if AABB intersects with frustum planes + * + * this could be useful for frustum culling using AABB. + * + * OPTIMIZATION HINT: + * if planes order is similar to LEFT, RIGHT, BOTTOM, TOP, NEAR, FAR + * then this method should run even faster because it would only use two + * planes if object is not inside the two planes + * fortunately cglm extracts planes as this order! just pass what you got! + * + * @param[in] box bounding box + * @param[in] planes frustum planes + */ +CGLM_INLINE +bool +glms_aabb_frustum(vec3s box[2], vec4s planes[6]) { + vec3 rawBox[2]; + vec4 rawPlanes[6]; + + glms_vec3_unpack(rawBox, box, 2); + glms_vec4_unpack(rawPlanes, planes, 6); + return glm_aabb_frustum(rawBox, rawPlanes); +} + +/*! + * @brief invalidate AABB min and max values + * + * @param[in, out] box bounding box + */ +CGLM_INLINE +void +glms_aabb_invalidate(vec3s box[2]) { + box[0] = glms_vec3_broadcast(FLT_MAX); + box[1] = glms_vec3_broadcast(-FLT_MAX); +} + +/*! + * @brief check if AABB is valid or not + * + * @param[in] box bounding box + */ +CGLM_INLINE +bool +glms_aabb_isvalid(vec3s box[2]) { + vec3 rawBox[2]; + glms_vec3_unpack(rawBox, box, 2); + return glm_aabb_isvalid(rawBox); +} + +/*! + * @brief distance between of min and max + * + * @param[in] box bounding box + */ +CGLM_INLINE +float +glms_aabb_size(vec3s box[2]) { + return glm_vec3_distance(box[0].raw, box[1].raw); +} + +/*! + * @brief radius of sphere which surrounds AABB + * + * @param[in] box bounding box + */ +CGLM_INLINE +float +glms_aabb_radius(vec3s box[2]) { + return glms_aabb_size(box) * 0.5f; +} + +/*! + * @brief computes center point of AABB + * + * @param[in] box bounding box + * @returns center of bounding box + */ +CGLM_INLINE +vec3s +glms_aabb_center(vec3s box[2]) { + return glms_vec3_center(box[0], box[1]); +} + +/*! + * @brief check if two AABB intersects + * + * @param[in] box bounding box + * @param[in] other other bounding box + */ +CGLM_INLINE +bool +glms_aabb_aabb(vec3s box[2], vec3s other[2]) { + vec3 rawBox[2]; + vec3 rawOther[2]; + + glms_vec3_unpack(rawBox, box, 2); + glms_vec3_unpack(rawOther, other, 2); + return glm_aabb_aabb(rawBox, rawOther); +} + +/*! + * @brief check if AABB intersects with sphere + * + * https://github.com/erich666/GraphicsGems/blob/master/gems/BoxSphere.c + * Solid Box - Solid Sphere test. + * + * @param[in] box solid bounding box + * @param[in] s solid sphere + */ +CGLM_INLINE +bool +glms_aabb_sphere(vec3s box[2], vec4s s) { + vec3 rawBox[2]; + + glms_vec3_unpack(rawBox, box, 2); + return glm_aabb_sphere(rawBox, s.raw); +} + +/*! + * @brief check if point is inside of AABB + * + * @param[in] box bounding box + * @param[in] point point + */ +CGLM_INLINE +bool +glms_aabb_point(vec3s box[2], vec3s point) { + vec3 rawBox[2]; + + glms_vec3_unpack(rawBox, box, 2); + return glm_aabb_point(rawBox, point.raw); +} + +/*! + * @brief check if AABB contains other AABB + * + * @param[in] box bounding box + * @param[in] other other bounding box + */ +CGLM_INLINE +bool +glms_aabb_contains(vec3s box[2], vec3s other[2]) { + vec3 rawBox[2]; + vec3 rawOther[2]; + + glms_vec3_unpack(rawBox, box, 2); + glms_vec3_unpack(rawOther, other, 2); + return glm_aabb_contains(rawBox, rawOther); +} + +#endif /* cglms_boxs_h */ diff --git a/include/cglm/struct/cam.h b/include/cglm/struct/cam.h new file mode 100644 index 0000000..2a92af7 --- /dev/null +++ b/include/cglm/struct/cam.h @@ -0,0 +1,646 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE mat4s glms_frustum(float left, float right, + float bottom, float top, + float nearZ, float farZ) + CGLM_INLINE mat4s glms_ortho(float left, float right, + float bottom, float top, + float nearZ, float farZ) + CGLM_INLINE mat4s glms_ortho_aabb(vec3s box[2]); + CGLM_INLINE mat4s glms_ortho_aabb_p(vec3s box[2], float padding); + CGLM_INLINE mat4s glms_ortho_aabb_pz(vec3s box[2], float padding); + CGLM_INLINE mat4s glms_ortho_default(float aspect) + CGLM_INLINE mat4s glms_ortho_default_s(float aspect, float size) + CGLM_INLINE mat4s glms_perspective(float fovy, + float aspect, + float nearZ, + float farZ) + CGLM_INLINE void glms_persp_move_far(mat4s proj, float deltaFar) + CGLM_INLINE mat4s glms_perspective_default(float aspect) + CGLM_INLINE void glms_perspective_resize(mat4s proj, float aspect) + CGLM_INLINE mat4s glms_lookat(vec3s eye, vec3s center, vec3s up) + CGLM_INLINE mat4s glms_look(vec3s eye, vec3s dir, vec3s up) + CGLM_INLINE mat4s glms_look_anyup(vec3s eye, vec3s dir) + CGLM_INLINE void glms_persp_decomp(mat4s proj, + float *nearv, float *farv, + float *top, float *bottom, + float *left, float *right) + CGLM_INLINE void glms_persp_decompv(mat4s proj, float dest[6]) + CGLM_INLINE void glms_persp_decomp_x(mat4s proj, float *left, float *right) + CGLM_INLINE void glms_persp_decomp_y(mat4s proj, float *top, float *bottom) + CGLM_INLINE void glms_persp_decomp_z(mat4s proj, float *nearv, float *farv) + CGLM_INLINE void glms_persp_decomp_far(mat4s proj, float *farZ) + CGLM_INLINE void glms_persp_decomp_near(mat4s proj, float *nearZ) + CGLM_INLINE float glms_persp_fovy(mat4s proj) + CGLM_INLINE float glms_persp_aspect(mat4s proj) + CGLM_INLINE vec4s glms_persp_sizes(mat4s proj, float fovy) + */ + +#ifndef cglms_cam_h +#define cglms_cam_h + +#include "../common.h" +#include "../types-struct.h" +#include "../plane.h" +#include "../cam.h" + +#ifndef CGLM_CLIPSPACE_INCLUDE_ALL +# if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO +# include "clipspace/ortho_lh_zo.h" +# include "clipspace/persp_lh_zo.h" +# include "clipspace/view_lh_zo.h" +# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO +# include "clipspace/ortho_lh_no.h" +# include "clipspace/persp_lh_no.h" +# include "clipspace/view_lh_no.h" +# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO +# include "clipspace/ortho_rh_zo.h" +# include "clipspace/persp_rh_zo.h" +# include "clipspace/view_rh_zo.h" +# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO +# include "clipspace/ortho_rh_no.h" +# include "clipspace/persp_rh_no.h" +# include "clipspace/view_rh_no.h" +# endif +#else +# include "clipspace/ortho_lh_zo.h" +# include "clipspace/persp_lh_zo.h" +# include "clipspace/ortho_lh_no.h" +# include "clipspace/persp_lh_no.h" +# include "clipspace/ortho_rh_zo.h" +# include "clipspace/persp_rh_zo.h" +# include "clipspace/ortho_rh_no.h" +# include "clipspace/persp_rh_no.h" +# include "clipspace/view_lh_zo.h" +# include "clipspace/view_lh_no.h" +# include "clipspace/view_rh_zo.h" +# include "clipspace/view_rh_no.h" +#endif + +/*! + * @brief set up perspective peprojection matrix + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_frustum(float left, float right, + float bottom, float top, + float nearZ, float farZ) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + return glms_frustum_lh_zo(left, right, bottom, top, nearZ, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + return glms_frustum_lh_no(left, right, bottom, top, nearZ, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + return glms_frustum_rh_zo(left, right, bottom, top, nearZ, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + return glms_frustum_rh_no(left, right, bottom, top, nearZ, farZ); +#endif +} + +/*! + * @brief set up orthographic projection matrix + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho(float left, float right, + float bottom, float top, + float nearZ, float farZ) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + return glms_ortho_lh_zo(left, right, bottom, top, nearZ, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + return glms_ortho_lh_no(left, right, bottom, top, nearZ, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + return glms_ortho_rh_zo(left, right, bottom, top, nearZ, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + return glms_ortho_rh_no(left, right, bottom, top, nearZ, farZ); +#endif +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_aabb(vec3s box[2]) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + return glms_ortho_aabb_lh_zo(box); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + return glms_ortho_aabb_lh_no(box); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + return glms_ortho_aabb_rh_zo(box); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + return glms_ortho_aabb_rh_no(box); +#endif +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_aabb_p(vec3s box[2], float padding) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + return glms_ortho_aabb_p_lh_zo(box, padding); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + return glms_ortho_aabb_p_lh_no(box, padding); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + return glms_ortho_aabb_p_rh_zo(box, padding); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + return glms_ortho_aabb_p_rh_no(box, padding); +#endif +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding for near and far + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_aabb_pz(vec3s box[2], float padding) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + return glms_ortho_aabb_pz_lh_zo(box, padding); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + return glms_ortho_aabb_pz_lh_no(box, padding); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + return glms_ortho_aabb_pz_rh_zo(box, padding); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + return glms_ortho_aabb_pz_rh_no(box, padding); +#endif +} + +/*! + * @brief set up unit orthographic projection matrix + * + * @param[in] aspect aspect ration ( width / height ) + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_default(float aspect) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + return glms_ortho_default_lh_zo(aspect); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + return glms_ortho_default_lh_no(aspect); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + return glms_ortho_default_rh_zo(aspect); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + return glms_ortho_default_rh_no(aspect); +#endif +} + +/*! + * @brief set up orthographic projection matrix with given CUBE size + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] size cube size + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_default_s(float aspect, float size) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + return glms_ortho_default_s_lh_zo(aspect, size); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + return glms_ortho_default_s_lh_no(aspect, size); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + return glms_ortho_default_s_rh_zo(aspect, size); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + return glms_ortho_default_s_rh_no(aspect, size); +#endif +} + +/*! + * @brief set up perspective projection matrix + * + * @param[in] fovy field of view angle + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping planes + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_perspective(float fovy, float aspect, float nearZ, float farZ) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + return glms_perspective_lh_zo(fovy, aspect, nearZ, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + return glms_perspective_lh_no(fovy, aspect, nearZ, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + return glms_perspective_rh_zo(fovy, aspect, nearZ, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + return glms_perspective_rh_no(fovy, aspect, nearZ, farZ); +#endif +} + +/*! + * @brief extend perspective projection matrix's far distance + * + * NOTE: if you dodn't want to create new matrix then use array api on struct.raw + * like glm_persp_move_far(prooj.raw, deltaFar) to avoid create new mat4 + * each time + * + * this function does not guarantee far >= near, be aware of that! + * + * @param[in, out] proj projection matrix to extend + * @param[in] deltaFar distance from existing far (negative to shink) + */ +CGLM_INLINE +mat4s +glms_persp_move_far(mat4s proj, float deltaFar) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + return glms_persp_move_far_lh_zo(proj, deltaFar); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + return glms_persp_move_far_lh_no(proj, deltaFar); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + return glms_persp_move_far_rh_zo(proj, deltaFar); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + return glms_persp_move_far_rh_no(proj, deltaFar); +#endif +} + +/*! + * @brief set up perspective projection matrix with default near/far + * and angle values + * + * @param[in] aspect aspect ratio ( width / height ) + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_perspective_default(float aspect) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + return glms_perspective_default_lh_zo(aspect); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + return glms_perspective_default_lh_no(aspect); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + return glms_perspective_default_rh_zo(aspect); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + return glms_perspective_default_rh_no(aspect); +#endif +} + +/*! + * @brief resize perspective matrix by aspect ratio ( width / height ) + * this makes very easy to resize proj matrix when window /viewport + * reized + * + * NOTE: if you dodn't want to create new matrix then use array api on struct.raw + * like glms_perspective_resize(proj.raw, aspect) to avoid create new mat4 + * each time + * + * @param[in, out] proj perspective projection matrix + * @param[in] aspect aspect ratio ( width / height ) + */ +CGLM_INLINE +mat4s +glms_perspective_resize(mat4s proj, float aspect) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + return glms_perspective_resize_lh_zo(proj, aspect); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + return glms_perspective_resize_lh_no(proj, aspect); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + return glms_perspective_resize_rh_zo(proj, aspect); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + return glms_perspective_resize_rh_no(proj, aspect); +#endif +} + +/*! + * @brief set up view matrix + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] center center vector + * @param[in] up up vector + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_lookat(vec3s eye, vec3s center, vec3s up) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + return glms_lookat_lh_zo(eye, center, up); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + return glms_lookat_lh_no(eye, center, up); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + return glms_lookat_rh_zo(eye, center, up); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + return glms_lookat_rh_no(eye, center, up); +#endif +} + +/*! + * @brief set up view matrix + * + * convenient wrapper for lookat: if you only have direction not target self + * then this might be useful. Because you need to get target from direction. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[in] up up vector + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_look(vec3s eye, vec3s dir, vec3s up) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + return glms_look_lh_zo(eye, dir, up); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + return glms_look_lh_no(eye, dir, up); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + return glms_look_rh_zo(eye, dir, up); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + return glms_look_rh_no(eye, dir, up); +#endif +} + +/*! + * @brief set up view matrix + * + * convenient wrapper for look: if you only have direction and if you don't + * care what UP vector is then this might be useful to create view matrix + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_look_anyup(vec3s eye, vec3s dir) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + return glms_look_anyup_lh_zo(eye, dir); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + return glms_look_anyup_lh_no(eye, dir); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + return glms_look_anyup_rh_zo(eye, dir); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + return glms_look_anyup_rh_no(eye, dir); +#endif +} + +/*! + * @brief decomposes frustum values of perspective projection. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + * @param[out] top top + * @param[out] bottom bottom + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glms_persp_decomp(mat4s proj, + float * __restrict nearZ, float * __restrict farZ, + float * __restrict top, float * __restrict bottom, + float * __restrict left, float * __restrict right) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glms_persp_decomp_lh_zo(proj, nearZ, farZ, top, bottom, left, right); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glms_persp_decomp_lh_no(proj, nearZ, farZ, top, bottom, left, right); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glms_persp_decomp_rh_zo(proj, nearZ, farZ, top, bottom, left, right); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glms_persp_decomp_rh_no(proj, nearZ, farZ, top, bottom, left, right); +#endif +} + +/*! + * @brief decomposes frustum values of perspective projection. + * this makes easy to get all values at once + * + * @param[in] proj perspective projection matrix + * @param[out] dest array + */ +CGLM_INLINE +void +glms_persp_decompv(mat4s proj, float dest[6]) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glms_persp_decompv_lh_zo(proj, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glms_persp_decompv_lh_no(proj, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glms_persp_decompv_rh_zo(proj, dest); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glms_persp_decompv_rh_no(proj, dest); +#endif +} + +/*! + * @brief decomposes left and right values of perspective projection. + * x stands for x axis (left / right axis) + * + * @param[in] proj perspective projection matrix + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glms_persp_decomp_x(mat4s proj, + float * __restrict left, + float * __restrict right) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glms_persp_decomp_x_lh_zo(proj, left, right); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glms_persp_decomp_x_lh_no(proj, left, right); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glms_persp_decomp_x_rh_zo(proj, left, right); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glms_persp_decomp_x_rh_no(proj, left, right); +#endif +} + +/*! + * @brief decomposes top and bottom values of perspective projection. + * y stands for y axis (top / botom axis) + * + * @param[in] proj perspective projection matrix + * @param[out] top top + * @param[out] bottom bottom + */ +CGLM_INLINE +void +glms_persp_decomp_y(mat4s proj, + float * __restrict top, + float * __restrict bottom) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glms_persp_decomp_y_lh_zo(proj, top, bottom); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glms_persp_decomp_y_lh_no(proj, top, bottom); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glms_persp_decomp_y_rh_zo(proj, top, bottom); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glms_persp_decomp_y_rh_no(proj, top, bottom); +#endif +} + +/*! + * @brief decomposes near and far values of perspective projection. + * z stands for z axis (near / far axis) + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + */ +CGLM_INLINE +void +glms_persp_decomp_z(mat4s proj, + float * __restrict nearZ, + float * __restrict farZ) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glms_persp_decomp_z_lh_zo(proj, nearZ, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glms_persp_decomp_z_lh_no(proj, nearZ, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glms_persp_decomp_z_rh_zo(proj, nearZ, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glms_persp_decomp_z_rh_no(proj, nearZ, farZ); +#endif +} + +/*! + * @brief decomposes far value of perspective projection. + * + * @param[in] proj perspective projection matrix + * @param[out] farZ far + */ +CGLM_INLINE +void +glms_persp_decomp_far(mat4s proj, float * __restrict farZ) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glms_persp_decomp_far_lh_zo(proj, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glms_persp_decomp_far_lh_no(proj, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glms_persp_decomp_far_rh_zo(proj, farZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glms_persp_decomp_far_rh_no(proj, farZ); +#endif +} + +/*! + * @brief decomposes near value of perspective projection. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + */ +CGLM_INLINE +void +glms_persp_decomp_near(mat4s proj, float * __restrict nearZ) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + glms_persp_decomp_near_lh_zo(proj, nearZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + glms_persp_decomp_near_lh_no(proj, nearZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + glms_persp_decomp_near_rh_zo(proj, nearZ); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + glms_persp_decomp_near_rh_no(proj, nearZ); +#endif +} + +/*! + * @brief returns field of view angle along the Y-axis (in radians) + * + * if you need to degrees, use glm_deg to convert it or use this: + * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glms_persp_fovy(mat4s proj) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + return glms_persp_fovy_lh_zo(proj); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + return glms_persp_fovy_lh_no(proj); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + return glms_persp_fovy_rh_zo(proj); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + return glms_persp_fovy_rh_no(proj); +#endif +} + +/*! + * @brief returns aspect ratio of perspective projection + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glms_persp_aspect(mat4s proj) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + return glms_persp_aspect_lh_zo(proj); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + return glms_persp_aspect_lh_no(proj); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + return glms_persp_aspect_rh_zo(proj); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + return glms_persp_aspect_rh_no(proj); +#endif +} + +/*! + * @brief returns sizes of near and far planes of perspective projection + * + * @param[in] proj perspective projection matrix + * @param[in] fovy fovy (see brief) + * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar] + */ +CGLM_INLINE +vec4s +glms_persp_sizes(mat4s proj, float fovy) { +#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO + return glms_persp_sizes_lh_zo(proj, fovy); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO + return glms_persp_sizes_lh_no(proj, fovy); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO + return glms_persp_sizes_rh_zo(proj, fovy); +#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO + return glms_persp_sizes_rh_no(proj, fovy); +#endif +} + +#endif /* cglms_cam_h */ diff --git a/include/cglm/struct/clipspace/ortho_lh_no.h b/include/cglm/struct/clipspace/ortho_lh_no.h new file mode 100644 index 0000000..5fcda54 --- /dev/null +++ b/include/cglm/struct/clipspace/ortho_lh_no.h @@ -0,0 +1,152 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE mat4s glms_ortho_lh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ) + CGLM_INLINE mat4s glms_ortho_aabb_lh_no(vec3s box[2]); + CGLM_INLINE mat4s glms_ortho_aabb_p_lh_no(vec3s box[2], float padding); + CGLM_INLINE mat4s glms_ortho_aabb_pz_lh_no(vec3s box[2], float padding); + CGLM_INLINE mat4s glms_ortho_default_lh_no(float aspect) + CGLM_INLINE mat4s glms_ortho_default_s_lh_no(float aspect, float size) + */ + +#ifndef cglms_ortho_lh_no_h +#define cglms_ortho_lh_no_h + +#include "../../common.h" +#include "../../types-struct.h" +#include "../../plane.h" +#include "../../cam.h" + +/*! + * @brief set up orthographic projection matrix + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_lh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ) { + mat4s dest; + glm_ortho_lh_no(left, right, bottom, top, nearZ, farZ, dest.raw); + return dest; +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_aabb_lh_no(vec3s box[2]) { + mat4s dest; + vec3 rawBox[2]; + + glms_vec3_unpack(rawBox, box, 2); + glm_ortho_aabb_lh_no(rawBox, dest.raw); + + return dest; +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_aabb_p_lh_no(vec3s box[2], float padding) { + mat4s dest; + vec3 rawBox[2]; + + glms_vec3_unpack(rawBox, box, 2); + glm_ortho_aabb_p_lh_no(rawBox, padding, dest.raw); + + return dest; +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding for near and far + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_aabb_pz_lh_no(vec3s box[2], float padding) { + mat4s dest; + vec3 rawBox[2]; + + glms_vec3_unpack(rawBox, box, 2); + glm_ortho_aabb_pz_lh_no(rawBox, padding, dest.raw); + + return dest; +} + +/*! + * @brief set up unit orthographic projection matrix + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] aspect aspect ration ( width / height ) + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_default_lh_no(float aspect) { + mat4s dest; + glm_ortho_default_lh_no(aspect, dest.raw); + return dest; +} + +/*! + * @brief set up orthographic projection matrix with given CUBE size + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] size cube size + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_default_s_lh_no(float aspect, float size) { + mat4s dest; + glm_ortho_default_s_lh_no(aspect, size, dest.raw); + return dest; +} + +#endif /* cglms_ortho_lh_no_h */ diff --git a/include/cglm/struct/clipspace/ortho_lh_zo.h b/include/cglm/struct/clipspace/ortho_lh_zo.h new file mode 100644 index 0000000..fe49247 --- /dev/null +++ b/include/cglm/struct/clipspace/ortho_lh_zo.h @@ -0,0 +1,152 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE mat4s glms_ortho_lh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ) + CGLM_INLINE mat4s glms_ortho_aabb_lh_zo(vec3s box[2]); + CGLM_INLINE mat4s glms_ortho_aabb_p_lh_zo(vec3s box[2], float padding); + CGLM_INLINE mat4s glms_ortho_aabb_pz_lh_zo(vec3s box[2], float padding); + CGLM_INLINE mat4s glms_ortho_default_lh_zo(float aspect) + CGLM_INLINE mat4s glms_ortho_default_s_lh_zo(float aspect, float size) + */ + +#ifndef cglms_ortho_lh_zo_h +#define cglms_ortho_lh_zo_h + +#include "../../common.h" +#include "../../types-struct.h" +#include "../../plane.h" +#include "../../cam.h" + +/*! + * @brief set up orthographic projection matrix + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_lh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ) { + mat4s dest; + glm_ortho_lh_zo(left, right, bottom, top, nearZ, farZ, dest.raw); + return dest; +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_aabb_lh_zo(vec3s box[2]) { + mat4s dest; + vec3 rawBox[2]; + + glms_vec3_unpack(rawBox, box, 2); + glm_ortho_aabb_lh_zo(rawBox, dest.raw); + + return dest; +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_aabb_p_lh_zo(vec3s box[2], float padding) { + mat4s dest; + vec3 rawBox[2]; + + glms_vec3_unpack(rawBox, box, 2); + glm_ortho_aabb_p_lh_zo(rawBox, padding, dest.raw); + + return dest; +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding for near and far + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_aabb_pz_lh_zo(vec3s box[2], float padding) { + mat4s dest; + vec3 rawBox[2]; + + glms_vec3_unpack(rawBox, box, 2); + glm_ortho_aabb_pz_lh_zo(rawBox, padding, dest.raw); + + return dest; +} + +/*! + * @brief set up unit orthographic projection matrix + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] aspect aspect ration ( width / height ) + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_default_lh_zo(float aspect) { + mat4s dest; + glm_ortho_default_lh_zo(aspect, dest.raw); + return dest; +} + +/*! + * @brief set up orthographic projection matrix with given CUBE size + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] size cube size + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_default_s_lh_zo(float aspect, float size) { + mat4s dest; + glm_ortho_default_s_lh_zo(aspect, size, dest.raw); + return dest; +} + +#endif /* cglms_ortho_lh_zo_h */ diff --git a/include/cglm/struct/clipspace/ortho_rh_no.h b/include/cglm/struct/clipspace/ortho_rh_no.h new file mode 100644 index 0000000..e88713f --- /dev/null +++ b/include/cglm/struct/clipspace/ortho_rh_no.h @@ -0,0 +1,152 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE mat4s glms_ortho_rh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ) + CGLM_INLINE mat4s glms_ortho_aabb_rh_no(vec3s box[2]); + CGLM_INLINE mat4s glms_ortho_aabb_p_rh_no(vec3s box[2], float padding); + CGLM_INLINE mat4s glms_ortho_aabb_pz_rh_no(vec3s box[2], float padding); + CGLM_INLINE mat4s glms_ortho_default_rh_no(float aspect) + CGLM_INLINE mat4s glms_ortho_default_s_rh_no(float aspect, float size) + */ + +#ifndef cglms_ortho_rh_no_h +#define cglms_ortho_rh_no_h + +#include "../../common.h" +#include "../../types-struct.h" +#include "../../plane.h" +#include "../../cam.h" + +/*! + * @brief set up orthographic projection matrix + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_rh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ) { + mat4s dest; + glm_ortho_rh_no(left, right, bottom, top, nearZ, farZ, dest.raw); + return dest; +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_aabb_rh_no(vec3s box[2]) { + mat4s dest; + vec3 rawBox[2]; + + glms_vec3_unpack(rawBox, box, 2); + glm_ortho_aabb_rh_no(rawBox, dest.raw); + + return dest; +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_aabb_p_rh_no(vec3s box[2], float padding) { + mat4s dest; + vec3 rawBox[2]; + + glms_vec3_unpack(rawBox, box, 2); + glm_ortho_aabb_p_rh_no(rawBox, padding, dest.raw); + + return dest; +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding for near and far + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_aabb_pz_rh_no(vec3s box[2], float padding) { + mat4s dest; + vec3 rawBox[2]; + + glms_vec3_unpack(rawBox, box, 2); + glm_ortho_aabb_pz_rh_no(rawBox, padding, dest.raw); + + return dest; +} + +/*! + * @brief set up unit orthographic projection matrix + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] aspect aspect ration ( width / height ) + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_default_rh_no(float aspect) { + mat4s dest; + glm_ortho_default_rh_no(aspect, dest.raw); + return dest; +} + +/*! + * @brief set up orthographic projection matrix with given CUBE size + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] size cube size + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_default_s_rh_no(float aspect, float size) { + mat4s dest; + glm_ortho_default_s_rh_no(aspect, size, dest.raw); + return dest; +} + +#endif /* cglms_ortho_rh_no_h */ diff --git a/include/cglm/struct/clipspace/ortho_rh_zo.h b/include/cglm/struct/clipspace/ortho_rh_zo.h new file mode 100644 index 0000000..8550b40 --- /dev/null +++ b/include/cglm/struct/clipspace/ortho_rh_zo.h @@ -0,0 +1,152 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE mat4s glms_ortho_rh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ) + CGLM_INLINE mat4s glms_ortho_aabb_rh_zo(vec3s box[2]); + CGLM_INLINE mat4s glms_ortho_aabb_p_rh_zo(vec3s box[2], float padding); + CGLM_INLINE mat4s glms_ortho_aabb_pz_rh_zo(vec3s box[2], float padding); + CGLM_INLINE mat4s glms_ortho_default_rh_zo(float aspect) + CGLM_INLINE mat4s glms_ortho_default_s_rh_zo(float aspect, float size) + */ + +#ifndef cglms_ortho_rh_zo_h +#define cglms_ortho_rh_zo_h + +#include "../../common.h" +#include "../../types-struct.h" +#include "../../plane.h" +#include "../../cam.h" + +/*! + * @brief set up orthographic projection matrix + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_rh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ) { + mat4s dest; + glm_ortho_rh_zo(left, right, bottom, top, nearZ, farZ, dest.raw); + return dest; +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_aabb_rh_zo(vec3s box[2]) { + mat4s dest; + vec3 rawBox[2]; + + glms_vec3_unpack(rawBox, box, 2); + glm_ortho_aabb_rh_zo(rawBox, dest.raw); + + return dest; +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_aabb_p_rh_zo(vec3s box[2], float padding) { + mat4s dest; + vec3 rawBox[2]; + + glms_vec3_unpack(rawBox, box, 2); + glm_ortho_aabb_p_rh_zo(rawBox, padding, dest.raw); + + return dest; +} + +/*! + * @brief set up orthographic projection matrix using bounding box + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * bounding box (AABB) must be in view space + * + * @param[in] box AABB + * @param[in] padding padding for near and far + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_aabb_pz_rh_zo(vec3s box[2], float padding) { + mat4s dest; + vec3 rawBox[2]; + + glms_vec3_unpack(rawBox, box, 2); + glm_ortho_aabb_pz_rh_zo(rawBox, padding, dest.raw); + + return dest; +} + +/*! + * @brief set up unit orthographic projection matrix + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] aspect aspect ration ( width / height ) + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_default_rh_zo(float aspect) { + mat4s dest; + glm_ortho_default_rh_zo(aspect, dest.raw); + return dest; +} + +/*! + * @brief set up orthographic projection matrix with given CUBE size + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] size cube size + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_ortho_default_s_rh_zo(float aspect, float size) { + mat4s dest; + glm_ortho_default_s_rh_zo(aspect, size, dest.raw); + return dest; +} + +#endif /* cglms_ortho_rh_zo_h */ diff --git a/include/cglm/struct/clipspace/persp_lh_no.h b/include/cglm/struct/clipspace/persp_lh_no.h new file mode 100644 index 0000000..f31c4b2 --- /dev/null +++ b/include/cglm/struct/clipspace/persp_lh_no.h @@ -0,0 +1,311 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE mat4s glms_frustum_lh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ) + CGLM_INLINE mat4s glms_perspective_lh_no(float fovy, + float aspect, + float nearZ, + float farZ) + CGLM_INLINE void glms_persp_move_far_lh_no(mat4s proj, float deltaFar) + CGLM_INLINE mat4s glms_perspective_default_lh_no(float aspect) + CGLM_INLINE void glms_perspective_resize_lh_no(mat4s proj, float aspect) + CGLM_INLINE void glms_persp_decomp_lh_no(mat4s proj, + float *nearv, float *farv, + float *top, float *bottom, + float *left, float *right) + CGLM_INLINE void glms_persp_decompv_lh_no(mat4s proj, float dest[6]) + CGLM_INLINE void glms_persp_decomp_x_lh_no(mat4s proj, float *left, float *right) + CGLM_INLINE void glms_persp_decomp_y_lh_no(mat4s proj, float *top, float *bottom) + CGLM_INLINE void glms_persp_decomp_z_lh_no(mat4s proj, float *nearv, float *farv) + CGLM_INLINE void glms_persp_decomp_far_lh_no(mat4s proj, float *farZ) + CGLM_INLINE void glms_persp_decomp_near_lh_no(mat4s proj, float *nearZ) + CGLM_INLINE float glms_persp_fovy_lh_no(mat4s proj) + CGLM_INLINE float glms_persp_aspect_lh_no(mat4s proj) + CGLM_INLINE vec4s glms_persp_sizes_lh_no(mat4s proj, float fovy) + */ + +#ifndef cglms_persp_lh_no_h +#define cglms_persp_lh_no_h + +#include "../../common.h" +#include "../../types-struct.h" +#include "../../plane.h" +#include "../../cam.h" + +/*! + * @brief set up perspective peprojection matrix + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_frustum_lh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ) { + mat4s dest; + glm_frustum_lh_no(left, right, bottom, top, nearZ, farZ, dest.raw); + return dest; +} + +/*! + * @brief set up perspective projection matrix + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] fovy field of view angle + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping planes + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_perspective_lh_no(float fovy, float aspect, float nearZ, float farZ) { + mat4s dest; + glm_perspective_lh_no(fovy, aspect, nearZ, farZ, dest.raw); + return dest; +} + +/*! + * @brief extend perspective projection matrix's far distance + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * NOTE: if you dodn't want to create new matrix then use array api on struct.raw + * like glms_persp_move_far_lh_no(prooj.raw, deltaFar) to avoid create new mat4 + * each time + * + * this function does not guarantee far >= near, be aware of that! + * + * @param[in, out] proj projection matrix to extend + * @param[in] deltaFar distance from existing far (negative to shink) + */ +CGLM_INLINE +mat4s +glms_persp_move_far_lh_no(mat4s proj, float deltaFar) { + mat4s dest; + dest = proj; + glm_persp_move_far_lh_no(dest.raw, deltaFar); + return dest; +} + +/*! + * @brief set up perspective projection matrix with default near/far + * and angle values with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] aspect aspect ratio ( width / height ) + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_perspective_default_lh_no(float aspect) { + mat4s dest; + glm_perspective_default_lh_no(aspect, dest.raw); + return dest; +} + +/*! + * @brief resize perspective matrix by aspect ratio ( width / height ) + * this makes very easy to resize proj matrix when window /viewport + * reized with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * NOTE: if you dodn't want to create new matrix then use array api on struct.raw + * like glm_perspective_resize_lh_no(proj.raw, aspect) to avoid create new mat4 + * each time + * + * @param[in, out] proj perspective projection matrix + * @param[in] aspect aspect ratio ( width / height ) + */ +CGLM_INLINE +mat4s +glms_perspective_resize_lh_no(mat4s proj, float aspect) { + mat4s dest; + dest = proj; + glm_perspective_resize_lh_no(aspect, dest.raw); + return dest; +} + +/*! + * @brief decomposes frustum values of perspective projection. + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + * @param[out] top top + * @param[out] bottom bottom + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glms_persp_decomp_lh_no(mat4s proj, + float * __restrict nearZ, float * __restrict farZ, + float * __restrict top, float * __restrict bottom, + float * __restrict left, float * __restrict right) { + glm_persp_decomp_lh_no(proj.raw, nearZ, farZ, top, bottom, left, right); +} + +/*! + * @brief decomposes frustum values of perspective projection. + * this makes easy to get all values at once + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] dest array + */ +CGLM_INLINE +void +glms_persp_decompv_lh_no(mat4s proj, float dest[6]) { + glm_persp_decompv_lh_no(proj.raw, dest); +} + +/*! + * @brief decomposes left and right values of perspective projection + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * x stands for x axis (left / right axis) + * + * @param[in] proj perspective projection matrix + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glms_persp_decomp_x_lh_no(mat4s proj, + float * __restrict left, + float * __restrict right) { + glm_persp_decomp_x_lh_no(proj.raw, left, right); +} + +/*! + * @brief decomposes top and bottom values of perspective projection + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * y stands for y axis (top / botom axis) + * + * @param[in] proj perspective projection matrix + * @param[out] top top + * @param[out] bottom bottom + */ +CGLM_INLINE +void +glms_persp_decomp_y_lh_no(mat4s proj, + float * __restrict top, + float * __restrict bottom) { + glm_persp_decomp_y_lh_no(proj.raw, top, bottom); +} + +/*! + * @brief decomposes near and far values of perspective projection + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * z stands for z axis (near / far axis) + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + */ +CGLM_INLINE +void +glms_persp_decomp_z_lh_no(mat4s proj, + float * __restrict nearZ, + float * __restrict farZ) { + glm_persp_decomp_z_lh_no(proj.raw, nearZ, farZ); +} + +/*! + * @brief decomposes far value of perspective projection + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] farZ far + */ +CGLM_INLINE +void +glms_persp_decomp_far_lh_no(mat4s proj, float * __restrict farZ) { + glm_persp_decomp_far_lh_no(proj.raw, farZ); +} + +/*! + * @brief decomposes near value of perspective projection + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + */ +CGLM_INLINE +void +glms_persp_decomp_near_lh_no(mat4s proj, float * __restrict nearZ) { + glm_persp_decomp_near_lh_no(proj.raw, nearZ); +} + +/*! + * @brief returns field of view angle along the Y-axis (in radians) + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * if you need to degrees, use glm_deg to convert it or use this: + * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glms_persp_fovy_lh_no(mat4s proj) { + return glm_persp_fovy_lh_no(proj.raw); +} + +/*! + * @brief returns aspect ratio of perspective projection + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glms_persp_aspect_lh_no(mat4s proj) { + return glm_persp_aspect_lh_no(proj.raw); +} + +/*! + * @brief returns sizes of near and far planes of perspective projection + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + * @param[in] fovy fovy (see brief) + * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar] + */ +CGLM_INLINE +vec4s +glms_persp_sizes_lh_no(mat4s proj, float fovy) { + vec4s dest; + glm_persp_sizes_lh_no(proj.raw, fovy, dest.raw); + return dest; +} + +#endif /* cglms_persp_lh_no_h */ diff --git a/include/cglm/struct/clipspace/persp_lh_zo.h b/include/cglm/struct/clipspace/persp_lh_zo.h new file mode 100644 index 0000000..52f1cc7 --- /dev/null +++ b/include/cglm/struct/clipspace/persp_lh_zo.h @@ -0,0 +1,311 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE mat4s glms_frustum_lh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ) + CGLM_INLINE mat4s glms_perspective_lh_zo(float fovy, + float aspect, + float nearZ, + float farZ) + CGLM_INLINE void glms_persp_move_far_lh_zo(mat4s proj, float deltaFar) + CGLM_INLINE mat4s glms_perspective_default_lh_zo(float aspect) + CGLM_INLINE void glms_perspective_resize_lh_zo(mat4s proj, float aspect) + CGLM_INLINE void glms_persp_decomp_lh_zo(mat4s proj, + float *nearv, float *farv, + float *top, float *bottom, + float *left, float *right) + CGLM_INLINE void glms_persp_decompv_lh_zo(mat4s proj, float dest[6]) + CGLM_INLINE void glms_persp_decomp_x_lh_zo(mat4s proj, float *left, float *right) + CGLM_INLINE void glms_persp_decomp_y_lh_zo(mat4s proj, float *top, float *bottom) + CGLM_INLINE void glms_persp_decomp_z_lh_zo(mat4s proj, float *nearv, float *farv) + CGLM_INLINE void glms_persp_decomp_far_lh_zo(mat4s proj, float *farZ) + CGLM_INLINE void glms_persp_decomp_near_lh_zo(mat4s proj, float *nearZ) + CGLM_INLINE float glms_persp_fovy_lh_zo(mat4s proj) + CGLM_INLINE float glms_persp_aspect_lh_zo(mat4s proj) + CGLM_INLINE vec4s glms_persp_sizes_lh_zo(mat4s proj, float fovy) + */ + +#ifndef cglms_persp_lh_zo_h +#define cglms_persp_lh_zo_h + +#include "../../common.h" +#include "../../types-struct.h" +#include "../../plane.h" +#include "../../cam.h" + +/*! + * @brief set up perspective peprojection matrix + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_frustum_lh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ) { + mat4s dest; + glm_frustum_lh_zo(left, right, bottom, top, nearZ, farZ, dest.raw); + return dest; +} + +/*! + * @brief set up perspective projection matrix + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] fovy field of view angle + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping planes + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_perspective_lh_zo(float fovy, float aspect, float nearZ, float farZ) { + mat4s dest; + glm_perspective_lh_zo(fovy, aspect, nearZ, farZ, dest.raw); + return dest; +} + +/*! + * @brief extend perspective projection matrix's far distance + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * NOTE: if you dodn't want to create new matrix then use array api on struct.raw + * like glms_persp_move_far_lh_zo(prooj.raw, deltaFar) to avoid create new mat4 + * each time + * + * this function does not guarantee far >= near, be aware of that! + * + * @param[in, out] proj projection matrix to extend + * @param[in] deltaFar distance from existing far (negative to shink) + */ +CGLM_INLINE +mat4s +glms_persp_move_far_lh_zo(mat4s proj, float deltaFar) { + mat4s dest; + dest = proj; + glm_persp_move_far_lh_zo(dest.raw, deltaFar); + return dest; +} + +/*! + * @brief set up perspective projection matrix with default near/far + * and angle values with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] aspect aspect ratio ( width / height ) + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_perspective_default_lh_zo(float aspect) { + mat4s dest; + glm_perspective_default_lh_zo(aspect, dest.raw); + return dest; +} + +/*! + * @brief resize perspective matrix by aspect ratio ( width / height ) + * this makes very easy to resize proj matrix when window /viewport + * reized with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * NOTE: if you dodn't want to create new matrix then use array api on struct.raw + * like glms_perspective_resize_lh_zo(proj.raw, aspect) to avoid create new mat4 + * each time + * + * @param[in, out] proj perspective projection matrix + * @param[in] aspect aspect ratio ( width / height ) + */ +CGLM_INLINE +mat4s +glms_perspective_resize_lh_zo(mat4s proj, float aspect) { + mat4s dest; + dest = proj; + glm_perspective_resize_lh_zo(aspect, dest.raw); + return dest; +} + +/*! + * @brief decomposes frustum values of perspective projection. + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + * @param[out] top top + * @param[out] bottom bottom + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glms_persp_decomp_lh_zo(mat4s proj, + float * __restrict nearZ, float * __restrict farZ, + float * __restrict top, float * __restrict bottom, + float * __restrict left, float * __restrict right) { + glm_persp_decomp_lh_zo(proj.raw, nearZ, farZ, top, bottom, left, right); +} + +/*! + * @brief decomposes frustum values of perspective projection. + * this makes easy to get all values at once + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] dest array + */ +CGLM_INLINE +void +glms_persp_decompv_lh_zo(mat4s proj, float dest[6]) { + glm_persp_decompv_lh_zo(proj.raw, dest); +} + +/*! + * @brief decomposes left and right values of perspective projection + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * x stands for x axis (left / right axis) + * + * @param[in] proj perspective projection matrix + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glms_persp_decomp_x_lh_zo(mat4s proj, + float * __restrict left, + float * __restrict right) { + glm_persp_decomp_x_lh_zo(proj.raw, left, right); +} + +/*! + * @brief decomposes top and bottom values of perspective projection + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * y stands for y axis (top / botom axis) + * + * @param[in] proj perspective projection matrix + * @param[out] top top + * @param[out] bottom bottom + */ +CGLM_INLINE +void +glms_persp_decomp_y_lh_zo(mat4s proj, + float * __restrict top, + float * __restrict bottom) { + glm_persp_decomp_y_lh_zo(proj.raw, top, bottom); +} + +/*! + * @brief decomposes near and far values of perspective projection + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * z stands for z axis (near / far axis) + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + */ +CGLM_INLINE +void +glms_persp_decomp_z_lh_zo(mat4s proj, + float * __restrict nearZ, + float * __restrict farZ) { + glm_persp_decomp_z_lh_zo(proj.raw, nearZ, farZ); +} + +/*! + * @brief decomposes far value of perspective projection + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] farZ far + */ +CGLM_INLINE +void +glms_persp_decomp_far_lh_zo(mat4s proj, float * __restrict farZ) { + glm_persp_decomp_far_lh_zo(proj.raw, farZ); +} + +/*! + * @brief decomposes near value of perspective projection + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + */ +CGLM_INLINE +void +glms_persp_decomp_near_lh_zo(mat4s proj, float * __restrict nearZ) { + glm_persp_decomp_near_lh_zo(proj.raw, nearZ); +} + +/*! + * @brief returns field of view angle along the Y-axis (in radians) + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * if you need to degrees, use glm_deg to convert it or use this: + * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glms_persp_fovy_lh_zo(mat4s proj) { + return glm_persp_fovy_lh_zo(proj.raw); +} + +/*! + * @brief returns aspect ratio of perspective projection + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glms_persp_aspect_lh_zo(mat4s proj) { + return glm_persp_aspect_lh_zo(proj.raw); +} + +/*! + * @brief returns sizes of near and far planes of perspective projection + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + * @param[in] fovy fovy (see brief) + * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar] + */ +CGLM_INLINE +vec4s +glms_persp_sizes_lh_zo(mat4s proj, float fovy) { + vec4s dest; + glm_persp_sizes_lh_zo(proj.raw, fovy, dest.raw); + return dest; +} + +#endif /* cglms_persp_lh_zo_h */ diff --git a/include/cglm/struct/clipspace/persp_rh_no.h b/include/cglm/struct/clipspace/persp_rh_no.h new file mode 100644 index 0000000..d382bcf --- /dev/null +++ b/include/cglm/struct/clipspace/persp_rh_no.h @@ -0,0 +1,311 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE mat4s glms_frustum_rh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ) + CGLM_INLINE mat4s glms_perspective_rh_no(float fovy, + float aspect, + float nearZ, + float farZ) + CGLM_INLINE void glms_persp_move_far_rh_no(mat4s proj, float deltaFar) + CGLM_INLINE mat4s glms_perspective_default_rh_no(float aspect) + CGLM_INLINE void glms_perspective_resize_rh_no(mat4s proj, float aspect) + CGLM_INLINE void glms_persp_decomp_rh_no(mat4s proj, + float *nearv, float *farv, + float *top, float *bottom, + float *left, float *right) + CGLM_INLINE void glms_persp_decompv_rh_no(mat4s proj, float dest[6]) + CGLM_INLINE void glms_persp_decomp_x_rh_no(mat4s proj, float *left, float *right) + CGLM_INLINE void glms_persp_decomp_y_rh_no(mat4s proj, float *top, float *bottom) + CGLM_INLINE void glms_persp_decomp_z_rh_no(mat4s proj, float *nearv, float *farv) + CGLM_INLINE void glms_persp_decomp_far_rh_no(mat4s proj, float *farZ) + CGLM_INLINE void glms_persp_decomp_near_rh_no(mat4s proj, float *nearZ) + CGLM_INLINE float glms_persp_fovy_rh_no(mat4s proj) + CGLM_INLINE float glms_persp_aspect_rh_no(mat4s proj) + CGLM_INLINE vec4s glms_persp_sizes_rh_no(mat4s proj, float fovy) + */ + +#ifndef cglms_persp_rh_no_h +#define cglms_persp_rh_no_h + +#include "../../common.h" +#include "../../types-struct.h" +#include "../../plane.h" +#include "../../cam.h" + +/*! + * @brief set up perspective peprojection matrix + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_frustum_rh_no(float left, float right, + float bottom, float top, + float nearZ, float farZ) { + mat4s dest; + glm_frustum_rh_no(left, right, bottom, top, nearZ, farZ, dest.raw); + return dest; +} + +/*! + * @brief set up perspective projection matrix + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] fovy field of view angle + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping planes + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_perspective_rh_no(float fovy, float aspect, float nearZ, float farZ) { + mat4s dest; + glm_perspective_rh_no(fovy, aspect, nearZ, farZ, dest.raw); + return dest; +} + +/*! + * @brief extend perspective projection matrix's far distance + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * NOTE: if you dodn't want to create new matrix then use array api on struct.raw + * like glms_persp_move_far_rh_no(prooj.raw, deltaFar) to avoid create new mat4 + * each time + * s + * this function does not guarantee far >= near, be aware of that! + * + * @param[in, out] proj projection matrix to extend + * @param[in] deltaFar distance from existing far (negative to shink) + */ +CGLM_INLINE +mat4s +glms_persp_move_far_rh_no(mat4s proj, float deltaFar) { + mat4s dest; + dest = proj; + glm_persp_move_far_rh_no(dest.raw, deltaFar); + return dest; +} + +/*! + * @brief set up perspective projection matrix with default near/far + * and angle values with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] aspect aspect ratio ( width / height ) + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_perspective_default_rh_no(float aspect) { + mat4s dest; + glm_perspective_default_rh_no(aspect, dest.raw); + return dest; +} + +/*! + * @brief resize perspective matrix by aspect ratio ( width / height ) + * this makes very easy to resize proj matrix when window /viewport + * reized with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * NOTE: if you dodn't want to create new matrix then use array api on struct.raw + * like glm_perspective_resize_rh_no(proj.raw, aspect) to avoid create new mat4 + * each time + * + * @param[in, out] proj perspective projection matrix + * @param[in] aspect aspect ratio ( width / height ) + */ +CGLM_INLINE +mat4s +glms_perspective_resize_rh_no(mat4s proj, float aspect) { + mat4s dest; + dest = proj; + glm_perspective_resize_rh_no(aspect, dest.raw); + return dest; +} + +/*! + * @brief decomposes frustum values of perspective projection. + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + * @param[out] top top + * @param[out] bottom bottom + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glms_persp_decomp_rh_no(mat4s proj, + float * __restrict nearZ, float * __restrict farZ, + float * __restrict top, float * __restrict bottom, + float * __restrict left, float * __restrict right) { + glm_persp_decomp_rh_no(proj.raw, nearZ, farZ, top, bottom, left, right); +} + +/*! + * @brief decomposes frustum values of perspective projection. + * this makes easy to get all values at once + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] dest array + */ +CGLM_INLINE +void +glms_persp_decompv_rh_no(mat4s proj, float dest[6]) { + glm_persp_decompv_rh_no(proj.raw, dest); +} + +/*! + * @brief decomposes left and right values of perspective projection + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * x stands for x axis (left / right axis) + * + * @param[in] proj perspective projection matrix + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glms_persp_decomp_x_rh_no(mat4s proj, + float * __restrict left, + float * __restrict right) { + glm_persp_decomp_x_rh_no(proj.raw, left, right); +} + +/*! + * @brief decomposes top and bottom values of perspective projection + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * y stands for y axis (top / botom axis) + * + * @param[in] proj perspective projection matrix + * @param[out] top top + * @param[out] bottom bottom + */ +CGLM_INLINE +void +glms_persp_decomp_y_rh_no(mat4s proj, + float * __restrict top, + float * __restrict bottom) { + glm_persp_decomp_y_rh_no(proj.raw, top, bottom); +} + +/*! + * @brief decomposes near and far values of perspective projection + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * z stands for z axis (near / far axis) + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + */ +CGLM_INLINE +void +glms_persp_decomp_z_rh_no(mat4s proj, + float * __restrict nearZ, + float * __restrict farZ) { + glm_persp_decomp_z_rh_no(proj.raw, nearZ, farZ); +} + +/*! + * @brief decomposes far value of perspective projection + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] farZ far + */ +CGLM_INLINE +void +glms_persp_decomp_far_rh_no(mat4s proj, float * __restrict farZ) { + glm_persp_decomp_far_rh_no(proj.raw, farZ); +} + +/*! + * @brief decomposes near value of perspective projection + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + */ +CGLM_INLINE +void +glms_persp_decomp_near_rh_no(mat4s proj, float * __restrict nearZ) { + glm_persp_decomp_near_rh_no(proj.raw, nearZ); +} + +/*! + * @brief returns field of view angle along the Y-axis (in radians) + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * if you need to degrees, use glm_deg to convert it or use this: + * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glms_persp_fovy_rh_no(mat4s proj) { + return glm_persp_fovy_rh_no(proj.raw); +} + +/*! + * @brief returns aspect ratio of perspective projection + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glms_persp_aspect_rh_no(mat4s proj) { + return glm_persp_aspect_rh_no(proj.raw); +} + +/*! + * @brief returns sizes of near and far planes of perspective projection + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * @param[in] proj perspective projection matrix + * @param[in] fovy fovy (see brief) + * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar] + */ +CGLM_INLINE +vec4s +glms_persp_sizes_rh_no(mat4s proj, float fovy) { + vec4s dest; + glm_persp_sizes_rh_no(proj.raw, fovy, dest.raw); + return dest; +} + +#endif /* cglms_persp_rh_no_h */ diff --git a/include/cglm/struct/clipspace/persp_rh_zo.h b/include/cglm/struct/clipspace/persp_rh_zo.h new file mode 100644 index 0000000..ca14402 --- /dev/null +++ b/include/cglm/struct/clipspace/persp_rh_zo.h @@ -0,0 +1,311 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE mat4s glms_frustum_rh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ) + CGLM_INLINE mat4s glms_perspective_rh_zo(float fovy, + float aspect, + float nearZ, + float farZ) + CGLM_INLINE void glms_persp_move_far_rh_zo(mat4s proj, float deltaFar) + CGLM_INLINE mat4s glms_perspective_default_rh_zo(float aspect) + CGLM_INLINE void glms_perspective_resize_rh_zo(mat4s proj, float aspect) + CGLM_INLINE void glms_persp_decomp_rh_zo(mat4s proj, + float *nearv, float *farv, + float *top, float *bottom, + float *left, float *right) + CGLM_INLINE void glms_persp_decompv_rh_zo(mat4s proj, float dest[6]) + CGLM_INLINE void glms_persp_decomp_x_rh_zo(mat4s proj, float *left, float *right) + CGLM_INLINE void glms_persp_decomp_y_rh_zo(mat4s proj, float *top, float *bottom) + CGLM_INLINE void glms_persp_decomp_z_rh_zo(mat4s proj, float *nearv, float *farv) + CGLM_INLINE void glms_persp_decomp_far_rh_zo(mat4s proj, float *farZ) + CGLM_INLINE void glms_persp_decomp_near_rh_zo(mat4s proj, float *nearZ) + CGLM_INLINE float glms_persp_fovy_rh_zo(mat4s proj) + CGLM_INLINE float glms_persp_aspect_rh_zo(mat4s proj) + CGLM_INLINE vec4s glms_persp_sizes_rh_zo(mat4s proj, float fovy) + */ + +#ifndef cglms_persp_rh_zo_h +#define cglms_persp_rh_zo_h + +#include "../../common.h" +#include "../../types-struct.h" +#include "../../plane.h" +#include "../../cam.h" + +/*! + * @brief set up perspective peprojection matrix + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] left viewport.left + * @param[in] right viewport.right + * @param[in] bottom viewport.bottom + * @param[in] top viewport.top + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping plane + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_frustum_rh_zo(float left, float right, + float bottom, float top, + float nearZ, float farZ) { + mat4s dest; + glm_frustum_rh_zo(left, right, bottom, top, nearZ, farZ, dest.raw); + return dest; +} + +/*! + * @brief set up perspective projection matrix + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] fovy field of view angle + * @param[in] aspect aspect ratio ( width / height ) + * @param[in] nearZ near clipping plane + * @param[in] farZ far clipping planes + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_perspective_rh_zo(float fovy, float aspect, float nearZ, float farZ) { + mat4s dest; + glm_perspective_rh_zo(fovy, aspect, nearZ, farZ, dest.raw); + return dest; +} + +/*! + * @brief extend perspective projection matrix's far distance + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * NOTE: if you dodn't want to create new matrix then use array api on struct.raw + * like glms_persp_move_far_rh_zo(prooj.raw, deltaFar) to avoid create new mat4 + * each time + * + * this function does not guarantee far >= near, be aware of that! + * + * @param[in, out] proj projection matrix to extend + * @param[in] deltaFar distance from existing far (negative to shink) + */ +CGLM_INLINE +mat4s +glms_persp_move_far_rh_zo(mat4s proj, float deltaFar) { + mat4s dest; + dest = proj; + glm_persp_move_far_rh_zo(dest.raw, deltaFar); + return dest; +} + +/*! + * @brief set up perspective projection matrix with default near/far + * and angle values with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] aspect aspect ratio ( width / height ) + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_perspective_default_rh_zo(float aspect) { + mat4s dest; + glm_perspective_default_rh_zo(aspect, dest.raw); + return dest; +} + +/*! + * @brief resize perspective matrix by aspect ratio ( width / height ) + * this makes very easy to resize proj matrix when window /viewport + * reized with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * NOTE: if you dodn't want to create new matrix then use array api on struct.raw + * like glm_perspective_resize_rh_zo(proj.raw, aspect) to avoid create new mat4 + * each time + * + * @param[in, out] proj perspective projection matrix + * @param[in] aspect aspect ratio ( width / height ) + */ +CGLM_INLINE +mat4s +glms_perspective_resize_rh_zo(mat4s proj, float aspect) { + mat4s dest; + dest = proj; + glm_perspective_resize_rh_zo(aspect, dest.raw); + return dest; +} + +/*! + * @brief decomposes frustum values of perspective projection. + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + * @param[out] top top + * @param[out] bottom bottom + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glms_persp_decomp_rh_zo(mat4s proj, + float * __restrict nearZ, float * __restrict farZ, + float * __restrict top, float * __restrict bottom, + float * __restrict left, float * __restrict right) { + glm_persp_decomp_rh_zo(proj.raw, nearZ, farZ, top, bottom, left, right); +} + +/*! + * @brief decomposes frustum values of perspective projection. + * this makes easy to get all values at once + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] dest array + */ +CGLM_INLINE +void +glms_persp_decompv_rh_zo(mat4s proj, float dest[6]) { + glm_persp_decompv_rh_zo(proj.raw, dest); +} + +/*! + * @brief decomposes left and right values of perspective projection + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * x stands for x axis (left / right axis) + * + * @param[in] proj perspective projection matrix + * @param[out] left left + * @param[out] right right + */ +CGLM_INLINE +void +glms_persp_decomp_x_rh_zo(mat4s proj, + float * __restrict left, + float * __restrict right) { + glm_persp_decomp_x_rh_zo(proj.raw, left, right); +} + +/*! + * @brief decomposes top and bottom values of perspective projection + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * y stands for y axis (top / botom axis) + * + * @param[in] proj perspective projection matrix + * @param[out] top top + * @param[out] bottom bottom + */ +CGLM_INLINE +void +glms_persp_decomp_y_rh_zo(mat4s proj, + float * __restrict top, + float * __restrict bottom) { + glm_persp_decomp_y_rh_zo(proj.raw, top, bottom); +} + +/*! + * @brief decomposes near and far values of perspective projection + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * z stands for z axis (near / far axis) + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + * @param[out] farZ far + */ +CGLM_INLINE +void +glms_persp_decomp_z_rh_zo(mat4s proj, + float * __restrict nearZ, + float * __restrict farZ) { + glm_persp_decomp_z_rh_zo(proj.raw, nearZ, farZ); +} + +/*! + * @brief decomposes far value of perspective projection + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] farZ far + */ +CGLM_INLINE +void +glms_persp_decomp_far_rh_zo(mat4s proj, float * __restrict farZ) { + glm_persp_decomp_far_rh_zo(proj.raw, farZ); +} + +/*! + * @brief decomposes near value of perspective projection + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + * @param[out] nearZ near + */ +CGLM_INLINE +void +glms_persp_decomp_near_rh_zo(mat4s proj, float * __restrict nearZ) { + glm_persp_decomp_near_rh_zo(proj.raw, nearZ); +} + +/*! + * @brief returns field of view angle along the Y-axis (in radians) + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * if you need to degrees, use glm_deg to convert it or use this: + * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glms_persp_fovy_rh_zo(mat4s proj) { + return glm_persp_fovy_rh_zo(proj.raw); +} + +/*! + * @brief returns aspect ratio of perspective projection + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + */ +CGLM_INLINE +float +glms_persp_aspect_rh_zo(mat4s proj) { + return glm_persp_aspect_rh_zo(proj.raw); +} + +/*! + * @brief returns sizes of near and far planes of perspective projection + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * @param[in] proj perspective projection matrix + * @param[in] fovy fovy (see brief) + * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar] + */ +CGLM_INLINE +vec4s +glms_persp_sizes_rh_zo(mat4s proj, float fovy) { + vec4s dest; + glm_persp_sizes_rh_zo(proj.raw, fovy, dest.raw); + return dest; +} + +#endif /* cglms_persp_rh_zo_h */ diff --git a/include/cglm/struct/clipspace/project_no.h b/include/cglm/struct/clipspace/project_no.h new file mode 100644 index 0000000..a12fb61 --- /dev/null +++ b/include/cglm/struct/clipspace/project_no.h @@ -0,0 +1,96 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE vec3s glms_unprojecti_no(vec3s pos, mat4s invMat, vec4s vp, vec3 dest) + CGLM_INLINE vec3s glms_project_no(vec3s pos, mat4s m, vec4s vp, vec3s dest) + */ + +#ifndef cglms_project_no_h +#define cglms_project_no_h + +#include "../../common.h" +#include "../../types-struct.h" +#include "../../plane.h" +#include "../../cam.h" + +/*! + * @brief maps the specified viewport coordinates into specified space [1] + * the matrix should contain projection matrix. + * + * if you don't have ( and don't want to have ) an inverse matrix then use + * glm_unproject version. You may use existing inverse of matrix in somewhere + * else, this is why glm_unprojecti exists to save save inversion cost + * + * [1] space: + * 1- if m = invProj: View Space + * 2- if m = invViewProj: World Space + * 3- if m = invMVP: Object Space + * + * You probably want to map the coordinates into object space + * so use invMVP as m + * + * Computing viewProj: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * glm_mat4_inv(viewProj, invMVP); + * + * @param[in] pos point/position in viewport coordinates + * @param[in] invMat matrix (see brief) + * @param[in] vp viewport as [x, y, width, height] + * + * @returns unprojected coordinates + */ +CGLM_INLINE +vec3s +glms_unprojecti_no(vec3s pos, mat4s invMat, vec4s vp, vec3 dest) { + vec3s dest; + glm_unprojecti_no(pos.raw, invMat.raw, vp.raw, dest.raw); + return dest; +} + +/*! + * @brief map object coordinates to window coordinates + * + * Computing MVP: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * + * @param[in] pos object coordinates + * @param[in] m MVP matrix + * @param[in] vp viewport as [x, y, width, height] + * + * @returns projected coordinates + */ +CGLM_INLINE +vec3s +glms_project_no(vec3s pos, mat4s m, vec4s vp, vec3s dest) { + vec3s dest; + glm_project_no(pos.raw, m.raw, vp.raw, dest.raw); + return dest; +} + +/*! + * @brief map object's z coordinate to window coordinates + * + * Computing MVP: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * + * @param[in] v object coordinates + * @param[in] m MVP matrix + * + * @returns projected z coordinate + */ +CGLM_INLINE +vec3s +glms_project_z_no(vec3s v, mat4s m) { + return glm_project_z_no(v.raw, m.raw); +} + +#endif /* cglms_project_rh_no_h */ diff --git a/include/cglm/struct/clipspace/project_zo.h b/include/cglm/struct/clipspace/project_zo.h new file mode 100644 index 0000000..c510396 --- /dev/null +++ b/include/cglm/struct/clipspace/project_zo.h @@ -0,0 +1,96 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE vec3s glms_unprojecti_no(vec3s pos, mat4s invMat, vec4s vp, vec3 dest) + CGLM_INLINE vec3s glms_project_no(vec3s pos, mat4s m, vec4s vp, vec3s dest) + */ + +#ifndef cglms_project_zo_h +#define cglms_project_zo_h + +#include "../../common.h" +#include "../../types-struct.h" +#include "../../plane.h" +#include "../../cam.h" + +/*! + * @brief maps the specified viewport coordinates into specified space [1] + * the matrix should contain projection matrix. + * + * if you don't have ( and don't want to have ) an inverse matrix then use + * glm_unproject version. You may use existing inverse of matrix in somewhere + * else, this is why glm_unprojecti exists to save save inversion cost + * + * [1] space: + * 1- if m = invProj: View Space + * 2- if m = invViewProj: World Space + * 3- if m = invMVP: Object Space + * + * You probably want to map the coordinates into object space + * so use invMVP as m + * + * Computing viewProj: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * glm_mat4_inv(viewProj, invMVP); + * + * @param[in] pos point/position in viewport coordinates + * @param[in] invMat matrix (see brief) + * @param[in] vp viewport as [x, y, width, height] + * + * @returns unprojected coordinates + */ +CGLM_INLINE +vec3s +glms_unprojecti_zo(vec3s pos, mat4s invMat, vec4s vp, vec3 dest) { + vec3s dest; + glm_unprojecti_zo(pos.raw, invMat.raw, vp.raw, dest.raw); + return dest; +} + +/*! + * @brief map object coordinates to window coordinates + * + * Computing MVP: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * + * @param[in] pos object coordinates + * @param[in] m MVP matrix + * @param[in] vp viewport as [x, y, width, height] + * + * @returns projected coordinates + */ +CGLM_INLINE +vec3s +glms_project_zo(vec3s pos, mat4s m, vec4s vp, vec3 dest) { + vec3s dest; + glm_project_zo(pos.raw, m.raw, vp.raw, dest.raw); + return dest; +} + +/*! + * @brief map object's z coordinate to window coordinates + * + * Computing MVP: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * + * @param[in] v object coordinates + * @param[in] m MVP matrix + * + * @returns projected z coordinate + */ +CGLM_INLINE +vec3s +glms_project_z_zo(vec3s v, mat4s m) { + return glm_project_z_zo(v.raw, m.raw); +} + +#endif /* cglm_project_zo_h */ diff --git a/include/cglm/struct/clipspace/view_lh_no.h b/include/cglm/struct/clipspace/view_lh_no.h new file mode 100644 index 0000000..cd8b5d9 --- /dev/null +++ b/include/cglm/struct/clipspace/view_lh_no.h @@ -0,0 +1,88 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE mat4s glms_lookat_lh_no(vec3s eye, vec3s center, vec3s up) + CGLM_INLINE mat4s glms_look_lh_no(vec3s eye, vec3s dir, vec3s up) + CGLM_INLINE mat4s glms_look_anyup_lh_no(vec3s eye, vec3s dir) + */ + +#ifndef cglms_view_lh_no_h +#define cglms_view_lh_no_h + +#include "../../common.h" +#include "../../types-struct.h" +#include "../../plane.h" +#include "../../cam.h" + +/*! + * @brief set up view matrix + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] center center vector + * @param[in] up up vector + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_lookat_lh_no(vec3s eye, vec3s center, vec3s up) { + mat4s dest; + glm_lookat_lh_no(eye.raw, center.raw, up.raw, dest.raw); + return dest; +} + +/*! + * @brief set up view matrix + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * convenient wrapper for lookat: if you only have direction not target self + * then this might be useful. Because you need to get target from direction. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[in] up up vector + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_look_lh_no(vec3s eye, vec3s dir, vec3s up) { + mat4s dest; + glm_look_lh_no(eye.raw, dir.raw, up.raw, dest.raw); + return dest; +} + +/*! + * @brief set up view matrix + * with a left-hand coordinate system and a + * clip-space of [-1, 1]. + * + * convenient wrapper for look: if you only have direction and if you don't + * care what UP vector is then this might be useful to create view matrix + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_look_anyup_lh_no(vec3s eye, vec3s dir) { + mat4s dest; + glm_look_anyup_lh_no(eye.raw, dir.raw, dest.raw); + return dest; +} + +#endif /* cglms_view_lh_no_h */ diff --git a/include/cglm/struct/clipspace/view_lh_zo.h b/include/cglm/struct/clipspace/view_lh_zo.h new file mode 100644 index 0000000..e2f5f5c --- /dev/null +++ b/include/cglm/struct/clipspace/view_lh_zo.h @@ -0,0 +1,88 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE mat4s glms_lookat_lh_zo(vec3s eye, vec3s center, vec3s up) + CGLM_INLINE mat4s glms_look_lh_zo(vec3s eye, vec3s dir, vec3s up) + CGLM_INLINE mat4s glms_look_anyup_lh_zo(vec3s eye, vec3s dir) + */ + +#ifndef cglms_view_lh_zo_h +#define cglms_view_lh_zo_h + +#include "../../common.h" +#include "../../types-struct.h" +#include "../../plane.h" +#include "../../cam.h" + +/*! + * @brief set up view matrix + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] center center vector + * @param[in] up up vector + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_lookat_lh_zo(vec3s eye, vec3s center, vec3s up) { + mat4s dest; + glm_lookat_lh_zo(eye.raw, center.raw, up.raw, dest.raw); + return dest; +} + +/*! + * @brief set up view matrix + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * convenient wrapper for lookat: if you only have direction not target self + * then this might be useful. Because you need to get target from direction. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[in] up up vector + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_look_lh_zo(vec3s eye, vec3s dir, vec3s up) { + mat4s dest; + glm_look_lh_zo(eye.raw, dir.raw, up.raw, dest.raw); + return dest; +} + +/*! + * @brief set up view matrix + * with a left-hand coordinate system and a + * clip-space of [0, 1]. + * + * convenient wrapper for look: if you only have direction and if you don't + * care what UP vector is then this might be useful to create view matrix + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_look_anyup_lh_zo(vec3s eye, vec3s dir) { + mat4s dest; + glm_look_anyup_lh_zo(eye.raw, dir.raw, dest.raw); + return dest; +} + +#endif /* cglms_view_lh_zo_h */ diff --git a/include/cglm/struct/clipspace/view_rh_no.h b/include/cglm/struct/clipspace/view_rh_no.h new file mode 100644 index 0000000..e49e735 --- /dev/null +++ b/include/cglm/struct/clipspace/view_rh_no.h @@ -0,0 +1,88 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE mat4s glms_lookat_rh_no(vec3s eye, vec3s center, vec3s up) + CGLM_INLINE mat4s glms_look_rh_no(vec3s eye, vec3s dir, vec3s up) + CGLM_INLINE mat4s glms_look_anyup_rh_no(vec3s eye, vec3s dir) + */ + +#ifndef cglms_view_rh_no_h +#define cglms_view_rh_no_h + +#include "../../common.h" +#include "../../types-struct.h" +#include "../../plane.h" +#include "../../cam.h" + +/*! + * @brief set up view matrix + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] center center vector + * @param[in] up up vector + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_lookat_rh_no(vec3s eye, vec3s center, vec3s up) { + mat4s dest; + glm_lookat_rh_no(eye.raw, center.raw, up.raw, dest.raw); + return dest; +} + +/*! + * @brief set up view matrix + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * convenient wrapper for lookat: if you only have direction not target self + * then this might be useful. Because you need to get target from direction. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[in] up up vector + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_look_rh_no(vec3s eye, vec3s dir, vec3s up) { + mat4s dest; + glm_look_rh_no(eye.raw, dir.raw, up.raw, dest.raw); + return dest; +} + +/*! + * @brief set up view matrix + * with a right-hand coordinate system and a + * clip-space of [-1, 1]. + * + * convenient wrapper for look: if you only have direction and if you don't + * care what UP vector is then this might be useful to create view matrix + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_look_anyup_rh_no(vec3s eye, vec3s dir) { + mat4s dest; + glm_look_anyup_rh_no(eye.raw, dir.raw, dest.raw); + return dest; +} + +#endif /* cglms_view_rh_no_h */ diff --git a/include/cglm/struct/clipspace/view_rh_zo.h b/include/cglm/struct/clipspace/view_rh_zo.h new file mode 100644 index 0000000..1347522 --- /dev/null +++ b/include/cglm/struct/clipspace/view_rh_zo.h @@ -0,0 +1,88 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE mat4s glms_lookat_rh_zo(vec3s eye, vec3s center, vec3s up) + CGLM_INLINE mat4s glms_look_rh_zo(vec3s eye, vec3s dir, vec3s up) + CGLM_INLINE mat4s glms_look_anyup_rh_zo(vec3s eye, vec3s dir) + */ + +#ifndef cglms_view_rh_zo_h +#define cglms_view_rh_zo_h + +#include "../../common.h" +#include "../../types-struct.h" +#include "../../plane.h" +#include "../../cam.h" + +/*! + * @brief set up view matrix + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] center center vector + * @param[in] up up vector + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_lookat_rh_zo(vec3s eye, vec3s center, vec3s up) { + mat4s dest; + glm_lookat_rh_zo(eye.raw, center.raw, up.raw, dest.raw); + return dest; +} + +/*! + * @brief set up view matrix + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * convenient wrapper for lookat: if you only have direction not target self + * then this might be useful. Because you need to get target from direction. + * + * NOTE: The UP vector must not be parallel to the line of sight from + * the eye point to the reference point + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @param[in] up up vector + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_look_rh_zo(vec3s eye, vec3s dir, vec3s up) { + mat4s dest; + glm_look_rh_zo(eye.raw, dir.raw, up.raw, dest.raw); + return dest; +} + +/*! + * @brief set up view matrix + * with a right-hand coordinate system and a + * clip-space of [0, 1]. + * + * convenient wrapper for look: if you only have direction and if you don't + * care what UP vector is then this might be useful to create view matrix + * + * @param[in] eye eye vector + * @param[in] dir direction vector + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_look_anyup_rh_zo(vec3s eye, vec3s dir) { + mat4s dest; + glm_look_anyup_rh_zo(eye.raw, dir.raw, dest.raw); + return dest; +} + +#endif /* cglms_view_rh_zo_h */ diff --git a/include/cglm/struct/color.h b/include/cglm/struct/color.h new file mode 100644 index 0000000..3ce78da --- /dev/null +++ b/include/cglm/struct/color.h @@ -0,0 +1,27 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglms_colors_h +#define cglms_colors_h + +#include "../common.h" +#include "../types-struct.h" +#include "../color.h" +#include "vec3.h" + +/*! + * @brief averages the color channels into one value + * + * @param[in] rgb RGB color + */ +CGLM_INLINE +float +glms_luminance(vec3s rgb) { + return glm_luminance(rgb.raw); +} + +#endif /* cglms_colors_h */ diff --git a/include/cglm/struct/curve.h b/include/cglm/struct/curve.h new file mode 100644 index 0000000..53ea359 --- /dev/null +++ b/include/cglm/struct/curve.h @@ -0,0 +1,40 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglms_curves_h +#define cglms_curves_h + +#include "../common.h" +#include "../types-struct.h" +#include "../curve.h" +#include "vec4.h" +#include "mat4.h" + +/*! + * @brief helper function to calculate S*M*C multiplication for curves + * + * This function does not encourage you to use SMC, + * instead it is a helper if you use SMC. + * + * if you want to specify S as vector then use more generic glm_mat4_rmc() func. + * + * Example usage: + * B(s) = glm_smc(s, GLM_BEZIER_MAT, (vec4){p0, c0, c1, p1}) + * + * @param[in] s parameter between 0 and 1 (this will be [s3, s2, s, 1]) + * @param[in] m basis matrix + * @param[in] c position/control vector + * + * @return B(s) + */ +CGLM_INLINE +float +glms_smc(float s, mat4s m, vec4s c) { + return glm_smc(s, m.raw, c.raw); +} + +#endif /* cglms_curves_h */ diff --git a/include/cglm/struct/euler.h b/include/cglm/struct/euler.h new file mode 100644 index 0000000..6575930 --- /dev/null +++ b/include/cglm/struct/euler.h @@ -0,0 +1,152 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + NOTE: + angles must be passed as [X-Angle, Y-Angle, Z-angle] order + For instance you don't pass angles as [Z-Angle, X-Angle, Y-angle] to + glm_euler_zxy funciton, All RELATED functions accept angles same order + which is [X, Y, Z]. + */ + +/* + Types: + enum glm_euler_seq + + Functions: + CGLM_INLINE vec3s glms_euler_angles(mat4s m) + CGLM_INLINE mat4s glms_euler_xyz(vec3s angles) + CGLM_INLINE mat4s glms_euler_xzy(vec3s angles) + CGLM_INLINE mat4s glms_euler_yxz(vec3s angles) + CGLM_INLINE mat4s glms_euler_yzx(vec3s angles) + CGLM_INLINE mat4s glms_euler_zxy(vec3s angles) + CGLM_INLINE mat4s glms_euler_zyx(vec3s angles) + CGLM_INLINE mat4s glms_euler_by_order(vec3s angles, glm_euler_seq ord) + */ + +#ifndef cglms_euler_h +#define cglms_euler_h + +#include "../common.h" +#include "../types-struct.h" +#include "../euler.h" + +/*! + * @brief extract euler angles (in radians) using xyz order + * + * @param[in] m affine transform + * @returns angles vector [x, y, z] + */ +CGLM_INLINE +vec3s +glms_euler_angles(mat4s m) { + vec3s dest; + glm_euler_angles(m.raw, dest.raw); + return dest; +} + +/*! + * @brief build rotation matrix from euler angles + * + * @param[in] angles angles as vector [Xangle, Yangle, Zangle] + * @returns rotation matrix + */ +CGLM_INLINE +mat4s +glms_euler_xyz(vec3s angles) { + mat4s dest; + glm_euler_xyz(angles.raw, dest.raw); + return dest; +} + +/*! + * @brief build rotation matrix from euler angles + * + * @param[in] angles angles as vector [Xangle, Yangle, Zangle] + * @returns rotation matrix + */ +CGLM_INLINE +mat4s +glms_euler_xzy(vec3s angles) { + mat4s dest; + glm_euler_xzy(angles.raw, dest.raw); + return dest; +} + + +/*! + * @brief build rotation matrix from euler angles + * + * @param[in] angles angles as vector [Xangle, Yangle, Zangle] + * @returns rotation matrix + */ +CGLM_INLINE +mat4s +glms_euler_yxz(vec3s angles) { + mat4s dest; + glm_euler_yxz(angles.raw, dest.raw); + return dest; +} + +/*! + * @brief build rotation matrix from euler angles + * + * @param[in] angles angles as vector [Xangle, Yangle, Zangle] + * @returns rotation matrix + */ +CGLM_INLINE +mat4s +glms_euler_yzx(vec3s angles) { + mat4s dest; + glm_euler_yzx(angles.raw, dest.raw); + return dest; +} + +/*! + * @brief build rotation matrix from euler angles + * + * @param[in] angles angles as vector [Xangle, Yangle, Zangle] + * @returns rotation matrix + */ +CGLM_INLINE +mat4s +glms_euler_zxy(vec3s angles) { + mat4s dest; + glm_euler_zxy(angles.raw, dest.raw); + return dest; +} + +/*! + * @brief build rotation matrix from euler angles + * + * @param[in] angles angles as vector [Xangle, Yangle, Zangle] + * @returns rotation matrix + */ +CGLM_INLINE +mat4s +glms_euler_zyx(vec3s angles) { + mat4s dest; + glm_euler_zyx(angles.raw, dest.raw); + return dest; +} + +/*! + * @brief build rotation matrix from euler angles + * + * @param[in] angles angles as vector [Xangle, Yangle, Zangle] + * @param[in] ord euler order + * @returns rotation matrix + */ +CGLM_INLINE +mat4s +glms_euler_by_order(vec3s angles, glm_euler_seq ord) { + mat4s dest; + glm_euler_by_order(angles.raw, ord, dest.raw); + return dest; +} + +#endif /* cglms_euler_h */ diff --git a/include/cglm/struct/frustum.h b/include/cglm/struct/frustum.h new file mode 100644 index 0000000..2c51d6d --- /dev/null +++ b/include/cglm/struct/frustum.h @@ -0,0 +1,155 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglms_frustums_h +#define cglms_frustums_h + +#include "../common.h" +#include "../types-struct.h" +#include "../frustum.h" +#include "plane.h" +#include "vec3.h" +#include "vec4.h" +#include "mat4.h" + +/* you can override clip space coords + but you have to provide all with same name + e.g.: define GLM_CSCOORD_LBN {0.0f, 0.0f, 1.0f, 1.0f} */ +#ifndef GLM_CUSTOM_CLIPSPACE + +/* near */ +#define GLMS_CSCOORD_LBN {-1.0f, -1.0f, -1.0f, 1.0f} +#define GLMS_CSCOORD_LTN {-1.0f, 1.0f, -1.0f, 1.0f} +#define GLMS_CSCOORD_RTN { 1.0f, 1.0f, -1.0f, 1.0f} +#define GLMS_CSCOORD_RBN { 1.0f, -1.0f, -1.0f, 1.0f} + +/* far */ +#define GLMS_CSCOORD_LBF {-1.0f, -1.0f, 1.0f, 1.0f} +#define GLMS_CSCOORD_LTF {-1.0f, 1.0f, 1.0f, 1.0f} +#define GLMS_CSCOORD_RTF { 1.0f, 1.0f, 1.0f, 1.0f} +#define GLMS_CSCOORD_RBF { 1.0f, -1.0f, 1.0f, 1.0f} + +#endif + +/*! + * @brief extracts view frustum planes + * + * planes' space: + * 1- if m = proj: View Space + * 2- if m = viewProj: World Space + * 3- if m = MVP: Object Space + * + * You probably want to extract planes in world space so use viewProj as m + * Computing viewProj: + * glm_mat4_mul(proj, view, viewProj); + * + * Exracted planes order: [left, right, bottom, top, near, far] + * + * @param[in] m matrix (see brief) + * @param[out] dest extracted view frustum planes (see brief) + */ +CGLM_INLINE +void +glms_frustum_planes(mat4s m, vec4s dest[6]) { + vec4 rawDest[6]; + glm_frustum_planes(m.raw, rawDest); + glms_vec4_pack(dest, rawDest, 6); +} + +/*! + * @brief extracts view frustum corners using clip-space coordinates + * + * corners' space: + * 1- if m = invViewProj: World Space + * 2- if m = invMVP: Object Space + * + * You probably want to extract corners in world space so use invViewProj + * Computing invViewProj: + * glm_mat4_mul(proj, view, viewProj); + * ... + * glm_mat4_inv(viewProj, invViewProj); + * + * if you have a near coord at i index, you can get it's far coord by i + 4 + * + * Find center coordinates: + * for (j = 0; j < 4; j++) { + * glm_vec3_center(corners[i], corners[i + 4], centerCorners[i]); + * } + * + * @param[in] invMat matrix (see brief) + * @param[out] dest exracted view frustum corners (see brief) + */ +CGLM_INLINE +void +glms_frustum_corners(mat4s invMat, vec4s dest[8]) { + vec4 rawDest[8]; + glm_frustum_corners(invMat.raw, rawDest); + glms_vec4_pack(dest, rawDest, 8); +} + +/*! + * @brief finds center of view frustum + * + * @param[in] corners view frustum corners + * @returns view frustum center + */ +CGLM_INLINE +vec4s +glms_frustum_center(vec4s corners[8]) { + vec4 rawCorners[8]; + vec4s r; + + glms_vec4_unpack(rawCorners, corners, 8); + glm_frustum_center(rawCorners, r.raw); + return r; +} + +/*! + * @brief finds bounding box of frustum relative to given matrix e.g. view mat + * + * @param[in] corners view frustum corners + * @param[in] m matrix to convert existing conners + * @param[out] box bounding box as array [min, max] + */ +CGLM_INLINE +void +glms_frustum_box(vec4s corners[8], mat4s m, vec3s box[2]) { + vec4 rawCorners[8]; + vec3 rawBox[2]; + + glms_vec4_unpack(rawCorners, corners, 8); + glm_frustum_box(rawCorners, m.raw, rawBox); + glms_vec3_pack(box, rawBox, 2); +} + +/*! + * @brief finds planes corners which is between near and far planes (parallel) + * + * this will be helpful if you want to split a frustum e.g. CSM/PSSM. This will + * find planes' corners but you will need to one more plane. + * Actually you have it, it is near, far or created previously with this func ;) + * + * @param[in] corners view frustum corners + * @param[in] splitDist split distance + * @param[in] farDist far distance (zFar) + * @param[out] planeCorners plane corners [LB, LT, RT, RB] + */ +CGLM_INLINE +void +glms_frustum_corners_at(vec4s corners[8], + float splitDist, + float farDist, + vec4s planeCorners[4]) { + vec4 rawCorners[8]; + vec4 rawPlaneCorners[4]; + + glms_vec4_unpack(rawCorners, corners, 8); + glm_frustum_corners_at(rawCorners, splitDist, farDist, rawPlaneCorners); + glms_vec4_pack(planeCorners, rawPlaneCorners, 8); +} + +#endif /* cglms_frustums_h */ diff --git a/include/cglm/struct/io.h b/include/cglm/struct/io.h new file mode 100644 index 0000000..ec28129 --- /dev/null +++ b/include/cglm/struct/io.h @@ -0,0 +1,82 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_mat4_print(mat4 matrix, FILE *ostream); + CGLM_INLINE void glm_mat3_print(mat3 matrix, FILE *ostream); + CGLM_INLINE void glm_vec4_print(vec4 vec, FILE *ostream); + CGLM_INLINE void glm_vec3_print(vec3 vec, FILE *ostream); + CGLM_INLINE void glm_ivec3_print(ivec3 vec, FILE *ostream); + CGLM_INLINE void glm_versor_print(versor vec, FILE *ostream); + */ + +#ifndef cglms_ios_h +#define cglms_ios_h + +#include "../common.h" +#include "../io.h" +#include "mat4.h" + +#include +#include + +CGLM_INLINE +void +glms_mat4_print(mat4s matrix, + FILE * __restrict ostream) { + + glm_mat4_print(matrix.raw, ostream); +} + +CGLM_INLINE +void +glms_mat3_print(mat3s matrix, + FILE * __restrict ostream) { + glm_mat3_print(matrix.raw, ostream); +} + +CGLM_INLINE +void +glms_vec4_print(vec4s vec, + FILE * __restrict ostream) { + glm_vec4_print(vec.raw, ostream); +} + +CGLM_INLINE +void +glms_vec3_print(vec3s vec, + FILE * __restrict ostream) { + glm_vec3_print(vec.raw, ostream); +} + +CGLM_INLINE +void +glms_ivec3_print(ivec3s vec, + FILE * __restrict ostream) { + glm_ivec3_print(vec.raw, ostream); +} + +CGLM_INLINE +void +glms_versor_print(versors vec, + FILE * __restrict ostream) { + glm_versor_print(vec.raw, ostream); +} + +CGLM_INLINE +void +glms_aabb_print(vec3s bbox[2], + const char * __restrict tag, + FILE * __restrict ostream) { + vec3 rawBbox[2]; + + glms_vec3_unpack(rawBbox, bbox, 2); + glm_aabb_print(rawBbox, tag, ostream); +} + +#endif /* cglms_ios_h */ diff --git a/include/cglm/struct/mat2.h b/include/cglm/struct/mat2.h new file mode 100644 index 0000000..a8ee27f --- /dev/null +++ b/include/cglm/struct/mat2.h @@ -0,0 +1,258 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Macros: + GLM_MAT2_IDENTITY_INIT + GLM_MAT2_ZERO_INIT + GLM_MAT2_IDENTITY + GLM_MAT2_ZERO + + Functions: + CGLM_INLINE void glms_mat2_identity(mat2 mat) + CGLM_INLINE void glms_mat2_identity_array(mat2 * restrict mat, size_t count) + CGLM_INLINE void glms_mat2_zero(mat2 mat) + CGLM_INLINE void glms_mat2_mul(mat2 m1, mat2 m2, mat2 dest) + CGLM_INLINE void glms_mat2_transpose_to(mat2 m, mat2 dest) + CGLM_INLINE void glms_mat2_transpose(mat2 m) + CGLM_INLINE void glms_mat2_mulv(mat2 m, vec2 v, vec2 dest) + CGLM_INLINE float glms_mat2_trace(mat2 m) + CGLM_INLINE void glms_mat2_scale(mat2 m, float s) + CGLM_INLINE float glms_mat2_det(mat2 mat) + CGLM_INLINE void glms_mat2_inv(mat2 mat, mat2 dest) + CGLM_INLINE void glms_mat2_swap_col(mat2 mat, int col1, int col2) + CGLM_INLINE void glms_mat2_swap_row(mat2 mat, int row1, int row2) + CGLM_INLINE float glms_mat2_rmc(vec2 r, mat2 m, vec2 c) + */ + +#ifndef cglms_mat2_h +#define cglms_mat2_h + +#include "../common.h" +#include "../types-struct.h" +#include "../mat2.h" + +#define GLMS_MAT2_IDENTITY_INIT {GLM_MAT2_IDENTITY_INIT} +#define GLMS_MAT2_ZERO_INIT {GLM_MAT2_ZERO_INIT} + +/* for C only */ +#define GLMS_MAT2_IDENTITY ((mat3s)GLMS_MAT2_IDENTITY_INIT) +#define GLMS_MAT2_ZERO ((mat3s)GLMS_MAT2_ZERO_INIT) + +/*! + * @brief make given matrix identity. It is identical with below, + * but it is more easy to do that with this func especially for members + * e.g. glm_mat2_identity(aStruct->aMatrix); + * + * @code + * glm_mat2_copy(GLM_MAT2_IDENTITY, mat); // C only + * + * // or + * mat2 mat = GLM_MAT2_IDENTITY_INIT; + * @endcode + * + * @returns identity matrix + */ +CGLM_INLINE +mat2s +glms_mat2_identity(void) { + mat2s r; + glm_mat2_identity(r.raw); + return r; +} + +/*! + * @brief make given matrix array's each element identity matrix + * + * @param[in, out] mat matrix array (must be aligned (16) + * if alignment is not disabled) + * + * @param[in] count count of matrices + */ +CGLM_INLINE +void +glms_mat2_identity_array(mat2s * __restrict mat, size_t count) { + CGLM_ALIGN_MAT mat2s t = GLMS_MAT2_IDENTITY_INIT; + size_t i; + + for (i = 0; i < count; i++) { + glm_mat2_copy(t.raw, mat[i].raw); + } +} + +/*! + * @brief make given matrix zero. + * + * @returns matrix + */ +CGLM_INLINE +mat2s +glms_mat2_zero(void) { + mat2s r; + glm_mat2_zero(r.raw); + return r; +} + +/*! + * @brief multiply m1 and m2 to dest + * + * m1, m2 and dest matrices can be same matrix, it is possible to write this: + * + * @code + * mat2 m = GLM_MAT2_IDENTITY_INIT; + * glm_mat2_mul(m, m, m); + * @endcode + * + * @param[in] m1 left matrix + * @param[in] m2 right matrix + * + * @returns matrix + */ +CGLM_INLINE +mat2s +glms_mat2_mul(mat2s m1, mat2s m2) { + mat2s r; + glm_mat2_mul(m1.raw, m2.raw, r.raw); + return r; +} + +/*! + * @brief transpose mat2 + * + * @param[in] m matrix to transpose + * + * @returns transposed matrix + */ +CGLM_INLINE +mat2s +glms_mat2_transpose(mat2s m) { + glm_mat2_transpose(m.raw); + return m; +} + +/*! + * @brief multiply mat2 with vec2 (column vector) and store in dest vector + * + * @param[in] m mat2 (left) + * @param[in] v vec2 (right, column vector) + * @returns vec2 (result, column vector) + */ +CGLM_INLINE +vec2s +glms_mat2_mulv(mat2s m, vec2s v) { + vec2s r; + glm_mat2_mulv(m.raw, v.raw, r.raw); + return r; +} + +/*! + * @brief trace of matrix + * + * sum of the elements on the main diagonal from upper left to the lower right + * + * @param[in] m matrix + */ +CGLM_INLINE +float +glms_mat2_trace(mat2s m) { + return glm_mat2_trace(m.raw); +} + +/*! + * @brief scale (multiply with scalar) matrix + * + * multiply matrix with scalar + * + * @param[in, out] m matrix + * @param[in] s scalar + * @returns matrix + */ +CGLM_INLINE +mat2s +glms_mat2_scale(mat2s m, float s) { + glm_mat2_scale(m.raw, s); + return m; +} + +/*! + * @brief mat2 determinant + * + * @param[in] mat matrix + * + * @return determinant + */ +CGLM_INLINE +float +glms_mat2_det(mat2s mat) { + return glm_mat2_det(mat.raw); +} + +/*! + * @brief inverse mat2 and store in dest + * + * @param[in] mat matrix + * @returns matrix + */ +CGLM_INLINE +mat2s +glms_mat2_inv(mat2s mat) { + mat2s r; + glm_mat2_inv(mat.raw, r.raw); + return r; +} + +/*! + * @brief swap two matrix columns + * + * @param[in] mat matrix + * @param[in] col1 col1 + * @param[in] col2 col2 + * @returns matrix + */ +CGLM_INLINE +mat2s +glms_mat2_swap_col(mat2s mat, int col1, int col2) { + glm_mat2_swap_col(mat.raw, col1, col2); + return mat; +} + +/*! + * @brief swap two matrix rows + * + * @param[in] mat matrix + * @param[in] row1 row1 + * @param[in] row2 row2 + * @returns matrix + */ +CGLM_INLINE +mat2s +glms_mat2_swap_row(mat2s mat, int row1, int row2) { + glm_mat2_swap_row(mat.raw, row1, row2); + return mat; +} + +/*! + * @brief helper for R (row vector) * M (matrix) * C (column vector) + * + * rmc stands for Row * Matrix * Column + * + * the result is scalar because R * M = Matrix1x2 (row vector), + * then Matrix1x2 * Vec2 (column vector) = Matrix1x1 (Scalar) + * + * @param[in] r row vector or matrix1x2 + * @param[in] m matrix2x2 + * @param[in] c column vector or matrix2x1 + * + * @return scalar value e.g. Matrix1x1 + */ +CGLM_INLINE +float +glms_mat2_rmc(vec2s r, mat2s m, vec2s c) { + return glm_mat2_rmc(r.raw, m.raw, c.raw); +} + +#endif /* cglms_mat2_h */ diff --git a/include/cglm/struct/mat3.h b/include/cglm/struct/mat3.h new file mode 100644 index 0000000..53a7273 --- /dev/null +++ b/include/cglm/struct/mat3.h @@ -0,0 +1,285 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Macros: + GLMS_MAT3_IDENTITY_INIT + GLMS_MAT3_ZERO_INIT + GLMS_MAT3_IDENTITY + GLMS_MAT3_ZERO + + Functions: + CGLM_INLINE mat3s glms_mat3_copy(mat3s mat); + CGLM_INLINE mat3s glms_mat3_identity(void); + CGLM_INLINE void glms_mat3_identity_array(mat3s * __restrict mat, size_t count); + CGLM_INLINE mat3s glms_mat3_zero(void); + CGLM_INLINE mat3s glms_mat3_mul(mat3s m1, mat3s m2); + CGLM_INLINE ma3s glms_mat3_transpose(mat3s m); + CGLM_INLINE vec3s glms_mat3_mulv(mat3s m, vec3s v); + CGLM_INLINE float glms_mat3_trace(mat3s m); + CGLM_INLINE versor glms_mat3_quat(mat3s m); + CGLM_INLINE mat3s glms_mat3_scale(mat3s m, float s); + CGLM_INLINE float glms_mat3_det(mat3s mat); + CGLM_INLINE mat3s glms_mat3_inv(mat3s mat); + CGLM_INLINE mat3s glms_mat3_swap_col(mat3s mat, int col1, int col2); + CGLM_INLINE mat3s glms_mat3_swap_row(mat3s mat, int row1, int row2); + CGLM_INLINE float glms_mat3_rmc(vec3s r, mat3s m, vec3s c); + */ + +#ifndef cglms_mat3s_h +#define cglms_mat3s_h + +#include "../common.h" +#include "../types-struct.h" +#include "../mat3.h" +#include "vec3.h" + +#define GLMS_MAT3_IDENTITY_INIT {GLM_MAT3_IDENTITY_INIT} +#define GLMS_MAT3_ZERO_INIT {GLM_MAT3_ZERO_INIT} + +/* for C only */ +#define GLMS_MAT3_IDENTITY ((mat3s)GLMS_MAT3_IDENTITY_INIT) +#define GLMS_MAT3_ZERO ((mat3s)GLMS_MAT3_ZERO_INIT) + +/*! + * @brief copy all members of [mat] to [dest] + * + * @param[in] mat source + * @returns destination + */ +CGLM_INLINE +mat3s +glms_mat3_copy(mat3s mat) { + mat3s r; + glm_mat3_copy(mat.raw, r.raw); + return r; +} + +/*! + * @brief make given matrix identity. It is identical with below, + * but it is more easy to do that with this func especially for members + * e.g. glm_mat3_identity(aStruct->aMatrix); + * + * @code + * glm_mat3_copy(GLM_MAT3_IDENTITY, mat); // C only + * + * // or + * mat3 mat = GLM_MAT3_IDENTITY_INIT; + * @endcode + * + * @returns destination + */ +CGLM_INLINE +mat3s +glms_mat3_identity(void) { + mat3s r; + glm_mat3_identity(r.raw); + return r; +} + +/*! + * @brief make given matrix array's each element identity matrix + * + * @param[in, out] mat matrix array (must be aligned (16/32) + * if alignment is not disabled) + * + * @param[in] count count of matrices + */ +CGLM_INLINE +void +glms_mat3_identity_array(mat3s * __restrict mat, size_t count) { + CGLM_ALIGN_MAT mat3s t = GLMS_MAT3_IDENTITY_INIT; + size_t i; + + for (i = 0; i < count; i++) { + glm_mat3_copy(t.raw, mat[i].raw); + } +} + +/*! + * @brief make given matrix zero. + * + * @returns matrix + */ +CGLM_INLINE +mat3s +glms_mat3_zero(void) { + mat3s r; + glm_mat3_zero(r.raw); + return r; +} + +/*! + * @brief multiply m1 and m2 to dest + * + * m1, m2 and dest matrices can be same matrix, it is possible to write this: + * + * @code + * mat3 m = GLM_MAT3_IDENTITY_INIT; + * glm_mat3_mul(m, m, m); + * @endcode + * + * @param[in] m1 left matrix + * @param[in] m2 right matrix + * @returns destination matrix + */ +CGLM_INLINE +mat3s +glms_mat3_mul(mat3s m1, mat3s m2) { + mat3s r; + glm_mat3_mul(m1.raw, m2.raw, r.raw); + return r; +} + +/*! + * @brief tranpose mat3 and store result in same matrix + * + * @param[in, out] m source and dest + */ +CGLM_INLINE +mat3s +glms_mat3_transpose(mat3s m) { + glm_mat3_transpose(m.raw); + return m; +} + +/*! + * @brief multiply mat3 with vec3 (column vector) and store in dest vector + * + * @param[in] m mat3 (left) + * @param[in] v vec3 (right, column vector) + * @returns vec3 (result, column vector) + */ +CGLM_INLINE +vec3s +glms_mat3_mulv(mat3s m, vec3s v) { + vec3s r; + glm_mat3_mulv(m.raw, v.raw, r.raw); + return r; +} + +/*! + * @brief trace of matrix + * + * sum of the elements on the main diagonal from upper left to the lower right + * + * @param[in] m matrix + */ +CGLM_INLINE +float +glms_mat3_trace(mat3s m) { + return glm_mat3_trace(m.raw); +} + +/*! + * @brief convert mat3 to quaternion + * + * @param[in] m rotation matrix + * @returns destination quaternion + */ +CGLM_INLINE +versors +glms_mat3_quat(mat3s m) { + versors r; + glm_mat3_quat(m.raw, r.raw); + return r; +} + +/*! + * @brief scale (multiply with scalar) matrix + * + * multiply matrix with scalar + * + * @param[in] m matrix + * @param[in] s scalar + * @returns scaled matrix + */ +CGLM_INLINE +mat3s +glms_mat3_scale(mat3s m, float s) { + glm_mat3_scale(m.raw, s); + return m; +} + +/*! + * @brief mat3 determinant + * + * @param[in] mat matrix + * + * @return determinant + */ +CGLM_INLINE +float +glms_mat3_det(mat3s mat) { + return glm_mat3_det(mat.raw); +} + +/*! + * @brief inverse mat3 and store in dest + * + * @param[in] mat matrix + * @returns inverse matrix + */ +CGLM_INLINE +mat3s +glms_mat3_inv(mat3s mat) { + mat3s r; + glm_mat3_inv(mat.raw, r.raw); + return r; +} + +/*! + * @brief swap two matrix columns + * + * @param[in] mat matrix + * @param[in] col1 col1 + * @param[in] col2 col2 + * @returns matrix + */ +CGLM_INLINE +mat3s +glms_mat3_swap_col(mat3s mat, int col1, int col2) { + glm_mat3_swap_col(mat.raw, col1, col2); + return mat; +} + +/*! + * @brief swap two matrix rows + * + * @param[in] mat matrix + * @param[in] row1 row1 + * @param[in] row2 row2 + * @returns matrix + */ +CGLM_INLINE +mat3s +glms_mat3_swap_row(mat3s mat, int row1, int row2) { + glm_mat3_swap_row(mat.raw, row1, row2); + return mat; +} + +/*! + * @brief helper for R (row vector) * M (matrix) * C (column vector) + * + * rmc stands for Row * Matrix * Column + * + * the result is scalar because R * M = Matrix1x3 (row vector), + * then Matrix1x3 * Vec3 (column vector) = Matrix1x1 (Scalar) + * + * @param[in] r row vector or matrix1x3 + * @param[in] m matrix3x3 + * @param[in] c column vector or matrix3x1 + * + * @return scalar value e.g. Matrix1x1 + */ +CGLM_INLINE +float +glms_mat3_rmc(vec3s r, mat3s m, vec3s c) { + return glm_mat3_rmc(r.raw, m.raw, c.raw); +} + +#endif /* cglms_mat3s_h */ diff --git a/include/cglm/struct/mat4.h b/include/cglm/struct/mat4.h new file mode 100644 index 0000000..28f80a3 --- /dev/null +++ b/include/cglm/struct/mat4.h @@ -0,0 +1,459 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/*! + * Most of functions in this header are optimized manually with SIMD + * if available. You dont need to call/incude SIMD headers manually + */ + +/* + Macros: + GLMS_MAT4_IDENTITY_INIT + GLMS_MAT4_ZERO_INIT + GLMS_MAT4_IDENTITY + GLMS_MAT4_ZERO + + Functions: + CGLM_INLINE mat4s glms_mat4_ucopy(mat4s mat); + CGLM_INLINE mat4s glms_mat4_copy(mat4s mat); + CGLM_INLINE mat4s glms_mat4_identity(void); + CGLM_INLINE void glms_mat4_identity_array(mat4s * __restrict mat, size_t count); + CGLM_INLINE mat4s glms_mat4_zero(void); + CGLM_INLINE mat3s glms_mat4_pick3(mat4s mat); + CGLM_INLINE mat3s glms_mat4_pick3t(mat4s mat); + CGLM_INLINE mat4s glms_mat4_ins3(mat3s mat); + CGLM_INLINE mat4s glms_mat4_mul(mat4s m1, mat4s m2); + CGLM_INLINE mat4s glms_mat4_mulN(mat4s * __restrict matrices[], uint32_t len); + CGLM_INLINE vec4s glms_mat4_mulv(mat4s m, vec4s v); + CGLM_INLINE float glms_mat4_trace(mat4s m); + CGLM_INLINE float glms_mat4_trace3(mat4s m); + CGLM_INLINE versors glms_mat4_quat(mat4s m); + CGLM_INLINE vec3s glms_mat4_mulv3(mat4s m, vec3s v, float last); + CGLM_INLINE mat4s glms_mat4_transpose(mat4s m); + CGLM_INLINE mat4s glms_mat4_scale_p(mat4s m, float s); + CGLM_INLINE mat4s glms_mat4_scale(mat4s m, float s); + CGLM_INLINE float glms_mat4_det(mat4s mat); + CGLM_INLINE mat4s glms_mat4_inv(mat4s mat); + CGLM_INLINE mat4s glms_mat4_inv_fast(mat4s mat); + CGLM_INLINE mat4s glms_mat4_swap_col(mat4s mat, int col1, int col2); + CGLM_INLINE mat4s glms_mat4_swap_row(mat4s mat, int row1, int row2); + CGLM_INLINE float glms_mat4_rmc(vec4s r, mat4s m, vec4s c); + */ + +#ifndef cglms_mat4s_h +#define cglms_mat4s_h + +#include "../common.h" +#include "../types-struct.h" +#include "../mat4.h" +#include "vec4.h" +#include "vec3.h" + +#define GLMS_MAT4_IDENTITY_INIT {GLM_MAT4_IDENTITY_INIT} +#define GLMS_MAT4_ZERO_INIT {GLM_MAT4_ZERO_INIT} + +/* for C only */ +#define GLMS_MAT4_IDENTITY ((mat4s)GLMS_MAT4_IDENTITY_INIT) +#define GLMS_MAT4_ZERO ((mat4s)GLMS_MAT4_ZERO_INIT) + +/*! + * @brief copy all members of [mat] to [dest] + * + * matrix may not be aligned, u stands for unaligned, this may be useful when + * copying a matrix from external source e.g. asset importer... + * + * @param[in] mat source + * @returns destination + */ +CGLM_INLINE +mat4s +glms_mat4_ucopy(mat4s mat) { + mat4s r; + glm_mat4_ucopy(mat.raw, r.raw); + return r; +} + +/*! + * @brief copy all members of [mat] to [dest] + * + * @param[in] mat source + * @returns destination + */ +CGLM_INLINE +mat4s +glms_mat4_copy(mat4s mat) { + mat4s r; + glm_mat4_copy(mat.raw, r.raw); + return r; +} + +/*! + * @brief make given matrix identity. It is identical with below, + * but it is more easy to do that with this func especially for members + * e.g. glm_mat4_identity(aStruct->aMatrix); + * + * @code + * glm_mat4_copy(GLM_MAT4_IDENTITY, mat); // C only + * + * // or + * mat4 mat = GLM_MAT4_IDENTITY_INIT; + * @endcode + * + * @retuns destination + */ +CGLM_INLINE +mat4s +glms_mat4_identity(void) { + mat4s r; + glm_mat4_identity(r.raw); + return r; +} + +/*! + * @brief make given matrix array's each element identity matrix + * + * @param[in, out] mat matrix array (must be aligned (16/32) + * if alignment is not disabled) + * + * @param[in] count count of matrices + */ +CGLM_INLINE +void +glms_mat4_identity_array(mat4s * __restrict mat, size_t count) { + CGLM_ALIGN_MAT mat4s t = GLMS_MAT4_IDENTITY_INIT; + size_t i; + + for (i = 0; i < count; i++) { + glm_mat4_copy(t.raw, mat[i].raw); + } +} + +/*! + * @brief make given matrix zero. + * + * @returns matrix + */ +CGLM_INLINE +mat4s +glms_mat4_zero(void) { + mat4s r; + glm_mat4_zero(r.raw); + return r; +} + +/*! + * @brief copy upper-left of mat4 to mat3 + * + * @param[in] mat source + * @returns destination + */ +CGLM_INLINE +mat3s +glms_mat4_pick3(mat4s mat) { + mat3s r; + glm_mat4_pick3(mat.raw, r.raw); + return r; +} + +/*! + * @brief copy upper-left of mat4 to mat3 (transposed) + * + * the postfix t stands for transpose + * + * @param[in] mat source + * @returns destination + */ +CGLM_INLINE +mat3s +glms_mat4_pick3t(mat4s mat) { + mat3s r; + glm_mat4_pick3t(mat.raw, r.raw); + return r; +} + +/*! + * @brief copy mat3 to mat4's upper-left + * + * @param[in] mat source + * @returns destination + */ +CGLM_INLINE +mat4s +glms_mat4_ins3(mat3s mat) { + mat4s r; + glm_mat4_ins3(mat.raw, r.raw); + return r; +} + +/*! + * @brief multiply m1 and m2 to dest + * + * m1, m2 and dest matrices can be same matrix, it is possible to write this: + * + * @code + * mat4 m = GLM_MAT4_IDENTITY_INIT; + * glm_mat4_mul(m, m, m); + * @endcode + * + * @param[in] m1 left matrix + * @param[in] m2 right matrix + * @returns destination matrix + */ +CGLM_INLINE +mat4s +glms_mat4_mul(mat4s m1, mat4s m2) { + mat4s r; + glm_mat4_mul(m1.raw, m2.raw, r.raw); + return r; +} + +/*! + * @brief mupliply N mat4 matrices and store result in dest + * + * this function lets you multiply multiple (more than two or more...) matrices + *

multiplication will be done in loop, this may reduce instructions + * size but if len is too small then compiler may unroll whole loop, + * usage: + * @code + * mat m1, m2, m3, m4, res; + * + * res = glm_mat4_mulN((mat4 *[]){&m1, &m2, &m3, &m4}, 4); + * @endcode + * + * @warning matrices parameter is pointer array not mat4 array! + * + * @param[in] matrices mat4 * array + * @param[in] len matrices count + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_mat4_mulN(mat4s * __restrict matrices[], uint32_t len) { + CGLM_ALIGN_MAT mat4s r = GLMS_MAT4_IDENTITY_INIT; + size_t i; + + for (i = 0; i < len; i++) { + r = glms_mat4_mul(r, *matrices[i]); + } + + return r; +} + +/*! + * @brief multiply mat4 with vec4 (column vector) and store in dest vector + * + * @param[in] m mat4 (left) + * @param[in] v vec4 (right, column vector) + * @returns vec4 (result, column vector) + */ +CGLM_INLINE +vec4s +glms_mat4_mulv(mat4s m, vec4s v) { + vec4s r; + glm_mat4_mulv(m.raw, v.raw, r.raw); + return r; +} + +/*! + * @brief trace of matrix + * + * sum of the elements on the main diagonal from upper left to the lower right + * + * @param[in] m matrix + */ +CGLM_INLINE +float +glms_mat4_trace(mat4s m) { + return glm_mat4_trace(m.raw); +} + +/*! + * @brief trace of matrix (rotation part) + * + * sum of the elements on the main diagonal from upper left to the lower right + * + * @param[in] m matrix + */ +CGLM_INLINE +float +glms_mat4_trace3(mat4s m) { + return glm_mat4_trace3(m.raw); +} + +/*! + * @brief convert mat4's rotation part to quaternion + * + * @param[in] m affine matrix + * @returns destination quaternion + */ +CGLM_INLINE +versors +glms_mat4_quat(mat4s m) { + versors r; + glm_mat4_quat(m.raw, r.raw); + return r; +} + +/*! + * @brief multiply vector with mat4 + * + * @param[in] m mat4(affine transform) + * @param[in] v vec3 + * @param[in] last 4th item to make it vec4 + * @returns result vector (vec3) + */ +CGLM_INLINE +vec3s +glms_mat4_mulv3(mat4s m, vec3s v, float last) { + vec3s r; + glm_mat4_mulv3(m.raw, v.raw, last, r.raw); + return r; +} + +/*! + * @brief tranpose mat4 and store result in same matrix + * + * @param[in] m source + * @returns result + */ +CGLM_INLINE +mat4s +glms_mat4_transpose(mat4s m) { + glm_mat4_transpose(m.raw); + return m; +} + +/*! + * @brief scale (multiply with scalar) matrix without simd optimization + * + * multiply matrix with scalar + * + * @param[in] m matrix + * @param[in] s scalar + * @returns matrix + */ +CGLM_INLINE +mat4s +glms_mat4_scale_p(mat4s m, float s) { + glm_mat4_scale_p(m.raw, s); + return m; +} + +/*! + * @brief scale (multiply with scalar) matrix + * + * multiply matrix with scalar + * + * @param[in] m matrix + * @param[in] s scalar + * @returns matrix + */ +CGLM_INLINE +mat4s +glms_mat4_scale(mat4s m, float s) { + glm_mat4_scale(m.raw, s); + return m; +} + +/*! + * @brief mat4 determinant + * + * @param[in] mat matrix + * + * @return determinant + */ +CGLM_INLINE +float +glms_mat4_det(mat4s mat) { + return glm_mat4_det(mat.raw); +} + +/*! + * @brief inverse mat4 and store in dest + * + * @param[in] mat matrix + * @returns inverse matrix + */ +CGLM_INLINE +mat4s +glms_mat4_inv(mat4s mat) { + mat4s r; + glm_mat4_inv(mat.raw, r.raw); + return r; +} + +/*! + * @brief inverse mat4 and store in dest + * + * this func uses reciprocal approximation without extra corrections + * e.g Newton-Raphson. this should work faster than normal, + * to get more precise use glm_mat4_inv version. + * + * NOTE: You will lose precision, glm_mat4_inv is more accurate + * + * @param[in] mat matrix + * @returns inverse matrix + */ +CGLM_INLINE +mat4s +glms_mat4_inv_fast(mat4s mat) { + mat4s r; + glm_mat4_inv_fast(mat.raw, r.raw); + return r; +} + +/*! + * @brief swap two matrix columns + * + * @param[in] mat matrix + * @param[in] col1 col1 + * @param[in] col2 col2 + * @returns matrix + */ +CGLM_INLINE +mat4s +glms_mat4_swap_col(mat4s mat, int col1, int col2) { + glm_mat4_swap_col(mat.raw, col1, col2); + return mat; +} + +/*! + * @brief swap two matrix rows + * + * @param[in] mat matrix + * @param[in] row1 row1 + * @param[in] row2 row2 + * @returns matrix + */ +CGLM_INLINE +mat4s +glms_mat4_swap_row(mat4s mat, int row1, int row2) { + glm_mat4_swap_row(mat.raw, row1, row2); + return mat; +} + +/*! + * @brief helper for R (row vector) * M (matrix) * C (column vector) + * + * rmc stands for Row * Matrix * Column + * + * the result is scalar because R * M = Matrix1x4 (row vector), + * then Matrix1x4 * Vec4 (column vector) = Matrix1x1 (Scalar) + * + * @param[in] r row vector or matrix1x4 + * @param[in] m matrix4x4 + * @param[in] c column vector or matrix4x1 + * + * @return scalar value e.g. B(s) + */ +CGLM_INLINE +float +glms_mat4_rmc(vec4s r, mat4s m, vec4s c) { + return glm_mat4_rmc(r.raw, m.raw, c.raw); +} + +#endif /* cglms_mat4s_h */ diff --git a/include/cglm/struct/plane.h b/include/cglm/struct/plane.h new file mode 100644 index 0000000..6a84ac7 --- /dev/null +++ b/include/cglm/struct/plane.h @@ -0,0 +1,40 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglms_planes_h +#define cglms_planes_h + +#include "../common.h" +#include "../types-struct.h" +#include "../plane.h" +#include "vec4.h" + +/* + Plane equation: Ax + By + Cz + D = 0; + + It stored in vec4 as [A, B, C, D]. (A, B, C) is normal and D is distance +*/ + +/* + Functions: + CGLM_INLINE vec4s glms_plane_normalize(vec4s plane); + */ + +/*! + * @brief normalizes a plane + * + * @param[in] plane plane to normalize + * @returns normalized plane + */ +CGLM_INLINE +vec4s +glms_plane_normalize(vec4s plane) { + glm_plane_normalize(plane.raw); + return plane; +} + +#endif /* cglms_planes_h */ diff --git a/include/cglm/struct/project.h b/include/cglm/struct/project.h new file mode 100644 index 0000000..00f76ff --- /dev/null +++ b/include/cglm/struct/project.h @@ -0,0 +1,120 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglms_projects_h +#define cglms_projects_h + +#include "../common.h" +#include "../types-struct.h" +#include "../project.h" +#include "vec3.h" +#include "vec4.h" +#include "mat4.h" + +/*! + * @brief maps the specified viewport coordinates into specified space [1] + * the matrix should contain projection matrix. + * + * if you don't have ( and don't want to have ) an inverse matrix then use + * glm_unproject version. You may use existing inverse of matrix in somewhere + * else, this is why glm_unprojecti exists to save save inversion cost + * + * [1] space: + * 1- if m = invProj: View Space + * 2- if m = invViewProj: World Space + * 3- if m = invMVP: Object Space + * + * You probably want to map the coordinates into object space + * so use invMVP as m + * + * Computing viewProj: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * glm_mat4_inv(viewProj, invMVP); + * + * @param[in] pos point/position in viewport coordinates + * @param[in] invMat matrix (see brief) + * @param[in] vp viewport as [x, y, width, height] + * @returns unprojected coordinates + */ +CGLM_INLINE +vec3s +glms_unprojecti(vec3s pos, mat4s invMat, vec4s vp) { + vec3s r; + glm_unprojecti(pos.raw, invMat.raw, vp.raw, r.raw); + return r; +} + +/*! + * @brief maps the specified viewport coordinates into specified space [1] + * the matrix should contain projection matrix. + * + * this is same as glm_unprojecti except this function get inverse matrix for + * you. + * + * [1] space: + * 1- if m = proj: View Space + * 2- if m = viewProj: World Space + * 3- if m = MVP: Object Space + * + * You probably want to map the coordinates into object space + * so use MVP as m + * + * Computing viewProj and MVP: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * + * @param[in] pos point/position in viewport coordinates + * @param[in] m matrix (see brief) + * @param[in] vp viewport as [x, y, width, height] + * @returns unprojected coordinates + */ +CGLM_INLINE +vec3s +glms_unproject(vec3s pos, mat4s m, vec4s vp) { + vec3s r; + glm_unproject(pos.raw, m.raw, vp.raw, r.raw); + return r; +} + +/*! + * @brief map object coordinates to window coordinates + * + * Computing MVP: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * + * @param[in] pos object coordinates + * @param[in] m MVP matrix + * @param[in] vp viewport as [x, y, width, height] + * @returns projected coordinates + */ +CGLM_INLINE +vec3s +glms_project(vec3s pos, mat4s m, vec4s vp) { + vec3s r; + glm_project(pos.raw, m.raw, vp.raw, r.raw); + return r; +} + +/*! + * @brief define a picking region + * + * @param[in] center center [x, y] of a picking region in window coordinates + * @param[in] size size [width, height] of the picking region in window coordinates + * @param[in] vp viewport as [x, y, width, height] + * @returns projected coordinates + */ +CGLM_INLINE +mat4s +glms_pickmatrix(vec2s center, vec2s size, vec4s vp) { + mat4s res; + glm_pickmatrix(center.raw, size.raw, vp.raw, res.raw); + return res; +} + +#endif /* cglms_projects_h */ diff --git a/include/cglm/struct/quat.h b/include/cglm/struct/quat.h new file mode 100644 index 0000000..d69675b --- /dev/null +++ b/include/cglm/struct/quat.h @@ -0,0 +1,565 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Macros: + GLMS_QUAT_IDENTITY_INIT + GLMS_QUAT_IDENTITY + + Functions: + CGLM_INLINE versors glms_quat_identity(void) + CGLM_INLINE void glms_quat_identity_array(versor *q, size_t count) + CGLM_INLINE versors glms_quat_init(float x, float y, float z, float w) + CGLM_INLINE versors glms_quatv(float angle, vec3s axis) + CGLM_INLINE versors glms_quat(float angle, float x, float y, float z) + CGLM_INLINE versors glms_quat_from_vecs(vec3s a, vec3s b) + CGLM_INLINE float glms_quat_norm(versors q) + CGLM_INLINE versors glms_quat_normalize(versors q) + CGLM_INLINE float glms_quat_dot(versors p, versors q) + CGLM_INLINE versors glms_quat_conjugate(versors q) + CGLM_INLINE versors glms_quat_inv(versors q) + CGLM_INLINE versors glms_quat_add(versors p, versors q) + CGLM_INLINE versors glms_quat_sub(versors p, versors q) + CGLM_INLINE vec3s glms_quat_imagn(versors q) + CGLM_INLINE float glms_quat_imaglen(versors q) + CGLM_INLINE float glms_quat_angle(versors q) + CGLM_INLINE vec3s glms_quat_axis(versors q) + CGLM_INLINE versors glms_quat_mul(versors p, versors q) + CGLM_INLINE mat4s glms_quat_mat4(versors q) + CGLM_INLINE mat4s glms_quat_mat4t(versors q) + CGLM_INLINE mat3s glms_quat_mat3(versors q) + CGLM_INLINE mat3s glms_quat_mat3t(versors q) + CGLM_INLINE versors glms_quat_lerp(versors from, versors to, float t) + CGLM_INLINE versors glms_quat_lerpc(versors from, versors to, float t) + CGLM_INLINE versors glms_quat_nlerp(versors from, versors to, float t) + CGLM_INLINE versors glms_quat_slerp(versors from, versors to, float t) + CGLM_INLINE mat4s. glms_quat_look(vec3s eye, versors ori) + CGLM_INLINE versors glms_quat_for(vec3s dir, vec3s fwd, vec3s up) + CGLM_INLINE versors glms_quat_forp(vec3s from, vec3s to, vec3s fwd, vec3s up) + CGLM_INLINE vec3s glms_quat_rotatev(versors q, vec3s v) + CGLM_INLINE mat4s glms_quat_rotate(mat4s m, versors q) + CGLM_INLINE mat4s glms_quat_rotate_at(mat4s m, versors q, vec3s pivot) + CGLM_INLINE mat4s glms_quat_rotate_atm(versors q, vec3s pivot) + */ + +#ifndef cglms_quat_h +#define cglms_quat_h + +#include "../common.h" +#include "../types-struct.h" +#include "../plane.h" +#include "../quat.h" + +/* + * IMPORTANT: + * ---------------------------------------------------------------------------- + * cglm stores quat as [x, y, z, w] since v0.3.6 + * + * it was [w, x, y, z] before v0.3.6 it has been changed to [x, y, z, w] + * with v0.3.6 version. + * ---------------------------------------------------------------------------- + */ + +#define GLMS_QUAT_IDENTITY_INIT {GLM_QUAT_IDENTITY_INIT} +#define GLMS_QUAT_IDENTITY ((versors)GLMS_QUAT_IDENTITY_INIT) + +/*! + * @brief makes given quat to identity + * + * @returns identity quaternion + */ +CGLM_INLINE +versors +glms_quat_identity(void) { + versors dest; + glm_quat_identity(dest.raw); + return dest; +} + +/*! + * @brief make given quaternion array's each element identity quaternion + * + * @param[in, out] q quat array (must be aligned (16) + * if alignment is not disabled) + * + * @param[in] count count of quaternions + */ +CGLM_INLINE +void +glms_quat_identity_array(versors * __restrict q, size_t count) { + CGLM_ALIGN(16) versor v = GLM_QUAT_IDENTITY_INIT; + size_t i; + + for (i = 0; i < count; i++) { + glm_vec4_copy(v, q[i].raw); + } +} + +/*! + * @brief inits quaterion with raw values + * + * @param[in] x x + * @param[in] y y + * @param[in] z z + * @param[in] w w (real part) + * @returns quaternion + */ +CGLM_INLINE +versors +glms_quat_init(float x, float y, float z, float w) { + versors dest; + glm_quat_init(dest.raw, x, y, z, w); + return dest; +} + +/*! + * @brief creates NEW quaternion with axis vector + * + * @param[in] angle angle (radians) + * @param[in] axis axis + * @returns quaternion + */ +CGLM_INLINE +versors +glms_quatv(float angle, vec3s axis) { + versors dest; + glm_quatv(dest.raw, angle, axis.raw); + return dest; +} + +/*! + * @brief creates NEW quaternion with individual axis components + * + * @param[in] angle angle (radians) + * @param[in] x axis.x + * @param[in] y axis.y + * @param[in] z axis.z + * @returns quaternion + */ +CGLM_INLINE +versors +glms_quat(float angle, float x, float y, float z) { + versors dest; + glm_quat(dest.raw, angle, x, y, z); + return dest; +} + +/*! + * @brief compute quaternion rotating vector A to vector B + * + * @param[in] a vec3 (must have unit length) + * @param[in] b vec3 (must have unit length) + * @returns quaternion (of unit length) + */ +CGLM_INLINE +versors +glms_quat_from_vecs(vec3s a, vec3s b) { + versors dest; + glm_quat_from_vecs(a.raw, b.raw, dest.raw); + return dest; +} + +/*! + * @brief returns norm (magnitude) of quaternion + * + * @param[in] q quaternion + */ +CGLM_INLINE +float +glms_quat_norm(versors q) { + return glm_quat_norm(q.raw); +} + +/*! + * @brief normalize quaternion + * + * @param[in] q quaternion + * @returns quaternion + */ +CGLM_INLINE +versors +glms_quat_normalize(versors q) { + versors dest; + glm_quat_normalize_to(q.raw, dest.raw); + return dest; +} + +/*! + * @brief dot product of two quaternion + * + * @param[in] p quaternion 1 + * @param[in] q quaternion 2 + * @returns dot product + */ +CGLM_INLINE +float +glms_quat_dot(versors p, versors q) { + return glm_quat_dot(p.raw, q.raw); +} + +/*! + * @brief conjugate of quaternion + * + * @param[in] q quaternion + * @returns conjugate + */ +CGLM_INLINE +versors +glms_quat_conjugate(versors q) { + versors dest; + glm_quat_conjugate(q.raw, dest.raw); + return dest; +} + +/*! + * @brief inverse of non-zero quaternion + * + * @param[in] q quaternion + * @returns inverse quaternion + */ +CGLM_INLINE +versors +glms_quat_inv(versors q) { + versors dest; + glm_quat_inv(q.raw, dest.raw); + return dest; +} + +/*! + * @brief add (componentwise) two quaternions and store result in dest + * + * @param[in] p quaternion 1 + * @param[in] q quaternion 2 + * @returns result quaternion + */ +CGLM_INLINE +versors +glms_quat_add(versors p, versors q) { + versors dest; + glm_quat_add(p.raw, q.raw, dest.raw); + return dest; +} + +/*! + * @brief subtract (componentwise) two quaternions and store result in dest + * + * @param[in] p quaternion 1 + * @param[in] q quaternion 2 + * @returns result quaternion + */ +CGLM_INLINE +versors +glms_quat_sub(versors p, versors q) { + versors dest; + glm_quat_sub(p.raw, q.raw, dest.raw); + return dest; +} + +/*! + * @brief returns normalized imaginary part of quaternion + * + * @param[in] q quaternion + */ +CGLM_INLINE +vec3s +glms_quat_imagn(versors q) { + vec3s dest; + glm_normalize_to(q.raw, dest.raw); + return dest; +} + +/*! + * @brief returns length of imaginary part of quaternion + * + * @param[in] q quaternion + */ +CGLM_INLINE +float +glms_quat_imaglen(versors q) { + return glm_quat_imaglen(q.raw); +} + +/*! + * @brief returns angle of quaternion + * + * @param[in] q quaternion + */ +CGLM_INLINE +float +glms_quat_angle(versors q) { + return glm_quat_angle(q.raw); +} + +/*! + * @brief axis of quaternion + * + * @param[in] q quaternion + * @returns axis of quaternion + */ +CGLM_INLINE +vec3s +glms_quat_axis(versors q) { + vec3s dest; + glm_quat_axis(q.raw, dest.raw); + return dest; +} + +/*! + * @brief multiplies two quaternion and stores result in dest + * this is also called Hamilton Product + * + * According to WikiPedia: + * The product of two rotation quaternions [clarification needed] will be + * equivalent to the rotation q followed by the rotation p + * + * @param[in] p quaternion 1 + * @param[in] q quaternion 2 + * @returns result quaternion + */ +CGLM_INLINE +versors +glms_quat_mul(versors p, versors q) { + versors dest; + glm_quat_mul(p.raw, q.raw, dest.raw); + return dest; +} + +/*! + * @brief convert quaternion to mat4 + * + * @param[in] q quaternion + * @returns result matrix + */ +CGLM_INLINE +mat4s +glms_quat_mat4(versors q) { + mat4s dest; + glm_quat_mat4(q.raw, dest.raw); + return dest; +} + +/*! + * @brief convert quaternion to mat4 (transposed) + * + * @param[in] q quaternion + * @returns result matrix as transposed + */ +CGLM_INLINE +mat4s +glms_quat_mat4t(versors q) { + mat4s dest; + glm_quat_mat4t(q.raw, dest.raw); + return dest; +} + +/*! + * @brief convert quaternion to mat3 + * + * @param[in] q quaternion + * @returns result matrix + */ +CGLM_INLINE +mat3s +glms_quat_mat3(versors q) { + mat3s dest; + glm_quat_mat3(q.raw, dest.raw); + return dest; +} + +/*! + * @brief convert quaternion to mat3 (transposed) + * + * @param[in] q quaternion + * @returns result matrix + */ +CGLM_INLINE +mat3s +glms_quat_mat3t(versors q) { + mat3s dest; + glm_quat_mat3t(q.raw, dest.raw); + return dest; +} + +/*! + * @brief interpolates between two quaternions + * using linear interpolation (LERP) + * + * @param[in] from from + * @param[in] to to + * @param[in] t interpolant (amount) + * @returns result quaternion + */ +CGLM_INLINE +versors +glms_quat_lerp(versors from, versors to, float t) { + versors dest; + glm_quat_lerp(from.raw, to.raw, t, dest.raw); + return dest; +} + +/*! + * @brief interpolates between two quaternions + * using linear interpolation (LERP) + * + * @param[in] from from + * @param[in] to to + * @param[in] t interpolant (amount) clamped between 0 and 1 + * @returns result quaternion + */ +CGLM_INLINE +versors +glms_quat_lerpc(versors from, versors to, float t) { + versors dest; + glm_quat_lerpc(from.raw, to.raw, t, dest.raw); + return dest; +} + +/*! + * @brief interpolates between two quaternions + * taking the shortest rotation path using + * normalized linear interpolation (NLERP) + * + * @param[in] from from + * @param[in] to to + * @param[in] t interpolant (amount) + * @returns result quaternion + */ +CGLM_INLINE +versors +glms_quat_nlerp(versors from, versors to, float t) { + versors dest; + glm_quat_nlerp(from.raw, to.raw, t, dest.raw); + return dest; +} + +/*! + * @brief interpolates between two quaternions + * using spherical linear interpolation (SLERP) + * + * @param[in] from from + * @param[in] to to + * @param[in] t amout + * @returns result quaternion + */ +CGLM_INLINE +versors +glms_quat_slerp(versors from, versors to, float t) { + versors dest; + glm_quat_slerp(from.raw, to.raw, t, dest.raw); + return dest; +} + +/*! + * @brief creates view matrix using quaternion as camera orientation + * + * @param[in] eye eye + * @param[in] ori orientation in world space as quaternion + * @returns view matrix + */ +CGLM_INLINE +mat4s +glms_quat_look(vec3s eye, versors ori) { + mat4s dest; + glm_quat_look(eye.raw, ori.raw, dest.raw); + return dest; +} + +/*! + * @brief creates look rotation quaternion + * + * @param[in] dir direction to look + * @param[in] up up vector + * @returns destination quaternion + */ +CGLM_INLINE +versors +glms_quat_for(vec3s dir, vec3s up) { + versors dest; + glm_quat_for(dir.raw, up.raw, dest.raw); + return dest; +} + +/*! + * @brief creates look rotation quaternion using source and + * destination positions p suffix stands for position + * + * @param[in] from source point + * @param[in] to destination point + * @param[in] up up vector + * @returns destination quaternion + */ +CGLM_INLINE +versors +glms_quat_forp(vec3s from, vec3s to, vec3s up) { + versors dest; + glm_quat_forp(from.raw, to.raw, up.raw, dest.raw); + return dest; +} + +/*! + * @brief rotate vector using using quaternion + * + * @param[in] q quaternion + * @param[in] v vector to rotate + * @returns rotated vector + */ +CGLM_INLINE +vec3s +glms_quat_rotatev(versors q, vec3s v) { + vec3s dest; + glm_quat_rotatev(q.raw, v.raw, dest.raw); + return dest; +} + +/*! + * @brief rotate existing transform matrix using quaternion + * + * @param[in] m existing transform matrix + * @param[in] q quaternion + * @returns rotated matrix/transform + */ +CGLM_INLINE +mat4s +glms_quat_rotate(mat4s m, versors q) { + glm_quat_rotate(m.raw, q.raw, m.raw); + return m; +} + +/*! + * @brief rotate existing transform matrix using quaternion at pivot point + * + * @param[in, out] m existing transform matrix + * @param[in] q quaternion + * @returns pivot + */ +CGLM_INLINE +mat4s +glms_quat_rotate_at(mat4s m, versors q, vec3s pivot) { + glm_quat_rotate_at(m.raw, q.raw, pivot.raw); + return m; +} + +/*! + * @brief rotate NEW transform matrix using quaternion at pivot point + * + * this creates rotation matrix, it assumes you don't have a matrix + * + * this should work faster than glm_quat_rotate_at because it reduces + * one glm_translate. + * + * @param[in] q quaternion + * @returns pivot + */ +CGLM_INLINE +mat4s +glms_quat_rotate_atm(versors q, vec3s pivot) { + mat4s dest; + glm_quat_rotate_atm(dest.raw, q.raw, pivot.raw); + return dest; +} + +#endif /* cglms_quat_h */ diff --git a/include/cglm/struct/sphere.h b/include/cglm/struct/sphere.h new file mode 100644 index 0000000..9859c72 --- /dev/null +++ b/include/cglm/struct/sphere.h @@ -0,0 +1,93 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglms_spheres_h +#define cglms_spheres_h + +#include "../common.h" +#include "../types-struct.h" +#include "../sphere.h" +#include "mat4.h" + +/* + Sphere Representation in cglm: [center.x, center.y, center.z, radii] + + You could use this representation or you can convert it to vec4 before call + any function + */ + +/*! + * @brief helper for getting sphere radius + * + * @param[in] s sphere + * + * @return returns radii + */ +CGLM_INLINE +float +glms_sphere_radii(vec4s s) { + return glm_sphere_radii(s.raw); +} + +/*! + * @brief apply transform to sphere, it is just wrapper for glm_mat4_mulv3 + * + * @param[in] s sphere + * @param[in] m transform matrix + * @returns transformed sphere + */ +CGLM_INLINE +vec4s +glms_sphere_transform(vec4s s, mat4s m) { + vec4s r; + glm_sphere_transform(s.raw, m.raw, r.raw); + return r; +} + +/*! + * @brief merges two spheres and creates a new one + * + * two sphere must be in same space, for instance if one in world space then + * the other must be in world space too, not in local space. + * + * @param[in] s1 sphere 1 + * @param[in] s2 sphere 2 + * returns merged/extended sphere + */ +CGLM_INLINE +vec4s +glms_sphere_merge(vec4s s1, vec4s s2) { + vec4s r; + glm_sphere_merge(s1.raw, s2.raw, r.raw); + return r; +} + +/*! + * @brief check if two sphere intersects + * + * @param[in] s1 sphere + * @param[in] s2 other sphere + */ +CGLM_INLINE +bool +glms_sphere_sphere(vec4s s1, vec4s s2) { + return glm_sphere_sphere(s1.raw, s2.raw); +} + +/*! + * @brief check if sphere intersects with point + * + * @param[in] s sphere + * @param[in] point point + */ +CGLM_INLINE +bool +glms_sphere_point(vec4s s, vec3s point) { + return glm_sphere_point(s.raw, point.raw); +} + +#endif /* cglms_spheres_h */ diff --git a/include/cglm/struct/vec2-ext.h b/include/cglm/struct/vec2-ext.h new file mode 100644 index 0000000..5d6682d --- /dev/null +++ b/include/cglm/struct/vec2-ext.h @@ -0,0 +1,239 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/*! + * @brief SIMD like functions + */ + +/* + Functions: + CGLM_INLINE vec2s glms_vec2_fill(float val) + CGLM_INLINE bool glms_vec2_eq(vec2s v, float val) + CGLM_INLINE bool glms_vec2_eq_eps(vec2s v, float val) + CGLM_INLINE bool glms_vec2_eq_all(vec2s v) + CGLM_INLINE bool glms_vec2_eqv(vec2s a, vec2s b) + CGLM_INLINE bool glms_vec2_eqv_eps(vec2s a, vec2s b) + CGLM_INLINE float glms_vec2_max(vec2s v) + CGLM_INLINE float glms_vec2_min(vec2s v) + CGLM_INLINE bool glms_vec2_isnan(vec2s v) + CGLM_INLINE bool glms_vec2_isinf(vec2s v) + CGLM_INLINE bool glms_vec2_isvalid(vec2s v) + CGLM_INLINE vec2s glms_vec2_sign(vec2s v) + CGLM_INLINE vec2s glms_vec2_sqrt(vec2s v) + */ + +#ifndef cglms_vec2s_ext_h +#define cglms_vec2s_ext_h + +#include "../common.h" +#include "../types-struct.h" +#include "../util.h" +#include "../vec2-ext.h" + +/*! + * @brief fill a vector with specified value + * + * @param[in] val value + * @returns dest + */ +CGLM_INLINE +vec2s +glms_vec2_fill(float val) { + vec2s r; + glm_vec2_fill(r.raw, val); + return r; +} + +/*! + * @brief check if vector is equal to value (without epsilon) + * + * @param[in] v vector + * @param[in] val value + */ +CGLM_INLINE +bool +glms_vec2_eq(vec2s v, float val) { + return glm_vec2_eq(v.raw, val); +} + +/*! + * @brief check if vector is equal to value (with epsilon) + * + * @param[in] v vector + * @param[in] val value + */ +CGLM_INLINE +bool +glms_vec2_eq_eps(vec2s v, float val) { + return glm_vec2_eq_eps(v.raw, val); +} + +/*! + * @brief check if vectors members are equal (without epsilon) + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glms_vec2_eq_all(vec2s v) { + return glm_vec2_eq_all(v.raw); +} + +/*! + * @brief check if vector is equal to another (without epsilon) + * + * @param[in] a vector + * @param[in] b vector + */ +CGLM_INLINE +bool +glms_vec2_eqv(vec2s a, vec2s b) { + return glm_vec2_eqv(a.raw, b.raw); +} + +/*! + * @brief check if vector is equal to another (with epsilon) + * + * @param[in] a vector + * @param[in] b vector + */ +CGLM_INLINE +bool +glms_vec2_eqv_eps(vec2s a, vec2s b) { + return glm_vec2_eqv_eps(a.raw, b.raw); +} + +/*! + * @brief max value of vector + * + * @param[in] v vector + */ +CGLM_INLINE +float +glms_vec2_max(vec2s v) { + return glm_vec2_max(v.raw); +} + +/*! + * @brief min value of vector + * + * @param[in] v vector + */ +CGLM_INLINE +float +glms_vec2_min(vec2s v) { + return glm_vec2_min(v.raw); +} + +/*! + * @brief check if all items are NaN (not a number) + * you should only use this in DEBUG mode or very critical asserts + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glms_vec2_isnan(vec2s v) { + return glm_vec2_isnan(v.raw); +} + +/*! + * @brief check if all items are INFINITY + * you should only use this in DEBUG mode or very critical asserts + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glms_vec2_isinf(vec2s v) { + return glm_vec2_isinf(v.raw); +} + +/*! + * @brief check if all items are valid number + * you should only use this in DEBUG mode or very critical asserts + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glms_vec2_isvalid(vec2s v) { + return glm_vec2_isvalid(v.raw); +} + +/*! + * @brief get sign of 32 bit float as +1, -1, 0 + * + * Important: It returns 0 for zero/NaN input + * + * @param v vector + * @returns sign vector + */ +CGLM_INLINE +vec2s +glms_vec2_sign(vec2s v) { + vec2s r; + glm_vec2_sign(v.raw, r.raw); + return r; +} + +/*! + * @brief square root of each vector item + * + * @param[in] v vector + * @returns destination vector + */ +CGLM_INLINE +vec2s +glms_vec2_sqrt(vec2s v) { + vec2s r; + glm_vec2_sqrt(v.raw, r.raw); + return r; +} + +/*! + * @brief treat vectors as complex numbers and multiply them as such. + * + * @param[in] a left number + * @param[in] b right number + * @param[out] dest destination number + */ +CGLM_INLINE +vec2s +glms_vec2_complex_mul(vec2s a, vec2s b, vec2s dest) { + glm_vec2_complex_mul(a.raw, b.raw, dest.raw); + return dest; +} + +/*! + * @brief treat vectors as complex numbers and divide them as such. + * + * @param[in] a left number (numerator) + * @param[in] b right number (denominator) + * @param[out] dest destination number + */ +CGLM_INLINE +vec2s +glms_vec2_complex_div(vec2s a, vec2s b, vec2s dest) { + glm_vec2_complex_div(a.raw, b.raw, dest.raw); + return dest; +} + +/*! + * @brief treat the vector as a complex number and conjugate it as such. + * + * @param[in] a the number + * @param[out] dest destination number + */ +CGLM_INLINE +vec2s +glms_vec2_complex_conjugate(vec2s a, vec2s dest) { + glm_vec2_complex_conjugate(a.raw, dest.raw); + return dest; +} + +#endif /* cglms_vec2s_ext_h */ diff --git a/include/cglm/struct/vec2.h b/include/cglm/struct/vec2.h new file mode 100644 index 0000000..60f66d3 --- /dev/null +++ b/include/cglm/struct/vec2.h @@ -0,0 +1,561 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Macros: + GLMS_VEC2_ONE_INIT + GLMS_VEC2_ZERO_INIT + GLMS_VEC2_ONE + GLMS_VEC2_ZERO + + Functions: + CGLM_INLINE vec2s glms_vec2(vec3s v3) + CGLM_INLINE void glms_vec2_pack(vec2s dst[], vec2 src[], size_t len) + CGLM_INLINE void glms_vec2_unpack(vec2 dst[], vec2s src[], size_t len) + CGLM_INLINE vec2s glms_vec2_zero(void) + CGLM_INLINE vec2s glms_vec2_one(void) + CGLM_INLINE float glms_vec2_dot(vec2s a, vec2s b) + CGLM_INLINE float glms_vec2_cross(vec2s a, vec2s b) + CGLM_INLINE float glms_vec2_norm2(vec2s v) + CGLM_INLINE float glms_vec2_norm(vec2s v) + CGLM_INLINE vec2s glms_vec2_add(vec2s a, vec2s b) + CGLM_INLINE vec2s glms_vec2_adds(vec2s a, float s) + CGLM_INLINE vec2s glms_vec2_sub(vec2s a, vec2s b) + CGLM_INLINE vec2s glms_vec2_subs(vec2s a, float s) + CGLM_INLINE vec2s glms_vec2_mul(vec2s a, vec2s b) + CGLM_INLINE vec2s glms_vec2_scale(vec2s v, float s) + CGLM_INLINE vec2s glms_vec2_scale_as(vec2s v, float s) + CGLM_INLINE vec2s glms_vec2_div(vec2s a, vec2s b) + CGLM_INLINE vec2s glms_vec2_divs(vec2s a, float s) + CGLM_INLINE vec2s glms_vec2_addadd(vec2s a, vec2s b, vec2s dest) + CGLM_INLINE vec2s glms_vec2_subadd(vec2s a, vec2s b, vec2s dest) + CGLM_INLINE vec2s glms_vec2_muladd(vec2s a, vec2s b, vec2s dest) + CGLM_INLINE vec2s glms_vec2_muladds(vec2s a, float s, vec2s dest) + CGLM_INLINE vec2s glms_vec2_maxadd(vec2s a, vec2s b, vec2s dest) + CGLM_INLINE vec2s glms_vec2_minadd(vec2s a, vec2s b, vec2s dest) + CGLM_INLINE vec2s glms_vec2_negate(vec2s v) + CGLM_INLINE vec2s glms_vec2_normalize(vec2s v) + CGLM_INLINE vec2s glms_vec2_rotate(vec2s v, float angle, vec2s axis) + CGLM_INLINE float glms_vec2_distance(vec2s a, vec2s b) + CGLM_INLINE float glms_vec2_distance2(vec2s a, vec2s b) + CGLM_INLINE vec2s glms_vec2_maxv(vec2s a, vec2s b) + CGLM_INLINE vec2s glms_vec2_minv(vec2s a, vec2s b) + CGLM_INLINE vec2s glms_vec2_clamp(vec2s v, float minVal, float maxVal) + CGLM_INLINE vec2s glms_vec2_lerp(vec2s from, vec2s to, float t) + */ + +#ifndef cglms_vec2s_h +#define cglms_vec2s_h + +#include "../common.h" +#include "../types-struct.h" +#include "../util.h" +#include "../vec2.h" +#include "vec2-ext.h" + +#define GLMS_VEC2_ONE_INIT {GLM_VEC2_ONE_INIT} +#define GLMS_VEC2_ZERO_INIT {GLM_VEC2_ZERO_INIT} + +#define GLMS_VEC2_ONE ((vec2s)GLMS_VEC2_ONE_INIT) +#define GLMS_VEC2_ZERO ((vec2s)GLMS_VEC2_ZERO_INIT) + +/*! + * @brief init vec2 using vec2 + * + * @param[in] v3 vector3 + * @returns destination + */ +CGLM_INLINE +vec2s +glms_vec2(vec3s v3) { + vec2s r; + glm_vec2(v3.raw, r.raw); + return r; +} + +/*! + * @brief pack an array of vec2 into an array of vec2s + * + * @param[out] dst array of vec2 + * @param[in] src array of vec2s + * @param[in] len number of elements + */ +CGLM_INLINE +void +glms_vec2_pack(vec2s dst[], vec2 src[], size_t len) { + size_t i; + + for (i = 0; i < len; i++) { + glm_vec2_copy(src[i], dst[i].raw); + } +} + +/*! + * @brief unpack an array of vec2s into an array of vec2 + * + * @param[out] dst array of vec2s + * @param[in] src array of vec2 + * @param[in] len number of elements + */ +CGLM_INLINE +void +glms_vec2_unpack(vec2 dst[], vec2s src[], size_t len) { + size_t i; + + for (i = 0; i < len; i++) { + glm_vec2_copy(src[i].raw, dst[i]); + } +} + +/*! + * @brief make vector zero + * + * @returns zero vector + */ +CGLM_INLINE +vec2s +glms_vec2_zero(void) { + vec2s r; + glm_vec2_zero(r.raw); + return r; +} + +/*! + * @brief make vector one + * + * @returns one vector + */ +CGLM_INLINE +vec2s +glms_vec2_one(void) { + vec2s r; + glm_vec2_one(r.raw); + return r; +} + +/*! + * @brief vec2 dot product + * + * @param[in] a vector1 + * @param[in] b vector2 + * + * @return dot product + */ +CGLM_INLINE +float +glms_vec2_dot(vec2s a, vec2s b) { + return glm_vec2_dot(a.raw, b.raw); +} + +/*! + * @brief vec2 cross product + * + * REF: http://allenchou.net/2013/07/cross-product-of-2d-vectors/ + * + * @param[in] a vector1 + * @param[in] b vector2 + * + * @return Z component of cross product + */ +CGLM_INLINE +float +glms_vec2_cross(vec2s a, vec2s b) { + return glm_vec2_cross(a.raw, b.raw); +} + +/*! + * @brief norm * norm (magnitude) of vec + * + * we can use this func instead of calling norm * norm, because it would call + * sqrtf fuction twice but with this func we can avoid func call, maybe this is + * not good name for this func + * + * @param[in] v vector + * + * @return norm * norm + */ +CGLM_INLINE +float +glms_vec2_norm2(vec2s v) { + return glm_vec2_norm2(v.raw); +} + +/*! + * @brief norm (magnitude) of vec2 + * + * @param[in] v vector + * + * @return norm + */ +CGLM_INLINE +float +glms_vec2_norm(vec2s v) { + return glm_vec2_norm(v.raw); +} + +/*! + * @brief add a vector to b vector store result in dest + * + * @param[in] a vector1 + * @param[in] b vector2 + * @returns destination vector + */ +CGLM_INLINE +vec2s +glms_vec2_add(vec2s a, vec2s b) { + vec2s r; + glm_vec2_add(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief add scalar to v vector store result in dest (d = v + s) + * + * @param[in] a vector + * @param[in] s scalar + * @returns destination vector + */ +CGLM_INLINE +vec2s +glms_vec2_adds(vec2s a, float s) { + vec2s r; + glm_vec2_adds(a.raw, s, r.raw); + return r; +} + +/*! + * @brief subtract b vector from a vector store result in dest + * + * @param[in] a vector1 + * @param[in] b vector2 + * @returns destination vector + */ +CGLM_INLINE +vec2s +glms_vec2_sub(vec2s a, vec2s b) { + vec2s r; + glm_vec2_sub(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief subtract scalar from v vector store result in dest (d = v - s) + * + * @param[in] a vector + * @param[in] s scalar + * @returns destination vector + */ +CGLM_INLINE +vec2s +glms_vec2_subs(vec2s a, float s) { + vec2s r; + glm_vec2_subs(a.raw, s, r.raw); + return r; +} + +/*! + * @brief multiply two vector (component-wise multiplication) + * + * @param a vector1 + * @param b vector2 + * @returns v3 = (a[0] * b[0], a[1] * b[1], a[2] * b[2]) + */ +CGLM_INLINE +vec2s +glms_vec2_mul(vec2s a, vec2s b) { + vec2s r; + glm_vec2_mul(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief multiply/scale vec2 vector with scalar: result = v * s + * + * @param[in] v vector + * @param[in] s scalar + * @returns destination vector + */ +CGLM_INLINE +vec2s +glms_vec2_scale(vec2s v, float s) { + vec2s r; + glm_vec2_scale(v.raw, s, r.raw); + return r; +} + +/*! + * @brief make vec2 vector scale as specified: result = unit(v) * s + * + * @param[in] v vector + * @param[in] s scalar + * @returns destination vector + */ +CGLM_INLINE +vec2s +glms_vec2_scale_as(vec2s v, float s) { + vec2s r; + glm_vec2_scale_as(v.raw, s, r.raw); + return r; +} + +/*! + * @brief div vector with another component-wise division: d = a / b + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns result = (a[0]/b[0], a[1]/b[1], a[2]/b[2]) + */ +CGLM_INLINE +vec2s +glms_vec2_div(vec2s a, vec2s b) { + vec2s r; + glm_vec2_div(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief div vector with scalar: d = v / s + * + * @param[in] a vector + * @param[in] s scalar + * @returns result = (a[0]/s, a[1]/s, a[2]/s) + */ +CGLM_INLINE +vec2s +glms_vec2_divs(vec2s a, float s) { + vec2s r; + glm_vec2_divs(a.raw, s, r.raw); + return r; +} + +/*! + * @brief add two vectors and add result to sum + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns dest += (a + b) + */ +CGLM_INLINE +vec2s +glms_vec2_addadd(vec2s a, vec2s b, vec2s dest) { + glm_vec2_addadd(a.raw, b.raw, dest.raw); + return dest; +} + +/*! + * @brief sub two vectors and add result to dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns dest += (a + b) + */ +CGLM_INLINE +vec2s +glms_vec2_subadd(vec2s a, vec2s b, vec2s dest) { + glm_vec2_subadd(a.raw, b.raw, dest.raw); + return dest; +} + +/*! + * @brief mul two vectors and add result to dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns dest += (a * b) + */ +CGLM_INLINE +vec2s +glms_vec2_muladd(vec2s a, vec2s b, vec2s dest) { + glm_vec2_muladd(a.raw, b.raw, dest.raw); + return dest; +} + +/*! + * @brief mul vector with scalar and add result to sum + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector + * @param[in] s scalar + * @returns dest += (a * b) + */ +CGLM_INLINE +vec2s +glms_vec2_muladds(vec2s a, float s, vec2s dest) { + glm_vec2_muladds(a.raw, s, dest.raw); + return dest; +} + +/*! + * @brief add max of two vector to result/dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns dest += max(a, b) + */ +CGLM_INLINE +vec2s +glms_vec2_maxadd(vec2s a, vec2s b, vec2s dest) { + glm_vec2_maxadd(a.raw, b.raw, dest.raw); + return dest; +} + +/*! + * @brief add min of two vector to result/dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns dest += min(a, b) + */ +CGLM_INLINE +vec2s +glms_vec2_minadd(vec2s a, vec2s b, vec2s dest) { + glm_vec2_minadd(a.raw, b.raw, dest.raw); + return dest; +} + +/*! + * @brief negate vector components + * + * @param[in] v vector + * @returns negated vector + */ +CGLM_INLINE +vec2s +glms_vec2_negate(vec2s v) { + glm_vec2_negate(v.raw); + return v; +} + +/*! + * @brief normalize vec2 and store result in same vec + * + * @param[in] v vector + * @returns normalized vector + */ +CGLM_INLINE +vec2s +glms_vec2_normalize(vec2s v) { + glm_vec2_normalize(v.raw); + return v; +} + +/*! + * @brief rotate vec2 by angle using Rodrigues' rotation formula + * + * @param[in] v vector + * @param[in] angle angle by radians + * @returns rotated vector + */ +CGLM_INLINE +vec2s +glms_vec2_rotate(vec2s v, float angle) { + vec2s r; + glm_vec2_rotate(v.raw, angle, r.raw); + return r; +} + +/** + * @brief distance between two vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @return distance + */ +CGLM_INLINE +float +glms_vec2_distance(vec2s a, vec2s b) { + return glm_vec2_distance(a.raw, b.raw); +} + +/** + * @brief squared distance between two vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @return squared distance (distance * distance) + */ +CGLM_INLINE +float +glms_vec2_distance2(vec2s a, vec2s b) { + return glm_vec2_distance2(a.raw, b.raw); +} + +/*! + * @brief max values of vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @returns destination + */ +CGLM_INLINE +vec2s +glms_vec2_maxv(vec2s a, vec2s b) { + vec2s r; + glm_vec2_maxv(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief min values of vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @returns destination + */ +CGLM_INLINE +vec2s +glms_vec2_minv(vec2s a, vec2s b) { + vec2s r; + glm_vec2_minv(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief clamp vector's individual members between min and max values + * + * @param[in] v vector + * @param[in] minVal minimum value + * @param[in] maxVal maximum value + * @returns clamped vector + */ +CGLM_INLINE +vec2s +glms_vec2_clamp(vec2s v, float minVal, float maxVal) { + glm_vec2_clamp(v.raw, minVal, maxVal); + return v; +} + +/*! + * @brief linear interpolation between two vectors + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) + * @returns destination + */ +CGLM_INLINE +vec2s +glms_vec2_lerp(vec2s from, vec2s to, float t) { + vec2s r; + glm_vec2_lerp(from.raw, to.raw, t, r.raw); + return r; +} + +#endif /* cglms_vec2s_h */ diff --git a/include/cglm/struct/vec3-ext.h b/include/cglm/struct/vec3-ext.h new file mode 100644 index 0000000..8e5ca70 --- /dev/null +++ b/include/cglm/struct/vec3-ext.h @@ -0,0 +1,257 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/*! + * @brief SIMD like functions + */ + +/* + Functions: + CGLM_INLINE vec3s glms_vec3_broadcast(float val); + CGLM_INLINE vec3s glms_vec3_fill(float val); + CGLM_INLINE bool glms_vec3_eq(vec3s v, float val); + CGLM_INLINE bool glms_vec3_eq_eps(vec3s v, float val); + CGLM_INLINE bool glms_vec3_eq_all(vec3s v); + CGLM_INLINE bool glms_vec3_eqv(vec3s a, vec3s b); + CGLM_INLINE bool glms_vec3_eqv_eps(vec3s a, vec3s b); + CGLM_INLINE float glms_vec3_max(vec3s v); + CGLM_INLINE float glms_vec3_min(vec3s v); + CGLM_INLINE bool glms_vec3_isnan(vec3s v); + CGLM_INLINE bool glms_vec3_isinf(vec3s v); + CGLM_INLINE bool glms_vec3_isvalid(vec3s v); + CGLM_INLINE vec3s glms_vec3_sign(vec3s v); + CGLM_INLINE vec3s glms_vec3_abs(vec3s v); + CGLM_INLINE vec3s glms_vec3_fract(vec3s v); + CGLM_INLINE float glms_vec3_hadd(vec3s v); + CGLM_INLINE vec3s glms_vec3_sqrt(vec3s v); + */ + +#ifndef cglms_vec3s_ext_h +#define cglms_vec3s_ext_h + +#include "../common.h" +#include "../types-struct.h" +#include "../util.h" +#include "../vec3-ext.h" + +/*! + * @brief fill a vector with specified value + * + * @param[in] val value + * @returns dest + */ +CGLM_INLINE +vec3s +glms_vec3_broadcast(float val) { + vec3s r; + glm_vec3_broadcast(val, r.raw); + return r; +} + +/*! + * @brief fill a vector with specified value + * + * @param[in] val value + * @returns dest + */ +CGLM_INLINE +vec3s +glms_vec3_fill(float val) { + vec3s r; + glm_vec3_fill(r.raw, val); + return r; +} + +/*! + * @brief check if vector is equal to value (without epsilon) + * + * @param[in] v vector + * @param[in] val value + */ +CGLM_INLINE +bool +glms_vec3_eq(vec3s v, float val) { + return glm_vec3_eq(v.raw, val); +} + +/*! + * @brief check if vector is equal to value (with epsilon) + * + * @param[in] v vector + * @param[in] val value + */ +CGLM_INLINE +bool +glms_vec3_eq_eps(vec3s v, float val) { + return glm_vec3_eq_eps(v.raw, val); +} + +/*! + * @brief check if vectors members are equal (without epsilon) + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glms_vec3_eq_all(vec3s v) { + return glm_vec3_eq_all(v.raw); +} + +/*! + * @brief check if vector is equal to another (without epsilon) + * + * @param[in] a vector + * @param[in] b vector + */ +CGLM_INLINE +bool +glms_vec3_eqv(vec3s a, vec3s b) { + return glm_vec3_eqv(a.raw, b.raw); +} + +/*! + * @brief check if vector is equal to another (with epsilon) + * + * @param[in] a vector + * @param[in] b vector + */ +CGLM_INLINE +bool +glms_vec3_eqv_eps(vec3s a, vec3s b) { + return glm_vec3_eqv_eps(a.raw, b.raw); +} + +/*! + * @brief max value of vector + * + * @param[in] v vector + */ +CGLM_INLINE +float +glms_vec3_max(vec3s v) { + return glm_vec3_max(v.raw); +} + +/*! + * @brief min value of vector + * + * @param[in] v vector + */ +CGLM_INLINE +float +glms_vec3_min(vec3s v) { + return glm_vec3_min(v.raw); +} + +/*! + * @brief check if all items are NaN (not a number) + * you should only use this in DEBUG mode or very critical asserts + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glms_vec3_isnan(vec3s v) { + return glm_vec3_isnan(v.raw); +} + +/*! + * @brief check if all items are INFINITY + * you should only use this in DEBUG mode or very critical asserts + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glms_vec3_isinf(vec3s v) { + return glm_vec3_isinf(v.raw); +} + +/*! + * @brief check if all items are valid number + * you should only use this in DEBUG mode or very critical asserts + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glms_vec3_isvalid(vec3s v) { + return glm_vec3_isvalid(v.raw); +} + +/*! + * @brief get sign of 32 bit float as +1, -1, 0 + * + * Important: It returns 0 for zero/NaN input + * + * @param v vector + * @returns sign vector + */ +CGLM_INLINE +vec3s +glms_vec3_sign(vec3s v) { + vec3s r; + glm_vec3_sign(v.raw, r.raw); + return r; +} + +/*! + * @brief absolute value of each vector item + * + * @param[in] v vector + * @return destination vector + */ +CGLM_INLINE +vec3s +glms_vec3_abs(vec3s v) { + vec3s r; + glm_vec3_abs(v.raw, r.raw); + return r; +} + +/*! + * @brief fractional part of each vector item + * + * @param[in] v vector + * @return dest destination vector + */ +CGLM_INLINE +vec3s +glms_vec3_fract(vec3s v) { + vec3s r; + glm_vec3_fract(v.raw, r.raw); + return r; +} + +/*! + * @brief vector reduction by summation + * @warning could overflow + * + * @param[in] v vector + * @return sum of all vector's elements + */ +CGLM_INLINE +float +glms_vec3_hadd(vec3s v) { + return glm_vec3_hadd(v.raw); +} + +/*! + * @brief square root of each vector item + * + * @param[in] v vector + * @returns destination vector + */ +CGLM_INLINE +vec3s +glms_vec3_sqrt(vec3s v) { + vec3s r; + glm_vec3_sqrt(v.raw, r.raw); + return r; +} + +#endif /* cglms_vec3s_ext_h */ diff --git a/include/cglm/struct/vec3.h b/include/cglm/struct/vec3.h new file mode 100644 index 0000000..7fa5b06 --- /dev/null +++ b/include/cglm/struct/vec3.h @@ -0,0 +1,970 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Macros: + GLMS_VEC3_ONE_INIT + GLMS_VEC3_ZERO_INIT + GLMS_VEC3_ONE + GLMS_VEC3_ZERO + GLMS_YUP + GLMS_ZUP + GLMS_XUP + + Functions: + CGLM_INLINE vec3s glms_vec3(vec4s v4); + CGLM_INLINE void glms_vec3_pack(vec3s dst[], vec3 src[], size_t len); + CGLM_INLINE void glms_vec3_unpack(vec3 dst[], vec3s src[], size_t len); + CGLM_INLINE vec3s glms_vec3_zero(void); + CGLM_INLINE vec3s glms_vec3_one(void); + CGLM_INLINE float glms_vec3_dot(vec3s a, vec3s b); + CGLM_INLINE float glms_vec3_norm2(vec3s v); + CGLM_INLINE float glms_vec3_norm(vec3s v); + CGLM_INLINE float glms_vec3_norm_one(vec3s v); + CGLM_INLINE float glms_vec3_norm_inf(vec3s v); + CGLM_INLINE vec3s glms_vec3_add(vec3s a, vec3s b); + CGLM_INLINE vec3s glms_vec3_adds(vec3s a, float s); + CGLM_INLINE vec3s glms_vec3_sub(vec3s a, vec3s b); + CGLM_INLINE vec3s glms_vec3_subs(vec3s a, float s); + CGLM_INLINE vec3s glms_vec3_mul(vec3s a, vec3s b); + CGLM_INLINE vec3s glms_vec3_scale(vec3s v, float s); + CGLM_INLINE vec3s glms_vec3_scale_as(vec3s v, float s); + CGLM_INLINE vec3s glms_vec3_div(vec3s a, vec3s b); + CGLM_INLINE vec3s glms_vec3_divs(vec3s a, float s); + CGLM_INLINE vec3s glms_vec3_addadd(vec3s a, vec3s b, vec3s dest); + CGLM_INLINE vec3s glms_vec3_subadd(vec3s a, vec3s b, vec3s dest); + CGLM_INLINE vec3s glms_vec3_muladd(vec3s a, vec3s b, vec3s dest); + CGLM_INLINE vec3s glms_vec3_muladds(vec3s a, float s, vec3s dest); + CGLM_INLINE vec3s glms_vec3_maxadd(vec3s a, vec3s b, vec3s dest); + CGLM_INLINE vec3s glms_vec3_minadd(vec3s a, vec3s b, vec3s dest); + CGLM_INLINE vec3s glms_vec3_flipsign(vec3s v); + CGLM_INLINE vec3s glms_vec3_negate(vec3s v); + CGLM_INLINE vec3s glms_vec3_inv(vec3s v); + CGLM_INLINE vec3s glms_vec3_normalize(vec3s v); + CGLM_INLINE vec3s glms_vec3_cross(vec3s a, vec3s b); + CGLM_INLINE vec3s glms_vec3_crossn(vec3s a, vec3s b); + CGLM_INLINE float glms_vec3_angle(vec3s a, vec3s b); + CGLM_INLINE vec3s glms_vec3_rotate(vec3s v, float angle, vec3s axis); + CGLM_INLINE vec3s glms_vec3_rotate_m4(mat4s m, vec3s v); + CGLM_INLINE vec3s glms_vec3_rotate_m3(mat3s m, vec3s v); + CGLM_INLINE vec3s glms_vec3_proj(vec3s a, vec3s b); + CGLM_INLINE vec3s glms_vec3_center(vec3s a, vec3s b); + CGLM_INLINE float glms_vec3_distance(vec3s a, vec3s b); + CGLM_INLINE float glms_vec3_distance2(vec3s a, vec3s b); + CGLM_INLINE vec3s glms_vec3_maxv(vec3s a, vec3s b); + CGLM_INLINE vec3s glms_vec3_minv(vec3s a, vec3s b); + CGLM_INLINE vec3s glms_vec3_ortho(vec3s v); + CGLM_INLINE vec3s glms_vec3_clamp(vec3s v, float minVal, float maxVal); + CGLM_INLINE vec3s glms_vec3_lerp(vec3s from, vec3s to, float t); + CGLM_INLINE vec3s glms_vec3_lerpc(vec3s from, vec3s to, float t); + CGLM_INLINE vec3s glms_vec3_mix(vec3s from, vec3s to, float t); + CGLM_INLINE vec3s glms_vec3_mixc(vec3s from, vec3s to, float t); + CGLM_INLINE vec3s glms_vec3_step_uni(float edge, vec3s x); + CGLM_INLINE vec3s glms_vec3_step(vec3s edge, vec3s x); + CGLM_INLINE vec3s glms_vec3_smoothstep_uni(float edge0, float edge1, vec3s x); + CGLM_INLINE vec3s glms_vec3_smoothstep(vec3s edge0, vec3s edge1, vec3s x); + CGLM_INLINE vec3s glms_vec3_smoothinterp(vec3s from, vec3s to, float t); + CGLM_INLINE vec3s glms_vec3_smoothinterpc(vec3s from, vec3s to, float t); + CGLM_INLINE vec3s glms_vec3_swizzle(vec3s v, int mask); + + Convenient: + CGLM_INLINE vec3s glms_cross(vec3s a, vec3s b); + CGLM_INLINE float glms_dot(vec3s a, vec3s b); + CGLM_INLINE vec3s glms_normalize(vec3s v); + */ + +#ifndef cglms_vec3s_h +#define cglms_vec3s_h + +#include "../common.h" +#include "../types-struct.h" +#include "../util.h" +#include "../vec3.h" +#include "vec3-ext.h" + +#define GLMS_VEC3_ONE_INIT {GLM_VEC3_ONE_INIT} +#define GLMS_VEC3_ZERO_INIT {GLM_VEC3_ZERO_INIT} + +#define GLMS_VEC3_ONE ((vec3s)GLMS_VEC3_ONE_INIT) +#define GLMS_VEC3_ZERO ((vec3s)GLMS_VEC3_ZERO_INIT) + +#define GLMS_YUP ((vec3s){{0.0f, 1.0f, 0.0f}}) +#define GLMS_ZUP ((vec3s){{0.0f, 0.0f, 1.0f}}) +#define GLMS_XUP ((vec3s){{1.0f, 0.0f, 0.0f}}) + +/*! + * @brief init vec3 using vec4 + * + * @param[in] v4 vector4 + * @returns destination + */ +CGLM_INLINE +vec3s +glms_vec3(vec4s v4) { + vec3s r; + glm_vec3(v4.raw, r.raw); + return r; +} + +/*! + * @brief pack an array of vec3 into an array of vec3s + * + * @param[out] dst array of vec3 + * @param[in] src array of vec3s + * @param[in] len number of elements + */ +CGLM_INLINE +void +glms_vec3_pack(vec3s dst[], vec3 src[], size_t len) { + size_t i; + + for (i = 0; i < len; i++) { + glm_vec3_copy(src[i], dst[i].raw); + } +} + +/*! + * @brief unpack an array of vec3s into an array of vec3 + * + * @param[out] dst array of vec3s + * @param[in] src array of vec3 + * @param[in] len number of elements + */ +CGLM_INLINE +void +glms_vec3_unpack(vec3 dst[], vec3s src[], size_t len) { + size_t i; + + for (i = 0; i < len; i++) { + glm_vec3_copy(src[i].raw, dst[i]); + } +} + +/*! + * @brief make vector zero + * + * @returns zero vector + */ +CGLM_INLINE +vec3s +glms_vec3_zero(void) { + vec3s r; + glm_vec3_zero(r.raw); + return r; +} + +/*! + * @brief make vector one + * + * @returns one vector + */ +CGLM_INLINE +vec3s +glms_vec3_one(void) { + vec3s r; + glm_vec3_one(r.raw); + return r; +} + +/*! + * @brief vec3 dot product + * + * @param[in] a vector1 + * @param[in] b vector2 + * + * @return dot product + */ +CGLM_INLINE +float +glms_vec3_dot(vec3s a, vec3s b) { + return glm_vec3_dot(a.raw, b.raw); +} + +/*! + * @brief norm * norm (magnitude) of vec + * + * we can use this func instead of calling norm * norm, because it would call + * sqrtf fuction twice but with this func we can avoid func call, maybe this is + * not good name for this func + * + * @param[in] v vector + * + * @return norm * norm + */ +CGLM_INLINE +float +glms_vec3_norm2(vec3s v) { + return glm_vec3_norm2(v.raw); +} + +/*! + * @brief norm (magnitude) of vec3 + * + * @param[in] v vector + * + * @return norm + */ +CGLM_INLINE +float +glms_vec3_norm(vec3s v) { + return glm_vec3_norm(v.raw); +} + +/*! + * @brief L1 norm of vec3 + * Also known as Manhattan Distance or Taxicab norm. + * L1 Norm is the sum of the magnitudes of the vectors in a space. + * It is calculated as the sum of the absolute values of the vector components. + * In this norm, all the components of the vector are weighted equally. + * + * This computes: + * R = |v[0]| + |v[1]| + |v[2]| + * + * @param[in] v vector + * + * @return L1 norm + */ +CGLM_INLINE +float +glms_vec3_norm_one(vec3s v) { + return glm_vec3_norm_one(v.raw); +} + +/*! + * @brief Infinity norm of vec3 + * Also known as Maximum norm. + * Infinity Norm is the largest magnitude among each element of a vector. + * It is calculated as the maximum of the absolute values of the vector components. + * + * This computes: + * inf norm = max(|v[0]|, |v[1]|, |v[2]|) + * + * @param[in] v vector + * + * @return Infinity norm + */ +CGLM_INLINE +float +glms_vec3_norm_inf(vec3s v) { + return glm_vec3_norm_inf(v.raw); +} + +/*! + * @brief add a vector to b vector store result in dest + * + * @param[in] a vector1 + * @param[in] b vector2 + * @returns destination vector + */ +CGLM_INLINE +vec3s +glms_vec3_add(vec3s a, vec3s b) { + vec3s r; + glm_vec3_add(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief add scalar to v vector store result in dest (d = v + s) + * + * @param[in] a vector + * @param[in] s scalar + * @returns destination vector + */ +CGLM_INLINE +vec3s +glms_vec3_adds(vec3s a, float s) { + vec3s r; + glm_vec3_adds(a.raw, s, r.raw); + return r; +} + +/*! + * @brief subtract b vector from a vector store result in dest + * + * @param[in] a vector1 + * @param[in] b vector2 + * @returns destination vector + */ +CGLM_INLINE +vec3s +glms_vec3_sub(vec3s a, vec3s b) { + vec3s r; + glm_vec3_sub(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief subtract scalar from v vector store result in dest (d = v - s) + * + * @param[in] a vector + * @param[in] s scalar + * @returns destination vector + */ +CGLM_INLINE +vec3s +glms_vec3_subs(vec3s a, float s) { + vec3s r; + glm_vec3_subs(a.raw, s, r.raw); + return r; +} + +/*! + * @brief multiply two vector (component-wise multiplication) + * + * @param a vector1 + * @param b vector2 + * @returns v3 = (a[0] * b[0], a[1] * b[1], a[2] * b[2]) + */ +CGLM_INLINE +vec3s +glms_vec3_mul(vec3s a, vec3s b) { + vec3s r; + glm_vec3_mul(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief multiply/scale vec3 vector with scalar: result = v * s + * + * @param[in] v vector + * @param[in] s scalar + * @returns destination vector + */ +CGLM_INLINE +vec3s +glms_vec3_scale(vec3s v, float s) { + vec3s r; + glm_vec3_scale(v.raw, s, r.raw); + return r; +} + +/*! + * @brief make vec3 vector scale as specified: result = unit(v) * s + * + * @param[in] v vector + * @param[in] s scalar + * @returns destination vector + */ +CGLM_INLINE +vec3s +glms_vec3_scale_as(vec3s v, float s) { + vec3s r; + glm_vec3_scale_as(v.raw, s, r.raw); + return r; +} + +/*! + * @brief div vector with another component-wise division: d = a / b + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns result = (a[0]/b[0], a[1]/b[1], a[2]/b[2]) + */ +CGLM_INLINE +vec3s +glms_vec3_div(vec3s a, vec3s b) { + vec3s r; + glm_vec3_div(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief div vector with scalar: d = v / s + * + * @param[in] a vector + * @param[in] s scalar + * @returns result = (a[0]/s, a[1]/s, a[2]/s) + */ +CGLM_INLINE +vec3s +glms_vec3_divs(vec3s a, float s) { + vec3s r; + glm_vec3_divs(a.raw, s, r.raw); + return r; +} + +/*! + * @brief add two vectors and add result to sum + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns dest += (a + b) + */ +CGLM_INLINE +vec3s +glms_vec3_addadd(vec3s a, vec3s b, vec3s dest) { + glm_vec3_addadd(a.raw, b.raw, dest.raw); + return dest; +} + +/*! + * @brief sub two vectors and add result to dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns dest += (a + b) + */ +CGLM_INLINE +vec3s +glms_vec3_subadd(vec3s a, vec3s b, vec3s dest) { + glm_vec3_subadd(a.raw, b.raw, dest.raw); + return dest; +} + +/*! + * @brief mul two vectors and add result to dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns dest += (a * b) + */ +CGLM_INLINE +vec3s +glms_vec3_muladd(vec3s a, vec3s b, vec3s dest) { + glm_vec3_muladd(a.raw, b.raw, dest.raw); + return dest; +} + +/*! + * @brief mul vector with scalar and add result to sum + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector + * @param[in] s scalar + * @returns dest += (a * b) + */ +CGLM_INLINE +vec3s +glms_vec3_muladds(vec3s a, float s, vec3s dest) { + glm_vec3_muladds(a.raw, s, dest.raw); + return dest; +} + +/*! + * @brief add max of two vector to result/dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns dest += max(a, b) + */ +CGLM_INLINE +vec3s +glms_vec3_maxadd(vec3s a, vec3s b, vec3s dest) { + glm_vec3_maxadd(a.raw, b.raw, dest.raw); + return dest; +} + +/*! + * @brief add min of two vector to result/dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns dest += min(a, b) + */ +CGLM_INLINE +vec3s +glms_vec3_minadd(vec3s a, vec3s b, vec3s dest) { + glm_vec3_minadd(a.raw, b.raw, dest.raw); + return dest; +} + +/*! + * @brief negate vector components and store result in dest + * + * @param[in] v vector + * @returns result vector + */ +CGLM_INLINE +vec3s +glms_vec3_flipsign(vec3s v) { + glm_vec3_flipsign(v.raw); + return v; +} + +/*! + * @brief negate vector components + * + * @param[in] v vector + * @returns negated vector + */ +CGLM_INLINE +vec3s +glms_vec3_negate(vec3s v) { + glm_vec3_negate(v.raw); + return v; +} + +/*! + * @brief normalize vec3 and store result in same vec + * + * @param[in] v vector + * @returns normalized vector + */ +CGLM_INLINE +vec3s +glms_vec3_normalize(vec3s v) { + glm_vec3_normalize(v.raw); + return v; +} + +/*! + * @brief cross product of two vector (RH) + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns destination + */ +CGLM_INLINE +vec3s +glms_vec3_cross(vec3s a, vec3s b) { + vec3s r; + glm_vec3_cross(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief cross product of two vector (RH) and normalize the result + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns destination + */ +CGLM_INLINE +vec3s +glms_vec3_crossn(vec3s a, vec3s b) { + vec3s r; + glm_vec3_crossn(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief angle betwen two vector + * + * @param[in] a vector1 + * @param[in] b vector2 + * + * @return angle as radians + */ +CGLM_INLINE +float +glms_vec3_angle(vec3s a, vec3s b) { + return glm_vec3_angle(a.raw, b.raw); +} + +/*! + * @brief rotate vec3 around axis by angle using Rodrigues' rotation formula + * + * @param[in] v vector + * @param[in] axis axis vector (must be unit vector) + * @param[in] angle angle by radians + * @returns rotated vector + */ +CGLM_INLINE +vec3s +glms_vec3_rotate(vec3s v, float angle, vec3s axis) { + glm_vec3_rotate(v.raw, angle, axis.raw); + return v; +} + +/*! + * @brief apply rotation matrix to vector + * + * matrix format should be (no perspective): + * a b c x + * e f g y + * i j k z + * 0 0 0 w + * + * @param[in] m affine matrix or rot matrix + * @param[in] v vector + * @returns rotated vector + */ +CGLM_INLINE +vec3s +glms_vec3_rotate_m4(mat4s m, vec3s v) { + vec3s r; + glm_vec3_rotate_m4(m.raw, v.raw, r.raw); + return r; +} + +/*! + * @brief apply rotation matrix to vector + * + * @param[in] m affine matrix or rot matrix + * @param[in] v vector + * @returns rotated vector + */ +CGLM_INLINE +vec3s +glms_vec3_rotate_m3(mat3s m, vec3s v) { + vec3s r; + glm_vec3_rotate_m3(m.raw, v.raw, r.raw); + return r; +} + +/*! + * @brief project a vector onto b vector + * + * @param[in] a vector1 + * @param[in] b vector2 + * @returns projected vector + */ +CGLM_INLINE +vec3s +glms_vec3_proj(vec3s a, vec3s b) { + vec3s r; + glm_vec3_proj(a.raw, b.raw, r.raw); + return r; +} + +/** + * @brief find center point of two vector + * + * @param[in] a vector1 + * @param[in] b vector2 + * @returns center point + */ +CGLM_INLINE +vec3s +glms_vec3_center(vec3s a, vec3s b) { + vec3s r; + glm_vec3_center(a.raw, b.raw, r.raw); + return r; +} + +/** + * @brief distance between two vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @return distance + */ +CGLM_INLINE +float +glms_vec3_distance(vec3s a, vec3s b) { + return glm_vec3_distance(a.raw, b.raw); +} + +/** + * @brief squared distance between two vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @return squared distance (distance * distance) + */ +CGLM_INLINE +float +glms_vec3_distance2(vec3s a, vec3s b) { + return glm_vec3_distance2(a.raw, b.raw); +} + +/*! + * @brief max values of vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @returns destination + */ +CGLM_INLINE +vec3s +glms_vec3_maxv(vec3s a, vec3s b) { + vec3s r; + glm_vec3_maxv(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief min values of vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @returns destination + */ +CGLM_INLINE +vec3s +glms_vec3_minv(vec3s a, vec3s b) { + vec3s r; + glm_vec3_minv(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief possible orthogonal/perpendicular vector + * + * @param[in] v vector + * @returns orthogonal/perpendicular vector + */ +CGLM_INLINE +vec3s +glms_vec3_ortho(vec3s v) { + vec3s r; + glm_vec3_ortho(v.raw, r.raw); + return r; +} + +/*! + * @brief clamp vector's individual members between min and max values + * + * @param[in] v vector + * @param[in] minVal minimum value + * @param[in] maxVal maximum value + * @returns clamped vector + */ +CGLM_INLINE +vec3s +glms_vec3_clamp(vec3s v, float minVal, float maxVal) { + glm_vec3_clamp(v.raw, minVal, maxVal); + return v; +} + +/*! + * @brief linear interpolation between two vectors + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) + * @returns destination + */ +CGLM_INLINE +vec3s +glms_vec3_lerp(vec3s from, vec3s to, float t) { + vec3s r; + glm_vec3_lerp(from.raw, to.raw, t, r.raw); + return r; +} + +/*! + * @brief linear interpolation between two vectors (clamped) + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) clamped between 0 and 1 + * @returns destination + */ +CGLM_INLINE +vec3s +glms_vec3_lerpc(vec3s from, vec3s to, float t) { + vec3s r; + glm_vec3_lerpc(from.raw, to.raw, t, r.raw); + return r; +} + +/*! + * @brief linear interpolation between two vectors + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) + * @returns destination + */ +CGLM_INLINE +vec3s +glms_vec3_mix(vec3s from, vec3s to, float t) { + vec3s r; + glm_vec3_mix(from.raw, to.raw, t, r.raw); + return r; +} + +/*! + * @brief linear interpolation between two vectors (clamped) + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) clamped between 0 and 1 + * @returns destination + */ +CGLM_INLINE +vec3s +glms_vec3_mixc(vec3s from, vec3s to, float t) { + vec3s r; + glm_vec3_mixc(from.raw, to.raw, t, r.raw); + return r; +} + +/*! + * @brief threshold function (unidimensional) + * + * @param[in] edge threshold + * @param[in] x value to test against threshold + * @returns 0.0 if x < edge, else 1.0 + */ +CGLM_INLINE +vec3s +glms_vec3_step_uni(float edge, vec3s x) { + vec3s r; + glm_vec3_step_uni(edge, x.raw, r.raw); + return r; +} + +/*! + * @brief threshold function + * + * @param[in] edge threshold + * @param[in] x value to test against threshold + * @returns 0.0 if x < edge, else 1.0 + */ +CGLM_INLINE +vec3s +glms_vec3_step(vec3s edge, vec3s x) { + vec3s r; + glm_vec3_step(edge.raw, x.raw, r.raw); + return r; +} + +/*! + * @brief threshold function with a smooth transition (unidimensional) + * + * @param[in] edge0 low threshold + * @param[in] edge1 high threshold + * @param[in] x value to test against threshold + * @returns destination + */ +CGLM_INLINE +vec3s +glms_vec3_smoothstep_uni(float edge0, float edge1, vec3s x) { + vec3s r; + glm_vec3_smoothstep_uni(edge0, edge1, x.raw, r.raw); + return r; +} + +/*! + * @brief threshold function with a smooth transition + * + * @param[in] edge0 low threshold + * @param[in] edge1 high threshold + * @param[in] x value to test against threshold + * @returns destination + */ +CGLM_INLINE +vec3s +glms_vec3_smoothstep(vec3s edge0, vec3s edge1, vec3s x) { + vec3s r; + glm_vec3_smoothstep(edge0.raw, edge1.raw, x.raw, r.raw); + return r; +} + +/*! + * @brief smooth Hermite interpolation between two vectors + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) + * @returns destination + */ +CGLM_INLINE +vec3s +glms_vec3_smoothinterp(vec3s from, vec3s to, float t) { + vec3s r; + glm_vec3_smoothinterp(from.raw, to.raw, t, r.raw); + return r; +} + +/*! + * @brief smooth Hermite interpolation between two vectors (clamped) + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) clamped between 0 and 1 + * @returns destination + */ +CGLM_INLINE +vec3s +glms_vec3_smoothinterpc(vec3s from, vec3s to, float t) { + vec3s r; + glm_vec3_smoothinterpc(from.raw, to.raw, t, r.raw); + return r; +} + +/*! + * @brief vec3 cross product + * + * this is just convenient wrapper + * + * @param[in] a source 1 + * @param[in] b source 2 + * @returns destination + */ +CGLM_INLINE +vec3s +glms_cross(vec3s a, vec3s b) { + vec3s r; + glm_cross(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief vec3 dot product + * + * this is just convenient wrapper + * + * @param[in] a vector1 + * @param[in] b vector2 + * @return dot product + */ +CGLM_INLINE +float +glms_dot(vec3s a, vec3s b) { + return glm_dot(a.raw, b.raw); +} + +/*! + * @brief normalize vec3 and store result in same vec + * + * this is just convenient wrapper + * + * @param[in] v vector + * @returns normalized vector + */ +CGLM_INLINE +vec3s +glms_normalize(vec3s v) { + glm_normalize(v.raw); + return v; +} + +/*! + * @brief swizzle vector components + * + * you can use existin masks e.g. GLM_XXX, GLM_ZYX + * + * @param[in] v source + * @param[in] mask mask + * @returns swizzled vector + */ +CGLM_INLINE +vec3s +glms_vec3_swizzle(vec3s v, int mask) { + vec3s dest; + glm_vec3_swizzle(v.raw, mask, dest.raw); + return dest; +} + +#endif /* cglms_vec3s_h */ diff --git a/include/cglm/struct/vec4-ext.h b/include/cglm/struct/vec4-ext.h new file mode 100644 index 0000000..d5cddec --- /dev/null +++ b/include/cglm/struct/vec4-ext.h @@ -0,0 +1,257 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/*! + * @brief SIMD like functions + */ + +/* + Functions: + CGLM_INLINE vec4s glms_vec4_broadcast(float val); + CGLM_INLINE vec4s glms_vec4_fill(float val); + CGLM_INLINE bool glms_vec4_eq(vec4s v, float val); + CGLM_INLINE bool glms_vec4_eq_eps(vec4s v, float val); + CGLM_INLINE bool glms_vec4_eq_all(vec4s v); + CGLM_INLINE bool glms_vec4_eqv(vec4s a, vec4s b); + CGLM_INLINE bool glms_vec4_eqv_eps(vec4s a, vec4s b); + CGLM_INLINE float glms_vec4_max(vec4s v); + CGLM_INLINE float glms_vec4_min(vec4s v); + CGLM_INLINE bool glms_vec4_isnan(vec4s v); + CGLM_INLINE bool glms_vec4_isinf(vec4s v); + CGLM_INLINE bool glms_vec4_isvalid(vec4s v); + CGLM_INLINE vec4s glms_vec4_sign(vec4s v); + CGLM_INLINE vec4s glms_vec4_abs(vec4s v); + CGLM_INLINE vec4s glms_vec4_fract(vec4s v); + CGLM_INLINE float glms_vec4_hadd(vec4s v); + CGLM_INLINE vec4s glms_vec4_sqrt(vec4s v); + */ + +#ifndef cglms_vec4s_ext_h +#define cglms_vec4s_ext_h + +#include "../common.h" +#include "../types-struct.h" +#include "../util.h" +#include "../vec4-ext.h" + +/*! + * @brief fill a vector with specified value + * + * @param val value + * @returns dest + */ +CGLM_INLINE +vec4s +glms_vec4_broadcast(float val) { + vec4s r; + glm_vec4_broadcast(val, r.raw); + return r; +} + +/*! + * @brief fill a vector with specified value + * + * @param val value + * @returns dest + */ +CGLM_INLINE +vec4s +glms_vec4_fill(float val) { + vec4s r; + glm_vec4_fill(r.raw, val); + return r; +} + +/*! + * @brief check if vector is equal to value (without epsilon) + * + * @param v vector + * @param val value + */ +CGLM_INLINE +bool +glms_vec4_eq(vec4s v, float val) { + return glm_vec4_eq(v.raw, val); +} + +/*! + * @brief check if vector is equal to value (with epsilon) + * + * @param v vector + * @param val value + */ +CGLM_INLINE +bool +glms_vec4_eq_eps(vec4s v, float val) { + return glm_vec4_eq_eps(v.raw, val); +} + +/*! + * @brief check if vectors members are equal (without epsilon) + * + * @param v vector + */ +CGLM_INLINE +bool +glms_vec4_eq_all(vec4s v) { + return glm_vec4_eq_all(v.raw); +} + +/*! + * @brief check if vector is equal to another (without epsilon) + * + * @param a vector + * @param b vector + */ +CGLM_INLINE +bool +glms_vec4_eqv(vec4s a, vec4s b) { + return glm_vec4_eqv(a.raw, b.raw); +} + +/*! + * @brief check if vector is equal to another (with epsilon) + * + * @param a vector + * @param b vector + */ +CGLM_INLINE +bool +glms_vec4_eqv_eps(vec4s a, vec4s b) { + return glm_vec4_eqv_eps(a.raw, b.raw); +} + +/*! + * @brief max value of vector + * + * @param v vector + */ +CGLM_INLINE +float +glms_vec4_max(vec4s v) { + return glm_vec4_max(v.raw); +} + +/*! + * @brief min value of vector + * + * @param v vector + */ +CGLM_INLINE +float +glms_vec4_min(vec4s v) { + return glm_vec4_min(v.raw); +} + +/*! + * @brief check if one of items is NaN (not a number) + * you should only use this in DEBUG mode or very critical asserts + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glms_vec4_isnan(vec4s v) { + return glm_vec4_isnan(v.raw); +} + +/*! + * @brief check if one of items is INFINITY + * you should only use this in DEBUG mode or very critical asserts + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glms_vec4_isinf(vec4s v) { + return glm_vec4_isinf(v.raw); +} + +/*! + * @brief check if all items are valid number + * you should only use this in DEBUG mode or very critical asserts + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glms_vec4_isvalid(vec4s v) { + return glm_vec4_isvalid(v.raw); +} + +/*! + * @brief get sign of 32 bit float as +1, -1, 0 + * + * Important: It returns 0 for zero/NaN input + * + * @param v vector + * @returns sign vector + */ +CGLM_INLINE +vec4s +glms_vec4_sign(vec4s v) { + vec4s r; + glm_vec4_sign(v.raw, r.raw); + return r; +} + +/*! + * @brief absolute value of each vector item + * + * @param[in] v vector + * @returns destination vector + */ +CGLM_INLINE +vec4s +glms_vec4_abs(vec4s v) { + vec4s r; + glm_vec4_abs(v.raw, r.raw); + return r; +} + +/*! + * @brief fractional part of each vector item + * + * @param[in] v vector + * @returns dest destination vector + */ +CGLM_INLINE +vec4s +glms_vec4_fract(vec4s v) { + vec4s r; + glm_vec4_fract(v.raw, r.raw); + return r; +} + +/*! + * @brief vector reduction by summation + * @warning could overflow + * + * @param[in] v vector + * @return sum of all vector's elements + */ +CGLM_INLINE +float +glms_vec4_hadd(vec4s v) { + return glm_vec4_hadd(v.raw); +} + +/*! + * @brief square root of each vector item + * + * @param[in] v vector + * @returns destination vector + */ +CGLM_INLINE +vec4s +glms_vec4_sqrt(vec4s v) { + vec4s r; + glm_vec4_sqrt(v.raw, r.raw); + return r; +} + +#endif /* cglms_vec4s_ext_h */ diff --git a/include/cglm/struct/vec4.h b/include/cglm/struct/vec4.h new file mode 100644 index 0000000..4469cb2 --- /dev/null +++ b/include/cglm/struct/vec4.h @@ -0,0 +1,814 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Macros: + GLMS_VEC4_ONE_INIT + GLMS_VEC4_BLACK_INIT + GLMS_VEC4_ZERO_INIT + GLMS_VEC4_ONE + GLMS_VEC4_BLACK + GLMS_VEC4_ZERO + + Functions: + CGLM_INLINE vec4s glms_vec4(vec3s v3, float last); + CGLM_INLINE vec3s glms_vec4_copy3(vec4s v); + CGLM_INLINE vec4s glms_vec4_copy(vec4s v); + CGLM_INLINE vec4s glms_vec4_ucopy(vec4s v); + CGLM_INLINE void glms_vec4_pack(vec4s dst[], vec4 src[], size_t len); + CGLM_INLINE void glms_vec4_unpack(vec4 dst[], vec4s src[], size_t len); + CGLM_INLINE float glms_vec4_dot(vec4s a, vec4s b); + CGLM_INLINE float glms_vec4_norm2(vec4s v); + CGLM_INLINE float glms_vec4_norm(vec4s v); + CGLM_INLINE float glms_vec4_norm_one(vec4s v); + CGLM_INLINE float glms_vec4_norm_inf(vec4s v); + CGLM_INLINE vec4s glms_vec4_add(vec4s a, vec4s b); + CGLM_INLINE vec4s glms_vec4_adds(vec4s v, float s); + CGLM_INLINE vec4s glms_vec4_sub(vec4s a, vec4s b); + CGLM_INLINE vec4s glms_vec4_subs(vec4s v, float s); + CGLM_INLINE vec4s glms_vec4_mul(vec4s a, vec4s b); + CGLM_INLINE vec4s glms_vec4_scale(vec4s v, float s); + CGLM_INLINE vec4s glms_vec4_scale_as(vec4s v, float s); + CGLM_INLINE vec4s glms_vec4_div(vec4s a, vec4s b); + CGLM_INLINE vec4s glms_vec4_divs(vec4s v, float s); + CGLM_INLINE vec4s glms_vec4_addadd(vec4s a, vec4s b, vec4s dest); + CGLM_INLINE vec4s glms_vec4_subadd(vec4s a, vec4s b, vec4s dest); + CGLM_INLINE vec4s glms_vec4_muladd(vec4s a, vec4s b, vec4s dest); + CGLM_INLINE vec4s glms_vec4_muladds(vec4s a, float s, vec4s dest); + CGLM_INLINE vec4s glms_vec4_maxadd(vec4s a, vec4s b, vec4s dest); + CGLM_INLINE vec4s glms_vec4_minadd(vec4s a, vec4s b, vec4s dest); + CGLM_INLINE vec4s glms_vec4_negate(vec4s v); + CGLM_INLINE vec4s glms_vec4_inv(vec4s v); + CGLM_INLINE vec4s glms_vec4_normalize(vec4s v); + CGLM_INLINE float glms_vec4_distance(vec4s a, vec4s b); + CGLM_INLINE float glms_vec4_distance2(vec4s a, vec4s b); + CGLM_INLINE vec4s glms_vec4_maxv(vec4s a, vec4s b); + CGLM_INLINE vec4s glms_vec4_minv(vec4s a, vec4s b); + CGLM_INLINE vec4s glms_vec4_clamp(vec4s v, float minVal, float maxVal); + CGLM_INLINE vec4s glms_vec4_lerp(vec4s from, vec4s to, float t); + CGLM_INLINE vec4s glms_vec4_lerpc(vec4s from, vec4s to, float t); + CGLM_INLINE vec4s glms_vec4_mix(vec4s from, vec4s to, float t); + CGLM_INLINE vec4s glms_vec4_mixc(vec4s from, vec4s to, float t); + CGLM_INLINE vec4s glms_vec4_step_uni(float edge, vec4s x); + CGLM_INLINE vec4s glms_vec4_step(vec4s edge, vec4s x); + CGLM_INLINE vec4s glms_vec4_smoothstep_uni(float edge0, float edge1, vec4s x); + CGLM_INLINE vec4s glms_vec4_smoothstep(vec4s edge0, vec4s edge1, vec4s x); + CGLM_INLINE vec4s glms_vec4_smoothinterp(vec4s from, vec4s to, float t); + CGLM_INLINE vec4s glms_vec4_smoothinterpc(vec4s from, vec4s to, float t); + CGLM_INLINE vec4s glms_vec4_cubic(float s); + CGLM_INLINE vec4s glms_vec4_swizzle(vec4s v, int mask); + */ + +#ifndef cglms_vec4s_h +#define cglms_vec4s_h + +#include "../common.h" +#include "../types-struct.h" +#include "../util.h" +#include "../vec4.h" +#include "vec4-ext.h" + +#define GLMS_VEC4_ONE_INIT {GLM_VEC4_ONE_INIT} +#define GLMS_VEC4_BLACK_INIT {GLM_VEC4_BLACK_INIT} +#define GLMS_VEC4_ZERO_INIT {GLM_VEC4_ZERO_INIT} + +#define GLMS_VEC4_ONE ((vec4s)GLM_VEC4_ONE_INIT) +#define GLMS_VEC4_BLACK ((vec4s)GLM_VEC4_BLACK_INIT) +#define GLMS_VEC4_ZERO ((vec4s)GLM_VEC4_ZERO_INIT) + +/*! + * @brief init vec4 using vec3 + * + * @param[in] v3 vector3 + * @param[in] last last item + * @returns destination + */ +CGLM_INLINE +vec4s +glms_vec4(vec3s v3, float last) { + vec4s r; + glm_vec4(v3.raw, last, r.raw); + return r; +} + +/*! + * @brief copy first 3 members of [a] to [dest] + * + * @param[in] v source + * @returns vec3 + */ +CGLM_INLINE +vec3s +glms_vec4_copy3(vec4s v) { + vec3s r; + glm_vec4_copy3(v.raw, r.raw); + return r; +} + +/*! + * @brief copy all members of [a] to [dest] + * + * @param[in] v source + * @returns destination + */ +CGLM_INLINE +vec4s +glms_vec4_copy(vec4s v) { + vec4s r; + glm_vec4_copy(v.raw, r.raw); + return r; +} + +/*! + * @brief copy all members of [a] to [dest] + * + * alignment is not required + * + * @param[in] v source + * @returns destination + */ +CGLM_INLINE +vec4s +glms_vec4_ucopy(vec4s v) { + vec4s r; + glm_vec4_ucopy(v.raw, r.raw); + return r; +} + +/*! + * @brief pack an array of vec4 into an array of vec4s + * + * @param[out] dst array of vec4 + * @param[in] src array of vec4s + * @param[in] len number of elements + */ +CGLM_INLINE +void +glms_vec4_pack(vec4s dst[], vec4 src[], size_t len) { + size_t i; + + for (i = 0; i < len; i++) { + glm_vec4_copy(src[i], dst[i].raw); + } +} + +/*! + * @brief unpack an array of vec4s into an array of vec4 + * + * @param[out] dst array of vec4s + * @param[in] src array of vec4 + * @param[in] len number of elements + */ +CGLM_INLINE +void +glms_vec4_unpack(vec4 dst[], vec4s src[], size_t len) { + size_t i; + + for (i = 0; i < len; i++) { + glm_vec4_copy(src[i].raw, dst[i]); + } +} + +/*! + * @brief make vector zero + * + * @returns zero vector + */ +CGLM_INLINE +vec4s +glms_vec4_zero(void) { + vec4s r; + glm_vec4_zero(r.raw); + return r; +} + +/*! + * @brief make vector one + * + * @returns one vector + */ +CGLM_INLINE +vec4s +glms_vec4_one(void) { + vec4s r; + glm_vec4_one(r.raw); + return r; +} + +/*! + * @brief vec4 dot product + * + * @param[in] a vector1 + * @param[in] b vector2 + * + * @return dot product + */ +CGLM_INLINE +float +glms_vec4_dot(vec4s a, vec4s b) { + return glm_vec4_dot(a.raw, b.raw); +} + +/*! + * @brief norm * norm (magnitude) of vec + * + * we can use this func instead of calling norm * norm, because it would call + * sqrtf fuction twice but with this func we can avoid func call, maybe this is + * not good name for this func + * + * @param[in] v vec4 + * + * @return norm * norm + */ +CGLM_INLINE +float +glms_vec4_norm2(vec4s v) { + return glm_vec4_norm2(v.raw); +} + +/*! + * @brief norm (magnitude) of vec4 + * + * @param[in] v vector + * + * @return norm + */ +CGLM_INLINE +float +glms_vec4_norm(vec4s v) { + return glm_vec4_norm(v.raw); +} + +/*! + * @brief L1 norm of vec4 + * Also known as Manhattan Distance or Taxicab norm. + * L1 Norm is the sum of the magnitudes of the vectors in a space. + * It is calculated as the sum of the absolute values of the vector components. + * In this norm, all the components of the vector are weighted equally. + * + * This computes: + * R = |v[0]| + |v[1]| + |v[2]| + |v[3]| + * + * @param[in] v vector + * + * @return L1 norm + */ +CGLM_INLINE +float +glms_vec4_norm_one(vec4s v) { + return glm_vec4_norm_one(v.raw); +} + +/*! + * @brief Infinity norm of vec4 + * Also known as Maximum norm. + * Infinity Norm is the largest magnitude among each element of a vector. + * It is calculated as the maximum of the absolute values of the vector components. + * + * This computes: + * inf norm = max(|v[0]|, |v[1]|, |v[2]|, |v[3]|) + * + * @param[in] v vector + * + * @return Infinity norm + */ +CGLM_INLINE +float +glms_vec4_norm_inf(vec4s v) { + return glm_vec4_norm_inf(v.raw); +} + +/*! + * @brief add b vector to a vector store result in dest + * + * @param[in] a vector1 + * @param[in] b vector2 + * @returns destination vector + */ +CGLM_INLINE +vec4s +glms_vec4_add(vec4s a, vec4s b) { + vec4s r; + glm_vec4_add(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief add scalar to v vector store result in dest (d = v + vec(s)) + * + * @param[in] v vector + * @param[in] s scalar + * @returns destination vector + */ +CGLM_INLINE +vec4s +glms_vec4_adds(vec4s v, float s) { + vec4s r; + glm_vec4_adds(v.raw, s, r.raw); + return r; +} + +/*! + * @brief subtract b vector from a vector store result in dest (d = a - b) + * + * @param[in] a vector1 + * @param[in] b vector2 + * @returns destination vector + */ +CGLM_INLINE +vec4s +glms_vec4_sub(vec4s a, vec4s b) { + vec4s r; + glm_vec4_sub(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief subtract scalar from v vector store result in dest (d = v - vec(s)) + * + * @param[in] v vector + * @param[in] s scalar + * @returns destination vector + */ +CGLM_INLINE +vec4s +glms_vec4_subs(vec4s v, float s) { + vec4s r; + glm_vec4_subs(v.raw, s, r.raw); + return r; +} + +/*! + * @brief multiply two vector (component-wise multiplication) + * + * @param a vector1 + * @param b vector2 + * @returns dest = (a[0] * b[0], a[1] * b[1], a[2] * b[2], a[3] * b[3]) + */ +CGLM_INLINE +vec4s +glms_vec4_mul(vec4s a, vec4s b) { + vec4s r; + glm_vec4_mul(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief multiply/scale vec4 vector with scalar: result = v * s + * + * @param[in] v vector + * @param[in] s scalar + * @returns destination vector + */ +CGLM_INLINE +vec4s +glms_vec4_scale(vec4s v, float s) { + vec4s r; + glm_vec4_scale(v.raw, s, r.raw); + return r; +} + +/*! + * @brief make vec4 vector scale as specified: result = unit(v) * s + * + * @param[in] v vector + * @param[in] s scalar + * @returns destination vector + */ +CGLM_INLINE +vec4s +glms_vec4_scale_as(vec4s v, float s) { + vec4s r; + glm_vec4_scale_as(v.raw, s, r.raw); + return r; +} + +/*! + * @brief div vector with another component-wise division: d = a / b + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns result = (a[0]/b[0], a[1]/b[1], a[2]/b[2], a[3]/b[3]) + */ +CGLM_INLINE +vec4s +glms_vec4_div(vec4s a, vec4s b) { + vec4s r; + glm_vec4_div(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief div vec4 vector with scalar: d = v / s + * + * @param[in] v vector + * @param[in] s scalar + * @returns destination vector + */ +CGLM_INLINE +vec4s +glms_vec4_divs(vec4s v, float s) { + vec4s r; + glm_vec4_divs(v.raw, s, r.raw); + return r; +} + +/*! + * @brief add two vectors and add result to sum + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns dest += (a + b) + */ +CGLM_INLINE +vec4s +glms_vec4_addadd(vec4s a, vec4s b, vec4s dest) { + glm_vec4_addadd(a.raw, b.raw, dest.raw); + return dest; +} + +/*! + * @brief sub two vectors and add result to dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns dest += (a - b) + */ +CGLM_INLINE +vec4s +glms_vec4_subadd(vec4s a, vec4s b, vec4s dest) { + glm_vec4_subadd(a.raw, b.raw, dest.raw); + return dest; +} + +/*! + * @brief mul two vectors and add result to dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns dest += (a * b) + */ +CGLM_INLINE +vec4s +glms_vec4_muladd(vec4s a, vec4s b, vec4s dest) { + glm_vec4_muladd(a.raw, b.raw, dest.raw); + return dest; +} + +/*! + * @brief mul vector with scalar and add result to sum + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector + * @param[in] s scalar + * @returns dest += (a * b) + */ +CGLM_INLINE +vec4s +glms_vec4_muladds(vec4s a, float s, vec4s dest) { + glm_vec4_muladds(a.raw, s, dest.raw); + return dest; +} + +/*! + * @brief add max of two vector to result/dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns dest += max(a, b) + */ +CGLM_INLINE +vec4s +glms_vec4_maxadd(vec4s a, vec4s b, vec4s dest) { + glm_vec4_maxadd(a.raw, b.raw, dest.raw); + return dest; +} + +/*! + * @brief add min of two vector to result/dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @returns dest += min(a, b) + */ +CGLM_INLINE +vec4s +glms_vec4_minadd(vec4s a, vec4s b, vec4s dest) { + glm_vec4_minadd(a.raw, b.raw, dest.raw); + return dest; +} + +/*! + * @brief negate vector components and store result in dest + * + * @param[in] v vector + * @returns result vector + */ +CGLM_INLINE +vec4s +glms_vec4_negate(vec4s v) { + glm_vec4_negate(v.raw); + return v; +} + +/*! + * @brief normalize vec4 and store result in same vec + * + * @param[in] v vector + * @returns normalized vector + */ +CGLM_INLINE +vec4s +glms_vec4_normalize(vec4s v) { + glm_vec4_normalize(v.raw); + return v; +} + +/** + * @brief distance between two vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @return returns distance + */ +CGLM_INLINE +float +glms_vec4_distance(vec4s a, vec4s b) { + return glm_vec4_distance(a.raw, b.raw); +} + +/** + * @brief squared distance between two vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @return returns squared distance + */ +CGLM_INLINE +float +glms_vec4_distance2(vec4s a, vec4s b) { + return glm_vec4_distance2(a.raw, b.raw); +} + +/*! + * @brief max values of vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @returns destination + */ +CGLM_INLINE +vec4s +glms_vec4_maxv(vec4s a, vec4s b) { + vec4s r; + glm_vec4_maxv(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief min values of vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @returns destination + */ +CGLM_INLINE +vec4s +glms_vec4_minv(vec4s a, vec4s b) { + vec4s r; + glm_vec4_minv(a.raw, b.raw, r.raw); + return r; +} + +/*! + * @brief clamp vector's individual members between min and max values + * + * @param[in] v vector + * @param[in] minVal minimum value + * @param[in] maxVal maximum value + * @returns clamped vector + */ +CGLM_INLINE +vec4s +glms_vec4_clamp(vec4s v, float minVal, float maxVal) { + glm_vec4_clamp(v.raw, minVal, maxVal); + return v; +} + +/*! + * @brief linear interpolation between two vectors + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) + * @returns destination + */ +CGLM_INLINE +vec4s +glms_vec4_lerp(vec4s from, vec4s to, float t) { + vec4s r; + glm_vec4_lerp(from.raw, to.raw, t, r.raw); + return r; +} + +/*! + * @brief linear interpolation between two vectors (clamped) + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) clamped between 0 and 1 + * @returns destination + */ +CGLM_INLINE +vec4s +glms_vec4_lerpc(vec4s from, vec4s to, float t) { + vec4s r; + glm_vec4_lerpc(from.raw, to.raw, t, r.raw); + return r; +} + +/*! + * @brief linear interpolation between two vectors + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) + * @returns destination + */ +CGLM_INLINE +vec4s +glms_vec4_mix(vec4s from, vec4s to, float t) { + vec4s r; + glm_vec4_mix(from.raw, to.raw, t, r.raw); + return r; +} + +/*! + * @brief linear interpolation between two vectors (clamped) + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) clamped between 0 and 1 + * @returns destination + */ +CGLM_INLINE +vec4s +glms_vec4_mixc(vec4s from, vec4s to, float t) { + vec4s r; + glm_vec4_mixc(from.raw, to.raw, t, r.raw); + return r; +} + +/*! + * @brief threshold function (unidimensional) + * + * @param[in] edge threshold + * @param[in] x value to test against threshold + * @returns 0.0 if x < edge, else 1.0 + */ +CGLM_INLINE +vec4s +glms_vec4_step_uni(float edge, vec4s x) { + vec4s r; + glm_vec4_step_uni(edge, x.raw, r.raw); + return r; +} + +/*! + * @brief threshold function + * + * @param[in] edge threshold + * @param[in] x value to test against threshold + * @returns 0.0 if x < edge, else 1.0 + */ +CGLM_INLINE +vec4s +glms_vec4_step(vec4s edge, vec4s x) { + vec4s r; + glm_vec4_step(edge.raw, x.raw, r.raw); + return r; +} + +/*! + * @brief threshold function with a smooth transition (unidimensional) + * + * @param[in] edge0 low threshold + * @param[in] edge1 high threshold + * @param[in] x value to test against threshold + * @returns destination + */ +CGLM_INLINE +vec4s +glms_vec4_smoothstep_uni(float edge0, float edge1, vec4s x) { + vec4s r; + glm_vec4_smoothstep_uni(edge0, edge1, x.raw, r.raw); + return r; +} + +/*! + * @brief threshold function with a smooth transition + * + * @param[in] edge0 low threshold + * @param[in] edge1 high threshold + * @param[in] x value to test against threshold + * @returns destination + */ +CGLM_INLINE +vec4s +glms_vec4_smoothstep(vec4s edge0, vec4s edge1, vec4s x) { + vec4s r; + glm_vec4_smoothstep(edge0.raw, edge1.raw, x.raw, r.raw); + return r; +} + +/*! + * @brief smooth Hermite interpolation between two vectors + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) + * @returns destination + */ +CGLM_INLINE +vec4s +glms_vec4_smoothinterp(vec4s from, vec4s to, float t) { + vec4s r; + glm_vec4_smoothinterp(from.raw, to.raw, t, r.raw); + return r; +} + +/*! + * @brief smooth Hermite interpolation between two vectors (clamped) + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) clamped between 0 and 1 + * @returns destination + */ +CGLM_INLINE +vec4s +glms_vec4_smoothinterpc(vec4s from, vec4s to, float t) { + vec4s r; + glm_vec4_smoothinterpc(from.raw, to.raw, t, r.raw); + return r; +} + +/*! + * @brief helper to fill vec4 as [S^3, S^2, S, 1] + * + * @param[in] s parameter + * @returns destination + */ +CGLM_INLINE +vec4s +glms_vec4_cubic(float s) { + vec4s r; + glm_vec4_cubic(s, r.raw); + return r; +} + +/*! + * @brief swizzle vector components + * + * you can use existin masks e.g. GLM_XXXX, GLM_WZYX + * + * @param[in] v source + * @param[in] mask mask + * @returns swizzled vector + */ +CGLM_INLINE +vec4s +glms_vec4_swizzle(vec4s v, int mask) { + vec4s dest; + glm_vec4_swizzle(v.raw, mask, dest.raw); + return dest; +} + +#endif /* cglms_vec4s_h */ diff --git a/include/cglm/types-struct.h b/include/cglm/types-struct.h new file mode 100644 index 0000000..1d91097 --- /dev/null +++ b/include/cglm/types-struct.h @@ -0,0 +1,218 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_types_struct_h +#define cglm_types_struct_h + +#include "types.h" + +/* + * Anonymous structs are available since C11, but we'd like to be compatible + * with C99 and C89 too. So let's figure out if we should be using them or not. + * It's simply a convenience feature, you can e.g. build the library with + * anonymous structs and your application without them and they'll still be + * compatible, cglm doesn't use the anonymous structs internally. + */ +#ifndef CGLM_USE_ANONYMOUS_STRUCT + /* If the user doesn't explicitly specify if they want anonymous structs or + * not, then we'll try to intuit an appropriate choice. */ +# if defined(CGLM_NO_ANONYMOUS_STRUCT) + /* The user has defined CGLM_NO_ANONYMOUS_STRUCT. This used to be the + * only #define governing the use of anonymous structs, so for backward + * compatibility, we still honor that choice and disable them. */ +# define CGLM_USE_ANONYMOUS_STRUCT 0 +# elif __STDC_VERSION__ >= 20112L || defined(_MSVC_VER) + /* We're compiling for C11 or this is the MSVC compiler. In either + * case, anonymous structs are available, so use them. */ +# define CGLM_USE_ANONYMOUS_STRUCT 1 +# elif defined(_MSC_VER) && (_MSC_VER >= 1900) /* Visual Studio 2015 */ + /* We can support anonymous structs + * since Visual Studio 2015 or 2017 (1910) maybe? */ +# define CGLM_USE_ANONYMOUS_STRUCT 1 +# else + /* Otherwise, we're presumably building for C99 or C89 and can't rely + * on anonymous structs being available. Turn them off. */ +# define CGLM_USE_ANONYMOUS_STRUCT 0 +# endif +#endif + +typedef union vec2s { + vec2 raw; +#if CGLM_USE_ANONYMOUS_STRUCT + struct { + float x; + float y; + }; + + struct { + float r; + float i; + }; + + struct { + float u; + float v; + }; + + struct { + float s; + float t; + }; +#endif +} vec2s; + +typedef union vec3s { + vec3 raw; +#if CGLM_USE_ANONYMOUS_STRUCT + struct { + float x; + float y; + float z; + }; + + struct { + float r; + float g; + float b; + }; +#endif +} vec3s; + +typedef union ivec2s { + ivec2 raw; +#if CGLM_USE_ANONYMOUS_STRUCT + struct { + int x; + int y; + }; + + struct { + int r; + int i; + }; + + struct { + int u; + int v; + }; + + struct { + int s; + int t; + }; +#endif +} ivec2s; + +typedef union ivec3s { + ivec3 raw; +#if CGLM_USE_ANONYMOUS_STRUCT + struct { + int x; + int y; + int z; + }; + + struct { + int r; + int g; + int b; + }; +#endif +} ivec3s; + +typedef union ivec4s { + ivec4 raw; +#if CGLM_USE_ANONYMOUS_STRUCT + struct { + int x; + int y; + int z; + int w; + }; + + struct { + int r; + int g; + int b; + int a; + }; +#endif +} ivec4s; + +typedef union CGLM_ALIGN_IF(16) vec4s { + vec4 raw; +#if CGLM_USE_ANONYMOUS_STRUCT + struct { + float x; + float y; + float z; + float w; + }; + + struct { + float r; + float g; + float b; + float a; + }; +#endif +} vec4s; + +typedef union CGLM_ALIGN_IF(16) versors { + vec4 raw; +#if CGLM_USE_ANONYMOUS_STRUCT + struct { + float x; + float y; + float z; + float w; + }; + + struct { + vec3s imag; + float real; + }; +#endif +} versors; + +typedef union mat2s { + mat2 raw; + vec2s col[2]; +#if CGLM_USE_ANONYMOUS_STRUCT + struct { + float m00, m01; + float m10, m11; + }; +#endif +} mat2s; + +typedef union mat3s { + mat3 raw; + vec3s col[3]; +#if CGLM_USE_ANONYMOUS_STRUCT + struct { + float m00, m01, m02; + float m10, m11, m12; + float m20, m21, m22; + }; +#endif +} mat3s; + +typedef union CGLM_ALIGN_MAT mat4s { + mat4 raw; + vec4s col[4]; +#if CGLM_USE_ANONYMOUS_STRUCT + struct { + float m00, m01, m02, m03; + float m10, m11, m12, m13; + float m20, m21, m22, m23; + float m30, m31, m32, m33; + }; +#endif +} mat4s; + +#endif /* cglm_types_struct_h */ diff --git a/include/cglm/types.h b/include/cglm/types.h new file mode 100644 index 0000000..a671c5a --- /dev/null +++ b/include/cglm/types.h @@ -0,0 +1,95 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_types_h +#define cglm_types_h + +#if defined(_MSC_VER) +/* do not use alignment for older visual studio versions */ +# if _MSC_VER < 1913 /* Visual Studio 2017 version 15.6 */ +# define CGLM_ALL_UNALIGNED +# define CGLM_ALIGN(X) /* no alignment */ +# else +# define CGLM_ALIGN(X) __declspec(align(X)) +# endif +#else +# define CGLM_ALIGN(X) __attribute((aligned(X))) +#endif + +#ifndef CGLM_ALL_UNALIGNED +# define CGLM_ALIGN_IF(X) CGLM_ALIGN(X) +#else +# define CGLM_ALIGN_IF(X) /* no alignment */ +#endif + +#ifdef __AVX__ +# define CGLM_ALIGN_MAT CGLM_ALIGN(32) +#else +# define CGLM_ALIGN_MAT CGLM_ALIGN(16) +#endif + +#ifdef __GNUC__ +# define CGLM_ASSUME_ALIGNED(expr, alignment) \ + __builtin_assume_aligned((expr), (alignment)) +#else +# define CGLM_ASSUME_ALIGNED(expr, alignment) (expr) +#endif + +#define CGLM_CASTPTR_ASSUME_ALIGNED(expr, type) \ + ((type*)CGLM_ASSUME_ALIGNED((expr), __alignof__(type))) + +typedef int ivec2[2]; +typedef int ivec3[3]; +typedef int ivec4[4]; + +typedef float vec2[2]; +typedef float vec3[3]; +typedef CGLM_ALIGN_IF(16) float vec4[4]; +typedef vec4 versor; /* |x, y, z, w| -> w is the last */ +typedef vec3 mat3[3]; +typedef CGLM_ALIGN_IF(16) vec2 mat2[2]; +typedef CGLM_ALIGN_MAT vec4 mat4[4]; + +/* + Important: cglm stores quaternion as [x, y, z, w] in memory since v0.4.0 + it was [w, x, y, z] before v0.4.0 ( v0.3.5 and earlier ). w is real part. +*/ + +#define GLM_E 2.71828182845904523536028747135266250 /* e */ +#define GLM_LOG2E 1.44269504088896340735992468100189214 /* log2(e) */ +#define GLM_LOG10E 0.434294481903251827651128918916605082 /* log10(e) */ +#define GLM_LN2 0.693147180559945309417232121458176568 /* loge(2) */ +#define GLM_LN10 2.30258509299404568401799145468436421 /* loge(10) */ +#define GLM_PI 3.14159265358979323846264338327950288 /* pi */ +#define GLM_PI_2 1.57079632679489661923132169163975144 /* pi/2 */ +#define GLM_PI_4 0.785398163397448309615660845819875721 /* pi/4 */ +#define GLM_1_PI 0.318309886183790671537767526745028724 /* 1/pi */ +#define GLM_2_PI 0.636619772367581343075535053490057448 /* 2/pi */ +#define GLM_2_SQRTPI 1.12837916709551257389615890312154517 /* 2/sqrt(pi) */ +#define GLM_SQRT2 1.41421356237309504880168872420969808 /* sqrt(2) */ +#define GLM_SQRT1_2 0.707106781186547524400844362104849039 /* 1/sqrt(2) */ + +#define GLM_Ef ((float)GLM_E) +#define GLM_LOG2Ef ((float)GLM_LOG2E) +#define GLM_LOG10Ef ((float)GLM_LOG10E) +#define GLM_LN2f ((float)GLM_LN2) +#define GLM_LN10f ((float)GLM_LN10) +#define GLM_PIf ((float)GLM_PI) +#define GLM_PI_2f ((float)GLM_PI_2) +#define GLM_PI_4f ((float)GLM_PI_4) +#define GLM_1_PIf ((float)GLM_1_PI) +#define GLM_2_PIf ((float)GLM_2_PI) +#define GLM_2_SQRTPIf ((float)GLM_2_SQRTPI) +#define GLM_SQRT2f ((float)GLM_SQRT2) +#define GLM_SQRT1_2f ((float)GLM_SQRT1_2) + +/* DEPRECATED! use GLM_PI and friends */ +#define CGLM_PI GLM_PIf +#define CGLM_PI_2 GLM_PI_2f +#define CGLM_PI_4 GLM_PI_4f + +#endif /* cglm_types_h */ diff --git a/include/cglm/util.h b/include/cglm/util.h new file mode 100644 index 0000000..53b1ed5 --- /dev/null +++ b/include/cglm/util.h @@ -0,0 +1,343 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE int glm_sign(int val); + CGLM_INLINE float glm_signf(float val); + CGLM_INLINE float glm_rad(float deg); + CGLM_INLINE float glm_deg(float rad); + CGLM_INLINE void glm_make_rad(float *deg); + CGLM_INLINE void glm_make_deg(float *rad); + CGLM_INLINE float glm_pow2(float x); + CGLM_INLINE float glm_min(float a, float b); + CGLM_INLINE float glm_max(float a, float b); + CGLM_INLINE float glm_clamp(float val, float minVal, float maxVal); + CGLM_INLINE float glm_clamp_zo(float val, float minVal, float maxVal); + CGLM_INLINE float glm_lerp(float from, float to, float t); + CGLM_INLINE float glm_lerpc(float from, float to, float t); + CGLM_INLINE float glm_step(float edge, float x); + CGLM_INLINE float glm_smooth(float t); + CGLM_INLINE float glm_smoothstep(float edge0, float edge1, float x); + CGLM_INLINE float glm_smoothinterp(float from, float to, float t); + CGLM_INLINE float glm_smoothinterpc(float from, float to, float t); + CGLM_INLINE bool glm_eq(float a, float b); + CGLM_INLINE float glm_percent(float from, float to, float current); + CGLM_INLINE float glm_percentc(float from, float to, float current); + */ + +#ifndef cglm_util_h +#define cglm_util_h + +#include "common.h" + +#define GLM_MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) +#define GLM_MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) + +/*! + * @brief get sign of 32 bit integer as +1, -1, 0 + * + * Important: It returns 0 for zero input + * + * @param val integer value + */ +CGLM_INLINE +int +glm_sign(int val) { + return ((val >> 31) - (-val >> 31)); +} + +/*! + * @brief get sign of 32 bit float as +1, -1, 0 + * + * Important: It returns 0 for zero/NaN input + * + * @param val float value + */ +CGLM_INLINE +float +glm_signf(float val) { + return (float)((val > 0.0f) - (val < 0.0f)); +} + +/*! + * @brief convert degree to radians + * + * @param[in] deg angle in degrees + */ +CGLM_INLINE +float +glm_rad(float deg) { + return deg * GLM_PIf / 180.0f; +} + +/*! + * @brief convert radians to degree + * + * @param[in] rad angle in radians + */ +CGLM_INLINE +float +glm_deg(float rad) { + return rad * 180.0f / GLM_PIf; +} + +/*! + * @brief convert exsisting degree to radians. this will override degrees value + * + * @param[in, out] deg pointer to angle in degrees + */ +CGLM_INLINE +void +glm_make_rad(float *deg) { + *deg = *deg * GLM_PIf / 180.0f; +} + +/*! + * @brief convert exsisting radians to degree. this will override radians value + * + * @param[in, out] rad pointer to angle in radians + */ +CGLM_INLINE +void +glm_make_deg(float *rad) { + *rad = *rad * 180.0f / GLM_PIf; +} + +/*! + * @brief multiplies given parameter with itself = x * x or powf(x, 2) + * + * @param[in] x x + */ +CGLM_INLINE +float +glm_pow2(float x) { + return x * x; +} + +/*! + * @brief find minimum of given two values + * + * @param[in] a number 1 + * @param[in] b number 2 + */ +CGLM_INLINE +float +glm_min(float a, float b) { + if (a < b) + return a; + return b; +} + +/*! + * @brief find maximum of given two values + * + * @param[in] a number 1 + * @param[in] b number 2 + */ +CGLM_INLINE +float +glm_max(float a, float b) { + if (a > b) + return a; + return b; +} + +/*! + * @brief clamp a number between min and max + * + * @param[in] val value to clamp + * @param[in] minVal minimum value + * @param[in] maxVal maximum value + */ +CGLM_INLINE +float +glm_clamp(float val, float minVal, float maxVal) { + return glm_min(glm_max(val, minVal), maxVal); +} + +/*! + * @brief clamp a number to zero and one + * + * @param[in] val value to clamp + */ +CGLM_INLINE +float +glm_clamp_zo(float val) { + return glm_clamp(val, 0.0f, 1.0f); +} + +/*! + * @brief linear interpolation between two numbers + * + * formula: from + t * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) + */ +CGLM_INLINE +float +glm_lerp(float from, float to, float t) { + return from + t * (to - from); +} + +/*! + * @brief clamped linear interpolation between two numbers + * + * formula: from + t * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) clamped between 0 and 1 + */ +CGLM_INLINE +float +glm_lerpc(float from, float to, float t) { + return glm_lerp(from, to, glm_clamp_zo(t)); +} + +/*! + * @brief threshold function + * + * @param[in] edge threshold + * @param[in] x value to test against threshold + * @return returns 0.0 if x < edge, else 1.0 + */ +CGLM_INLINE +float +glm_step(float edge, float x) { + /* branching - no type conversion */ + return (x < edge) ? 0.0f : 1.0f; + /* + * An alternative implementation without branching + * but with type conversion could be: + * return !(x < edge); + */ +} + +/*! + * @brief smooth Hermite interpolation + * + * formula: t^2 * (3-2t) + * + * @param[in] t interpolant (amount) + */ +CGLM_INLINE +float +glm_smooth(float t) { + return t * t * (3.0f - 2.0f * t); +} + +/*! + * @brief threshold function with a smooth transition (according to OpenCL specs) + * + * formula: t^2 * (3-2t) + * + * @param[in] edge0 low threshold + * @param[in] edge1 high threshold + * @param[in] x interpolant (amount) + */ +CGLM_INLINE +float +glm_smoothstep(float edge0, float edge1, float x) { + float t; + t = glm_clamp_zo((x - edge0) / (edge1 - edge0)); + return glm_smooth(t); +} + +/*! + * @brief smoothstep interpolation between two numbers + * + * formula: from + smoothstep(t) * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) + */ +CGLM_INLINE +float +glm_smoothinterp(float from, float to, float t) { + return from + glm_smooth(t) * (to - from); +} + +/*! + * @brief clamped smoothstep interpolation between two numbers + * + * formula: from + smoothstep(t) * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) clamped between 0 and 1 + */ +CGLM_INLINE +float +glm_smoothinterpc(float from, float to, float t) { + return glm_smoothinterp(from, to, glm_clamp_zo(t)); +} + +/*! + * @brief check if two float equal with using EPSILON + * + * @param[in] a a + * @param[in] b b + */ +CGLM_INLINE +bool +glm_eq(float a, float b) { + return fabsf(a - b) <= GLM_FLT_EPSILON; +} + +/*! + * @brief percentage of current value between start and end value + * + * maybe fraction could be alternative name. + * + * @param[in] from from value + * @param[in] to to value + * @param[in] current current value + */ +CGLM_INLINE +float +glm_percent(float from, float to, float current) { + float t; + + if ((t = to - from) == 0.0f) + return 1.0f; + + return (current - from) / t; +} + +/*! + * @brief clamped percentage of current value between start and end value + * + * @param[in] from from value + * @param[in] to to value + * @param[in] current current value + */ +CGLM_INLINE +float +glm_percentc(float from, float to, float current) { + return glm_clamp_zo(glm_percent(from, to, current)); +} + +/*! +* @brief swap two float values +* +* @param[in] a float value 1 (pointer) +* @param[in] b float value 2 (pointer) +*/ +CGLM_INLINE +void +glm_swapf(float * __restrict a, float * __restrict b) { + float t; + t = *a; + *a = *b; + *b = t; +} + +#endif /* cglm_util_h */ diff --git a/include/cglm/vec2-ext.h b/include/cglm/vec2-ext.h new file mode 100644 index 0000000..4f65fad --- /dev/null +++ b/include/cglm/vec2-ext.h @@ -0,0 +1,254 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_vec2_fill(vec2 v, float val) + CGLM_INLINE bool glm_vec2_eq(vec2 v, float val); + CGLM_INLINE bool glm_vec2_eq_eps(vec2 v, float val); + CGLM_INLINE bool glm_vec2_eq_all(vec2 v); + CGLM_INLINE bool glm_vec2_eqv(vec2 a, vec2 b); + CGLM_INLINE bool glm_vec2_eqv_eps(vec2 a, vec2 b); + CGLM_INLINE float glm_vec2_max(vec2 v); + CGLM_INLINE float glm_vec2_min(vec2 v); + CGLM_INLINE bool glm_vec2_isnan(vec2 v); + CGLM_INLINE bool glm_vec2_isinf(vec2 v); + CGLM_INLINE bool glm_vec2_isvalid(vec2 v); + CGLM_INLINE void glm_vec2_sign(vec2 v, vec2 dest); + CGLM_INLINE void glm_vec2_abs(vec2 v, vec2 dest); + CGLM_INLINE void glm_vec2_sqrt(vec2 v, vec2 dest); + CGLM_INLINE void glm_vec2_complex_mul(vec2 a, vec2 b, vec2 dest) + CGLM_INLINE void glm_vec2_complex_div(vec2 a, vec2 b, vec2 dest) + CGLM_INLINE void glm_vec2_complex_conjugate(vec2 a, vec2 dest) + */ + +#ifndef cglm_vec2_ext_h +#define cglm_vec2_ext_h + +#include "common.h" +#include "util.h" + +/*! + * @brief fill a vector with specified value + * + * @param[out] v dest + * @param[in] val value + */ +CGLM_INLINE +void +glm_vec2_fill(vec2 v, float val) { + v[0] = v[1] = val; +} + +/*! + * @brief check if vector is equal to value (without epsilon) + * + * @param[in] v vector + * @param[in] val value + */ +CGLM_INLINE +bool +glm_vec2_eq(vec2 v, float val) { + return v[0] == val && v[0] == v[1]; +} + +/*! + * @brief check if vector is equal to value (with epsilon) + * + * @param[in] v vector + * @param[in] val value + */ +CGLM_INLINE +bool +glm_vec2_eq_eps(vec2 v, float val) { + return fabsf(v[0] - val) <= GLM_FLT_EPSILON + && fabsf(v[1] - val) <= GLM_FLT_EPSILON; +} + +/*! + * @brief check if vectors members are equal (without epsilon) + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glm_vec2_eq_all(vec2 v) { + return glm_vec2_eq_eps(v, v[0]); +} + +/*! + * @brief check if vector is equal to another (without epsilon) + * + * @param[in] a vector + * @param[in] b vector + */ +CGLM_INLINE +bool +glm_vec2_eqv(vec2 a, vec2 b) { + return a[0] == b[0] && a[1] == b[1]; +} + +/*! + * @brief check if vector is equal to another (with epsilon) + * + * @param[in] a vector + * @param[in] b vector + */ +CGLM_INLINE +bool +glm_vec2_eqv_eps(vec2 a, vec2 b) { + return fabsf(a[0] - b[0]) <= GLM_FLT_EPSILON + && fabsf(a[1] - b[1]) <= GLM_FLT_EPSILON; +} + +/*! + * @brief max value of vector + * + * @param[in] v vector + */ +CGLM_INLINE +float +glm_vec2_max(vec2 v) { + return glm_max(v[0], v[1]); +} + +/*! + * @brief min value of vector + * + * @param[in] v vector + */ +CGLM_INLINE +float +glm_vec2_min(vec2 v) { + return glm_min(v[0], v[1]); +} + +/*! + * @brief check if all items are NaN (not a number) + * you should only use this in DEBUG mode or very critical asserts + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glm_vec2_isnan(vec2 v) { + return isnan(v[0]) || isnan(v[1]); +} + +/*! + * @brief check if all items are INFINITY + * you should only use this in DEBUG mode or very critical asserts + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glm_vec2_isinf(vec2 v) { + return isinf(v[0]) || isinf(v[1]); +} + +/*! + * @brief check if all items are valid number + * you should only use this in DEBUG mode or very critical asserts + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glm_vec2_isvalid(vec2 v) { + return !glm_vec2_isnan(v) && !glm_vec2_isinf(v); +} + +/*! + * @brief get sign of 32 bit float as +1, -1, 0 + * + * Important: It returns 0 for zero/NaN input + * + * @param v vector + */ +CGLM_INLINE +void +glm_vec2_sign(vec2 v, vec2 dest) { + dest[0] = glm_signf(v[0]); + dest[1] = glm_signf(v[1]); +} + +/*! + * @brief absolute value of v + * + * @param[in] v vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec2_abs(vec2 v, vec2 dest) { + dest[0] = fabsf(v[0]); + dest[1] = fabsf(v[1]); +} + +/*! + * @brief square root of each vector item + * + * @param[in] v vector + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec2_sqrt(vec2 v, vec2 dest) { + dest[0] = sqrtf(v[0]); + dest[1] = sqrtf(v[1]); +} + +/*! + * @brief treat vectors as complex numbers and multiply them as such. + * + * @param[in] a left number + * @param[in] b right number + * @param[out] dest destination number + */ +CGLM_INLINE +void +glm_vec2_complex_mul(vec2 a, vec2 b, vec2 dest) { + float tr, ti; + tr = a[0] * b[0] - a[1] * b[1]; + ti = a[0] * b[1] + a[1] * b[0]; + dest[0] = tr; + dest[1] = ti; +} + +/*! + * @brief treat vectors as complex numbers and divide them as such. + * + * @param[in] a left number (numerator) + * @param[in] b right number (denominator) + * @param[out] dest destination number + */ +CGLM_INLINE +void +glm_vec2_complex_div(vec2 a, vec2 b, vec2 dest) { + float tr, ti; + float const ibnorm2 = 1.0f / (b[0] * b[0] + b[1] * b[1]); + tr = ibnorm2 * (a[0] * b[0] + a[1] * b[1]); + ti = ibnorm2 * (a[1] * b[0] - a[0] * b[1]); + dest[0] = tr; + dest[1] = ti; +} + +/*! + * @brief treat the vector as a complex number and conjugate it as such. + * + * @param[in] a the number + * @param[out] dest destination number + */ +CGLM_INLINE +void +glm_vec2_complex_conjugate(vec2 a, vec2 dest) { + dest[0] = a[0]; + dest[1] = -a[1]; +} + +#endif /* cglm_vec2_ext_h */ diff --git a/include/cglm/vec2.h b/include/cglm/vec2.h new file mode 100644 index 0000000..73ecea9 --- /dev/null +++ b/include/cglm/vec2.h @@ -0,0 +1,585 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Macros: + GLM_VEC2_ONE_INIT + GLM_VEC2_ZERO_INIT + GLM_VEC2_ONE + GLM_VEC2_ZERO + + Functions: + CGLM_INLINE void glm_vec2(float * __restrict v, vec2 dest) + CGLM_INLINE void glm_vec2_copy(vec2 a, vec2 dest) + CGLM_INLINE void glm_vec2_zero(vec2 v) + CGLM_INLINE void glm_vec2_one(vec2 v) + CGLM_INLINE float glm_vec2_dot(vec2 a, vec2 b) + CGLM_INLINE float glm_vec2_cross(vec2 a, vec2 b) + CGLM_INLINE float glm_vec2_norm2(vec2 v) + CGLM_INLINE float glm_vec2_norm(vec2 vec) + CGLM_INLINE void glm_vec2_add(vec2 a, vec2 b, vec2 dest) + CGLM_INLINE void glm_vec2_adds(vec2 v, float s, vec2 dest) + CGLM_INLINE void glm_vec2_sub(vec2 a, vec2 b, vec2 dest) + CGLM_INLINE void glm_vec2_subs(vec2 v, float s, vec2 dest) + CGLM_INLINE void glm_vec2_mul(vec2 a, vec2 b, vec2 d) + CGLM_INLINE void glm_vec2_scale(vec2 v, float s, vec2 dest) + CGLM_INLINE void glm_vec2_scale_as(vec2 v, float s, vec2 dest) + CGLM_INLINE void glm_vec2_div(vec2 a, vec2 b, vec2 dest) + CGLM_INLINE void glm_vec2_divs(vec2 v, float s, vec2 dest) + CGLM_INLINE void glm_vec2_addadd(vec2 a, vec2 b, vec2 dest) + CGLM_INLINE void glm_vec2_subadd(vec2 a, vec2 b, vec2 dest) + CGLM_INLINE void glm_vec2_muladd(vec2 a, vec2 b, vec2 dest) + CGLM_INLINE void glm_vec2_muladds(vec2 a, float s, vec2 dest) + CGLM_INLINE void glm_vec2_maxadd(vec2 a, vec2 b, vec2 dest) + CGLM_INLINE void glm_vec2_minadd(vec2 a, vec2 b, vec2 dest) + CGLM_INLINE void glm_vec2_negate_to(vec2 v, vec2 dest) + CGLM_INLINE void glm_vec2_negate(vec2 v) + CGLM_INLINE void glm_vec2_normalize(vec2 v) + CGLM_INLINE void glm_vec2_normalize_to(vec2 vec, vec2 dest) + CGLM_INLINE void glm_vec2_rotate(vec2 v, float angle, vec2 dest) + CGLM_INLINE float glm_vec2_distance2(vec2 a, vec2 b) + CGLM_INLINE float glm_vec2_distance(vec2 a, vec2 b) + CGLM_INLINE void glm_vec2_maxv(vec2 v1, vec2 v2, vec2 dest) + CGLM_INLINE void glm_vec2_minv(vec2 v1, vec2 v2, vec2 dest) + CGLM_INLINE void glm_vec2_clamp(vec2 v, float minVal, float maxVal) + CGLM_INLINE void glm_vec2_lerp(vec2 from, vec2 to, float t, vec2 dest) + + */ + +#ifndef cglm_vec2_h +#define cglm_vec2_h + +#include "common.h" +#include "util.h" +#include "vec2-ext.h" + +#define GLM_VEC2_ONE_INIT {1.0f, 1.0f} +#define GLM_VEC2_ZERO_INIT {0.0f, 0.0f} + +#define GLM_VEC2_ONE ((vec2)GLM_VEC2_ONE_INIT) +#define GLM_VEC2_ZERO ((vec2)GLM_VEC2_ZERO_INIT) + +/*! + * @brief init vec2 using another vector + * + * @param[in] v a vector + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec2(float * __restrict v, vec2 dest) { + dest[0] = v[0]; + dest[1] = v[1]; +} + +/*! + * @brief copy all members of [a] to [dest] + * + * @param[in] a source + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec2_copy(vec2 a, vec2 dest) { + dest[0] = a[0]; + dest[1] = a[1]; +} + +/*! + * @brief make vector zero + * + * @param[in, out] v vector + */ +CGLM_INLINE +void +glm_vec2_zero(vec2 v) { + v[0] = v[1] = 0.0f; +} + +/*! + * @brief make vector one + * + * @param[in, out] v vector + */ +CGLM_INLINE +void +glm_vec2_one(vec2 v) { + v[0] = v[1] = 1.0f; +} + +/*! + * @brief vec2 dot product + * + * @param[in] a vector1 + * @param[in] b vector2 + * + * @return dot product + */ +CGLM_INLINE +float +glm_vec2_dot(vec2 a, vec2 b) { + return a[0] * b[0] + a[1] * b[1]; +} + +/*! + * @brief vec2 cross product + * + * REF: http://allenchou.net/2013/07/cross-product-of-2d-vectors/ + * + * @param[in] a vector1 + * @param[in] b vector2 + * + * @return Z component of cross product + */ +CGLM_INLINE +float +glm_vec2_cross(vec2 a, vec2 b) { + /* just calculate the z-component */ + return a[0] * b[1] - a[1] * b[0]; +} + +/*! + * @brief norm * norm (magnitude) of vec + * + * we can use this func instead of calling norm * norm, because it would call + * sqrtf fuction twice but with this func we can avoid func call, maybe this is + * not good name for this func + * + * @param[in] v vector + * + * @return norm * norm + */ +CGLM_INLINE +float +glm_vec2_norm2(vec2 v) { + return glm_vec2_dot(v, v); +} + +/*! + * @brief norm (magnitude) of vec2 + * + * @param[in] vec vector + * + * @return norm + */ +CGLM_INLINE +float +glm_vec2_norm(vec2 vec) { + return sqrtf(glm_vec2_norm2(vec)); +} + +/*! + * @brief add a vector to b vector store result in dest + * + * @param[in] a vector1 + * @param[in] b vector2 + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec2_add(vec2 a, vec2 b, vec2 dest) { + dest[0] = a[0] + b[0]; + dest[1] = a[1] + b[1]; +} + +/*! + * @brief add scalar to v vector store result in dest (d = v + s) + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec2_adds(vec2 v, float s, vec2 dest) { + dest[0] = v[0] + s; + dest[1] = v[1] + s; +} + +/*! + * @brief subtract b vector from a vector store result in dest + * + * @param[in] a vector1 + * @param[in] b vector2 + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec2_sub(vec2 a, vec2 b, vec2 dest) { + dest[0] = a[0] - b[0]; + dest[1] = a[1] - b[1]; +} + +/*! + * @brief subtract scalar from v vector store result in dest (d = v - s) + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec2_subs(vec2 v, float s, vec2 dest) { + dest[0] = v[0] - s; + dest[1] = v[1] - s; +} + +/*! + * @brief multiply two vector (component-wise multiplication) + * + * @param a v1 + * @param b v2 + * @param dest v3 = (a[0] * b[0], a[1] * b[1]) + */ +CGLM_INLINE +void +glm_vec2_mul(vec2 a, vec2 b, vec2 dest) { + dest[0] = a[0] * b[0]; + dest[1] = a[1] * b[1]; +} + +/*! + * @brief multiply/scale vector with scalar: result = v * s + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec2_scale(vec2 v, float s, vec2 dest) { + dest[0] = v[0] * s; + dest[1] = v[1] * s; +} + +/*! + * @brief scale as vector specified: result = unit(v) * s + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec2_scale_as(vec2 v, float s, vec2 dest) { + float norm; + norm = glm_vec2_norm(v); + + if (norm == 0.0f) { + glm_vec2_zero(dest); + return; + } + + glm_vec2_scale(v, s / norm, dest); +} + +/*! + * @brief div vector with another component-wise division: d = a / b + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest result = (a[0]/b[0], a[1]/b[1]) + */ +CGLM_INLINE +void +glm_vec2_div(vec2 a, vec2 b, vec2 dest) { + dest[0] = a[0] / b[0]; + dest[1] = a[1] / b[1]; +} + +/*! + * @brief div vector with scalar: d = v / s + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest result = (a[0]/s, a[1]/s) + */ +CGLM_INLINE +void +glm_vec2_divs(vec2 v, float s, vec2 dest) { + dest[0] = v[0] / s; + dest[1] = v[1] / s; +} + +/*! + * @brief add two vectors and add result to sum + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest dest += (a + b) + */ +CGLM_INLINE +void +glm_vec2_addadd(vec2 a, vec2 b, vec2 dest) { + dest[0] += a[0] + b[0]; + dest[1] += a[1] + b[1]; +} + +/*! + * @brief sub two vectors and add result to dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest dest += (a + b) + */ +CGLM_INLINE +void +glm_vec2_subadd(vec2 a, vec2 b, vec2 dest) { + dest[0] += a[0] - b[0]; + dest[1] += a[1] - b[1]; +} + +/*! + * @brief mul two vectors and add result to dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest dest += (a * b) + */ +CGLM_INLINE +void +glm_vec2_muladd(vec2 a, vec2 b, vec2 dest) { + dest[0] += a[0] * b[0]; + dest[1] += a[1] * b[1]; +} + +/*! + * @brief mul vector with scalar and add result to sum + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector + * @param[in] s scalar + * @param[out] dest dest += (a * b) + */ +CGLM_INLINE +void +glm_vec2_muladds(vec2 a, float s, vec2 dest) { + dest[0] += a[0] * s; + dest[1] += a[1] * s; +} + +/*! + * @brief add max of two vector to result/dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest dest += max(a, b) + */ +CGLM_INLINE +void +glm_vec2_maxadd(vec2 a, vec2 b, vec2 dest) { + dest[0] += glm_max(a[0], b[0]); + dest[1] += glm_max(a[1], b[1]); +} + +/*! + * @brief add min of two vector to result/dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest dest += min(a, b) + */ +CGLM_INLINE +void +glm_vec2_minadd(vec2 a, vec2 b, vec2 dest) { + dest[0] += glm_min(a[0], b[0]); + dest[1] += glm_min(a[1], b[1]); +} + +/*! + * @brief negate vector components and store result in dest + * + * @param[in] v vector + * @param[out] dest result vector + */ +CGLM_INLINE +void +glm_vec2_negate_to(vec2 v, vec2 dest) { + dest[0] = -v[0]; + dest[1] = -v[1]; +} + +/*! + * @brief negate vector components + * + * @param[in, out] v vector + */ +CGLM_INLINE +void +glm_vec2_negate(vec2 v) { + glm_vec2_negate_to(v, v); +} + +/*! + * @brief normalize vector and store result in same vec + * + * @param[in, out] v vector + */ +CGLM_INLINE +void +glm_vec2_normalize(vec2 v) { + float norm; + + norm = glm_vec2_norm(v); + + if (norm == 0.0f) { + v[0] = v[1] = 0.0f; + return; + } + + glm_vec2_scale(v, 1.0f / norm, v); +} + +/*! + * @brief normalize vector to dest + * + * @param[in] v source + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec2_normalize_to(vec2 v, vec2 dest) { + float norm; + + norm = glm_vec2_norm(v); + + if (norm == 0.0f) { + glm_vec2_zero(dest); + return; + } + + glm_vec2_scale(v, 1.0f / norm, dest); +} + +/*! + * @brief rotate vec2 around origin by angle (CCW: counterclockwise) + * + * Formula: + * 𝑥2 = cos(a)𝑥1 − sin(a)𝑦1 + * 𝑦2 = sin(a)𝑥1 + cos(a)𝑦1 + * + * @param[in] v vector to rotate + * @param[in] angle angle by radians + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec2_rotate(vec2 v, float angle, vec2 dest) { + float c, s, x1, y1; + + c = cosf(angle); + s = sinf(angle); + + x1 = v[0]; + y1 = v[1]; + + dest[0] = c * x1 - s * y1; + dest[1] = s * x1 + c * y1; +} + +/** + * @brief squared distance between two vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @return returns squared distance (distance * distance) + */ +CGLM_INLINE +float +glm_vec2_distance2(vec2 a, vec2 b) { + return glm_pow2(b[0] - a[0]) + glm_pow2(b[1] - a[1]); +} + +/** + * @brief distance between two vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @return returns distance + */ +CGLM_INLINE +float +glm_vec2_distance(vec2 a, vec2 b) { + return sqrtf(glm_vec2_distance2(a, b)); +} + +/*! + * @brief max values of vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec2_maxv(vec2 a, vec2 b, vec2 dest) { + dest[0] = glm_max(a[0], b[0]); + dest[1] = glm_max(a[1], b[1]); +} + +/*! + * @brief min values of vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec2_minv(vec2 a, vec2 b, vec2 dest) { + dest[0] = glm_min(a[0], b[0]); + dest[1] = glm_min(a[1], b[1]); +} + +/*! + * @brief clamp vector's individual members between min and max values + * + * @param[in, out] v vector + * @param[in] minval minimum value + * @param[in] maxval maximum value + */ +CGLM_INLINE +void +glm_vec2_clamp(vec2 v, float minval, float maxval) { + v[0] = glm_clamp(v[0], minval, maxval); + v[1] = glm_clamp(v[1], minval, maxval); +} + +/*! + * @brief linear interpolation between two vector + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) clamped between 0 and 1 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec2_lerp(vec2 from, vec2 to, float t, vec2 dest) { + vec2 s, v; + + /* from + s * (to - from) */ + glm_vec2_fill(s, glm_clamp_zo(t)); + glm_vec2_sub(to, from, v); + glm_vec2_mul(s, v, v); + glm_vec2_add(from, v, dest); +} + +#endif /* cglm_vec2_h */ diff --git a/include/cglm/vec3-ext.h b/include/cglm/vec3-ext.h new file mode 100644 index 0000000..802f4cb --- /dev/null +++ b/include/cglm/vec3-ext.h @@ -0,0 +1,272 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/*! + * @brief SIMD like functions + */ + +/* + Functions: + CGLM_INLINE void glm_vec3_broadcast(float val, vec3 d); + CGLM_INLINE void glm_vec3_fill(vec3 v, float val); + CGLM_INLINE bool glm_vec3_eq(vec3 v, float val); + CGLM_INLINE bool glm_vec3_eq_eps(vec3 v, float val); + CGLM_INLINE bool glm_vec3_eq_all(vec3 v); + CGLM_INLINE bool glm_vec3_eqv(vec3 a, vec3 b); + CGLM_INLINE bool glm_vec3_eqv_eps(vec3 a, vec3 b); + CGLM_INLINE float glm_vec3_max(vec3 v); + CGLM_INLINE float glm_vec3_min(vec3 v); + CGLM_INLINE bool glm_vec3_isnan(vec3 v); + CGLM_INLINE bool glm_vec3_isinf(vec3 v); + CGLM_INLINE bool glm_vec3_isvalid(vec3 v); + CGLM_INLINE void glm_vec3_sign(vec3 v, vec3 dest); + CGLM_INLINE void glm_vec3_abs(vec3 v, vec3 dest); + CGLM_INLINE void glm_vec3_fract(vec3 v, vec3 dest); + CGLM_INLINE float glm_vec3_hadd(vec3 v); + CGLM_INLINE void glm_vec3_sqrt(vec3 v, vec3 dest); + */ + +#ifndef cglm_vec3_ext_h +#define cglm_vec3_ext_h + +#include "common.h" +#include "util.h" + +/*! + * @brief fill a vector with specified value + * + * @param[in] val value + * @param[out] d dest + */ +CGLM_INLINE +void +glm_vec3_broadcast(float val, vec3 d) { + d[0] = d[1] = d[2] = val; +} + +/*! + * @brief fill a vector with specified value + * + * @param[out] v dest + * @param[in] val value + */ +CGLM_INLINE +void +glm_vec3_fill(vec3 v, float val) { + v[0] = v[1] = v[2] = val; +} + +/*! + * @brief check if vector is equal to value (without epsilon) + * + * @param[in] v vector + * @param[in] val value + */ +CGLM_INLINE +bool +glm_vec3_eq(vec3 v, float val) { + return v[0] == val && v[0] == v[1] && v[0] == v[2]; +} + +/*! + * @brief check if vector is equal to value (with epsilon) + * + * @param[in] v vector + * @param[in] val value + */ +CGLM_INLINE +bool +glm_vec3_eq_eps(vec3 v, float val) { + return fabsf(v[0] - val) <= GLM_FLT_EPSILON + && fabsf(v[1] - val) <= GLM_FLT_EPSILON + && fabsf(v[2] - val) <= GLM_FLT_EPSILON; +} + +/*! + * @brief check if vectors members are equal (without epsilon) + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glm_vec3_eq_all(vec3 v) { + return glm_vec3_eq_eps(v, v[0]); +} + +/*! + * @brief check if vector is equal to another (without epsilon) + * + * @param[in] a vector + * @param[in] b vector + */ +CGLM_INLINE +bool +glm_vec3_eqv(vec3 a, vec3 b) { + return a[0] == b[0] + && a[1] == b[1] + && a[2] == b[2]; +} + +/*! + * @brief check if vector is equal to another (with epsilon) + * + * @param[in] a vector + * @param[in] b vector + */ +CGLM_INLINE +bool +glm_vec3_eqv_eps(vec3 a, vec3 b) { + return fabsf(a[0] - b[0]) <= GLM_FLT_EPSILON + && fabsf(a[1] - b[1]) <= GLM_FLT_EPSILON + && fabsf(a[2] - b[2]) <= GLM_FLT_EPSILON; +} + +/*! + * @brief max value of vector + * + * @param[in] v vector + */ +CGLM_INLINE +float +glm_vec3_max(vec3 v) { + float max; + + max = v[0]; + if (v[1] > max) + max = v[1]; + if (v[2] > max) + max = v[2]; + + return max; +} + +/*! + * @brief min value of vector + * + * @param[in] v vector + */ +CGLM_INLINE +float +glm_vec3_min(vec3 v) { + float min; + + min = v[0]; + if (v[1] < min) + min = v[1]; + if (v[2] < min) + min = v[2]; + + return min; +} + +/*! + * @brief check if all items are NaN (not a number) + * you should only use this in DEBUG mode or very critical asserts + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glm_vec3_isnan(vec3 v) { + return isnan(v[0]) || isnan(v[1]) || isnan(v[2]); +} + +/*! + * @brief check if all items are INFINITY + * you should only use this in DEBUG mode or very critical asserts + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glm_vec3_isinf(vec3 v) { + return isinf(v[0]) || isinf(v[1]) || isinf(v[2]); +} + +/*! + * @brief check if all items are valid number + * you should only use this in DEBUG mode or very critical asserts + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glm_vec3_isvalid(vec3 v) { + return !glm_vec3_isnan(v) && !glm_vec3_isinf(v); +} + +/*! + * @brief get sign of 32 bit float as +1, -1, 0 + * + * Important: It returns 0 for zero/NaN input + * + * @param v vector + */ +CGLM_INLINE +void +glm_vec3_sign(vec3 v, vec3 dest) { + dest[0] = glm_signf(v[0]); + dest[1] = glm_signf(v[1]); + dest[2] = glm_signf(v[2]); +} + +/*! + * @brief absolute value of each vector item + * + * @param[in] v vector + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec3_abs(vec3 v, vec3 dest) { + dest[0] = fabsf(v[0]); + dest[1] = fabsf(v[1]); + dest[2] = fabsf(v[2]); +} + +/*! + * @brief fractional part of each vector item + * + * @param[in] v vector + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec3_fract(vec3 v, vec3 dest) { + dest[0] = fminf(v[0] - floorf(v[0]), 0.999999940395355224609375f); + dest[1] = fminf(v[1] - floorf(v[1]), 0.999999940395355224609375f); + dest[2] = fminf(v[2] - floorf(v[2]), 0.999999940395355224609375f); +} + +/*! + * @brief vector reduction by summation + * @warning could overflow + * + * @param[in] v vector + * @return sum of all vector's elements + */ +CGLM_INLINE +float +glm_vec3_hadd(vec3 v) { + return v[0] + v[1] + v[2]; +} + +/*! + * @brief square root of each vector item + * + * @param[in] v vector + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec3_sqrt(vec3 v, vec3 dest) { + dest[0] = sqrtf(v[0]); + dest[1] = sqrtf(v[1]); + dest[2] = sqrtf(v[2]); +} + +#endif /* cglm_vec3_ext_h */ diff --git a/include/cglm/vec3.h b/include/cglm/vec3.h new file mode 100644 index 0000000..b9fff9c --- /dev/null +++ b/include/cglm/vec3.h @@ -0,0 +1,1082 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Macros: + GLM_VEC3_ONE_INIT + GLM_VEC3_ZERO_INIT + GLM_VEC3_ONE + GLM_VEC3_ZERO + GLM_YUP + GLM_ZUP + GLM_XUP + + Functions: + CGLM_INLINE void glm_vec3(vec4 v4, vec3 dest); + CGLM_INLINE void glm_vec3_copy(vec3 a, vec3 dest); + CGLM_INLINE void glm_vec3_zero(vec3 v); + CGLM_INLINE void glm_vec3_one(vec3 v); + CGLM_INLINE float glm_vec3_dot(vec3 a, vec3 b); + CGLM_INLINE float glm_vec3_norm2(vec3 v); + CGLM_INLINE float glm_vec3_norm(vec3 v); + CGLM_INLINE float glm_vec3_norm_one(vec3 v); + CGLM_INLINE float glm_vec3_norm_inf(vec3 v); + CGLM_INLINE void glm_vec3_add(vec3 a, vec3 b, vec3 dest); + CGLM_INLINE void glm_vec3_adds(vec3 a, float s, vec3 dest); + CGLM_INLINE void glm_vec3_sub(vec3 a, vec3 b, vec3 dest); + CGLM_INLINE void glm_vec3_subs(vec3 a, float s, vec3 dest); + CGLM_INLINE void glm_vec3_mul(vec3 a, vec3 b, vec3 dest); + CGLM_INLINE void glm_vec3_scale(vec3 v, float s, vec3 dest); + CGLM_INLINE void glm_vec3_scale_as(vec3 v, float s, vec3 dest); + CGLM_INLINE void glm_vec3_div(vec3 a, vec3 b, vec3 dest); + CGLM_INLINE void glm_vec3_divs(vec3 a, float s, vec3 dest); + CGLM_INLINE void glm_vec3_addadd(vec3 a, vec3 b, vec3 dest); + CGLM_INLINE void glm_vec3_subadd(vec3 a, vec3 b, vec3 dest); + CGLM_INLINE void glm_vec3_muladd(vec3 a, vec3 b, vec3 dest); + CGLM_INLINE void glm_vec3_muladds(vec3 a, float s, vec3 dest); + CGLM_INLINE void glm_vec3_maxadd(vec3 a, vec3 b, vec3 dest); + CGLM_INLINE void glm_vec3_minadd(vec3 a, vec3 b, vec3 dest); + CGLM_INLINE void glm_vec3_flipsign(vec3 v); + CGLM_INLINE void glm_vec3_flipsign_to(vec3 v, vec3 dest); + CGLM_INLINE void glm_vec3_negate_to(vec3 v, vec3 dest); + CGLM_INLINE void glm_vec3_negate(vec3 v); + CGLM_INLINE void glm_vec3_inv(vec3 v); + CGLM_INLINE void glm_vec3_inv_to(vec3 v, vec3 dest); + CGLM_INLINE void glm_vec3_normalize(vec3 v); + CGLM_INLINE void glm_vec3_normalize_to(vec3 v, vec3 dest); + CGLM_INLINE void glm_vec3_cross(vec3 a, vec3 b, vec3 d); + CGLM_INLINE void glm_vec3_crossn(vec3 a, vec3 b, vec3 dest); + CGLM_INLINE float glm_vec3_angle(vec3 a, vec3 b); + CGLM_INLINE void glm_vec3_rotate(vec3 v, float angle, vec3 axis); + CGLM_INLINE void glm_vec3_rotate_m4(mat4 m, vec3 v, vec3 dest); + CGLM_INLINE void glm_vec3_rotate_m3(mat3 m, vec3 v, vec3 dest); + CGLM_INLINE void glm_vec3_proj(vec3 a, vec3 b, vec3 dest); + CGLM_INLINE void glm_vec3_center(vec3 a, vec3 b, vec3 dest); + CGLM_INLINE float glm_vec3_distance(vec3 a, vec3 b); + CGLM_INLINE float glm_vec3_distance2(vec3 a, vec3 b); + CGLM_INLINE void glm_vec3_maxv(vec3 a, vec3 b, vec3 dest); + CGLM_INLINE void glm_vec3_minv(vec3 a, vec3 b, vec3 dest); + CGLM_INLINE void glm_vec3_ortho(vec3 v, vec3 dest); + CGLM_INLINE void glm_vec3_clamp(vec3 v, float minVal, float maxVal); + CGLM_INLINE void glm_vec3_lerp(vec3 from, vec3 to, float t, vec3 dest); + CGLM_INLINE void glm_vec3_lerpc(vec3 from, vec3 to, float t, vec3 dest); + CGLM_INLINE void glm_vec3_mix(vec3 from, vec3 to, float t, vec3 dest); + CGLM_INLINE void glm_vec3_mixc(vec3 from, vec3 to, float t, vec3 dest); + CGLM_INLINE void glm_vec3_step_uni(float edge, vec3 x, vec3 dest); + CGLM_INLINE void glm_vec3_step(vec3 edge, vec3 x, vec3 dest); + CGLM_INLINE void glm_vec3_smoothstep_uni(float edge0, float edge1, vec3 x, vec3 dest); + CGLM_INLINE void glm_vec3_smoothstep(vec3 edge0, vec3 edge1, vec3 x, vec3 dest); + CGLM_INLINE void glm_vec3_smoothinterp(vec3 from, vec3 to, float t, vec3 dest); + CGLM_INLINE void glm_vec3_smoothinterpc(vec3 from, vec3 to, float t, vec3 dest); + CGLM_INLINE void glm_vec3_swizzle(vec3 v, int mask, vec3 dest); + + Convenient: + CGLM_INLINE void glm_cross(vec3 a, vec3 b, vec3 d); + CGLM_INLINE float glm_dot(vec3 a, vec3 b); + CGLM_INLINE void glm_normalize(vec3 v); + CGLM_INLINE void glm_normalize_to(vec3 v, vec3 dest); + + DEPRECATED: + glm_vec3_dup + glm_vec3_flipsign + glm_vec3_flipsign_to + glm_vec3_inv + glm_vec3_inv_to + glm_vec3_mulv + */ + +#ifndef cglm_vec3_h +#define cglm_vec3_h + +#include "common.h" +#include "vec4.h" +#include "vec3-ext.h" +#include "util.h" + +/* DEPRECATED! use _copy, _ucopy versions */ +#define glm_vec3_dup(v, dest) glm_vec3_copy(v, dest) +#define glm_vec3_flipsign(v) glm_vec3_negate(v) +#define glm_vec3_flipsign_to(v, dest) glm_vec3_negate_to(v, dest) +#define glm_vec3_inv(v) glm_vec3_negate(v) +#define glm_vec3_inv_to(v, dest) glm_vec3_negate_to(v, dest) +#define glm_vec3_mulv(a, b, d) glm_vec3_mul(a, b, d) + +#define GLM_VEC3_ONE_INIT {1.0f, 1.0f, 1.0f} +#define GLM_VEC3_ZERO_INIT {0.0f, 0.0f, 0.0f} + +#define GLM_VEC3_ONE ((vec3)GLM_VEC3_ONE_INIT) +#define GLM_VEC3_ZERO ((vec3)GLM_VEC3_ZERO_INIT) + +#define GLM_YUP ((vec3){0.0f, 1.0f, 0.0f}) +#define GLM_ZUP ((vec3){0.0f, 0.0f, 1.0f}) +#define GLM_XUP ((vec3){1.0f, 0.0f, 0.0f}) +#define GLM_FORWARD ((vec3){0.0f, 0.0f, -1.0f}) + +#define GLM_XXX GLM_SHUFFLE3(0, 0, 0) +#define GLM_YYY GLM_SHUFFLE3(1, 1, 1) +#define GLM_ZZZ GLM_SHUFFLE3(2, 2, 2) +#define GLM_ZYX GLM_SHUFFLE3(0, 1, 2) + +/*! + * @brief init vec3 using vec4 + * + * @param[in] v4 vector4 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3(vec4 v4, vec3 dest) { + dest[0] = v4[0]; + dest[1] = v4[1]; + dest[2] = v4[2]; +} + +/*! + * @brief copy all members of [a] to [dest] + * + * @param[in] a source + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3_copy(vec3 a, vec3 dest) { + dest[0] = a[0]; + dest[1] = a[1]; + dest[2] = a[2]; +} + +/*! + * @brief make vector zero + * + * @param[in, out] v vector + */ +CGLM_INLINE +void +glm_vec3_zero(vec3 v) { + v[0] = v[1] = v[2] = 0.0f; +} + +/*! + * @brief make vector one + * + * @param[in, out] v vector + */ +CGLM_INLINE +void +glm_vec3_one(vec3 v) { + v[0] = v[1] = v[2] = 1.0f; +} + +/*! + * @brief vec3 dot product + * + * @param[in] a vector1 + * @param[in] b vector2 + * + * @return dot product + */ +CGLM_INLINE +float +glm_vec3_dot(vec3 a, vec3 b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +} + +/*! + * @brief norm * norm (magnitude) of vec + * + * we can use this func instead of calling norm * norm, because it would call + * sqrtf fuction twice but with this func we can avoid func call, maybe this is + * not good name for this func + * + * @param[in] v vector + * + * @return norm * norm + */ +CGLM_INLINE +float +glm_vec3_norm2(vec3 v) { + return glm_vec3_dot(v, v); +} + +/*! + * @brief euclidean norm (magnitude), also called L2 norm + * this will give magnitude of vector in euclidean space + * + * @param[in] v vector + * + * @return norm + */ +CGLM_INLINE +float +glm_vec3_norm(vec3 v) { + return sqrtf(glm_vec3_norm2(v)); +} + +/*! + * @brief L1 norm of vec3 + * Also known as Manhattan Distance or Taxicab norm. + * L1 Norm is the sum of the magnitudes of the vectors in a space. + * It is calculated as the sum of the absolute values of the vector components. + * In this norm, all the components of the vector are weighted equally. + * + * This computes: + * R = |v[0]| + |v[1]| + |v[2]| + * + * @param[in] v vector + * + * @return L1 norm + */ +CGLM_INLINE +float +glm_vec3_norm_one(vec3 v) { + vec3 t; + glm_vec3_abs(v, t); + return glm_vec3_hadd(t); +} + +/*! + * @brief infinity norm of vec3 + * Also known as Maximum norm. + * Infinity Norm is the largest magnitude among each element of a vector. + * It is calculated as the maximum of the absolute values of the vector components. + * + * This computes: + * inf norm = max(|v[0]|, |v[1]|, |v[2]|) + * + * @param[in] v vector + * + * @return infinity norm + */ +CGLM_INLINE +float +glm_vec3_norm_inf(vec3 v) { + vec3 t; + glm_vec3_abs(v, t); + return glm_vec3_max(t); +} + +/*! + * @brief add a vector to b vector store result in dest + * + * @param[in] a vector1 + * @param[in] b vector2 + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec3_add(vec3 a, vec3 b, vec3 dest) { + dest[0] = a[0] + b[0]; + dest[1] = a[1] + b[1]; + dest[2] = a[2] + b[2]; +} + +/*! + * @brief add scalar to v vector store result in dest (d = v + s) + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec3_adds(vec3 v, float s, vec3 dest) { + dest[0] = v[0] + s; + dest[1] = v[1] + s; + dest[2] = v[2] + s; +} + +/*! + * @brief subtract b vector from a vector store result in dest + * + * @param[in] a vector1 + * @param[in] b vector2 + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec3_sub(vec3 a, vec3 b, vec3 dest) { + dest[0] = a[0] - b[0]; + dest[1] = a[1] - b[1]; + dest[2] = a[2] - b[2]; +} + +/*! + * @brief subtract scalar from v vector store result in dest (d = v - s) + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec3_subs(vec3 v, float s, vec3 dest) { + dest[0] = v[0] - s; + dest[1] = v[1] - s; + dest[2] = v[2] - s; +} + +/*! + * @brief multiply two vector (component-wise multiplication) + * + * @param a vector1 + * @param b vector2 + * @param dest v3 = (a[0] * b[0], a[1] * b[1], a[2] * b[2]) + */ +CGLM_INLINE +void +glm_vec3_mul(vec3 a, vec3 b, vec3 dest) { + dest[0] = a[0] * b[0]; + dest[1] = a[1] * b[1]; + dest[2] = a[2] * b[2]; +} + +/*! + * @brief multiply/scale vec3 vector with scalar: result = v * s + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec3_scale(vec3 v, float s, vec3 dest) { + dest[0] = v[0] * s; + dest[1] = v[1] * s; + dest[2] = v[2] * s; +} + +/*! + * @brief make vec3 vector scale as specified: result = unit(v) * s + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec3_scale_as(vec3 v, float s, vec3 dest) { + float norm; + norm = glm_vec3_norm(v); + + if (norm == 0.0f) { + glm_vec3_zero(dest); + return; + } + + glm_vec3_scale(v, s / norm, dest); +} + +/*! + * @brief div vector with another component-wise division: d = a / b + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest result = (a[0]/b[0], a[1]/b[1], a[2]/b[2]) + */ +CGLM_INLINE +void +glm_vec3_div(vec3 a, vec3 b, vec3 dest) { + dest[0] = a[0] / b[0]; + dest[1] = a[1] / b[1]; + dest[2] = a[2] / b[2]; +} + +/*! + * @brief div vector with scalar: d = v / s + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest result = (a[0]/s, a[1]/s, a[2]/s) + */ +CGLM_INLINE +void +glm_vec3_divs(vec3 v, float s, vec3 dest) { + dest[0] = v[0] / s; + dest[1] = v[1] / s; + dest[2] = v[2] / s; +} + +/*! + * @brief add two vectors and add result to sum + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest dest += (a + b) + */ +CGLM_INLINE +void +glm_vec3_addadd(vec3 a, vec3 b, vec3 dest) { + dest[0] += a[0] + b[0]; + dest[1] += a[1] + b[1]; + dest[2] += a[2] + b[2]; +} + +/*! + * @brief sub two vectors and add result to dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest dest += (a + b) + */ +CGLM_INLINE +void +glm_vec3_subadd(vec3 a, vec3 b, vec3 dest) { + dest[0] += a[0] - b[0]; + dest[1] += a[1] - b[1]; + dest[2] += a[2] - b[2]; +} + +/*! + * @brief mul two vectors and add result to dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest dest += (a * b) + */ +CGLM_INLINE +void +glm_vec3_muladd(vec3 a, vec3 b, vec3 dest) { + dest[0] += a[0] * b[0]; + dest[1] += a[1] * b[1]; + dest[2] += a[2] * b[2]; +} + +/*! + * @brief mul vector with scalar and add result to sum + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector + * @param[in] s scalar + * @param[out] dest dest += (a * b) + */ +CGLM_INLINE +void +glm_vec3_muladds(vec3 a, float s, vec3 dest) { + dest[0] += a[0] * s; + dest[1] += a[1] * s; + dest[2] += a[2] * s; +} + +/*! + * @brief add max of two vector to result/dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest dest += max(a, b) + */ +CGLM_INLINE +void +glm_vec3_maxadd(vec3 a, vec3 b, vec3 dest) { + dest[0] += glm_max(a[0], b[0]); + dest[1] += glm_max(a[1], b[1]); + dest[2] += glm_max(a[2], b[2]); +} + +/*! + * @brief add min of two vector to result/dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest dest += min(a, b) + */ +CGLM_INLINE +void +glm_vec3_minadd(vec3 a, vec3 b, vec3 dest) { + dest[0] += glm_min(a[0], b[0]); + dest[1] += glm_min(a[1], b[1]); + dest[2] += glm_min(a[2], b[2]); +} + +/*! + * @brief negate vector components and store result in dest + * + * @param[in] v vector + * @param[out] dest result vector + */ +CGLM_INLINE +void +glm_vec3_negate_to(vec3 v, vec3 dest) { + dest[0] = -v[0]; + dest[1] = -v[1]; + dest[2] = -v[2]; +} + +/*! + * @brief negate vector components + * + * @param[in, out] v vector + */ +CGLM_INLINE +void +glm_vec3_negate(vec3 v) { + glm_vec3_negate_to(v, v); +} + +/*! + * @brief normalize vec3 and store result in same vec + * + * @param[in, out] v vector + */ +CGLM_INLINE +void +glm_vec3_normalize(vec3 v) { + float norm; + + norm = glm_vec3_norm(v); + + if (norm == 0.0f) { + v[0] = v[1] = v[2] = 0.0f; + return; + } + + glm_vec3_scale(v, 1.0f / norm, v); +} + +/*! + * @brief normalize vec3 to dest + * + * @param[in] v source + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3_normalize_to(vec3 v, vec3 dest) { + float norm; + + norm = glm_vec3_norm(v); + + if (norm == 0.0f) { + glm_vec3_zero(dest); + return; + } + + glm_vec3_scale(v, 1.0f / norm, dest); +} + +/*! + * @brief cross product of two vector (RH) + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3_cross(vec3 a, vec3 b, vec3 dest) { + vec3 c; + /* (u2.v3 - u3.v2, u3.v1 - u1.v3, u1.v2 - u2.v1) */ + c[0] = a[1] * b[2] - a[2] * b[1]; + c[1] = a[2] * b[0] - a[0] * b[2]; + c[2] = a[0] * b[1] - a[1] * b[0]; + glm_vec3_copy(c, dest); +} + +/*! + * @brief cross product of two vector (RH) and normalize the result + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3_crossn(vec3 a, vec3 b, vec3 dest) { + glm_vec3_cross(a, b, dest); + glm_vec3_normalize(dest); +} + +/*! + * @brief angle betwen two vector + * + * @param[in] a vector1 + * @param[in] b vector2 + * + * @return angle as radians + */ +CGLM_INLINE +float +glm_vec3_angle(vec3 a, vec3 b) { + float norm, dot; + + /* maybe compiler generate approximation instruction (rcp) */ + norm = 1.0f / (glm_vec3_norm(a) * glm_vec3_norm(b)); + dot = glm_vec3_dot(a, b) * norm; + + if (dot > 1.0f) + return 0.0f; + else if (dot < -1.0f) + return CGLM_PI; + + return acosf(dot); +} + +/*! + * @brief rotate vec3 around axis by angle using Rodrigues' rotation formula + * + * @param[in, out] v vector + * @param[in] axis axis vector (must be unit vector) + * @param[in] angle angle by radians + */ +CGLM_INLINE +void +glm_vec3_rotate(vec3 v, float angle, vec3 axis) { + vec3 v1, v2, k; + float c, s; + + c = cosf(angle); + s = sinf(angle); + + glm_vec3_normalize_to(axis, k); + + /* Right Hand, Rodrigues' rotation formula: + v = v*cos(t) + (kxv)sin(t) + k*(k.v)(1 - cos(t)) + */ + glm_vec3_scale(v, c, v1); + + glm_vec3_cross(k, v, v2); + glm_vec3_scale(v2, s, v2); + + glm_vec3_add(v1, v2, v1); + + glm_vec3_scale(k, glm_vec3_dot(k, v) * (1.0f - c), v2); + glm_vec3_add(v1, v2, v); +} + +/*! + * @brief apply rotation matrix to vector + * + * matrix format should be (no perspective): + * a b c x + * e f g y + * i j k z + * 0 0 0 w + * + * @param[in] m affine matrix or rot matrix + * @param[in] v vector + * @param[out] dest rotated vector + */ +CGLM_INLINE +void +glm_vec3_rotate_m4(mat4 m, vec3 v, vec3 dest) { + vec4 x, y, z, res; + + glm_vec4_normalize_to(m[0], x); + glm_vec4_normalize_to(m[1], y); + glm_vec4_normalize_to(m[2], z); + + glm_vec4_scale(x, v[0], res); + glm_vec4_muladds(y, v[1], res); + glm_vec4_muladds(z, v[2], res); + + glm_vec3(res, dest); +} + +/*! + * @brief apply rotation matrix to vector + * + * @param[in] m affine matrix or rot matrix + * @param[in] v vector + * @param[out] dest rotated vector + */ +CGLM_INLINE +void +glm_vec3_rotate_m3(mat3 m, vec3 v, vec3 dest) { + vec4 res, x, y, z; + + glm_vec4(m[0], 0.0f, x); + glm_vec4(m[1], 0.0f, y); + glm_vec4(m[2], 0.0f, z); + + glm_vec4_normalize(x); + glm_vec4_normalize(y); + glm_vec4_normalize(z); + + glm_vec4_scale(x, v[0], res); + glm_vec4_muladds(y, v[1], res); + glm_vec4_muladds(z, v[2], res); + + glm_vec3(res, dest); +} + +/*! + * @brief project a vector onto b vector + * + * @param[in] a vector1 + * @param[in] b vector2 + * @param[out] dest projected vector + */ +CGLM_INLINE +void +glm_vec3_proj(vec3 a, vec3 b, vec3 dest) { + glm_vec3_scale(b, + glm_vec3_dot(a, b) / glm_vec3_norm2(b), + dest); +} + +/** + * @brief find center point of two vector + * + * @param[in] a vector1 + * @param[in] b vector2 + * @param[out] dest center point + */ +CGLM_INLINE +void +glm_vec3_center(vec3 a, vec3 b, vec3 dest) { + glm_vec3_add(a, b, dest); + glm_vec3_scale(dest, 0.5f, dest); +} + +/** + * @brief squared distance between two vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @return returns squared distance (distance * distance) + */ +CGLM_INLINE +float +glm_vec3_distance2(vec3 a, vec3 b) { + return glm_pow2(a[0] - b[0]) + + glm_pow2(a[1] - b[1]) + + glm_pow2(a[2] - b[2]); +} + +/** + * @brief distance between two vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @return returns distance + */ +CGLM_INLINE +float +glm_vec3_distance(vec3 a, vec3 b) { + return sqrtf(glm_vec3_distance2(a, b)); +} + +/*! + * @brief max values of vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3_maxv(vec3 a, vec3 b, vec3 dest) { + dest[0] = glm_max(a[0], b[0]); + dest[1] = glm_max(a[1], b[1]); + dest[2] = glm_max(a[2], b[2]); +} + +/*! + * @brief min values of vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3_minv(vec3 a, vec3 b, vec3 dest) { + dest[0] = glm_min(a[0], b[0]); + dest[1] = glm_min(a[1], b[1]); + dest[2] = glm_min(a[2], b[2]); +} + +/*! + * @brief possible orthogonal/perpendicular vector + * + * @param[in] v vector + * @param[out] dest orthogonal/perpendicular vector + */ +CGLM_INLINE +void +glm_vec3_ortho(vec3 v, vec3 dest) { + float ignore; + float f = modff(fabsf(v[0]) + 0.5f, &ignore); + vec3 result = {-v[1], v[0] - f * v[2], f * v[1]}; + glm_vec3_copy(result, dest); +} + +/*! + * @brief clamp vector's individual members between min and max values + * + * @param[in, out] v vector + * @param[in] minVal minimum value + * @param[in] maxVal maximum value + */ +CGLM_INLINE +void +glm_vec3_clamp(vec3 v, float minVal, float maxVal) { + v[0] = glm_clamp(v[0], minVal, maxVal); + v[1] = glm_clamp(v[1], minVal, maxVal); + v[2] = glm_clamp(v[2], minVal, maxVal); +} + +/*! + * @brief linear interpolation between two vectors + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3_lerp(vec3 from, vec3 to, float t, vec3 dest) { + vec3 s, v; + + /* from + s * (to - from) */ + glm_vec3_broadcast(t, s); + glm_vec3_sub(to, from, v); + glm_vec3_mul(s, v, v); + glm_vec3_add(from, v, dest); +} + +/*! + * @brief linear interpolation between two vectors (clamped) + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) clamped between 0 and 1 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3_lerpc(vec3 from, vec3 to, float t, vec3 dest) { + glm_vec3_lerp(from, to, glm_clamp_zo(t), dest); +} + +/*! + * @brief linear interpolation between two vectors + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3_mix(vec3 from, vec3 to, float t, vec3 dest) { + glm_vec3_lerp(from, to, t, dest); +} + +/*! + * @brief linear interpolation between two vectors (clamped) + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) clamped between 0 and 1 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3_mixc(vec3 from, vec3 to, float t, vec3 dest) { + glm_vec3_lerpc(from, to, t, dest); +} + +/*! + * @brief threshold function (unidimensional) + * + * @param[in] edge threshold + * @param[in] x value to test against threshold + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3_step_uni(float edge, vec3 x, vec3 dest) { + dest[0] = glm_step(edge, x[0]); + dest[1] = glm_step(edge, x[1]); + dest[2] = glm_step(edge, x[2]); +} + +/*! + * @brief threshold function + * + * @param[in] edge threshold + * @param[in] x value to test against threshold + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3_step(vec3 edge, vec3 x, vec3 dest) { + dest[0] = glm_step(edge[0], x[0]); + dest[1] = glm_step(edge[1], x[1]); + dest[2] = glm_step(edge[2], x[2]); +} + +/*! + * @brief threshold function with a smooth transition (unidimensional) + * + * @param[in] edge0 low threshold + * @param[in] edge1 high threshold + * @param[in] x value to test against threshold + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3_smoothstep_uni(float edge0, float edge1, vec3 x, vec3 dest) { + dest[0] = glm_smoothstep(edge0, edge1, x[0]); + dest[1] = glm_smoothstep(edge0, edge1, x[1]); + dest[2] = glm_smoothstep(edge0, edge1, x[2]); +} + +/*! + * @brief threshold function with a smooth transition + * + * @param[in] edge0 low threshold + * @param[in] edge1 high threshold + * @param[in] x value to test against threshold + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3_smoothstep(vec3 edge0, vec3 edge1, vec3 x, vec3 dest) { + dest[0] = glm_smoothstep(edge0[0], edge1[0], x[0]); + dest[1] = glm_smoothstep(edge0[1], edge1[1], x[1]); + dest[2] = glm_smoothstep(edge0[2], edge1[2], x[2]); +} + +/*! + * @brief smooth Hermite interpolation between two vectors + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3_smoothinterp(vec3 from, vec3 to, float t, vec3 dest) { + vec3 s, v; + + /* from + s * (to - from) */ + glm_vec3_broadcast(glm_smooth(t), s); + glm_vec3_sub(to, from, v); + glm_vec3_mul(s, v, v); + glm_vec3_add(from, v, dest); +} + +/*! + * @brief smooth Hermite interpolation between two vectors (clamped) + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) clamped between 0 and 1 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3_smoothinterpc(vec3 from, vec3 to, float t, vec3 dest) { + glm_vec3_smoothinterp(from, to, glm_clamp_zo(t), dest); +} + +/*! + * @brief swizzle vector components + * + * you can use existin masks e.g. GLM_XXX, GLM_ZYX + * + * @param[in] v source + * @param[in] mask mask + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3_swizzle(vec3 v, int mask, vec3 dest) { + vec3 t; + + t[0] = v[(mask & (3 << 0))]; + t[1] = v[(mask & (3 << 2)) >> 2]; + t[2] = v[(mask & (3 << 4)) >> 4]; + + glm_vec3_copy(t, dest); +} + +/*! + * @brief vec3 cross product + * + * this is just convenient wrapper + * + * @param[in] a source 1 + * @param[in] b source 2 + * @param[out] d destination + */ +CGLM_INLINE +void +glm_cross(vec3 a, vec3 b, vec3 d) { + glm_vec3_cross(a, b, d); +} + +/*! + * @brief vec3 dot product + * + * this is just convenient wrapper + * + * @param[in] a vector1 + * @param[in] b vector2 + * + * @return dot product + */ +CGLM_INLINE +float +glm_dot(vec3 a, vec3 b) { + return glm_vec3_dot(a, b); +} + +/*! + * @brief normalize vec3 and store result in same vec + * + * this is just convenient wrapper + * + * @param[in, out] v vector + */ +CGLM_INLINE +void +glm_normalize(vec3 v) { + glm_vec3_normalize(v); +} + +/*! + * @brief normalize vec3 to dest + * + * this is just convenient wrapper + * + * @param[in] v source + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_normalize_to(vec3 v, vec3 dest) { + glm_vec3_normalize_to(v, dest); +} + +#endif /* cglm_vec3_h */ diff --git a/include/cglm/vec4-ext.h b/include/cglm/vec4-ext.h new file mode 100644 index 0000000..e4e20cb --- /dev/null +++ b/include/cglm/vec4-ext.h @@ -0,0 +1,313 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/*! + * @brief SIMD like functions + */ + +/* + Functions: + CGLM_INLINE void glm_vec4_broadcast(float val, vec4 d); + CGLM_INLINE void glm_vec4_fill(vec4 v, float val); + CGLM_INLINE bool glm_vec4_eq(vec4 v, float val); + CGLM_INLINE bool glm_vec4_eq_eps(vec4 v, float val); + CGLM_INLINE bool glm_vec4_eq_all(vec4 v); + CGLM_INLINE bool glm_vec4_eqv(vec4 a, vec4 b); + CGLM_INLINE bool glm_vec4_eqv_eps(vec4 a, vec4 b); + CGLM_INLINE float glm_vec4_max(vec4 v); + CGLM_INLINE float glm_vec4_min(vec4 v); + CGLM_INLINE bool glm_vec4_isnan(vec4 v); + CGLM_INLINE bool glm_vec4_isinf(vec4 v); + CGLM_INLINE bool glm_vec4_isvalid(vec4 v); + CGLM_INLINE void glm_vec4_sign(vec4 v, vec4 dest); + CGLM_INLINE void glm_vec4_abs(vec4 v, vec4 dest); + CGLM_INLINE void glm_vec4_fract(vec4 v, vec4 dest); + CGLM_INLINE float glm_vec4_hadd(vec4 v); + CGLM_INLINE void glm_vec4_sqrt(vec4 v, vec4 dest); + */ + +#ifndef cglm_vec4_ext_h +#define cglm_vec4_ext_h + +#include "common.h" +#include "vec3-ext.h" + +/*! + * @brief fill a vector with specified value + * + * @param val value + * @param d dest + */ +CGLM_INLINE +void +glm_vec4_broadcast(float val, vec4 d) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(d, _mm_set1_ps(val)); +#else + d[0] = d[1] = d[2] = d[3] = val; +#endif +} + +/*! + * @brief fill a vector with specified value + * + * @param v dest + * @param val value + */ +CGLM_INLINE +void +glm_vec4_fill(vec4 v, float val) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(v, _mm_set1_ps(val)); +#else + v[0] = v[1] = v[2] = v[3] = val; +#endif +} + +/*! + * @brief check if vector is equal to value (without epsilon) + * + * @param v vector + * @param val value + */ +CGLM_INLINE +bool +glm_vec4_eq(vec4 v, float val) { + return v[0] == val + && v[0] == v[1] + && v[0] == v[2] + && v[0] == v[3]; +} + +/*! + * @brief check if vector is equal to value (with epsilon) + * + * @param v vector + * @param val value + */ +CGLM_INLINE +bool +glm_vec4_eq_eps(vec4 v, float val) { + return fabsf(v[0] - val) <= GLM_FLT_EPSILON + && fabsf(v[1] - val) <= GLM_FLT_EPSILON + && fabsf(v[2] - val) <= GLM_FLT_EPSILON + && fabsf(v[3] - val) <= GLM_FLT_EPSILON; +} + +/*! + * @brief check if vectors members are equal (without epsilon) + * + * @param v vector + */ +CGLM_INLINE +bool +glm_vec4_eq_all(vec4 v) { + return glm_vec4_eq_eps(v, v[0]); +} + +/*! + * @brief check if vector is equal to another (without epsilon) + * + * @param a vector + * @param b vector + */ +CGLM_INLINE +bool +glm_vec4_eqv(vec4 a, vec4 b) { + return a[0] == b[0] + && a[1] == b[1] + && a[2] == b[2] + && a[3] == b[3]; +} + +/*! + * @brief check if vector is equal to another (with epsilon) + * + * @param a vector + * @param b vector + */ +CGLM_INLINE +bool +glm_vec4_eqv_eps(vec4 a, vec4 b) { + return fabsf(a[0] - b[0]) <= GLM_FLT_EPSILON + && fabsf(a[1] - b[1]) <= GLM_FLT_EPSILON + && fabsf(a[2] - b[2]) <= GLM_FLT_EPSILON + && fabsf(a[3] - b[3]) <= GLM_FLT_EPSILON; +} + +/*! + * @brief max value of vector + * + * @param v vector + */ +CGLM_INLINE +float +glm_vec4_max(vec4 v) { + float max; + + max = glm_vec3_max(v); + if (v[3] > max) + max = v[3]; + + return max; +} + +/*! + * @brief min value of vector + * + * @param v vector + */ +CGLM_INLINE +float +glm_vec4_min(vec4 v) { + float min; + + min = glm_vec3_min(v); + if (v[3] < min) + min = v[3]; + + return min; +} + +/*! + * @brief check if one of items is NaN (not a number) + * you should only use this in DEBUG mode or very critical asserts + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glm_vec4_isnan(vec4 v) { + return isnan(v[0]) || isnan(v[1]) || isnan(v[2]) || isnan(v[3]); +} + +/*! + * @brief check if one of items is INFINITY + * you should only use this in DEBUG mode or very critical asserts + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glm_vec4_isinf(vec4 v) { + return isinf(v[0]) || isinf(v[1]) || isinf(v[2]) || isinf(v[3]); +} + +/*! + * @brief check if all items are valid number + * you should only use this in DEBUG mode or very critical asserts + * + * @param[in] v vector + */ +CGLM_INLINE +bool +glm_vec4_isvalid(vec4 v) { + return !glm_vec4_isnan(v) && !glm_vec4_isinf(v); +} + +/*! + * @brief get sign of 32 bit float as +1, -1, 0 + * + * Important: It returns 0 for zero/NaN input + * + * @param v vector + */ +CGLM_INLINE +void +glm_vec4_sign(vec4 v, vec4 dest) { +#if defined( __SSE2__ ) || defined( __SSE2__ ) + __m128 x0, x1, x2, x3, x4; + + x0 = glmm_load(v); + x1 = _mm_set_ps(0.0f, 0.0f, 1.0f, -1.0f); + x2 = glmm_splat(x1, 2); + + x3 = _mm_and_ps(_mm_cmpgt_ps(x0, x2), glmm_splat(x1, 1)); + x4 = _mm_and_ps(_mm_cmplt_ps(x0, x2), glmm_splat(x1, 0)); + + glmm_store(dest, _mm_or_ps(x3, x4)); +#else + dest[0] = glm_signf(v[0]); + dest[1] = glm_signf(v[1]); + dest[2] = glm_signf(v[2]); + dest[3] = glm_signf(v[3]); +#endif +} + +/*! + * @brief absolute value of each vector item + * + * @param[in] v vector + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec4_abs(vec4 v, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(dest, glmm_abs(glmm_load(v))); +#elif defined(CGLM_NEON_FP) + vst1q_f32(dest, vabsq_f32(vld1q_f32(v))); +#else + dest[0] = fabsf(v[0]); + dest[1] = fabsf(v[1]); + dest[2] = fabsf(v[2]); + dest[3] = fabsf(v[3]); +#endif +} + +/*! + * @brief fractional part of each vector item + * + * @param[in] v vector + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec4_fract(vec4 v, vec4 dest) { + dest[0] = fminf(v[0] - floorf(v[0]), 0.999999940395355224609375f); + dest[1] = fminf(v[1] - floorf(v[1]), 0.999999940395355224609375f); + dest[2] = fminf(v[2] - floorf(v[2]), 0.999999940395355224609375f); + dest[3] = fminf(v[3] - floorf(v[3]), 0.999999940395355224609375f); +} + +/*! + * @brief vector reduction by summation + * @warning could overflow + * + * @param[in] v vector + * @return sum of all vector's elements + */ +CGLM_INLINE +float +glm_vec4_hadd(vec4 v) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + return glmm_hadd(glmm_load(v)); +#else + return v[0] + v[1] + v[2] + v[3]; +#endif +} + +/*! + * @brief square root of each vector item + * + * @param[in] v vector + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec4_sqrt(vec4 v, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(dest, _mm_sqrt_ps(glmm_load(v))); +#else + dest[0] = sqrtf(v[0]); + dest[1] = sqrtf(v[1]); + dest[2] = sqrtf(v[2]); + dest[3] = sqrtf(v[3]); +#endif +} + +#endif /* cglm_vec4_ext_h */ diff --git a/include/cglm/vec4.h b/include/cglm/vec4.h new file mode 100644 index 0000000..8e95ec5 --- /dev/null +++ b/include/cglm/vec4.h @@ -0,0 +1,1066 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Macros: + GLM_VEC4_ONE_INIT + GLM_VEC4_BLACK_INIT + GLM_VEC4_ZERO_INIT + GLM_VEC4_ONE + GLM_VEC4_BLACK + GLM_VEC4_ZERO + + Functions: + CGLM_INLINE void glm_vec4(vec3 v3, float last, vec4 dest); + CGLM_INLINE void glm_vec4_copy3(vec4 a, vec3 dest); + CGLM_INLINE void glm_vec4_copy(vec4 v, vec4 dest); + CGLM_INLINE void glm_vec4_ucopy(vec4 v, vec4 dest); + CGLM_INLINE float glm_vec4_dot(vec4 a, vec4 b); + CGLM_INLINE float glm_vec4_norm2(vec4 v); + CGLM_INLINE float glm_vec4_norm(vec4 v); + CGLM_INLINE float glm_vec4_norm_one(vec4 v); + CGLM_INLINE float glm_vec4_norm_inf(vec4 v); + CGLM_INLINE void glm_vec4_add(vec4 a, vec4 b, vec4 dest); + CGLM_INLINE void glm_vec4_adds(vec4 v, float s, vec4 dest); + CGLM_INLINE void glm_vec4_sub(vec4 a, vec4 b, vec4 dest); + CGLM_INLINE void glm_vec4_subs(vec4 v, float s, vec4 dest); + CGLM_INLINE void glm_vec4_mul(vec4 a, vec4 b, vec4 dest); + CGLM_INLINE void glm_vec4_scale(vec4 v, float s, vec4 dest); + CGLM_INLINE void glm_vec4_scale_as(vec4 v, float s, vec4 dest); + CGLM_INLINE void glm_vec4_div(vec4 a, vec4 b, vec4 dest); + CGLM_INLINE void glm_vec4_divs(vec4 v, float s, vec4 dest); + CGLM_INLINE void glm_vec4_addadd(vec4 a, vec4 b, vec4 dest); + CGLM_INLINE void glm_vec4_subadd(vec4 a, vec4 b, vec4 dest); + CGLM_INLINE void glm_vec4_muladd(vec4 a, vec4 b, vec4 dest); + CGLM_INLINE void glm_vec4_muladds(vec4 a, float s, vec4 dest); + CGLM_INLINE void glm_vec4_maxadd(vec4 a, vec4 b, vec4 dest); + CGLM_INLINE void glm_vec4_minadd(vec4 a, vec4 b, vec4 dest); + CGLM_INLINE void glm_vec4_negate(vec4 v); + CGLM_INLINE void glm_vec4_inv(vec4 v); + CGLM_INLINE void glm_vec4_inv_to(vec4 v, vec4 dest); + CGLM_INLINE void glm_vec4_normalize(vec4 v); + CGLM_INLINE void glm_vec4_normalize_to(vec4 vec, vec4 dest); + CGLM_INLINE float glm_vec4_distance(vec4 a, vec4 b); + CGLM_INLINE float glm_vec4_distance2(vec4 a, vec4 b); + CGLM_INLINE void glm_vec4_maxv(vec4 a, vec4 b, vec4 dest); + CGLM_INLINE void glm_vec4_minv(vec4 a, vec4 b, vec4 dest); + CGLM_INLINE void glm_vec4_clamp(vec4 v, float minVal, float maxVal); + CGLM_INLINE void glm_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest); + CGLM_INLINE void glm_vec4_lerpc(vec4 from, vec4 to, float t, vec4 dest); + CGLM_INLINE void glm_vec4_step_uni(float edge, vec4 x, vec4 dest); + CGLM_INLINE void glm_vec4_step(vec4 edge, vec4 x, vec4 dest); + CGLM_INLINE void glm_vec4_smoothstep_uni(float edge0, float edge1, vec4 x, vec4 dest); + CGLM_INLINE void glm_vec4_smoothstep(vec4 edge0, vec4 edge1, vec4 x, vec4 dest); + CGLM_INLINE void glm_vec4_smoothinterp(vec4 from, vec4 to, float t, vec4 dest); + CGLM_INLINE void glm_vec4_smoothinterpc(vec4 from, vec4 to, float t, vec4 dest); + CGLM_INLINE void glm_vec4_swizzle(vec4 v, int mask, vec4 dest); + + DEPRECATED: + glm_vec4_dup + glm_vec4_flipsign + glm_vec4_flipsign_to + glm_vec4_inv + glm_vec4_inv_to + glm_vec4_mulv + */ + +#ifndef cglm_vec4_h +#define cglm_vec4_h + +#include "common.h" +#include "vec4-ext.h" +#include "util.h" + +/* DEPRECATED! functions */ +#define glm_vec4_dup3(v, dest) glm_vec4_copy3(v, dest) +#define glm_vec4_dup(v, dest) glm_vec4_copy(v, dest) +#define glm_vec4_flipsign(v) glm_vec4_negate(v) +#define glm_vec4_flipsign_to(v, dest) glm_vec4_negate_to(v, dest) +#define glm_vec4_inv(v) glm_vec4_negate(v) +#define glm_vec4_inv_to(v, dest) glm_vec4_negate_to(v, dest) +#define glm_vec4_mulv(a, b, d) glm_vec4_mul(a, b, d) + +#define GLM_VEC4_ONE_INIT {1.0f, 1.0f, 1.0f, 1.0f} +#define GLM_VEC4_BLACK_INIT {0.0f, 0.0f, 0.0f, 1.0f} +#define GLM_VEC4_ZERO_INIT {0.0f, 0.0f, 0.0f, 0.0f} + +#define GLM_VEC4_ONE ((vec4)GLM_VEC4_ONE_INIT) +#define GLM_VEC4_BLACK ((vec4)GLM_VEC4_BLACK_INIT) +#define GLM_VEC4_ZERO ((vec4)GLM_VEC4_ZERO_INIT) + +#define GLM_XXXX GLM_SHUFFLE4(0, 0, 0, 0) +#define GLM_YYYY GLM_SHUFFLE4(1, 1, 1, 1) +#define GLM_ZZZZ GLM_SHUFFLE4(2, 2, 2, 2) +#define GLM_WWWW GLM_SHUFFLE4(3, 3, 3, 3) +#define GLM_WZYX GLM_SHUFFLE4(0, 1, 2, 3) + +/*! + * @brief init vec4 using vec3 + * + * @param[in] v3 vector3 + * @param[in] last last item + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4(vec3 v3, float last, vec4 dest) { + dest[0] = v3[0]; + dest[1] = v3[1]; + dest[2] = v3[2]; + dest[3] = last; +} + +/*! + * @brief copy first 3 members of [a] to [dest] + * + * @param[in] a source + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_copy3(vec4 a, vec3 dest) { + dest[0] = a[0]; + dest[1] = a[1]; + dest[2] = a[2]; +} + +/*! + * @brief copy all members of [a] to [dest] + * + * @param[in] v source + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_copy(vec4 v, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(dest, glmm_load(v)); +#elif defined(CGLM_NEON_FP) + vst1q_f32(dest, vld1q_f32(v)); +#else + dest[0] = v[0]; + dest[1] = v[1]; + dest[2] = v[2]; + dest[3] = v[3]; +#endif +} + +/*! + * @brief copy all members of [a] to [dest] + * + * alignment is not required + * + * @param[in] v source + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_ucopy(vec4 v, vec4 dest) { + dest[0] = v[0]; + dest[1] = v[1]; + dest[2] = v[2]; + dest[3] = v[3]; +} + +/*! + * @brief make vector zero + * + * @param[in, out] v vector + */ +CGLM_INLINE +void +glm_vec4_zero(vec4 v) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(v, _mm_setzero_ps()); +#elif defined(CGLM_NEON_FP) + vst1q_f32(v, vdupq_n_f32(0.0f)); +#else + v[0] = 0.0f; + v[1] = 0.0f; + v[2] = 0.0f; + v[3] = 0.0f; +#endif +} + +/*! + * @brief make vector one + * + * @param[in, out] v vector + */ +CGLM_INLINE +void +glm_vec4_one(vec4 v) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(v, _mm_set1_ps(1.0f)); +#elif defined(CGLM_NEON_FP) + vst1q_f32(v, vdupq_n_f32(1.0f)); +#else + v[0] = 1.0f; + v[1] = 1.0f; + v[2] = 1.0f; + v[3] = 1.0f; +#endif +} + +/*! + * @brief vec4 dot product + * + * @param[in] a vector1 + * @param[in] b vector2 + * + * @return dot product + */ +CGLM_INLINE +float +glm_vec4_dot(vec4 a, vec4 b) { +#if defined(CGLM_SIMD) + return glmm_dot(glmm_load(a), glmm_load(b)); +#else + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; +#endif +} + +/*! + * @brief norm * norm (magnitude) of vec + * + * we can use this func instead of calling norm * norm, because it would call + * sqrtf fuction twice but with this func we can avoid func call, maybe this is + * not good name for this func + * + * @param[in] v vec4 + * + * @return norm * norm + */ +CGLM_INLINE +float +glm_vec4_norm2(vec4 v) { + return glm_vec4_dot(v, v); +} + +/*! + * @brief euclidean norm (magnitude), also called L2 norm + * this will give magnitude of vector in euclidean space + * + * @param[in] v vector + * + * @return norm + */ +CGLM_INLINE +float +glm_vec4_norm(vec4 v) { +#if defined(CGLM_SIMD) + return glmm_norm(glmm_load(v)); +#else + return sqrtf(glm_vec4_dot(v, v)); +#endif +} + +/*! + * @brief L1 norm of vec4 + * Also known as Manhattan Distance or Taxicab norm. + * L1 Norm is the sum of the magnitudes of the vectors in a space. + * It is calculated as the sum of the absolute values of the vector components. + * In this norm, all the components of the vector are weighted equally. + * + * This computes: + * L1 norm = |v[0]| + |v[1]| + |v[2]| + |v[3]| + * + * @param[in] v vector + * + * @return L1 norm + */ +CGLM_INLINE +float +glm_vec4_norm_one(vec4 v) { +#if defined(CGLM_SIMD) + return glmm_norm_one(glmm_load(v)); +#else + vec4 t; + glm_vec4_abs(v, t); + return glm_vec4_hadd(t); +#endif +} + +/*! + * @brief infinity norm of vec4 + * Also known as Maximum norm. + * Infinity Norm is the largest magnitude among each element of a vector. + * It is calculated as the maximum of the absolute values of the vector components. + * + * This computes: + * inf norm = max(|v[0]|, |v[1]|, |v[2]|, |v[3]|) + * + * @param[in] v vector + * + * @return infinity norm + */ +CGLM_INLINE +float +glm_vec4_norm_inf(vec4 v) { +#if defined(CGLM_SIMD) + return glmm_norm_inf(glmm_load(v)); +#else + vec4 t; + glm_vec4_abs(v, t); + return glm_vec4_max(t); +#endif +} + +/*! + * @brief add b vector to a vector store result in dest + * + * @param[in] a vector1 + * @param[in] b vector2 + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec4_add(vec4 a, vec4 b, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(dest, _mm_add_ps(glmm_load(a), glmm_load(b))); +#elif defined(CGLM_NEON_FP) + vst1q_f32(dest, vaddq_f32(vld1q_f32(a), vld1q_f32(b))); +#else + dest[0] = a[0] + b[0]; + dest[1] = a[1] + b[1]; + dest[2] = a[2] + b[2]; + dest[3] = a[3] + b[3]; +#endif +} + +/*! + * @brief add scalar to v vector store result in dest (d = v + vec(s)) + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec4_adds(vec4 v, float s, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(dest, _mm_add_ps(glmm_load(v), _mm_set1_ps(s))); +#elif defined(CGLM_NEON_FP) + vst1q_f32(dest, vaddq_f32(vld1q_f32(v), vdupq_n_f32(s))); +#else + dest[0] = v[0] + s; + dest[1] = v[1] + s; + dest[2] = v[2] + s; + dest[3] = v[3] + s; +#endif +} + +/*! + * @brief subtract b vector from a vector store result in dest (d = a - b) + * + * @param[in] a vector1 + * @param[in] b vector2 + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec4_sub(vec4 a, vec4 b, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(dest, _mm_sub_ps(glmm_load(a), glmm_load(b))); +#elif defined(CGLM_NEON_FP) + vst1q_f32(dest, vsubq_f32(vld1q_f32(a), vld1q_f32(b))); +#else + dest[0] = a[0] - b[0]; + dest[1] = a[1] - b[1]; + dest[2] = a[2] - b[2]; + dest[3] = a[3] - b[3]; +#endif +} + +/*! + * @brief subtract scalar from v vector store result in dest (d = v - vec(s)) + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec4_subs(vec4 v, float s, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(dest, _mm_sub_ps(glmm_load(v), _mm_set1_ps(s))); +#elif defined(CGLM_NEON_FP) + vst1q_f32(dest, vsubq_f32(vld1q_f32(v), vdupq_n_f32(s))); +#else + dest[0] = v[0] - s; + dest[1] = v[1] - s; + dest[2] = v[2] - s; + dest[3] = v[3] - s; +#endif +} + +/*! + * @brief multiply two vector (component-wise multiplication) + * + * @param a vector1 + * @param b vector2 + * @param dest dest = (a[0] * b[0], a[1] * b[1], a[2] * b[2], a[3] * b[3]) + */ +CGLM_INLINE +void +glm_vec4_mul(vec4 a, vec4 b, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(dest, _mm_mul_ps(glmm_load(a), glmm_load(b))); +#elif defined(CGLM_NEON_FP) + vst1q_f32(dest, vmulq_f32(vld1q_f32(a), vld1q_f32(b))); +#else + dest[0] = a[0] * b[0]; + dest[1] = a[1] * b[1]; + dest[2] = a[2] * b[2]; + dest[3] = a[3] * b[3]; +#endif +} + +/*! + * @brief multiply/scale vec4 vector with scalar: result = v * s + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec4_scale(vec4 v, float s, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(dest, _mm_mul_ps(glmm_load(v), _mm_set1_ps(s))); +#elif defined(CGLM_NEON_FP) + vst1q_f32(dest, vmulq_f32(vld1q_f32(v), vdupq_n_f32(s))); +#else + dest[0] = v[0] * s; + dest[1] = v[1] * s; + dest[2] = v[2] * s; + dest[3] = v[3] * s; +#endif +} + +/*! + * @brief make vec4 vector scale as specified: result = unit(v) * s + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec4_scale_as(vec4 v, float s, vec4 dest) { + float norm; + norm = glm_vec4_norm(v); + + if (norm == 0.0f) { + glm_vec4_zero(dest); + return; + } + + glm_vec4_scale(v, s / norm, dest); +} + +/*! + * @brief div vector with another component-wise division: d = a / b + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest result = (a[0]/b[0], a[1]/b[1], a[2]/b[2], a[3]/b[3]) + */ +CGLM_INLINE +void +glm_vec4_div(vec4 a, vec4 b, vec4 dest) { +#if defined(CGLM_SIMD) + glmm_store(dest, glmm_div(glmm_load(a), glmm_load(b))); +#else + dest[0] = a[0] / b[0]; + dest[1] = a[1] / b[1]; + dest[2] = a[2] / b[2]; + dest[3] = a[3] / b[3]; +#endif +} + +/*! + * @brief div vec4 vector with scalar: d = v / s + * + * @param[in] v vector + * @param[in] s scalar + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec4_divs(vec4 v, float s, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(dest, _mm_div_ps(glmm_load(v), _mm_set1_ps(s))); +#else + glm_vec4_scale(v, 1.0f / s, dest); +#endif +} + +/*! + * @brief add two vectors and add result to sum + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest dest += (a + b) + */ +CGLM_INLINE +void +glm_vec4_addadd(vec4 a, vec4 b, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(dest, _mm_add_ps(glmm_load(dest), + _mm_add_ps(glmm_load(a), + glmm_load(b)))); +#elif defined(CGLM_NEON_FP) + vst1q_f32(dest, vaddq_f32(vld1q_f32(dest), + vaddq_f32(vld1q_f32(a), + vld1q_f32(b)))); +#else + dest[0] += a[0] + b[0]; + dest[1] += a[1] + b[1]; + dest[2] += a[2] + b[2]; + dest[3] += a[3] + b[3]; +#endif +} + +/*! + * @brief sub two vectors and add result to dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest dest += (a - b) + */ +CGLM_INLINE +void +glm_vec4_subadd(vec4 a, vec4 b, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(dest, _mm_add_ps(glmm_load(dest), + _mm_sub_ps(glmm_load(a), + glmm_load(b)))); +#elif defined(CGLM_NEON_FP) + vst1q_f32(dest, vaddq_f32(vld1q_f32(dest), + vsubq_f32(vld1q_f32(a), + vld1q_f32(b)))); +#else + dest[0] += a[0] - b[0]; + dest[1] += a[1] - b[1]; + dest[2] += a[2] - b[2]; + dest[3] += a[3] - b[3]; +#endif +} + +/*! + * @brief mul two vectors and add result to dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest dest += (a * b) + */ +CGLM_INLINE +void +glm_vec4_muladd(vec4 a, vec4 b, vec4 dest) { +#if defined(CGLM_SIMD) + glmm_store(dest, glmm_fmadd(glmm_load(a), glmm_load(b), glmm_load(dest))); +#else + dest[0] += a[0] * b[0]; + dest[1] += a[1] * b[1]; + dest[2] += a[2] * b[2]; + dest[3] += a[3] * b[3]; +#endif +} + +/*! + * @brief mul vector with scalar and add result to sum + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector + * @param[in] s scalar + * @param[out] dest dest += (a * b) + */ +CGLM_INLINE +void +glm_vec4_muladds(vec4 a, float s, vec4 dest) { +#if defined(CGLM_SIMD) + glmm_store(dest, glmm_fmadd(glmm_load(a), glmm_set1(s), glmm_load(dest))); +#else + dest[0] += a[0] * s; + dest[1] += a[1] * s; + dest[2] += a[2] * s; + dest[3] += a[3] * s; +#endif +} + +/*! + * @brief add max of two vector to result/dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest dest += max(a, b) + */ +CGLM_INLINE +void +glm_vec4_maxadd(vec4 a, vec4 b, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(dest, _mm_add_ps(glmm_load(dest), + _mm_max_ps(glmm_load(a), + glmm_load(b)))); +#elif defined(CGLM_NEON_FP) + vst1q_f32(dest, vaddq_f32(vld1q_f32(dest), + vmaxq_f32(vld1q_f32(a), + vld1q_f32(b)))); +#else + dest[0] += glm_max(a[0], b[0]); + dest[1] += glm_max(a[1], b[1]); + dest[2] += glm_max(a[2], b[2]); + dest[3] += glm_max(a[3], b[3]); +#endif +} + +/*! + * @brief add min of two vector to result/dest + * + * it applies += operator so dest must be initialized + * + * @param[in] a vector 1 + * @param[in] b vector 2 + * @param[out] dest dest += min(a, b) + */ +CGLM_INLINE +void +glm_vec4_minadd(vec4 a, vec4 b, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(dest, _mm_add_ps(glmm_load(dest), + _mm_min_ps(glmm_load(a), + glmm_load(b)))); +#elif defined(CGLM_NEON_FP) + vst1q_f32(dest, vaddq_f32(vld1q_f32(dest), + vminq_f32(vld1q_f32(a), + vld1q_f32(b)))); +#else + dest[0] += glm_min(a[0], b[0]); + dest[1] += glm_min(a[1], b[1]); + dest[2] += glm_min(a[2], b[2]); + dest[3] += glm_min(a[3], b[3]); +#endif +} + +/*! + * @brief negate vector components and store result in dest + * + * @param[in] v vector + * @param[out] dest result vector + */ +CGLM_INLINE +void +glm_vec4_negate_to(vec4 v, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(dest, _mm_xor_ps(glmm_load(v), _mm_set1_ps(-0.0f))); +#elif defined(CGLM_NEON_FP) + vst1q_f32(dest, vnegq_f32(vld1q_f32(v))); +#else + dest[0] = -v[0]; + dest[1] = -v[1]; + dest[2] = -v[2]; + dest[3] = -v[3]; +#endif +} + +/*! + * @brief flip sign of all vec4 members + * + * @param[in, out] v vector + */ +CGLM_INLINE +void +glm_vec4_negate(vec4 v) { + glm_vec4_negate_to(v, v); +} + +/*! + * @brief normalize vec4 to dest + * + * @param[in] v source + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_normalize_to(vec4 v, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + __m128 xdot, x0; + float dot; + + x0 = glmm_load(v); + xdot = glmm_vdot(x0, x0); + dot = _mm_cvtss_f32(xdot); + + if (dot == 0.0f) { + glmm_store(dest, _mm_setzero_ps()); + return; + } + + glmm_store(dest, _mm_div_ps(x0, _mm_sqrt_ps(xdot))); +#else + float norm; + + norm = glm_vec4_norm(v); + + if (norm == 0.0f) { + glm_vec4_zero(dest); + return; + } + + glm_vec4_scale(v, 1.0f / norm, dest); +#endif +} + +/*! + * @brief normalize vec4 and store result in same vec + * + * @param[in, out] v vector + */ +CGLM_INLINE +void +glm_vec4_normalize(vec4 v) { + glm_vec4_normalize_to(v, v); +} + +/** + * @brief distance between two vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @return returns distance + */ +CGLM_INLINE +float +glm_vec4_distance(vec4 a, vec4 b) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + return glmm_norm(_mm_sub_ps(glmm_load(a), glmm_load(b))); +#elif defined(CGLM_NEON_FP) + return glmm_norm(vsubq_f32(glmm_load(a), glmm_load(b))); +#else + return sqrtf(glm_pow2(a[0] - b[0]) + + glm_pow2(a[1] - b[1]) + + glm_pow2(a[2] - b[2]) + + glm_pow2(a[3] - b[3])); +#endif +} + +/** + * @brief squared distance between two vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @return returns squared distance + */ +CGLM_INLINE +float +glm_vec4_distance2(vec4 a, vec4 b) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + return glmm_norm2(_mm_sub_ps(glmm_load(a), glmm_load(b))); +#elif defined(CGLM_NEON_FP) + return glmm_norm2(vsubq_f32(glmm_load(a), glmm_load(b))); +#else + return glm_pow2(a[0] - b[0]) + + glm_pow2(a[1] - b[1]) + + glm_pow2(a[2] - b[2]) + + glm_pow2(a[3] - b[3]); +#endif +} + +/*! + * @brief max values of vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_maxv(vec4 a, vec4 b, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(dest, _mm_max_ps(glmm_load(a), glmm_load(b))); +#elif defined(CGLM_NEON_FP) + vst1q_f32(dest, vmaxq_f32(vld1q_f32(a), vld1q_f32(b))); +#else + dest[0] = glm_max(a[0], b[0]); + dest[1] = glm_max(a[1], b[1]); + dest[2] = glm_max(a[2], b[2]); + dest[3] = glm_max(a[3], b[3]); +#endif +} + +/*! + * @brief min values of vectors + * + * @param[in] a vector1 + * @param[in] b vector2 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_minv(vec4 a, vec4 b, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(dest, _mm_min_ps(glmm_load(a), glmm_load(b))); +#elif defined(CGLM_NEON_FP) + vst1q_f32(dest, vminq_f32(vld1q_f32(a), vld1q_f32(b))); +#else + dest[0] = glm_min(a[0], b[0]); + dest[1] = glm_min(a[1], b[1]); + dest[2] = glm_min(a[2], b[2]); + dest[3] = glm_min(a[3], b[3]); +#endif +} + +/*! + * @brief clamp vector's individual members between min and max values + * + * @param[in, out] v vector + * @param[in] minVal minimum value + * @param[in] maxVal maximum value + */ +CGLM_INLINE +void +glm_vec4_clamp(vec4 v, float minVal, float maxVal) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glmm_store(v, _mm_min_ps(_mm_max_ps(glmm_load(v), _mm_set1_ps(minVal)), + _mm_set1_ps(maxVal))); +#elif defined(CGLM_NEON_FP) + vst1q_f32(v, vminq_f32(vmaxq_f32(vld1q_f32(v), vdupq_n_f32(minVal)), + vdupq_n_f32(maxVal))); +#else + v[0] = glm_clamp(v[0], minVal, maxVal); + v[1] = glm_clamp(v[1], minVal, maxVal); + v[2] = glm_clamp(v[2], minVal, maxVal); + v[3] = glm_clamp(v[3], minVal, maxVal); +#endif +} + +/*! + * @brief linear interpolation between two vectors + * + * formula: from + t * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest) { + vec4 s, v; + + /* from + s * (to - from) */ + glm_vec4_broadcast(t, s); + glm_vec4_sub(to, from, v); + glm_vec4_mul(s, v, v); + glm_vec4_add(from, v, dest); +} + +/*! + * @brief linear interpolation between two vectors (clamped) + * + * formula: from + t * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) clamped between 0 and 1 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_lerpc(vec4 from, vec4 to, float t, vec4 dest) { + glm_vec4_lerp(from, to, glm_clamp_zo(t), dest); +} + +/*! + * @brief linear interpolation between two vectors + * + * formula: from + t * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_mix(vec4 from, vec4 to, float t, vec4 dest) { + glm_vec4_lerp(from, to, t, dest); +} + +/*! + * @brief linear interpolation between two vectors (clamped) + * + * formula: from + t * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) clamped between 0 and 1 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_mixc(vec4 from, vec4 to, float t, vec4 dest) { + glm_vec4_lerpc(from, to, t, dest); +} + +/*! + * @brief threshold function (unidimensional) + * + * @param[in] edge threshold + * @param[in] x value to test against threshold + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_step_uni(float edge, vec4 x, vec4 dest) { + dest[0] = glm_step(edge, x[0]); + dest[1] = glm_step(edge, x[1]); + dest[2] = glm_step(edge, x[2]); + dest[3] = glm_step(edge, x[3]); +} + +/*! + * @brief threshold function + * + * @param[in] edge threshold + * @param[in] x value to test against threshold + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_step(vec4 edge, vec4 x, vec4 dest) { + dest[0] = glm_step(edge[0], x[0]); + dest[1] = glm_step(edge[1], x[1]); + dest[2] = glm_step(edge[2], x[2]); + dest[3] = glm_step(edge[3], x[3]); +} + +/*! + * @brief threshold function with a smooth transition (unidimensional) + * + * @param[in] edge0 low threshold + * @param[in] edge1 high threshold + * @param[in] x value to test against threshold + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_smoothstep_uni(float edge0, float edge1, vec4 x, vec4 dest) { + dest[0] = glm_smoothstep(edge0, edge1, x[0]); + dest[1] = glm_smoothstep(edge0, edge1, x[1]); + dest[2] = glm_smoothstep(edge0, edge1, x[2]); + dest[3] = glm_smoothstep(edge0, edge1, x[3]); +} + +/*! + * @brief threshold function with a smooth transition + * + * @param[in] edge0 low threshold + * @param[in] edge1 high threshold + * @param[in] x value to test against threshold + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_smoothstep(vec4 edge0, vec4 edge1, vec4 x, vec4 dest) { + dest[0] = glm_smoothstep(edge0[0], edge1[0], x[0]); + dest[1] = glm_smoothstep(edge0[1], edge1[1], x[1]); + dest[2] = glm_smoothstep(edge0[2], edge1[2], x[2]); + dest[3] = glm_smoothstep(edge0[3], edge1[3], x[3]); +} + +/*! + * @brief smooth Hermite interpolation between two vectors + * + * formula: t^2 * (3 - 2*t) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_smoothinterp(vec4 from, vec4 to, float t, vec4 dest) { + vec4 s, v; + + /* from + smoothstep * (to - from) */ + glm_vec4_broadcast(glm_smooth(t), s); + glm_vec4_sub(to, from, v); + glm_vec4_mul(s, v, v); + glm_vec4_add(from, v, dest); +} + +/*! + * @brief smooth Hermite interpolation between two vectors (clamped) + * + * formula: t^2 * (3 - 2*t) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) clamped between 0 and 1 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_smoothinterpc(vec4 from, vec4 to, float t, vec4 dest) { + glm_vec4_smoothinterp(from, to, glm_clamp_zo(t), dest); +} + +/*! + * @brief helper to fill vec4 as [S^3, S^2, S, 1] + * + * @param[in] s parameter + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_cubic(float s, vec4 dest) { + float ss; + + ss = s * s; + + dest[0] = ss * s; + dest[1] = ss; + dest[2] = s; + dest[3] = 1.0f; +} + +/*! + * @brief swizzle vector components + * + * you can use existin masks e.g. GLM_XXXX, GLM_WZYX + * + * @param[in] v source + * @param[in] mask mask + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_swizzle(vec4 v, int mask, vec4 dest) { + vec4 t; + + t[0] = v[(mask & (3 << 0))]; + t[1] = v[(mask & (3 << 2)) >> 2]; + t[2] = v[(mask & (3 << 4)) >> 4]; + t[3] = v[(mask & (3 << 6)) >> 6]; + + glm_vec4_copy(t, dest); +} + +#endif /* cglm_vec4_h */ diff --git a/include/cglm/version.h b/include/cglm/version.h new file mode 100644 index 0000000..5ad6e53 --- /dev/null +++ b/include/cglm/version.h @@ -0,0 +1,15 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_version_h +#define cglm_version_h + +#define CGLM_VERSION_MAJOR 0 +#define CGLM_VERSION_MINOR 8 +#define CGLM_VERSION_PATCH 9 + +#endif /* cglm_version_h */ diff --git a/src/GAME.h b/src/GAME.h new file mode 100644 index 0000000..04290ef --- /dev/null +++ b/src/GAME.h @@ -0,0 +1,90 @@ +/* + * DESCRIPTION: + * Global variable and constants. +*/ + +#pragma once + +#include "engine/event.h" +#include "engine/font.h" +#include "engine/io.h" +#include "engine/glyph.h" +#include "engine/keyboard.h" +#include "engine/mouse.h" +#include "engine/music.h" +#include "engine/renderer.h" +#include "engine/sound.h" +#include "engine/tick.h" +#include "engine/window.h" + +#include "game/ecs/ECS_TYPES.h" +#include "game/state/STATE_TYPES.h" + +#define TEXTURE_COUNT TEXTURE_LOGO + 1 +enum TextureType +{ + TEXTURE_PLAYER, + TEXTURE_FOLLOWER, + TEXTURE_ENEMY, + TEXTURE_PARTICLE, + TEXTURE_WARNING, + TEXTURE_LOGO +}; + +#define SOUND_COUNT SOUND_SELECT + 1 +enum SoundType +{ + SOUND_COLLIDE, + SOUND_HURT, + SOUND_LEVEL, + SOUND_WARNING, + SOUND_HOVER, + SOUND_SELECT +}; + +#define MUSIC_COUNT MUSIC_ETHNICA + 1 +enum MusicType +{ + MUSIC_ETHNICA +}; + +#define SHADER_COUNT SHADER_TEXTURE_QUAD + 1 +enum ShaderType +{ + SHADER_TEXTURE_QUAD +}; + +#define FONT_COUNT FONT_BIG + 1 +enum FontType +{ + FONT_SMALL, + FONT_BIG +}; + +struct Game +{ + enum StateType state; + struct Camera camera; + struct ECS ecs; + struct Event event; + struct Keyboard keyboard; + struct Mouse mouse; + struct Renderer renderer; + struct Sound sounds[SOUND_COUNT]; + struct Texture textures[TEXTURE_COUNT]; + struct Music music[MUSIC_COUNT]; + struct Shader shaders[SHADER_COUNT]; + struct Font fonts[FONT_COUNT]; + struct Tick tick; + struct Window window; + struct Play play; + struct Menu menu; + struct Results results; + u32 score; + vec4 bounds; + bool isQuit; + bool isPaused; + bool isMute; +}; + +extern struct Game game; diff --git a/src/engine/atlas.c b/src/engine/atlas.c new file mode 100644 index 0000000..e4007a0 --- /dev/null +++ b/src/engine/atlas.c @@ -0,0 +1,36 @@ +/* + * DESCRIPTION: + * Texture atlas functions. +*/ + +#include "atlas.h" + +/* Initializes an atlas. */ +void +atlas_init(struct Atlas* self, struct Texture texture, s32 frameW, s32 frameH, s32 rows, s32 cols) +{ + self->texture = texture; + self->frameW = frameW; + self->frameH = frameH; + self->rows = rows; + self->cols = cols; + + self->index = 0; +} + +/* Obtains the texture coordinates for an atlas frame. */ +void +atlas_uv_get(struct Atlas* self, vec2 uvMin, vec2 uvMax) +{ + vec2 pos; + s32 col; + s32 row; + + pos[0] = (f32)(self->index / self->rows) * self->frameW; + pos[1] = (f32)(self->index % self->rows) * self->frameH; + + uvMin[0] = (f32)pos[0] / self->texture.w; + uvMin[1] = (f32)pos[1] / self->texture.h; + uvMax[0] = (f32)(pos[0] + self->frameW) / self->texture.w; + uvMax[1] = (f32)(pos[1] + self->frameH) / self->texture.h; +} diff --git a/src/engine/atlas.h b/src/engine/atlas.h new file mode 100644 index 0000000..702fe51 --- /dev/null +++ b/src/engine/atlas.h @@ -0,0 +1,19 @@ +/* + * DESCRIPTION: + * atlas.c header. +*/ + +#include "texture.h" + +struct Atlas +{ + struct Texture texture; + s32 frameW; + s32 frameH; + s32 rows; + s32 cols; + s32 index; +}; + +void atlas_init(struct Atlas* atlas, struct Texture texture, s32 frameW, s32 frameH, s32 rows, s32 cols); +void atlas_uv_get(struct Atlas* atlas, vec2 uvMin, vec2 uvMax); diff --git a/src/engine/camera.c b/src/engine/camera.c new file mode 100644 index 0000000..176d779 --- /dev/null +++ b/src/engine/camera.c @@ -0,0 +1,146 @@ +/* + * DESCRIPTION: + * Camera code. +*/ + +#include "camera.h" + +/* Initialize perspective camera. */ +void +camera_perspective_init(struct Camera* self, f32 fov, f32 aspect) +{ + memset(self, '\0', sizeof(struct Camera)); + + self->type = CAMERA_PERSPECTIVE; + + self->fov = fov; + self->yaw = CAMERA_PERSPECTIVE_YAW_DEFAULT; + self->pitch = 0; + + self->aspect = aspect; + + camera_update(self); +} + +/* Initialize orthographic camera. */ +void +camera_orthographic_init(struct Camera* self, vec2 size) +{ + memset(self, '\0', sizeof(struct Camera)); + + self->type = CAMERA_ORTHOGRAPHIC; + glm_vec2_copy(size, self->size); + + camera_update(self); +} + +/* Returns view matrix of camera. */ +void +camera_view_set(struct Camera* self) +{ + vec3 positionFront; + + glm_mat4_identity(self->view); + + switch (self->type) + { + case CAMERA_PERSPECTIVE: + glm_vec3_add(self->position, self->front, positionFront); + glm_lookat(self->position, positionFront, self->up, self->view); + break; + case CAMERA_ORTHOGRAPHIC: + glm_mat4_identity(self->view); + break; + default: + break; + } +} + +/* Gets projection of camera. */ +void +camera_projection_set(struct Camera* self) +{ + glm_mat4_identity(self->projection); + + switch (self->type) + { + case CAMERA_PERSPECTIVE: + glm_perspective + ( + self->fov, + self->aspect, + CAMERA_PERSPECTIVE_NEAR, + CAMERA_PERSPECTIVE_FAR, + self->projection + ); + break; + case CAMERA_ORTHOGRAPHIC: + glm_ortho + ( + 0.0f, + self->size[0], + self->size[1], + 0.0f, + CAMERA_ORTHOGRAPHIC_NEAR, + CAMERA_ORTHOGRAPHIC_FAR, + self->projection + ); + break; + default: + break; + } +} + +/* Sets the camera to a position. */ +void +camera_position_set(struct Camera* self, vec3 position) +{ + glm_vec3_copy(position, self->position); +} + +/* Sets camera's vectors. */ +void +camera_vector_set(struct Camera* self) +{ + vec3 worldUp = {0.0f, 1.0f, 0.0f}; + + switch (self->type) + { + case CAMERA_PERSPECTIVE: + + self->front[0] = cos(self->yaw) * cos(self->pitch); + self->front[1] = sin(self->pitch); + self->front[2] = sin(self->yaw) * cos(self->pitch); + glm_vec3_normalize(self->front); + glm_vec3_crossn(self->front, worldUp, self->right); + glm_vec3_crossn(self->right, self->front, self->up); + break; + case CAMERA_ORTHOGRAPHIC: + break; + default: + break; + } +} + +/* Sets an orthographic camera's size. */ +void +camera_orthographic_size_set(struct Camera* self, vec2 size) +{ + glm_vec2_copy(size, self->size); +} + +/* Sets an orthographic camera's size to a window's. */ +void +camera_orthographic_window_set(struct Camera* self, struct Window* window) +{ + camera_orthographic_size_set(self, window->size); +} + +/* Updates camera. */ +void +camera_update(struct Camera* self) +{ + camera_vector_set(self); + camera_view_set(self); + camera_projection_set(self); +} diff --git a/src/engine/camera.h b/src/engine/camera.h new file mode 100644 index 0000000..75b4cc4 --- /dev/null +++ b/src/engine/camera.h @@ -0,0 +1,49 @@ +/* + * DESCRIPTION: + * camera.c header. +*/ + +#pragma once + +#include +#include + +#include "window.h" + +#define CAMERA_ORTHOGRAPHIC_FAR -1.0f +#define CAMERA_ORTHOGRAPHIC_NEAR 1.0f +#define CAMERA_PERSPECTIVE_FAR 100.0f +#define CAMERA_PERSPECTIVE_NEAR 0.1f +#define CAMERA_PERSPECTIVE_YAW_DEFAULT (-M_PI / 2) + +enum CameraType +{ + CAMERA_PERSPECTIVE, + CAMERA_ORTHOGRAPHIC +}; + +struct Camera +{ + enum CameraType type; + vec3 position; + f32 aspect; + f32 fov; + vec2 size; + vec3 front; + vec3 up; + vec3 right; + f32 yaw; + f32 pitch; + mat4 view; + mat4 projection; +}; + +void camera_perspective_init(struct Camera* self, f32 fov, f32 aspect); +void camera_orthographic_init(struct Camera* self, vec2 size); +void camera_orthographic_size_set(struct Camera* self, vec2 size); +void camera_orthographic_window_set(struct Camera* self, struct Window* window); +void camera_position_set(struct Camera* self, vec3 position); +void camera_projection_set(struct Camera* self); +void camera_view_set(struct Camera* self); +void camera_vector_set(struct Camera* self); +void camera_update(struct Camera* self); diff --git a/src/engine/event.c b/src/engine/event.c new file mode 100644 index 0000000..6813d50 --- /dev/null +++ b/src/engine/event.c @@ -0,0 +1,65 @@ +/* + * DESCRIPTION: + * Event handling. +*/ + +#include "event.h" + +/* Updates events. */ +void +event_update(struct Event* self) +{ + SDL_Event event; + + self->isWindowLeft = false; + self->isWindowResized = false; + + memcpy(&self->prev, &self->curr, sizeof(bool) * EVENT_COUNT); + memset(&self->curr, '\0', sizeof(bool) * EVENT_COUNT); + + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_WINDOWEVENT: + switch (event.window.event) + { + case SDL_WINDOWEVENT_LEAVE: + self->isWindowLeft = true; + break; + case SDL_WINDOWEVENT_RESIZED: + case SDL_WINDOWEVENT_SIZE_CHANGED: + self->isWindowResized = true; + default: + break; + } + break; + case SDL_QUIT: + self->curr[EVENT_QUIT] = true; + break; + default: + break; + } + } +} + +/* Is a given event pressed? */ +bool +event_press(struct Event* self, enum EventType type) +{ + return (self->curr[type] && !self->prev[type]); +} + +/* Is a given event held? */ +bool +event_held(struct Event* self, enum EventType type) +{ + return (self->curr[type] && self->prev[type]); +} + +/* Is a given event released? */ +bool +event_release(struct Event* self, enum EventType type) +{ + return (!self->curr[type] && self->prev[type]); +} diff --git a/src/engine/event.h b/src/engine/event.h new file mode 100644 index 0000000..65bd44b --- /dev/null +++ b/src/engine/event.h @@ -0,0 +1,29 @@ +/* + * DESCRIPTION: + * event.c header. +*/ + +#pragma once + +#include + +#include "../util/UTIL.h" + +#define EVENT_COUNT EVENT_QUIT + 1 +enum EventType +{ + EVENT_QUIT +}; + +struct Event +{ + bool isWindowLeft; + bool isWindowResized; + bool curr[EVENT_COUNT]; + bool prev[EVENT_COUNT]; +}; + +void event_update(struct Event* self); +bool event_press(struct Event* self, enum EventType type); +bool event_held(struct Event* self, enum EventType type); +bool event_release(struct Event* self, enum EventType type); diff --git a/src/engine/font.c b/src/engine/font.c new file mode 100644 index 0000000..d6901f4 --- /dev/null +++ b/src/engine/font.c @@ -0,0 +1,46 @@ +/* + * DESCRIPTION: + * TrueType font functions. +*/ + +#include "font.h" + +/* Returns line skip of font. */ +s32 +font_line_skip_get(struct Font* self) +{ + return TTF_FontLineSkip(self->ttf); +} + +/* Returns height of font. */ +s32 +font_height_get(struct Font* self) +{ + return TTF_FontHeight(self->ttf); +} + +/* Inits a font. */ +bool +font_init(struct Font* self, char* path, s32 size) +{ + self->ttf = TTF_OpenFont(path, size); + + if (!self->ttf) + return false; + + self->size = size; + self->isInit = true; + + return true; +} + +/* Frees a font. */ +void +font_free(struct Font* self) +{ + if (self->isInit) + { + TTF_CloseFont(self->ttf); + self->isInit = false; + } +} diff --git a/src/engine/font.h b/src/engine/font.h new file mode 100644 index 0000000..2a5ddd9 --- /dev/null +++ b/src/engine/font.h @@ -0,0 +1,22 @@ +/* + * DESCRIPTION: + * font.c header. +*/ + +#pragma once + +#include "../util/UTIL.h" + +#include + +struct Font +{ + TTF_Font* ttf; + s32 size; + bool isInit; +}; + +s32 font_height_get(struct Font* self); +s32 font_line_skip_get(struct Font* self); +bool font_init(struct Font* self, char* path, s32 size); +void font_free(struct Font* self); diff --git a/src/engine/glew.c b/src/engine/glew.c new file mode 100644 index 0000000..4b630ca --- /dev/null +++ b/src/engine/glew.c @@ -0,0 +1,13 @@ +/* + * DESCRIPTION: + * GLEW functions. +*/ + +#include "glew.h" + +/* Inits GLEW. */ +void +glew_init(void) +{ + glewInit(); +} diff --git a/src/engine/glew.h b/src/engine/glew.h new file mode 100644 index 0000000..b529fc0 --- /dev/null +++ b/src/engine/glew.h @@ -0,0 +1,10 @@ +/* + * DESCRIPTION: + * glew.c header. +*/ + +#pragma once + +#include + +void glew_init(void); diff --git a/src/engine/glyph.c b/src/engine/glyph.c new file mode 100644 index 0000000..ff1ca94 --- /dev/null +++ b/src/engine/glyph.c @@ -0,0 +1,67 @@ +/* + * DESCRIPTION: + * Glyph functions. +*/ + +#include "glyph.h" + +/* Returns width of glyph. */ +s32 +glyph_width_get(struct Font* font, char glyph) +{ + struct GlyphMetrics glyphMetrics; + + glyph_metrics_get(&glyphMetrics, font, glyph); + + return glyphMetrics.maxX - glyphMetrics.minX; +} + +/* Determines the kerning between two glyphs. */ +s32 +glyph_kerning_get(struct Font* font, char glyph, char nextGlyph) +{ + return TTF_GetFontKerningSizeGlyphs(font->ttf, glyph, nextGlyph); +} + +/* Obtains glyph metrics, given a glyph and a font. */ +void +glyph_metrics_get(struct GlyphMetrics* self, struct Font* font, char glyph) +{ + TTF_GlyphMetrics + ( + font->ttf, + glyph, + &self->minX, + &self->maxX, + &self->minY, + &self->maxY, + &self->advance + ); +} + +/* Creates a texture from a glyph. */ +bool +glyph_texture_init(struct Texture* texture, struct Font* font, char glyph) +{ + struct SDL_Surface* surface; + struct SDL_Surface* textSurface; + ivec2 size; + + size[0] = glyph_width_get(font, glyph); + size[1] = font_height_get(font); + + surface_rgba_init(&surface, size); + + textSurface = TTF_RenderGlyph_Blended(font->ttf, glyph, GLYPH_COLOR); + + SDL_BlitSurface(textSurface, NULL, surface, NULL); + + SDL_FreeSurface(textSurface); + + texture_surface_init(texture, surface); + + SDL_FreeSurface(surface); + + return true; +} + diff --git a/src/engine/glyph.h b/src/engine/glyph.h new file mode 100644 index 0000000..7b99d84 --- /dev/null +++ b/src/engine/glyph.h @@ -0,0 +1,26 @@ +/* + * DESCRIPTION: + * text.c header. +*/ + +#pragma once + +#include "font.h" +#include "texture.h" +#include "surface.h" + +struct GlyphMetrics +{ + s32 minX; + s32 minY; + s32 maxX; + s32 maxY; + s32 advance; +}; + +static const SDL_Color GLYPH_COLOR = {255, 255, 255, 255}; + +s32 glyph_width_get(struct Font* font, char glyph); +s32 glyph_kerning_get(struct Font* font, char glyph, char nextGlyph); +bool glyph_texture_init(struct Texture* texture, struct Font* font, char glyph); +void glyph_metrics_get(struct GlyphMetrics* self, struct Font* font, char glyph); diff --git a/src/engine/io.c b/src/engine/io.c new file mode 100644 index 0000000..37a25e1 --- /dev/null +++ b/src/engine/io.c @@ -0,0 +1,46 @@ +/* + * DESCRIPTION: + * File writing/reading. +*/ + +#include "io.h" + +/* Opens a file for reading. */ +bool +file_read(char* path, char* buffer, size_t size) +{ + SDL_RWops* io; + + if (!path || !buffer) + return false; + + io = SDL_RWFromFile(path, "r"); + + if (!io) + return false; + + SDL_RWread(io, buffer, size, 1); + + SDL_RWclose(io); + + return true; +} + +/* Writes data to a file. */ +bool +file_write(char* path, void* data, size_t size) +{ + SDL_RWops* io; + + if (!path || !data) + return false; + + io = SDL_RWFromFile(path, "w"); + + if (!io) + return false; + + SDL_RWwrite(io, data, size, 1); + + return true; +} diff --git a/src/engine/io.h b/src/engine/io.h new file mode 100644 index 0000000..66a2d62 --- /dev/null +++ b/src/engine/io.h @@ -0,0 +1,13 @@ +/* + * DESCRIPTION: + * io.c header. +*/ + +#pragma once + +#include "../util/UTIL.h" + +#include + +bool file_read(char* path, char* buffer, size_t size); +bool file_write(char* path, void* data, size_t size); diff --git a/src/engine/keyboard.c b/src/engine/keyboard.c new file mode 100644 index 0000000..c73baba --- /dev/null +++ b/src/engine/keyboard.c @@ -0,0 +1,36 @@ +#include "keyboard.h" + +/* Updates the keyboard. */ +void +keyboard_update(struct Keyboard* self) +{ + const u8* state; + + memcpy(&self->prev, &self->curr, sizeof(u8) * KEY_COUNT); + memset(&self->curr, '\0', sizeof(u8) * KEY_COUNT); + + state = SDL_GetKeyboardState(NULL); + + memcpy(&self->curr, state, KEY_COUNT); +} + +/* Is the given key pressed? */ +bool +keyboard_press(struct Keyboard* self, enum KeyType type) +{ + return (self->curr[type] && !self->prev[type]); +} + +/* Is the given key held? */ +bool +keyboard_held(struct Keyboard* self, enum KeyType type) +{ + return (self->curr[type] && self->prev[type]); +} + +/* Is the given key released? */ +bool +keyboard_release(struct Keyboard* self, enum KeyType type) +{ + return (!self->curr[type] && self->prev[type]); +} diff --git a/src/engine/keyboard.h b/src/engine/keyboard.h new file mode 100644 index 0000000..a4849a1 --- /dev/null +++ b/src/engine/keyboard.h @@ -0,0 +1,245 @@ +/* + * DESCRIPTION: + * keyboard.c header. +*/ + +#pragma once + +#include + +#include "../util/UTIL.h" + +#define KEY_COUNT 255 +enum KeyType +{ + KEYBOARD_UNKNOWN = 0, + KEYBOARD_UNKNOWN_TWO = 1, + KEYBOARD_UNKNOWN_THREE = 2, + KEYBOARD_UNKNOWN_FOUR = 3, + KEYBOARD_A = 4, + KEYBOARD_B = 5, + KEYBOARD_C = 6, + KEYBOARD_D = 7, + KEYBOARD_E = 8, + KEYBOARD_F = 9, + KEYBOARD_G = 10, + KEYBOARD_H = 11, + KEYBOARD_I = 12, + KEYBOARD_J = 13, + KEYBOARD_K = 14, + KEYBOARD_L = 15, + KEYBOARD_M = 16, + KEYBOARD_N = 17, + KEYBOARD_O = 18, + KEYBOARD_P = 19, + KEYBOARD_Q = 20, + KEYBOARD_R = 21, + KEYBOARD_S = 22, + KEYBOARD_T = 23, + KEYBOARD_U = 24, + KEYBOARD_V = 25, + KEYBOARD_W = 26, + KEYBOARD_X = 27, + KEYBOARD_Y = 28, + KEYBOARD_Z = 29, + KEYBOARD_1 = 30, + KEYBOARD_2 = 31, + KEYBOARD_3 = 32, + KEYBOARD_4 = 33, + KEYBOARD_5 = 34, + KEYBOARD_6 = 35, + KEYBOARD_7 = 36, + KEYBOARD_8 = 37, + KEYBOARD_9 = 38, + KEYBOARD_0 = 39, + KEYBOARD_RETURN = 40, + KEYBOARD_ESCAPE = 41, + KEYBOARD_BACKSPACE = 42, + KEYBOARD_TAB = 43, + KEYBOARD_SPACE = 44, + KEYBOARD_MINUS = 45, + KEYBOARD_EQUALS = 46, + KEYBOARD_LEFTBRACKET = 47, + KEYBOARD_RIGHTBRACKET = 48, + KEYBOARD_BACKSLASH = 49, + KEYBOARD_NONUSHASH = 50, + KEYBOARD_SEMICOLON = 51, + KEYBOARD_APOSTROPHE = 52, + KEYBOARD_GRAVE = 53, + KEYBOARD_COMMA = 54, + KEYBOARD_PERIOD = 55, + KEYBOARD_SLASH = 56, + KEYBOARD_CAPSLOCK = 57, + KEYBOARD_F1 = 58, + KEYBOARD_F2 = 59, + KEYBOARD_F3 = 60, + KEYBOARD_F4 = 61, + KEYBOARD_F5 = 62, + KEYBOARD_F6 = 63, + KEYBOARD_F7 = 64, + KEYBOARD_F8 = 65, + KEYBOARD_F9 = 66, + KEYBOARD_F10 = 67, + KEYBOARD_F11 = 68, + KEYBOARD_F12 = 69, + KEYBOARD_PRINTSCREEN = 70, + KEYBOARD_SCROLLLOCK = 71, + KEYBOARD_PAUSE = 72, + KEYBOARD_INSERT = 73, + KEYBOARD_HOME = 74, + KEYBOARD_PAGEUP = 75, + KEYBOARD_DELETE = 76, + KEYBOARD_END = 77, + KEYBOARD_PAGEDOWN = 78, + KEYBOARD_RIGHT = 79, + KEYBOARD_LEFT = 80, + KEYBOARD_DOWN = 81, + KEYBOARD_UP = 82, + KEYBOARD_NUMLOCKCLEAR = 83, + KEYBOARD_KP_DIVIDE = 84, + KEYBOARD_KP_MULTIPLY = 85, + KEYBOARD_KP_MINUS = 86, + KEYBOARD_KP_PLUS = 87, + KEYBOARD_KP_ENTER = 88, + KEYBOARD_KP_1 = 89, + KEYBOARD_KP_2 = 90, + KEYBOARD_KP_3 = 91, + KEYBOARD_KP_4 = 92, + KEYBOARD_KP_5 = 93, + KEYBOARD_KP_6 = 94, + KEYBOARD_KP_7 = 95, + KEYBOARD_KP_8 = 96, + KEYBOARD_KP_9 = 97, + KEYBOARD_KP_0 = 98, + KEYBOARD_KP_PERIOD = 99, + KEYBOARD_NONUSBACKSLASH = 100, + KEYBOARD_APPLICATION = 101, + KEYBOARD_POWER = 102, + KEYBOARD_KP_EQUALS = 103, + KEYBOARD_F13 = 104, + KEYBOARD_F14 = 105, + KEYBOARD_F15 = 106, + KEYBOARD_F16 = 107, + KEYBOARD_F17 = 108, + KEYBOARD_F18 = 109, + KEYBOARD_F19 = 110, + KEYBOARD_F20 = 111, + KEYBOARD_F21 = 112, + KEYBOARD_F22 = 113, + KEYBOARD_F23 = 114, + KEYBOARD_F24 = 115, + KEYBOARD_EXECUTE = 116, + KEYBOARD_HELP = 117, + KEYBOARD_MENU = 118, + KEYBOARD_SELECT = 119, + KEYBOARD_STOP = 120, + KEYBOARD_AGAIN = 121, + KEYBOARD_UNDO = 122, + KEYBOARD_CUT = 123, + KEYBOARD_COPY = 124, + KEYBOARD_PASTE = 125, + KEYBOARD_FIND = 126, + KEYBOARD_MUTE = 127, + KEYBOARD_VOLUMEUP = 128, + KEYBOARD_VOLUMEDOWN = 129, + KEYBOARD_LOCKINGCAPSLOCK = 130, + KEYBOARD_LOCKINGNUMLOCK = 131, + KEYBOARD_LOCKINGSCROLLLOCK = 132, + KEYBOARD_KP_COMMA = 133, + KEYBOARD_KP_EQUALSAS400 = 134, + KEYBOARD_INTERNATIONAL1 = 135, + KEYBOARD_INTERNATIONAL2 = 136, + KEYBOARD_INTERNATIONAL3 = 137, + KEYBOARD_INTERNATIONAL4 = 138, + KEYBOARD_INTERNATIONAL5 = 139, + KEYBOARD_INTERNATIONAL6 = 140, + KEYBOARD_INTERNATIONAL7 = 141, + KEYBOARD_INTERNATIONAL8 = 142, + KEYBOARD_INTERNATIONAL9 = 143, + KEYBOARD_LANG1 = 144, + KEYBOARD_LANG2 = 145, + KEYBOARD_LANG3 = 146, + KEYBOARD_LANG4 = 147, + KEYBOARD_LANG5 = 148, + KEYBOARD_LANG6 = 149, + KEYBOARD_LANG7 = 150, + KEYBOARD_LANG8 = 151, + KEYBOARD_LANG9 = 152, + KEYBOARD_ALTERASE = 153, + KEYBOARD_SYSREQ = 154, + KEYBOARD_CANCEL = 155, + KEYBOARD_CLEAR = 156, + KEYBOARD_PRIOR = 157, + KEYBOARD_RETURN2 = 158, + KEYBOARD_SEPARATOR = 159, + KEYBOARD_OUT = 160, + KEYBOARD_OPER = 161, + KEYBOARD_CLEARAGAIN = 162, + KEYBOARD_CRSEL = 163, + KEYBOARD_EXSEL = 164, + KEYBOARD_KP_00 = 176, + KEYBOARD_KP_000 = 177, + KEYBOARD_THOUSANDSSEPARATOR = 178, + KEYBOARD_DECIMALSEPARATOR = 179, + KEYBOARD_CURRENCYUNIT = 180, + KEYBOARD_CURRENCYSUBUNIT = 181, + KEYBOARD_KP_LEFTPAREN = 182, + KEYBOARD_KP_RIGHTPAREN = 183, + KEYBOARD_KP_LEFTBRACE = 184, + KEYBOARD_KP_RIGHTBRACE = 185, + KEYBOARD_KP_TAB = 186, + KEYBOARD_KP_BACKSPACE = 187, + KEYBOARD_KP_A = 188, + KEYBOARD_KP_B = 189, + KEYBOARD_KP_C = 190, + KEYBOARD_KP_D = 191, + KEYBOARD_KP_E = 192, + KEYBOARD_KP_F = 193, + KEYBOARD_KP_XOR = 194, + KEYBOARD_KP_POWER = 195, + KEYBOARD_KP_PERCENT = 196, + KEYBOARD_KP_LESS = 197, + KEYBOARD_KP_GREATER = 198, + KEYBOARD_KP_AMPERSAND = 199, + KEYBOARD_KP_DBLAMPERSAND = 200, + KEYBOARD_KP_VERTICALBAR = 201, + KEYBOARD_KP_DBLVERTICALBAR = 202, + KEYBOARD_KP_COLON = 203, + KEYBOARD_KP_HASH = 204, + KEYBOARD_KP_SPACE = 205, + KEYBOARD_KP_AT = 206, + KEYBOARD_KP_EXCLAM = 207, + KEYBOARD_KP_MEMSTORE = 208, + KEYBOARD_KP_MEMRECALL = 209, + KEYBOARD_KP_MEMCLEAR = 210, + KEYBOARD_KP_MEMADD = 211, + KEYBOARD_KP_MEMSUBTRACT = 212, + KEYBOARD_KP_MEMMULTIPLY = 213, + KEYBOARD_KP_MEMDIVIDE = 214, + KEYBOARD_KP_PLUSMINUS = 215, + KEYBOARD_KP_CLEAR = 216, + KEYBOARD_KP_CLEARENTRY = 217, + KEYBOARD_KP_BINARY = 218, + KEYBOARD_KP_OCTAL = 219, + KEYBOARD_KP_DECIMAL = 220, + KEYBOARD_KP_HEXADECIMAL = 221, + KEYBOARD_LCTRL = 224, + KEYBOARD_LSHIFT = 225, + KEYBOARD_LALT = 226, + KEYBOARD_LGUI = 227, + KEYBOARD_RCTRL = 228, + KEYBOARD_RSHIFT = 229, + KEYBOARD_RALT = 230, + KEYBOARD_RGUI = 231 +}; + +struct Keyboard +{ + u8 curr[KEY_COUNT]; + u8 prev[KEY_COUNT]; +}; + +void keyboard_update(struct Keyboard* self); +bool keyboard_press(struct Keyboard* self, enum KeyType type); +bool keyboard_held(struct Keyboard* self, enum KeyType type); +bool keyboard_release(struct Keyboard* self, enum KeyType type); diff --git a/src/engine/mouse.c b/src/engine/mouse.c new file mode 100644 index 0000000..a5ebfd3 --- /dev/null +++ b/src/engine/mouse.c @@ -0,0 +1,55 @@ +/* + * DESCRIPTION: + * Mouse functions. +*/ + +#include "mouse.h" + +/* Updates the mouse. */ +void +mouse_update(struct Mouse* self) +{ + s32 state; + s32 x; + s32 y; + + memcpy(&self->prev, &self->curr, sizeof(bool) * MOUSE_COUNT); + memset(&self->curr, '\0', sizeof(bool) * MOUSE_COUNT); + + state = SDL_GetMouseState(NULL, NULL); + + if ((state & SDL_BUTTON_LMASK) != 0) + self->curr[MOUSE_LEFT] = true; + + if ((state & SDL_BUTTON_MMASK) != 0) + self->curr[MOUSE_MIDDLE] = true; + + if ((state & SDL_BUTTON_RMASK) != 0) + self->curr[MOUSE_RIGHT] = true; + + SDL_GetMouseState(&x, &y); + + self->position[0] = (f32)x; + self->position[1] = (f32)y; +} + +/* Is a given mouse button pressed? */ +bool +mouse_press(struct Mouse* self, enum MouseType type) +{ + return (self->curr[type] && !self->prev[type]); +} + +/* Is a given mouse button held? */ +bool +mouse_held(struct Mouse* self, enum MouseType type) +{ + return (self->curr[type] && self->prev[type]); +} + +/* Is a given mouse button released? */ +bool +mouse_release(struct Mouse* self, enum MouseType type) +{ + return (!self->curr[type] && self->prev[type]); +} diff --git a/src/engine/mouse.h b/src/engine/mouse.h new file mode 100644 index 0000000..79ffbc1 --- /dev/null +++ b/src/engine/mouse.h @@ -0,0 +1,31 @@ +/* + * DESCRIPTION: + * mouse.c header. +*/ + +#pragma once + +#include + +#include "../util/UTIL.h" + +#define MOUSE_COUNT MOUSE_RIGHT + 1 +enum MouseType +{ + MOUSE_NONE, + MOUSE_LEFT, + MOUSE_MIDDLE, + MOUSE_RIGHT +}; + +struct Mouse +{ + vec2 position; + bool curr[MOUSE_COUNT]; + bool prev[MOUSE_COUNT]; +}; + +void mouse_update(struct Mouse* self); +bool mouse_press(struct Mouse* self, enum MouseType type); +bool mouse_held(struct Mouse* self, enum MouseType type); +bool mouse_release(struct Mouse* self, enum MouseType type); diff --git a/src/engine/music.c b/src/engine/music.c new file mode 100644 index 0000000..075592c --- /dev/null +++ b/src/engine/music.c @@ -0,0 +1,69 @@ +/* + * DESCRIPTION: + * Music functions. +*/ + +#include "music.h" + +/* Initializes music. */ +bool +music_init(struct Music* self, char* path) +{ + self->chunk = Mix_LoadMUS(path); + + if (!self->chunk) + return false; + + self->isInit = true; + + return true; +} + +/* Frees music. */ +void +music_free(struct Music* self) +{ + if (self->isInit) + { + Mix_FreeMusic(self->chunk); + self->isInit = false; + } +} + +/* Plays music, specifying if it loops. */ +void +music_play(struct Music* self, bool isLoop) +{ + if (isLoop) + Mix_PlayMusic(self->chunk, -1); + else + Mix_PlayMusic(self->chunk, 0); +} + +/* Resumes music, if it was paused before. */ +void +music_resume(void) +{ + Mix_ResumeMusic(); +} + +/* Pauses music. */ +void +music_pause(void) +{ + Mix_PauseMusic(); +} + +/* Stops music. */ +void +music_stop(void) +{ + Mix_HaltMusic(); +} + +/* Is music playing? */ +bool +music_is_playing(void) +{ + return Mix_PlayingMusic(); +} diff --git a/src/engine/music.h b/src/engine/music.h new file mode 100644 index 0000000..1edb02a --- /dev/null +++ b/src/engine/music.h @@ -0,0 +1,24 @@ +/* + * DESCRIPTION: + * music.c header. +*/ + +#pragma once + +#include + +#include "../util/UTIL.h" + +struct Music +{ + Mix_Music* chunk; + bool isInit; +}; + +bool music_is_playing(void); +void music_free(struct Music* self); +bool music_init(struct Music* self, char* path); +void music_pause(void); +void music_play(struct Music* self, bool isLoop); +void music_resume(void); +void music_stop(void); diff --git a/src/engine/renderer.c b/src/engine/renderer.c new file mode 100644 index 0000000..05def0f --- /dev/null +++ b/src/engine/renderer.c @@ -0,0 +1,108 @@ +/* + * DESCRIPTION: + * Basic rendering. +*/ + +#include "renderer.h" + +/* Initializes renderer. */ +void +renderer_init(struct Renderer* self, struct Window* window, enum CameraType type) +{ + self->window = window; + + self->glContext = SDL_GL_CreateContext(self->window->sdl); + + glew_init(); + + vao_init(&self->vao); + vbo_init(&self->vbo, GL_ARRAY_BUFFER, true); + vbo_init(&self->ebo, GL_ELEMENT_ARRAY_BUFFER, true); + + switch (type) + { + case CAMERA_PERSPECTIVE: + camera_perspective_init + ( + &self->camera, + RENDERER_CAMERA_PERSPECTIVE_FOV_DEFAULT, + RENDERER_CAMERA_PERSPECTIVE_ASPECT_DEFAULT + ); + break; + case CAMERA_ORTHOGRAPHIC: + camera_orthographic_init(&self->camera, self->window->size); + break; + default: + break; + } +} + +/* Frees renderer. */ +void +renderer_free(struct Renderer* self) +{ + memset(self, '\0', sizeof(struct Renderer)); + SDL_GL_DeleteContext(self->glContext); +} + +/* Sets renderer's viewport. */ +void +renderer_viewport_set(struct Renderer* self, ivec4 viewport) +{ + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); +} + +/* Sets the renderer's viewport to its window. */ +void +renderer_viewport_window_set(struct Renderer* self) +{ + ivec4 viewport; + + window_ivec4_get(self->window, viewport); + + renderer_viewport_set(self, viewport); +} + +/* Uses the specified shader. */ +void +renderer_shader_use(struct Renderer* self, struct Shader* shader) +{ + self->shader = shader; + shader_use(shader); +} + +/* Sets the renderer clear color. */ +void +renderer_clear_color_set(struct Renderer* self, vec4 color) +{ + glClearColor(color[0], color[1], color[2], color[3]); + + glm_vec4_copy(color, self->clearColor); +} + +/* Clears the renderer. */ +void +renderer_clear(struct Renderer* self) +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +/* Presents renderer. */ +void +renderer_present(struct Renderer* self) +{ + SDL_GL_SwapWindow(self->window->sdl); +} + +/* Updates renderer. */ +void +renderer_update(struct Renderer* self) +{ + renderer_viewport_window_set(self); + camera_update(&self->camera); + + if (self->camera.type == CAMERA_ORTHOGRAPHIC) + camera_orthographic_window_set(&self->camera, self->window); +} + + diff --git a/src/engine/renderer.h b/src/engine/renderer.h new file mode 100644 index 0000000..77e7fb2 --- /dev/null +++ b/src/engine/renderer.h @@ -0,0 +1,39 @@ +/* + * DESCRIPTION: + * renderer.c header. +*/ + +#pragma once + +#include "atlas.h" +#include "camera.h" +#include "glew.h" +#include "shader.h" +#include "vao.h" +#include "vbo.h" +#include "vertexattribute.h" + +#define RENDERER_CAMERA_PERSPECTIVE_FOV_DEFAULT 90.0f +#define RENDERER_CAMERA_PERSPECTIVE_ASPECT_DEFAULT 1.0f + +struct Renderer +{ + SDL_GLContext glContext; + struct Camera camera; + struct Window* window; + struct Shader* shader; + struct VAO vao; + struct VBO ebo; + struct VBO vbo; + vec4 clearColor; +}; + +void renderer_init(struct Renderer* self, struct Window* window, enum CameraType type); +void renderer_clear_color_set(struct Renderer* self, vec4 color); +void renderer_viewport_window_set(struct Renderer* self); +void renderer_viewport_set(struct Renderer* self, ivec4 viewport); +void renderer_clear(struct Renderer* self); +void renderer_update(struct Renderer* self); +void renderer_free(struct Renderer* self); +void renderer_present(struct Renderer* self); +void renderer_shader_use(struct Renderer* self, struct Shader* shader); diff --git a/src/engine/sdl.c b/src/engine/sdl.c new file mode 100644 index 0000000..b334f0f --- /dev/null +++ b/src/engine/sdl.c @@ -0,0 +1,65 @@ +/* + * DESCRIPTION: + * Handles basic SDL functions. +*/ + +#include "sdl.h" + +/* Initializes SDL. */ +void +sdl_init(void) +{ + if (SDL_INIT_VIDEO < 0) + { + printf("SDL2 ERROR: %s\n", SDL_GetError()); + exit(EXIT_FAILURE); + } + else + printf("SDL2 VIDEO LOADED\n"); + + if (SDL_INIT_TIMER < 0) + { + printf("SDL2 ERROR: %s\n", SDL_GetError()); + exit(EXIT_FAILURE); + } + else + printf("SDL2 TIMER LOADED\n"); + + if (IMG_Init(IMG_FLAGS) < 0) + { + printf("SDL_image ERROR: %s\n", IMG_GetError()); + exit(EXIT_FAILURE); + } + else + printf("SDL_image LOADED\n"); + + if (TTF_Init() < 0) + { + printf("SDL_ttf ERROR: %s\n", TTF_GetError()); + exit(EXIT_FAILURE); + } + else + printf("SDL_ttf LOADED\n"); + + if (Mix_OpenAudio(MIX_FREQUENCY, MIX_DEFAULT_FORMAT, MIX_CHANNELS, MIX_SAMPLE_SIZE) < 0) + { + printf("SDL_mixer ERROR: %s\n", TTF_GetError()); + exit(EXIT_FAILURE); + } + else + printf("SDL_mixer LOADED\n"); + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); +} + +/* Quits SDL. */ +void +sdl_quit(void) +{ + SDL_Quit(); + Mix_CloseAudio(); + IMG_Quit(); +} diff --git a/src/engine/sdl.h b/src/engine/sdl.h new file mode 100644 index 0000000..500fc0d --- /dev/null +++ b/src/engine/sdl.h @@ -0,0 +1,18 @@ +/* + * DESCRIPTION: + * sdl.c header. +*/ + +#pragma once + +#include +#include +#include +#include + +#define MIX_FREQUENCY 44100 +#define MIX_SAMPLE_SIZE 2048 +#define IMG_FLAGS (IMG_INIT_PNG) + +void sdl_init(void); +void sdl_quit(void); diff --git a/src/engine/shader.c b/src/engine/shader.c new file mode 100644 index 0000000..362641f --- /dev/null +++ b/src/engine/shader.c @@ -0,0 +1,125 @@ +/* + * DESCRIPTION: + * OpenGL shader abstraction. +*/ + +#include "shader.h" + +/* Given two GLSL strings representing the vertex/fragment shaders, + * initializes and compiles shader program. */ +bool +shader_init(struct Shader* self, char* vertex, char* fragment) +{ + s32 success; + char log[SHADER_LOG_MAX]; + + GLuint vertexHandle; + GLuint fragmentHandle; + + vertexHandle = glCreateShader(GL_VERTEX_SHADER); + fragmentHandle = glCreateShader(GL_FRAGMENT_SHADER); + + glShaderSource(vertexHandle, 1, (const char* const*)&vertex, NULL); + glShaderSource(fragmentHandle, 1, (const char* const*)&fragment, NULL); + + glCompileShader(vertexHandle); + glCompileShader(fragmentHandle); + + glGetShaderiv(vertexHandle, GL_COMPILE_STATUS, &success); + + if (!success) + { + glGetShaderInfoLog(vertexHandle, SHADER_LOG_MAX, NULL, log); + printf("COMPILE ERROR: Shader #%i | %s\n", vertexHandle, log); + return false; + } + else + printf("COMPILE SUCCESS: Shader #%i\n", vertexHandle); + + glGetShaderiv(fragmentHandle, GL_COMPILE_STATUS, &success); + + if (!success) + { + glGetShaderInfoLog(fragmentHandle, SHADER_LOG_MAX, NULL, log); + printf("COMPILE ERROR: Shader #%i | %s\n", fragmentHandle, log); + return false; + } + else + printf("COMPILE SUCCESS: Shader #%i\n", fragmentHandle); + + self->handle = glCreateProgram(); + + glAttachShader(self->handle, vertexHandle); + glAttachShader(self->handle, fragmentHandle); + + glLinkProgram(self->handle); + + glDeleteShader(vertexHandle); + glDeleteShader(fragmentHandle); + + self->isInit = true; + + return true; +} + +/* Uses the specified shader program. */ +void +shader_use(struct Shader* self) +{ + glUseProgram(self->handle); +} + +/* Frees a shader program. */ +void +shader_free(struct Shader* self) +{ + if (self->isInit) + { + glDeleteProgram(self->handle); + self->isInit = false; + } +} + +/* Sets a s32 uniform. */ +void +shader_uniform_s32_set(struct Shader* self, char* name, s32 value) +{ + glUniform1i(glGetUniformLocation(self->handle, name), value); +} + +/* Sets a f32 uniform. */ +void +shader_uniform_f32_set(struct Shader* self, char* name, f32 value) +{ + glUniform1i(glGetUniformLocation(self->handle, name), value); +} + +/* Sets a vec3 uniform. */ +void +shader_uniform_vec3_set(struct Shader* self, char* name, vec3 value) +{ + glUniform3fv(glGetUniformLocation(self->handle, name), 1, value); +} + +/* Sets a vec4 uniform. */ +void +shader_uniform_vec4_set(struct Shader* self, char* name, vec4 value) +{ + glUniform4fv(glGetUniformLocation(self->handle, name), 1, value); +} + +/* Sets a mat4 uniform. */ +void +shader_uniform_mat4_set(struct Shader* self, char* name, mat4 value) +{ + glUniformMatrix4fv(glGetUniformLocation(self->handle, name), 1, GL_FALSE, (f32*)value); +} + +/* Sets a texture uniform. */ +void +shader_uniform_texture_set(struct Shader* self, char* name, struct Texture* texture, s32 index) +{ + glActiveTexture(GL_TEXTURE0 + index); + texture_bind(texture); + glUniform1i(glGetUniformLocation(self->handle, name), index); +} diff --git a/src/engine/shader.h b/src/engine/shader.h new file mode 100644 index 0000000..158aa80 --- /dev/null +++ b/src/engine/shader.h @@ -0,0 +1,29 @@ +/* + * DESCRIPTION: + * shader.c header. +*/ + +#pragma once + +#include +#include + +#include "texture.h" + +#define SHADER_LOG_MAX 1024 + +struct Shader +{ + GLuint handle; + bool isInit; +}; + +bool shader_init(struct Shader* self, char* vertex, char* fragment); +void shader_use(struct Shader* self); +void shader_free(struct Shader* self); +void shader_uniform_f32_set(struct Shader* self, char* name, f32 value); +void shader_uniform_s32_set(struct Shader* self, char* name, s32 value); +void shader_uniform_mat4_set(struct Shader* self, char* name, mat4 value); +void shader_uniform_vec3_set(struct Shader* self, char* name, vec3 value); +void shader_uniform_vec4_set(struct Shader* self, char* name, vec4 value); +void shader_uniform_texture_set(struct Shader* self, char* name, struct Texture* texture, s32 index); diff --git a/src/engine/sound.c b/src/engine/sound.c new file mode 100644 index 0000000..1f6e844 --- /dev/null +++ b/src/engine/sound.c @@ -0,0 +1,38 @@ +/* + * DESCRIPTION: + * Sound functions. +*/ + +#include "sound.h" + +/* Initializes a sound. */ +bool +sound_init(struct Sound* self, char* path) +{ + self->chunk = Mix_LoadWAV(path); + + if (!self->chunk) + return false; + + self->isInit = true; + + return true; +} + +/* Frees a sound. */ +void +sound_free(struct Sound* self) +{ + if (self->isInit) + { + Mix_FreeChunk(self->chunk); + self->isInit = false; + } +} + +/* Plays a sound, specifying a channel. */ +void +sound_play(struct Sound* self, s32 channel) +{ + Mix_PlayChannel(-1, self->chunk, 0); +} diff --git a/src/engine/sound.h b/src/engine/sound.h new file mode 100644 index 0000000..196818a --- /dev/null +++ b/src/engine/sound.h @@ -0,0 +1,20 @@ +/* + * DESCRIPTION: + * sound.c header. +*/ + +#pragma once + +#include + +#include "../util/UTIL.h" + +struct Sound +{ + struct Mix_Chunk* chunk; + bool isInit; +}; + +bool sound_init(struct Sound* self, char* path); +void sound_free(struct Sound* self); +void sound_play(struct Sound* self, s32 channel); diff --git a/src/engine/surface.c b/src/engine/surface.c new file mode 100644 index 0000000..661544b --- /dev/null +++ b/src/engine/surface.c @@ -0,0 +1,23 @@ +/* + * DESCRIPTION: + * SDL_Surface functions. +*/ + +#include "surface.h" + +/* Initializes an RGBA8888 surface. */ +void +surface_rgba_init(struct SDL_Surface** self, ivec2 size) +{ + *self = SDL_CreateRGBSurface + ( + 0, + size[0], + size[1], + 32, + 0xFF000000, + 0x00FF0000, + 0x0000FF00, + 0x000000FF + ); +} diff --git a/src/engine/surface.h b/src/engine/surface.h new file mode 100644 index 0000000..90c6297 --- /dev/null +++ b/src/engine/surface.h @@ -0,0 +1,12 @@ +/* + * DESCRIPTION: + * surface.c header. +*/ + +#pragma once + +#include + +#include "../util/UTIL.h" + +void surface_rgba_init(struct SDL_Surface** self, ivec2 size); diff --git a/src/engine/texture.c b/src/engine/texture.c new file mode 100644 index 0000000..2820215 --- /dev/null +++ b/src/engine/texture.c @@ -0,0 +1,70 @@ +/* + * DESCRIPTION: + * OpenGL texture abstraction. +*/ + +#include "texture.h" + +/* Given an SDL_Surface, creates a GL texture from it. */ +/* NOTE: loading only supports RGBA */ +bool +texture_surface_init(struct Texture* self, struct SDL_Surface* surface) +{ + if (!self->isInit) + { + glGenTextures(1, &self->handle); + self->isInit = true; + } + + if (!surface) + return false; + + self->w = surface->w; + self->h = surface->h; + + texture_bind(self); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self->w, self->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels); + + glGenerateMipmap(GL_TEXTURE_2D); + + return true; +} + +/* Initializes the OpenGL texture, given image data. */ +bool +texture_init(struct Texture* self, char* path) +{ + struct SDL_Surface* surface; + + surface = IMG_Load(path); + + if (!surface) + return false; + + texture_surface_init(self, surface); + + SDL_FreeSurface(surface); + + return true; +} + +/* Binds a texture. */ +void +texture_bind(struct Texture* self) +{ + glBindTexture(GL_TEXTURE_2D, self->handle); +} + +/* Frees texture. */ +void +texture_free(struct Texture* self) +{ + glDeleteTextures(1, &self->handle); + memset(self, '\0', sizeof(struct Texture)); +} diff --git a/src/engine/texture.h b/src/engine/texture.h new file mode 100644 index 0000000..5f4497e --- /dev/null +++ b/src/engine/texture.h @@ -0,0 +1,29 @@ +/* + * DESCRIPTION: + * texture.c header. +*/ + +#pragma once + +#include +#include + +#include +#include +#include + +#include "../util/UTIL.h" + +struct Texture +{ + GLuint handle; + s32 w; + s32 h; + s32 channels; + bool isInit; +}; + +bool texture_init(struct Texture* self, char* path); +bool texture_surface_init(struct Texture* self, struct SDL_Surface* surface); +void texture_bind(struct Texture* self); +void texture_free(struct Texture* self); diff --git a/src/engine/tick.c b/src/engine/tick.c new file mode 100644 index 0000000..9307499 --- /dev/null +++ b/src/engine/tick.c @@ -0,0 +1,16 @@ +/* + * DESCRIPTION: + * Handles ticks; game intervals. +*/ + +#include "tick.h" + +/* Update ticks. */ +void +tick_update(struct Tick* self) +{ + self->prev = self->curr; + self->curr = SDL_GetTicks64(); + self->delta = self->curr - self->prev; + self->cum += self->delta; +} diff --git a/src/engine/tick.h b/src/engine/tick.h new file mode 100644 index 0000000..393c5d4 --- /dev/null +++ b/src/engine/tick.h @@ -0,0 +1,20 @@ +/* + * DESCRIPTION: + * tick.c header. +*/ + +#pragma once + +#include + +#include "../util/UTIL.h" + +struct Tick +{ + u64 curr; + u64 prev; + u64 delta; + u64 cum; +}; + +void tick_update(struct Tick* self); diff --git a/src/engine/vao.c b/src/engine/vao.c new file mode 100644 index 0000000..2b68b42 --- /dev/null +++ b/src/engine/vao.c @@ -0,0 +1,35 @@ +/* + * DESCRIPTION: + * OpenGL Vertex Array Object (VAO) abstractions. +*/ + +#include "vao.h" + +/* Initializes a VAO. */ +void +vao_init(struct VAO* self) +{ + glGenVertexArrays(1, &self->handle); +} + +/* Binds VAO. */ +void +vao_bind(struct VAO* self) +{ + glBindVertexArray(self->handle); +} + +/* Unbinds VAO. */ +void +vao_unbind(void) +{ + glBindVertexArray(0); +} + +/* Frees VAO. */ +void +vao_free(struct VAO* self) +{ + glDeleteVertexArrays(1, &self->handle); + memset(self, '\0', sizeof(struct VAO)); +} diff --git a/src/engine/vao.h b/src/engine/vao.h new file mode 100644 index 0000000..b8799b6 --- /dev/null +++ b/src/engine/vao.h @@ -0,0 +1,21 @@ +/* + * DESCRIPTION: + * vao.c header. +*/ + +#pragma once + +#include +#include + +#include "../util/UTIL.h" + +struct VAO +{ + GLuint handle; +}; + +void vao_init(struct VAO* self); +void vao_bind(struct VAO* self); +void vao_unbind(void); +void vao_free(struct VAO* self); diff --git a/src/engine/vbo.c b/src/engine/vbo.c new file mode 100644 index 0000000..3da5fcb --- /dev/null +++ b/src/engine/vbo.c @@ -0,0 +1,38 @@ +/* + * DESCRIPTION: + * OpenGL Vertex Buffer Object (VBO) abstractions. +*/ + +#include "vbo.h" + +/* Initializes/generates a VBO. */ +void +vbo_init(struct VBO* self, GLint type, bool isDynamic) +{ + self->isDynamic = isDynamic; + self->type = type; + + glGenBuffers(1, &self->handle); +} + +/* Bind a VBO, specifying a type. */ +void +vbo_bind(struct VBO* self) +{ + glBindBuffer(self->type, self->handle); +} + +/* Frees a given VBO. */ +void +vbo_free(struct VBO* self) +{ + glDeleteBuffers(1, &self->handle); + memset(self, '\0', sizeof(struct VBO)); +} + +/* Binds and sends data to a VBO. */ +void +vbo_buffer(struct VBO* self, size_t size, void* data) +{ + glBufferData(self->type, size, data, self->isDynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); +} diff --git a/src/engine/vbo.h b/src/engine/vbo.h new file mode 100644 index 0000000..d22dda2 --- /dev/null +++ b/src/engine/vbo.h @@ -0,0 +1,23 @@ +/* + * DESCRIPTION: + * vbo.c header. +*/ + +#pragma once + +#include +#include + +#include "../util/UTIL.h" + +typedef struct VBO +{ + GLuint handle; + GLint type; + bool isDynamic; +} VBO; + +void vbo_buffer(struct VBO* self, size_t size, void* data); +void vbo_bind(struct VBO* self); +void vbo_free(struct VBO* self); +void vbo_init(struct VBO* self, GLint type, bool isDynamic); diff --git a/src/engine/vertexattribute.c b/src/engine/vertexattribute.c new file mode 100644 index 0000000..c9d3a90 --- /dev/null +++ b/src/engine/vertexattribute.c @@ -0,0 +1,30 @@ +/* + * DESCRIPTION: + * OpenGL Vertex attribute abstraction. +*/ + +#include "vertexattribute.h" + +/* Sets and enables a vertex attribute. */ +void +vertex_attribute_set(GLuint index, GLint size, GLenum type, GLsizei stride, size_t offset) +{ + switch (type) + { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_INT_2_10_10_10_REV: + case GL_UNSIGNED_INT_2_10_10_10_REV: + glVertexAttribIPointer(index, size, type, stride, (void*)offset); + break; + default: + glVertexAttribPointer(index, size, type, GL_FALSE, stride, (void*)offset); + break; + } + + glEnableVertexAttribArray(index); +} diff --git a/src/engine/vertexattribute.h b/src/engine/vertexattribute.h new file mode 100644 index 0000000..d8244d8 --- /dev/null +++ b/src/engine/vertexattribute.h @@ -0,0 +1,13 @@ +/* + * DESCRIPTION: + * vertexattribute.c header. +*/ + +#pragma once + +#include +#include + +#include "../util/UTIL.h" + +void vertex_attribute_set(GLuint index, GLint size, GLenum type, GLsizei stride, size_t offset); diff --git a/src/engine/window.c b/src/engine/window.c new file mode 100644 index 0000000..28cd4b8 --- /dev/null +++ b/src/engine/window.c @@ -0,0 +1,106 @@ +/* + * DESCRIPTION: + * Window functionality. +*/ + +#include "window.h" + +/* Initializes a window; needs menu, width, height, and flags. */ +void +window_init(struct Window* self, char* name, vec2 size, u32 flags) +{ + self->name = name; + self->flags = flags; + + glm_vec2_copy(size, self->size); + + self->isFullscreen = false; + + self->sdl = SDL_CreateWindow + ( + name, + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + (s32)self->size[0], + (s32)self->size[1], + flags + ); +} + +/* Frees a given window. */ +void +window_free(struct Window* self) +{ + SDL_DestroyWindow(self->sdl); + + memset(self, '\0', sizeof(struct Window)); +} + +/* Returns window size. */ +void +window_ivec4_get(struct Window* self, ivec4 vector) +{ + vector[0] = 0; + vector[1] = 0; + vector[2] = self->size[0]; + vector[3] = self->size[1]; +} + +/* Sets video mode to fullscreen. */ +void +window_fullscreen_enter(struct Window* self) +{ + SDL_DisplayMode dm; + s32 w; + s32 h; + + SDL_GetCurrentDisplayMode(0, &dm); + + w = dm.w; + h = dm.h; + + SDL_SetWindowSize(self->sdl, w, h); + + self->isFullscreen = true; + + SDL_SetWindowFullscreen(self->sdl, SDL_WINDOW_FULLSCREEN); +} + +/* Exit fullscreen.*/ +void +window_fullscreen_exit(struct Window* self) +{ + self->isFullscreen = false; + + SDL_SetWindowFullscreen(self->sdl, 0); +} + +void +window_fullscreen_toggle(struct Window* self) +{ + if (!self->isFullscreen) + window_fullscreen_enter(self); + else + window_fullscreen_exit(self); +} + +/* Updates window. */ +void +window_update(struct Window* self) +{ + s32 w; + s32 h; + + SDL_GetWindowSize(self->sdl, &w, &h); + + self->size[0] = (f32)w; + self->size[1] = (f32)h; +} + +/* Window coords -> OpenGL coords. */ +void +window_coords_to_gl(struct Window* self, vec2 position, vec2 dest) +{ + dest[0] = ((position[0] / (f32)self->size[0]) * 2.0f) - 1.0f; + dest[1] = ((position[1] / (f32)self->size[1]) * 2.0f) - 1.0f; +} diff --git a/src/engine/window.h b/src/engine/window.h new file mode 100644 index 0000000..fc6a132 --- /dev/null +++ b/src/engine/window.h @@ -0,0 +1,28 @@ +/* + * DESCRIPTION: + * window.c header. +*/ + +#pragma once + +#include + +#include "../util/UTIL.h" + +struct Window +{ + struct SDL_Window* sdl; + char* name; + u32 flags; + vec2 size; + bool isFullscreen; +}; + +void window_init(struct Window* self, char* name, vec2 size, u32 flags); +void window_free(struct Window* self); +void window_update(struct Window* self); +void window_fullscreen_enter(struct Window* self); +void window_fullscreen_exit(struct Window* self); +void window_fullscreen_toggle(struct Window* self); +void window_ivec4_get(struct Window* self, ivec4 vector); +void window_coords_to_gl(struct Window* self, vec2 position, vec2 dest); diff --git a/src/game/ecs/ECS_TYPES.h b/src/game/ecs/ECS_TYPES.h new file mode 100644 index 0000000..6dec530 --- /dev/null +++ b/src/game/ecs/ECS_TYPES.h @@ -0,0 +1,73 @@ +/* + * DESCRIPTION: + * ECS types. +*/ + +#pragma once + +#include "../../util/UTIL.h" + +#define ECS_FUNCTION_COUNT ECS_FUNCTION_DRAW + 1 +enum ECSFunctionType +{ + ECS_FUNCTION_ADD, + ECS_FUNCTION_DELETE, + ECS_FUNCTION_UPDATE_F, + ECS_FUNCTION_UPDATE_V, + ECS_FUNCTION_DRAW +}; + +#define ECS_C_COUNT ECS_C_UI_BUTTON + 1 +enum ECSComponentType +{ + ECS_C_CHASE, + ECS_C_CIRCLE, + ECS_C_CIRCLE_COLLIDE, + ECS_C_COLOR, + ECS_C_COLOR_CHANGE, + ECS_C_COLOR_COLLIDE_DELETE, + ECS_C_CONTACT_DAMAGE, + ECS_C_CONTROL, + ECS_C_DAMAGE, + ECS_C_FLASH, + ECS_C_GAME_OBJECT, + ECS_C_HEALTH, + ECS_C_MOVE, + ECS_C_ORBIT, + ECS_C_PARTICLE_SPAWN, + ECS_C_PHYSICS, + ECS_C_PLAYER_ATLAS_HEALTH, + ECS_C_PLAYER_DEATH, + ECS_C_PULSATE, + ECS_C_ROTATION, + ECS_C_SCALE, + ECS_C_SPIN, + ECS_C_SPRITE, + ECS_C_STUN, + ECS_C_TEXT, + ECS_C_TIME_DELETE, + ECS_C_UI_BUTTON +}; + +struct ECS; + +typedef void (*ECSRegister)(void); +typedef void (*ECSFunction)(void*); + +struct ECSSystem +{ + ECSFunction functions[ECS_FUNCTION_COUNT]; +}; + +struct ECSComponentList +{ + struct ECSSystem system; + struct Vector components; + enum ECSComponentType type; +}; + +struct ECS +{ + struct ECSComponentList lists[ECS_C_COUNT]; + u32 nextID; +}; diff --git a/src/game/ecs/c_chase.c b/src/game/ecs/c_chase.c new file mode 100644 index 0000000..567a36b --- /dev/null +++ b/src/game/ecs/c_chase.c @@ -0,0 +1,59 @@ +/* + * DESCRIPTION: + * Chase component. +*/ + +#include "c_chase.h" + +static void update_f(struct CChase* self); + +/* Draws a chase component. */ +static void +update_f(struct CChase* self) +{ + struct CPhysics* physics; + struct CPhysics* targetPhysics; + f32 angle; + + physics = ecs_get(self->id, ECS_C_PHYSICS); + targetPhysics = ecs_get(self->targetID, ECS_C_PHYSICS); + + if (!physics || !targetPhysics) + return; + + angle = ATAN + ( + targetPhysics->position[0], + physics->position[0], + targetPhysics->position[1], + physics->position[1] + ); + + physics->velocity[0] -= (cos(angle) * self->speed); + physics->velocity[1] -= (sin(angle) * self->speed); +} + +/* Sets chase component values. */ +void +c_chase_set(struct CChase* self, u32 targetID, f32 speed) +{ + self->targetID = targetID; + self->speed = speed; +} + +/* Registers chase component. */ +void +c_chase_register(void) +{ + ecs_register + ( + ECS_C_CHASE, + sizeof(struct CChase), + C_CHASE_LIMIT, + NULL, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_chase.h b/src/game/ecs/c_chase.h new file mode 100644 index 0000000..69875e7 --- /dev/null +++ b/src/game/ecs/c_chase.h @@ -0,0 +1,20 @@ +/* + * DESCRIPTION: + * c_chase.c header. +*/ + +#pragma once + +#include "c_physics.h" + +#define C_CHASE_LIMIT 0xFF + +struct CChase +{ + u32 id; + u32 targetID; + f32 speed; +}; + +void c_chase_set(struct CChase* self, u32 targetID, f32 speed); +void c_chase_register(void); diff --git a/src/game/ecs/c_circle.c b/src/game/ecs/c_circle.c new file mode 100644 index 0000000..e31f793 --- /dev/null +++ b/src/game/ecs/c_circle.c @@ -0,0 +1,30 @@ +/* + * DESCRIPTION: + * Circle component. +*/ + +#include "c_circle.h" + +/* Sets circle component values. */ +void +c_circle_set(struct CCircle* self, f32 radius) +{ + self->radius = radius; +} + +/* Registers circle component. */ +void +c_circle_register(void) +{ + ecs_register + ( + ECS_C_CIRCLE, + sizeof(struct CCircle), + C_CIRCLE_LIMIT, + NULL, + NULL, + NULL, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_circle.h b/src/game/ecs/c_circle.h new file mode 100644 index 0000000..2b4e000 --- /dev/null +++ b/src/game/ecs/c_circle.h @@ -0,0 +1,19 @@ +/* + * DESCRIPTION: + * c_circle.c header. +*/ + +#pragma once + +#include "entity.h" + +#define C_CIRCLE_LIMIT 0xFF + +struct CCircle +{ + u32 id; + f32 radius; +}; + +void c_circle_set(struct CCircle* self, f32 radius); +void c_circle_register(void); diff --git a/src/game/ecs/c_circle_collide.c b/src/game/ecs/c_circle_collide.c new file mode 100644 index 0000000..f780580 --- /dev/null +++ b/src/game/ecs/c_circle_collide.c @@ -0,0 +1,100 @@ +/* + * DESCRIPTION: + * Circle collide component. +*/ + +#include "c_circle_collide.h" + +static bool collide(struct CCircle* a, struct CCircle* b); +static void add(struct CCircleCollide* self); +static void update_f(struct CCircleCollide* self); +static void delete(struct CCircleCollide* self); + +/* Are two circle components colliding? */ +static bool +collide(struct CCircle* a, struct CCircle* b) +{ + struct CPhysics* aPhysics; + struct CPhysics* bPhysics; + f32 distance; + f32 sum; + + aPhysics = ecs_get(a->id, ECS_C_PHYSICS); + bPhysics = ecs_get(b->id, ECS_C_PHYSICS); + + if (!aPhysics || !bPhysics) + return false; + + distance = DISTANCE_2D + ( + aPhysics->position[0], + bPhysics->position[0], + aPhysics->position[1], + bPhysics->position[1] + ); + + sum = a->radius + b->radius; + + if (distance < sum) + return true; + + return false; +} + +/* Adds circle collide component. */ +static void +add(struct CCircleCollide* self) +{ + vector_init(&self->collisions, sizeof(u32), C_CIRCLE_COLLIDE_COLLISIONS_LIMIT); +} + +/* Deletes circle collide component. */ +static void +delete(struct CCircleCollide* self) +{ + vector_free(&self->collisions); +} + +/* Draws a circle collide component. */ +static void +update_f(struct CCircleCollide* self) +{ + struct CCircle* circle; + + circle = ecs_get(self->id, ECS_C_CIRCLE); + + vector_clear(&self->collisions); + + if (!circle) + return; + + for (s32 i = 0; i < (s32)game.ecs.lists[ECS_C_CIRCLE].components.count; i++) + { + struct CCircle* collideCircle; + + collideCircle = ecs_from_index_get(i, ECS_C_CIRCLE); + + if (collideCircle->id == self->id) + continue; + + if (collide(circle, collideCircle)) + vector_push(&self->collisions, &collideCircle->id); + } +} + +/* Registers circle collide component. */ +void +c_circle_collide_register(void) +{ + ecs_register + ( + ECS_C_CIRCLE_COLLIDE, + sizeof(struct CCircleCollide), + C_CIRCLE_COLLIDE_LIMIT, + (ECSFunction)add, + (ECSFunction)delete, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_circle_collide.h b/src/game/ecs/c_circle_collide.h new file mode 100644 index 0000000..5f65030 --- /dev/null +++ b/src/game/ecs/c_circle_collide.h @@ -0,0 +1,20 @@ +/* + * DESCRIPTION: + * c_circle_collide.c header. +*/ + +#pragma once + +#include "c_circle.h" +#include "c_physics.h" + +#define C_CIRCLE_COLLIDE_LIMIT 0xFF +#define C_CIRCLE_COLLIDE_COLLISIONS_LIMIT C_CIRCLE_COLLIDE_LIMIT + +struct CCircleCollide +{ + u32 id; + struct Vector collisions; /* u32; CCircle ID */ +}; + +void c_circle_collide_register(void); diff --git a/src/game/ecs/c_color.c b/src/game/ecs/c_color.c new file mode 100644 index 0000000..935e240 --- /dev/null +++ b/src/game/ecs/c_color.c @@ -0,0 +1,30 @@ +/* + * DESCRIPTION: + * Color component. +*/ + +#include "c_color.h" + +/* Sets color component. */ +void +c_color_set(struct CColor* self, enum CColorType type) +{ + self->type = type; +} + +/* Registers color component. */ +void +c_color_register(void) +{ + ecs_register + ( + ECS_C_COLOR, + sizeof(struct CColor), + C_COLOR_LIMIT, + NULL, + NULL, + NULL, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_color.h b/src/game/ecs/c_color.h new file mode 100644 index 0000000..fe416a0 --- /dev/null +++ b/src/game/ecs/c_color.h @@ -0,0 +1,40 @@ +/* + * DESCRIPTION: + * c_color.c header. +*/ + +#pragma once + +#include "entity.h" + +#define C_COLOR_LIMIT 0xFF + +#define C_COLOR_COUNT C_COLOR_CYAN + 1 +enum CColorType +{ + C_COLOR_GREEN, + C_COLOR_BLUE, + C_COLOR_RED, + C_COLOR_YELLOW, + C_COLOR_MAGENTA, + C_COLOR_CYAN +}; + +struct CColor +{ + u32 id; + enum CColorType type; +}; + +static const vec4 C_COLOR_VALUES[C_COLOR_COUNT] = +{ + {0.30f, 1.00f, 0.30f, 1.00f}, + {0.20f, 0.50f, 0.80f, 1.00f}, + {1.00f, 0.20f, 0.20f, 1.00f}, + {1.00f, 1.00f, 0.30f, 1.00f}, + {1.00f, 0.20f, 0.90f, 1.00f}, + {0.20f, 1.00f, 0.90f, 1.00f} +}; + +void c_color_set(struct CColor* self, enum CColorType type); +void c_color_register(void); diff --git a/src/game/ecs/c_color_change.c b/src/game/ecs/c_color_change.c new file mode 100644 index 0000000..593b93a --- /dev/null +++ b/src/game/ecs/c_color_change.c @@ -0,0 +1,116 @@ +/* + * DESCRIPTION: + * Color change component. +*/ + +#include "c_color_change.h" + +static void add(struct CColorChange* self); +static void update_f(struct CColorChange* self); + +/* Adds a color change component. */ +static void +add(struct CColorChange* self) +{ + self->isFinished = true; +} + +/* Updates an color change component. */ +static void +update_f(struct CColorChange* self) +{ + f32 progress; + struct CSprite* sprite; + struct CText* text; + vec4 current; + vec4 difference; + vec4 step; + vec4* color; + + sprite = ecs_get(self->id, ECS_C_SPRITE); + text = ecs_get(self->id, ECS_C_TEXT); + + if (self->isFinished) + return; + + if (sprite) + color = &sprite->color; + else if (text) + color = &text->color; + else + return; + + progress = (f32)self->timer / self->timerMax; + + switch (self->type) + { + case C_COLOR_CHANGE_TO: + case C_COLOR_CHANGE_TO_STICK: + glm_vec4_copy(self->baseColor, current); + glm_vec4_sub(current, self->color, difference); + glm_vec4_scale(difference, (1.0f - progress), step); + glm_vec4_sub(current, step, current); + glm_vec4_copy(current, *color); + break; + case C_COLOR_CHANGE_FROM: + case C_COLOR_CHANGE_FROM_STICK: + glm_vec4_copy(self->color, current); + glm_vec4_sub(current, self->baseColor, difference); + glm_vec4_scale(difference, (1.0f - progress), step); + glm_vec4_sub(current, step, current); + glm_vec4_copy(current, *color); + break; + default: + break; + } + + self->timer--; + + if (self->timer <= 0) + { + switch (self->type) + { + case C_COLOR_CHANGE_TO: + case C_COLOR_CHANGE_FROM: + glm_vec4_copy(self->baseColor, *color); + break; + case C_COLOR_CHANGE_TO_STICK: + case C_COLOR_CHANGE_FROM_STICK: + default: + break; + } + + self->isFinished = true; + } +} + +/* Sets color_change component. */ +void +c_color_change_set(struct CColorChange* self, vec4 baseColor, vec4 color, s32 timerMax, enum CColorChangeType type) +{ + glm_vec4_copy(baseColor, self->baseColor); + glm_vec4_copy(color, self->color); + + self->timerMax = timerMax; + self->type = type; + + self->timer = self->timerMax; + self->isFinished = false; +} + +/* Registers color_change component. */ +void +c_color_change_register(void) +{ + ecs_register + ( + ECS_C_COLOR_CHANGE, + sizeof(struct CColorChange), + C_COLOR_CHANGE_LIMIT, + (ECSFunction)add, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_color_change.h b/src/game/ecs/c_color_change.h new file mode 100644 index 0000000..53b0f4a --- /dev/null +++ b/src/game/ecs/c_color_change.h @@ -0,0 +1,34 @@ +/* + * DESCRIPTION: + * c_color_change.c header. +*/ + +#pragma once + +#include "c_sprite.h" +#include "c_text.h" + +#define C_COLOR_CHANGE_LIMIT 0xFF + +#define C_COLOR_CHANGE_COUNT C_COLOR_CHANGE_STICK + 1 +enum CColorChangeType +{ + C_COLOR_CHANGE_TO, + C_COLOR_CHANGE_FROM, + C_COLOR_CHANGE_TO_STICK, + C_COLOR_CHANGE_FROM_STICK +}; + +struct CColorChange +{ + u32 id; + vec4 baseColor; + vec4 color; + s32 timer; + s32 timerMax; + bool isFinished; + enum CColorChangeType type; +}; + +void c_color_change_set(struct CColorChange* self, vec4 baseColor, vec4 color, s32 timerMax, enum CColorChangeType type); +void c_color_change_register(void); diff --git a/src/game/ecs/c_color_collide_delete.c b/src/game/ecs/c_color_collide_delete.c new file mode 100644 index 0000000..998576d --- /dev/null +++ b/src/game/ecs/c_color_collide_delete.c @@ -0,0 +1,130 @@ +/* + * DESCRIPTION: + * Color collide delete component. + * For when one of the player's colored orbs hits an enemy. +*/ + +#include "c_color_collide_delete.h" + +static void delete_effect(struct CColorCollideDelete* self, u32 id); +static void delete_check(struct CColorCollideDelete* self, u32 id); +static void update_f(struct CColorCollideDelete* self); + +/* Visual effect of color collide delete. */ +static void +delete_effect(struct CColorCollideDelete* self, u32 id) +{ + struct CColor* color; + struct CSprite* sprite; + struct CColorChange* colorChange; + struct CScale* scale; + struct CPhysics* collidePhysics; + struct CParticleSpawn* particleSpawn; + u32 particleID; + vec3 position; + + sprite = ecs_get(self->id, ECS_C_SPRITE); + colorChange = ecs_get(self->id, ECS_C_COLOR_CHANGE); + color = ecs_get(self->id, ECS_C_COLOR); + scale = ecs_get(self->id, ECS_C_SCALE); + collidePhysics = ecs_get(id, ECS_C_PHYSICS); + particleSpawn = ecs_get(id, ECS_C_PARTICLE_SPAWN); + + if (!sprite || !colorChange || !scale || !color || !collidePhysics || !particleSpawn) + return; + + c_color_change_set + ( + colorChange, + C_COLOR_VALUES[color->type], + COLOR_OPAQUE, + C_COLOR_COLLIDE_DELETE_COLOR_CHANGE_TIMER_MAX, + C_COLOR_CHANGE_FROM + ); + + c_scale_set + ( + scale, + C_COLOR_COLLIDE_DELETE_SCALE_BASE_VALUE, + C_COLOR_COLLIDE_DELETE_SCALE_VALUE, + C_COLOR_COLLIDE_DELETE_SCALE_TIMER_MAX, + C_COLOR_COLLIDE_DELETE_SCALE_TYPE + ); + + glm_vec3_copy(collidePhysics->position, position); + + c_particle_spawn(particleSpawn, position); + + sound_play(&game.sounds[SOUND_COLLIDE], -1); +} + +/* + * Checks if the color of the collision is the same as this. + * If so, removes it. +*/ +static void +delete_check(struct CColorCollideDelete* self, u32 id) +{ + struct CColor* color; + struct CColor* collideColor; + + color = ecs_get(self->id, ECS_C_COLOR); + collideColor = ecs_get(id, ECS_C_COLOR); + + if (!color || !collideColor) + return; + + if (collideColor->type == color->type) + { + delete_effect(self, id); + self->isCollided = true; + self->collideID = id; + entity_delete(id); + } +} + +/* Draws a color collide delete component. */ +static void +update_f(struct CColorCollideDelete* self) +{ + struct CCircleCollide* circleCollide; + + if (self->isDisabled) + return; + + circleCollide = ecs_get(self->id, ECS_C_CIRCLE_COLLIDE); + + self->isCollided = false; + + if (!circleCollide) + return; + + if (circleCollide->collisions.count == 0) + return; + + for (s32 i = 0; i < (s32)circleCollide->collisions.count; i++) + { + u32* id; + + id = (u32*)vector_get(&circleCollide->collisions, i); + + delete_check(self, *id); + } +} + +/* Registers color collide delete component. */ +void +c_color_collide_delete_register(void) +{ + ecs_register + ( + ECS_C_COLOR_COLLIDE_DELETE, + sizeof(struct CColorCollideDelete), + C_COLOR_COLLIDE_DELETE_LIMIT, + NULL, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_color_collide_delete.h b/src/game/ecs/c_color_collide_delete.h new file mode 100644 index 0000000..bf55fa2 --- /dev/null +++ b/src/game/ecs/c_color_collide_delete.h @@ -0,0 +1,28 @@ +/* + * DESCRIPTION: + * c_color_collide_delete.c header. +*/ + +#pragma once + +#include "c_circle_collide.h" +#include "c_color.h" +#include "c_particle_spawn.h" + +#define C_COLOR_COLLIDE_DELETE_LIMIT 0xFF + +#define C_COLOR_COLLIDE_DELETE_COLOR_CHANGE_TIMER_MAX 30 +#define C_COLOR_COLLIDE_DELETE_SCALE_TIMER_MAX 30 +#define C_COLOR_COLLIDE_DELETE_SCALE_VALUE -1.0f +#define C_COLOR_COLLIDE_DELETE_SCALE_BASE_VALUE 1.0f +#define C_COLOR_COLLIDE_DELETE_SCALE_TYPE C_SCALE_FROM + +struct CColorCollideDelete +{ + u32 id; + bool isDisabled; + bool isCollided; + u32 collideID; +}; + +void c_color_collide_delete_register(void); diff --git a/src/game/ecs/c_contact_damage.c b/src/game/ecs/c_contact_damage.c new file mode 100644 index 0000000..ecc2239 --- /dev/null +++ b/src/game/ecs/c_contact_damage.c @@ -0,0 +1,53 @@ +/* + * DESCRIPTION: + * Contact damage component. +*/ + +#include "c_contact_damage.h" + +static void update_f(struct CContactDamage* self); + +/* Draws a contact damage component. */ +static void +update_f(struct CContactDamage* self) +{ + struct CCircleCollide* circleCollide; + + circleCollide = ecs_get(self->id, ECS_C_CIRCLE_COLLIDE); + + if (!circleCollide) + return; + + for (s32 i = 0; i < (s32)circleCollide->collisions.count; i++) + { + struct CDamage* damage; + u32* id; + + id = (u32*)vector_get(&circleCollide->collisions, i); + + damage = ecs_get(*id, ECS_C_DAMAGE); + + if (!damage || damage->isDisabled) + continue; + + damage->isDamaged = true; + break; + } +} + +/* Registers contact damage component. */ +void +c_contact_damage_register(void) +{ + ecs_register + ( + ECS_C_CONTACT_DAMAGE, + sizeof(struct CContactDamage), + C_CONTACT_DAMAGE_LIMIT, + NULL, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_contact_damage.h b/src/game/ecs/c_contact_damage.h new file mode 100644 index 0000000..0c287a7 --- /dev/null +++ b/src/game/ecs/c_contact_damage.h @@ -0,0 +1,18 @@ +/* + * DESCRIPTION: + * c_contact_damage.c header. +*/ + +#pragma once + +#include "c_circle_collide.h" +#include "c_damage.h" + +#define C_CONTACT_DAMAGE_LIMIT 0xFF + +struct CContactDamage +{ + u32 id; +}; + +void c_contact_damage_register(void); diff --git a/src/game/ecs/c_control.c b/src/game/ecs/c_control.c new file mode 100644 index 0000000..93d49a1 --- /dev/null +++ b/src/game/ecs/c_control.c @@ -0,0 +1,65 @@ +/* + * DESCRIPTION: + * Physics component. +*/ + +#include "c_control.h" + +static void update_f(struct CControl* self); + +/* Draws a control component. */ +static void +update_f(struct CControl* self) +{ + struct CPhysics* physics; + vec2 glMouse; + vec2 glPosition; + f32 distance; + f32 angle; + f32 travel; + + physics = ecs_get(self->id, ECS_C_PHYSICS); + + if (!physics || self->isDisabled) + return; + + window_coords_to_gl(&game.window, game.mouse.position, glMouse); + window_coords_to_gl(&game.window, physics->position, glPosition); + + distance = DISTANCE_2D(glPosition[0], glMouse[0], glPosition[1], glMouse[1]); + + if (distance < self->moveMinimum) + return; + + travel = distance / self->speed; + + angle = ATAN(glPosition[0], glMouse[0], glPosition[1], glMouse[1]); + + physics->velocity[0] += cos(angle) * travel; + physics->velocity[1] += sin(angle) * travel; +} + +/* Sets control component values. */ +void +c_control_set(struct CControl* self, f32 speed, f32 moveMinimum) +{ + self->speed = speed; + self->moveMinimum = moveMinimum; +} + +/* Registers control component. */ +void +c_control_register(void) +{ + ecs_register + ( + ECS_C_CONTROL, + sizeof(struct CControl), + C_CONTROL_LIMIT, + NULL, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_control.h b/src/game/ecs/c_control.h new file mode 100644 index 0000000..3ea2eb1 --- /dev/null +++ b/src/game/ecs/c_control.h @@ -0,0 +1,21 @@ +/* + * DESCRIPTION: + * c_control.c header. +*/ + +#pragma once + +#include "c_physics.h" + +#define C_CONTROL_LIMIT 0xFF + +struct CControl +{ + u32 id; + bool isDisabled; + f32 speed; + f32 moveMinimum; +}; + +void c_control_set(struct CControl* self, f32 speed, f32 moveMinimum); +void c_control_register(void); diff --git a/src/game/ecs/c_damage.c b/src/game/ecs/c_damage.c new file mode 100644 index 0000000..dd15062 --- /dev/null +++ b/src/game/ecs/c_damage.c @@ -0,0 +1,71 @@ +/* + * DESCRIPTION: + * Damage component. +*/ + +#include "c_damage.h" + +static void update_f(struct CDamage* self); + +/* Updates a damage component. */ +static void +update_f(struct CDamage* self) +{ + struct CHealth* health; + struct CFlash* flash; + struct CStun* stun; + + health = ecs_get(self->id, ECS_C_HEALTH); + + self->isDamageUpdate = false; + + if (!health) + return; + + if (self->timer > 0) + { + self->timer--; + self->isDamaged = false; + return; + } + + if (!self->isDamaged || health->isDead) + return; + + self->timer = C_DAMAGE_TIMER; + + flash = ecs_get(self->id, ECS_C_FLASH); + stun = ecs_get(self->id, ECS_C_STUN); + + if (!flash || !stun) + return; + + self->isDamageUpdate = true; + + c_flash_set(flash, game.renderer.clearColor, C_DAMAGE_FLASH_COLOR, C_DAMAGE_TIMER, C_FLASH_STROBE); + + c_stun_set(stun, C_DAMAGE_TIMER); + + health->current--; + + self->isDamaged = false; + + sound_play(&game.sounds[SOUND_HURT], -1); +} + +/* Registers damage component. */ +void +c_damage_register(void) +{ + ecs_register + ( + ECS_C_DAMAGE, + sizeof(struct CDamage), + C_DAMAGE_LIMIT, + NULL, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_damage.h b/src/game/ecs/c_damage.h new file mode 100644 index 0000000..054abe6 --- /dev/null +++ b/src/game/ecs/c_damage.h @@ -0,0 +1,26 @@ +/* + * DESCRIPTION: + * c_damage.c header. +*/ + +#pragma once + +#include "c_health.h" +#include "c_flash.h" +#include "c_stun.h" + +#define C_DAMAGE_LIMIT 0xFF +#define C_DAMAGE_TIMER 18 + +struct CDamage +{ + u32 id; + u32 timer; + bool isDisabled; + bool isDamaged; + bool isDamageUpdate; +}; + +static const vec4 C_DAMAGE_FLASH_COLOR = {1.0f, 0.0f, 0.0f, 1.0f}; + +void c_damage_register(void); diff --git a/src/game/ecs/c_flash.c b/src/game/ecs/c_flash.c new file mode 100644 index 0000000..0963601 --- /dev/null +++ b/src/game/ecs/c_flash.c @@ -0,0 +1,81 @@ +/* + * DESCRIPTION: + * Flash component. +*/ + +#include "c_flash.h" + +static void update_f(struct CFlash* self); + +/* Updates flash component. */ +static void +update_f(struct CFlash* self) +{ + vec4 color; + f32 progress; + + if (self->isFinished) + return; + + progress = (f32)self->timer / self->timerMax; + + glm_vec4_copy(self->color, color); + + switch (self->type) + { + case C_FLASH_VANISH: + glm_vec4_scale(color, progress, color); + break; + case C_FLASH_APPEAR: + glm_vec4_scale(color, (1.0f - progress), color); + break; + case C_FLASH_STROBE: + glm_vec4_scale(color, sin((M_PI * 2) * (progress * 2.0f)), color); + break; + case C_FLASH_CONSTANT: + glm_vec4_copy(self->color, color); + break; + default: + break; + } + + renderer_clear_color_set(&game.renderer, color); + + if (self->timer <= 0) + { + renderer_clear_color_set(&game.renderer, self->baseColor); + self->timer = 0; + self->isFinished = true; + } + else + self->timer--; +} + +/* Sets flash component info. */ +void +c_flash_set(struct CFlash* self, vec4 baseColor, vec4 color, s32 timerMax, enum CFlashType type) +{ + self->timerMax = timerMax; + self->type = type; + glm_vec4_copy(baseColor, self->baseColor); + glm_vec4_copy(color, self->color); + self->timer = self->timerMax; + self->isFinished = false; +} + +/* Registers flash component. */ +void +c_flash_register(void) +{ + ecs_register + ( + ECS_C_FLASH, + sizeof(struct CFlash), + C_FLASH_LIMIT, + NULL, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_flash.h b/src/game/ecs/c_flash.h new file mode 100644 index 0000000..2cc8c76 --- /dev/null +++ b/src/game/ecs/c_flash.h @@ -0,0 +1,33 @@ +/* + * DESCRIPTION: + * c_flash.c header. +*/ + +#pragma once + +#include "entity.h" + +#define C_FLASH_LIMIT 0xFF + +#define C_FLASH_COUNT C_FLASH_STROBE + 1 +enum CFlashType +{ + C_FLASH_VANISH, + C_FLASH_APPEAR, + C_FLASH_STROBE, + C_FLASH_CONSTANT +}; + +struct CFlash +{ + u32 id; + bool isFinished; + enum CFlashType type; + s32 timer; + s32 timerMax; + vec4 baseColor; + vec4 color; +}; + +void c_flash_set(struct CFlash* self, vec4 baseColor, vec4 color, s32 timerMax, enum CFlashType type); +void c_flash_register(void); diff --git a/src/game/ecs/c_game_object.c b/src/game/ecs/c_game_object.c new file mode 100644 index 0000000..1cdba8a --- /dev/null +++ b/src/game/ecs/c_game_object.c @@ -0,0 +1,107 @@ +/* + * DESCRIPTION: + * Game object component. +*/ + +#include "c_game_object.h" + +static void update_f(struct CGameObject* self); + +/* Draws a game object component. */ +static void +update_f(struct CGameObject* self) +{ + struct CPhysics* physics; + struct CSprite* sprite; + + physics = ecs_get(self->id, ECS_C_PHYSICS); + sprite = ecs_get(self->id, ECS_C_SPRITE); + + if (!physics || !sprite) + return; + + glm_vec3_copy(physics->position, sprite->position); +} + +/* Sets game object component to specified values. */ +void +c_game_object_set +( + struct CGameObject* self, + struct Texture texture, + enum ShaderType shader, + enum OriginType origin, + vec2 size, + vec3 position, + vec4 color, + f32 friction, + f32 velocityMax, + f32 radius +) +{ + + struct CPhysics* physics; + struct CSprite* sprite; + struct CCircle* circle; + + physics = ecs_add(self->id, ECS_C_PHYSICS); + sprite = ecs_add(self->id, ECS_C_SPRITE); + circle = ecs_add(self->id, ECS_C_CIRCLE); + ecs_add(self->id, ECS_C_CIRCLE_COLLIDE); + + c_sprite_set(sprite, texture, shader, origin, size, color, position); + c_physics_set(physics, position, friction, velocityMax); + c_circle_set(circle, radius); +} + +/* Sets game object component to specified values, plus additional texture atlas info. */ +void +c_game_object_atlas_set +( + struct CGameObject* self, + struct Texture texture, + enum ShaderType shader, + enum OriginType origin, + s32 frameW, + s32 frameH, + s32 rows, + s32 cols, + vec2 size, + vec3 position, + vec4 color, + f32 friction, + f32 velocityMax, + f32 radius +) +{ + struct CPhysics* physics; + struct CSprite* sprite; + struct CCircle* circle; + + physics = ecs_add(self->id, ECS_C_PHYSICS); + sprite = ecs_add(self->id, ECS_C_SPRITE); + circle = ecs_add(self->id, ECS_C_CIRCLE); + ecs_add(self->id, ECS_C_CIRCLE_COLLIDE); + + c_sprite_atlas_set(sprite, texture, shader, origin, frameW, frameH, rows, cols, size, color, position); + c_physics_set(physics, position, friction, velocityMax); + c_circle_set(circle, radius); +} + + +/* Registers game_object component. */ +void +c_game_object_register(void) +{ + ecs_register + ( + ECS_C_GAME_OBJECT, + sizeof(struct CGameObject), + C_GAME_OBJECT_LIMIT, + NULL, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_game_object.h b/src/game/ecs/c_game_object.h new file mode 100644 index 0000000..65372bb --- /dev/null +++ b/src/game/ecs/c_game_object.h @@ -0,0 +1,51 @@ +/* + * DESCRIPTION: + * c_game_object.c header. +*/ + +#pragma once + +#include "c_circle.h" +#include "c_physics.h" +#include "c_sprite.h" + +#define C_GAME_OBJECT_LIMIT 0xFF + +struct CGameObject +{ + u32 id; +}; + +void c_game_object_register(void); + +void c_game_object_set +( + struct CGameObject* self, + struct Texture texture, + enum ShaderType shader, + enum OriginType origin, + vec2 size, + vec3 position, + vec4 color, + f32 friction, + f32 velocityMax, + f32 radius +); + +void c_game_object_atlas_set +( + struct CGameObject* self, + struct Texture texture, + enum ShaderType shader, + enum OriginType origin, + s32 frameW, + s32 frameH, + s32 rows, + s32 cols, + vec2 size, + vec3 position, + vec4 color, + f32 friction, + f32 velocityMax, + f32 radius +); diff --git a/src/game/ecs/c_health.c b/src/game/ecs/c_health.c new file mode 100644 index 0000000..2ceb7f5 --- /dev/null +++ b/src/game/ecs/c_health.c @@ -0,0 +1,47 @@ +/* + * DESCRIPTION: + * Health component. +*/ + +#include "c_health.h" + +static void update_f(struct CHealth* self); + +/* Draws a health component. */ +static void +update_f(struct CHealth* self) +{ + if (self->current <= 0) + { + self->current = 0; + self->isDead = true; + } + else + self->isDead = false; +} + +/* Sets health component. */ +void +c_health_set(struct CHealth* self, s32 max) +{ + self->max = max; + self->current = self->max; + self->isDead = false; +} + +/* Registers health component. */ +void +c_health_register(void) +{ + ecs_register + ( + ECS_C_HEALTH, + sizeof(struct CHealth), + C_HEALTH_LIMIT, + NULL, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_health.h b/src/game/ecs/c_health.h new file mode 100644 index 0000000..6221c4e --- /dev/null +++ b/src/game/ecs/c_health.h @@ -0,0 +1,21 @@ +/* + * DESCRIPTION: + * c_health.c header. +*/ + +#pragma once + +#include "entity.h" + +#define C_HEALTH_LIMIT 0xFF + +struct CHealth +{ + u32 id; + s32 current; + s32 max; + bool isDead; +}; + +void c_health_set(struct CHealth* self, s32 max); +void c_health_register(void); diff --git a/src/game/ecs/c_move.c b/src/game/ecs/c_move.c new file mode 100644 index 0000000..7cde627 --- /dev/null +++ b/src/game/ecs/c_move.c @@ -0,0 +1,116 @@ +/* + * DESCRIPTION: + * Move component. +*/ + +#include "c_move.h" + +static void add(struct CMove* self); +static void update_f(struct CMove* self); + +static void +add(struct CMove* self) +{ + self->isFinished = true; +} + +/* Updates an move component. */ +static void +update_f(struct CMove* self) +{ + struct CSprite* sprite; + struct CText* text; + f32 progress; + f32 distance; + vec3* position; + vec3 difference; + vec3 step; + vec3 current; + + sprite = ecs_get(self->id, ECS_C_SPRITE); + text = ecs_get(self->id, ECS_C_TEXT); + + if (self->isFinished) + return; + + if (sprite) + position = &sprite->position; + else if (text) + position = &text->position; + else + return; + + progress = (f32)self->timer / self->timerMax; + + switch (self->type) + { + case C_MOVE_TO: + case C_MOVE_TO_STICK: + glm_vec3_copy(self->start, current); + glm_vec3_sub(current, self->end, difference); + glm_vec3_scale(difference, (1.0f - progress), step); + glm_vec3_sub(current, step, current); + glm_vec3_copy(current, *position); + break; + case C_MOVE_FROM: + case C_MOVE_FROM_STICK: + glm_vec3_copy(self->end, current); + glm_vec3_sub(current, self->start, difference); + glm_vec3_scale(difference, (1.0f - progress), step); + glm_vec3_sub(current, step, current); + glm_vec3_copy(current, *position); + break; + default: + break; + } + + self->timer--; + + if (self->timer <= 0) + { + switch (self->type) + { + case C_MOVE_TO: + case C_MOVE_FROM: + glm_vec3_copy(self->start, *position); + break; + case C_MOVE_TO_STICK: + case C_MOVE_FROM_STICK: + default: + break; + } + + self->isFinished = true; + } +} + +/* Sets move component. */ +void +c_move_set(struct CMove* self, vec3 start, vec3 end, s32 timerMax, enum CMoveType type) +{ + glm_vec3_copy(start, self->start); + glm_vec3_copy(end, self->end); + + self->timerMax = timerMax; + self->type = type; + + self->timer = self->timerMax; + self->isFinished = false; +} + +/* Registers move component. */ +void +c_move_register(void) +{ + ecs_register + ( + ECS_C_MOVE, + sizeof(struct CMove), + C_MOVE_LIMIT, + (ECSFunction)add, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_move.h b/src/game/ecs/c_move.h new file mode 100644 index 0000000..fee614b --- /dev/null +++ b/src/game/ecs/c_move.h @@ -0,0 +1,34 @@ +/* + * DESCRIPTION: + * c_move.c header. +*/ + +#pragma once + +#include "c_sprite.h" +#include "c_text.h" + +#define C_MOVE_LIMIT 0xFF + +#define C_MOVE_COUNT C_MOVE_FROM_STICK + 1 +enum CMoveType +{ + C_MOVE_TO, + C_MOVE_FROM, + C_MOVE_TO_STICK, + C_MOVE_FROM_STICK, +}; + +struct CMove +{ + u32 id; + vec3 start; + vec3 end; + s32 timer; + s32 timerMax; + bool isFinished; + enum CMoveType type; +}; + +void c_move_set(struct CMove* self, vec3 start, vec3 end, s32 timerMax, enum CMoveType type); +void c_move_register(void); diff --git a/src/game/ecs/c_orbit.c b/src/game/ecs/c_orbit.c new file mode 100644 index 0000000..6d0732b --- /dev/null +++ b/src/game/ecs/c_orbit.c @@ -0,0 +1,125 @@ +/* + * DESCRIPTION: + * Orbit component; for the follower orbs of the player. +*/ + +#include "c_orbit.h" + +static void object_position_set(struct COrbit* self, u32 id, s32 index); + +static void add(struct COrbit* self); +static void delete(struct COrbit* self); +static void update_f(struct COrbit* self); + +/* Sets the position of a object in orbit. */ +static void +object_position_set(struct COrbit* self, u32 id, s32 index) +{ + struct CPhysics* physics; + struct CRotation* rotation; + struct CPhysics* objectPhysics; + f32 offset; + vec3 position; + + physics = ecs_get(self->id, ECS_C_PHYSICS); + rotation = ecs_get(self->id, ECS_C_ROTATION); + objectPhysics = ecs_get(id, ECS_C_PHYSICS); + + if (!physics || !rotation || !objectPhysics) + return; + + offset = (f32)(RADIANS_MAX / self->objects.count) * index; + + glm_vec3_copy(physics->position, position); + + position[0] -= physics->velocity[0]; + position[1] -= physics->velocity[1]; + + objectPhysics->position[0] = position[0] + (-cos(rotation->angle + offset)) * self->offset; + objectPhysics->position[1] = position[1] + (sin(rotation->angle + offset)) * self->offset; +} + +/* Adds orbit component. */ +static void +add(struct COrbit* self) +{ + vector_init(&self->objects, sizeof(u32), C_ORBIT_GAME_OBJECT_LIMIT); +} + +/* Deletes orbit component. */ +static void +delete(struct COrbit* self) +{ + for (s32 i = 0; i < (s32)self->objects.count; i++) + { + u32* id; + + id = (u32*)vector_get(&self->objects, i); + + entity_delete(*id); + } + + vector_free(&self->objects); +} + +/* Draws a orbit component. */ +static void +update_f(struct COrbit* self) +{ + if (self->objects.count == 0) + return; + + for (s32 i = 0; i < (s32)self->objects.count; i++) + { + u32* id; + + id = (u32*)vector_get(&self->objects, i); + + object_position_set(self, *id, i); + } +} + +/* Given a GameObject id, adds it to the orbit. */ +void +c_orbit_object_add(struct COrbit* self, u32 id) +{ + vector_push(&self->objects, &id); +} + +/* Given a GameObjct id, removes it from orbit. */ +void +c_orbit_object_delete(struct COrbit* self, u32 id) +{ + vector_remove_from_data(&self->objects, &id); +} + +/* Removes all objects from COrbit. */ +void +c_orbit_object_clear(struct COrbit* self, u32 id) +{ + vector_clear(&self->objects); +} + +/* Sets orbit component. */ +void +c_orbit_set(struct COrbit* self, f32 offset) +{ + self->offset = offset; +} + +/* Registers orbit component. */ +void +c_orbit_register(void) +{ + ecs_register + ( + ECS_C_ORBIT, + sizeof(struct COrbit), + C_ORBIT_LIMIT, + (ECSFunction)add, + (ECSFunction)delete, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_orbit.h b/src/game/ecs/c_orbit.h new file mode 100644 index 0000000..d1ce5d3 --- /dev/null +++ b/src/game/ecs/c_orbit.h @@ -0,0 +1,25 @@ +/* + * DESCRIPTION: + * c_orbit.c header. +*/ + +#pragma once + +#include "c_game_object.h" +#include "c_rotation.h" + +#define C_ORBIT_LIMIT 0xFF +#define C_ORBIT_GAME_OBJECT_LIMIT 0xFF + +struct COrbit +{ + u32 id; + struct Vector objects; /* u32; GameObject ID */ + f32 offset; +}; + +void c_orbit_set(struct COrbit* self, f32 offset); +void c_orbit_object_add(struct COrbit* self, u32 id); +void c_orbit_object_delete(struct COrbit* self, u32 id); +void c_orbit_object_clear(struct COrbit* self, u32 id); +void c_orbit_register(void); diff --git a/src/game/ecs/c_particle_spawn.c b/src/game/ecs/c_particle_spawn.c new file mode 100644 index 0000000..c7a8f10 --- /dev/null +++ b/src/game/ecs/c_particle_spawn.c @@ -0,0 +1,71 @@ +/* + * DESCRIPTION: + * ParticleSpawn component. +*/ + +#include "c_particle_spawn.h" + +static f32 spin_speed_get(void); + +static f32 +spin_speed_get(void) +{ + return (RANDOM * (PARTICLE_SPAWN_SPIN_SPEED_MAX - PARTICLE_SPAWN_SPIN_SPEED_MIN) + PARTICLE_SPAWN_SPIN_SPEED_MIN); +} + +/* Spawns a particle at a given location. */ +void +c_particle_spawn(struct CParticleSpawn* self, vec3 position) +{ + u32 lilParticleID; + u32 bigParticleID; + f32 lilParticleSpinSpeed; + f32 bigParticleSpinSpeed; + + lilParticleID = entity_add(); + bigParticleID = entity_add(); + + lilParticleSpinSpeed = spin_speed_get(); + bigParticleSpinSpeed = spin_speed_get(); + + particle_init + ( + lilParticleID, + position, + PARTICLE_SPAWN_LIL_PARTICLE_BASE_COLOR, + COLOR_TRANSPARENT, + PARTICLE_SPAWN_LIL_PARTICLE_SIZE, + PARTICLE_SPAWN_SCALE, + lilParticleSpinSpeed, + PARTICLE_SPAWN_TIMER + ); + + particle_init + ( + bigParticleID, + position, + PARTICLE_SPAWN_BIG_PARTICLE_BASE_COLOR, + COLOR_TRANSPARENT, + PARTICLE_SPAWN_BIG_PARTICLE_SIZE, + PARTICLE_SPAWN_SCALE, + bigParticleSpinSpeed, + PARTICLE_SPAWN_TIMER + ); +} + +/* Registers particle_spawn component. */ +void +c_particle_spawn_register(void) +{ + ecs_register + ( + ECS_C_PARTICLE_SPAWN, + sizeof(struct CParticleSpawn), + C_PARTICLE_SPAWN_LIMIT, + NULL, + NULL, + NULL, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_particle_spawn.h b/src/game/ecs/c_particle_spawn.h new file mode 100644 index 0000000..52318d3 --- /dev/null +++ b/src/game/ecs/c_particle_spawn.h @@ -0,0 +1,28 @@ +/* + * DESCRIPTION: + * c_particle_spawn.c header. +*/ + +#pragma once + +#include "e_particle.h" + +#define C_PARTICLE_SPAWN_LIMIT 0xFF + +#define PARTICLE_SPAWN_SCALE 2.0f +#define PARTICLE_SPAWN_SPIN_SPEED_MIN -0.01f +#define PARTICLE_SPAWN_SPIN_SPEED_MAX 0.01f +#define PARTICLE_SPAWN_TIMER 20 + +static const vec4 PARTICLE_SPAWN_BIG_PARTICLE_BASE_COLOR = {1.0f, 1.0f, 1.0f, 0.5f}; +static const vec4 PARTICLE_SPAWN_LIL_PARTICLE_BASE_COLOR = {1.0f, 1.0f, 1.0f, 1.0f}; +static const vec2 PARTICLE_SPAWN_BIG_PARTICLE_SIZE = {30.0f, 30.0f}; +static const vec2 PARTICLE_SPAWN_LIL_PARTICLE_SIZE = {15.0f, 15.0f}; + +struct CParticleSpawn +{ + u32 id; +}; + +void c_particle_spawn(struct CParticleSpawn* self, vec3 position); +void c_particle_spawn_register(void); diff --git a/src/game/ecs/c_physics.c b/src/game/ecs/c_physics.c new file mode 100644 index 0000000..cc388c6 --- /dev/null +++ b/src/game/ecs/c_physics.c @@ -0,0 +1,47 @@ +/* + * DESCRIPTION: + * Physics component. +*/ + +#include "c_physics.h" + +static void update_f(struct CPhysics* self); + +/* Draws a physics component. */ +static void +update_f(struct CPhysics* self) +{ + glm_vec3_add(self->position, self->velocity, self->position); + glm_vec3_scale(self->velocity, self->friction, self->velocity); + + self->velocity[0] = CLAMP(self->velocity[0], -self->velocityMax, self->velocityMax); + self->velocity[1] = CLAMP(self->velocity[1], -self->velocityMax, self->velocityMax); + self->velocity[2] = CLAMP(self->velocity[2], -self->velocityMax, self->velocityMax); +} + +/* Sets physics component. */ +void +c_physics_set(struct CPhysics* self, vec3 position, f32 friction, f32 velocityMax) +{ + glm_vec3_copy(position, self->position); + + self->friction = friction; + self->velocityMax = velocityMax; +} + +/* Registers physics component. */ +void +c_physics_register(void) +{ + ecs_register + ( + ECS_C_PHYSICS, + sizeof(struct CPhysics), + C_PHYSICS_LIMIT, + NULL, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_physics.h b/src/game/ecs/c_physics.h new file mode 100644 index 0000000..433d1ad --- /dev/null +++ b/src/game/ecs/c_physics.h @@ -0,0 +1,22 @@ +/* + * DESCRIPTION: + * c_physics.c header. +*/ + +#pragma once + +#include "entity.h" + +#define C_PHYSICS_LIMIT 0xFF + +struct CPhysics +{ + u32 id; + f32 velocityMax; + f32 friction; + vec3 position; + vec3 velocity; +}; + +void c_physics_set(struct CPhysics* self, vec3 position, f32 friction, f32 velocityMax); +void c_physics_register(void); diff --git a/src/game/ecs/c_player_atlas_health.c b/src/game/ecs/c_player_atlas_health.c new file mode 100644 index 0000000..18e215a --- /dev/null +++ b/src/game/ecs/c_player_atlas_health.c @@ -0,0 +1,42 @@ +/* + * DESCRIPTION: + * Player atlas health component. + * Changes the player's atlas frame in conjunction with its health. +*/ + +#include "c_player_atlas_health.h" + +static void update_f(struct CPlayerAtlasHealth* self); + +/* Draws a player_atlas_health component. */ +static void +update_f(struct CPlayerAtlasHealth* self) +{ + struct CSprite* sprite; + struct CHealth* health; + + sprite = ecs_get(self->id, ECS_C_SPRITE); + health = ecs_get(self->id, ECS_C_HEALTH); + + if (!sprite || !health) + return; + + sprite->atlas.index = health->max - health->current; +} + +/* Registers player_atlas_health component. */ +void +c_player_atlas_health_register(void) +{ + ecs_register + ( + ECS_C_PLAYER_ATLAS_HEALTH, + sizeof(struct CPlayerAtlasHealth), + C_PLAYER_ATLAS_HEALTH_LIMIT, + NULL, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_player_atlas_health.h b/src/game/ecs/c_player_atlas_health.h new file mode 100644 index 0000000..401d443 --- /dev/null +++ b/src/game/ecs/c_player_atlas_health.h @@ -0,0 +1,18 @@ +/* + * DESCRIPTION: + * c_player_atlas_health.c header. +*/ + +#pragma once + +#include "c_health.h" +#include "c_sprite.h" + +#define C_PLAYER_ATLAS_HEALTH_LIMIT 0xFF + +struct CPlayerAtlasHealth +{ + u32 id; +}; + +void c_player_atlas_health_register(void); diff --git a/src/game/ecs/c_player_death.c b/src/game/ecs/c_player_death.c new file mode 100644 index 0000000..29c8226 --- /dev/null +++ b/src/game/ecs/c_player_death.c @@ -0,0 +1,188 @@ +/* + * DESCRIPTION: + * Player death component. +*/ + +#include "c_player_death.h" + +static void state_set(struct CPlayerDeath* self, enum CPlayerDeathState state); +static void add(struct CPlayerDeath* self); +static void begin(struct CPlayerDeath* self); +static void update_f(struct CPlayerDeath* self); + +/* Sets death state. */ +static void +state_set(struct CPlayerDeath* self, enum CPlayerDeathState state) +{ + struct CScale* scale; + struct CColorChange* colorChange; + + scale = ecs_get(self->id, ECS_C_SCALE); + colorChange = ecs_get(self->id, ECS_C_COLOR_CHANGE); + + self->state = state; + + switch (self->state) + { + case C_PLAYER_DEATH_PULSATE: + self->timer = C_PLAYER_DEATH_PULSATE_TIME; + break; + case C_PLAYER_DEATH_GROW: + c_scale_set + ( + scale, + C_PLAYER_DEATH_GROW_SCALE_BASE_VALUE, + C_PLAYER_DEATH_GROW_SCALE_VALUE, + C_PLAYER_DEATH_GROW_TIME, + C_SCALE_TO_STICK + ); + + c_color_change_set + ( + colorChange, + C_PLAYER_DEATH_GROW_COLOR_CHANGE_BASE_COLOR, + C_PLAYER_DEATH_GROW_COLOR_CHANGE_COLOR, + C_PLAYER_DEATH_GROW_TIME, + C_COLOR_CHANGE_TO_STICK + ); + + self->timer = C_PLAYER_DEATH_GROW_TIME; + break; + case C_PLAYER_DEATH_VANISH: + c_scale_set + ( + scale, + C_PLAYER_DEATH_VANISH_SCALE_BASE_VALUE, + C_PLAYER_DEATH_VANISH_SCALE_VALUE, + C_PLAYER_DEATH_VANISH_TIME, + C_SCALE_TO_STICK + ); + + c_color_change_set + ( + colorChange, + C_PLAYER_DEATH_VANISH_COLOR_CHANGE_BASE_COLOR, + C_PLAYER_DEATH_VANISH_COLOR_CHANGE_COLOR, + C_PLAYER_DEATH_VANISH_TIME, + C_COLOR_CHANGE_TO_STICK + ); + + self->timer = C_PLAYER_DEATH_VANISH_TIME; + break; + case C_PLAYER_DEATH_NONE: + case C_PLAYER_DEATH_END: + default: + break; + } +} + +/* Begins death process. */ +static void +begin(struct CPlayerDeath* self) +{ + struct CRotation* rotation; + struct CControl* control; + struct COrbit* orbit; + struct CPulsate* pulsate; + + control = ecs_get(self->id, ECS_C_CONTROL); + rotation = ecs_get(self->id, ECS_C_ROTATION); + orbit = ecs_get(self->id, ECS_C_ORBIT); + pulsate = ecs_get(self->id, ECS_C_PULSATE); + + if (!control || !rotation || !orbit) + return; + + control->isDisabled = true; + rotation->isDisabled = true; + pulsate->isDisabled = true; + + for (s32 i = 0; i < (s32)orbit->objects.count; i++) + { + struct CTimeDelete* timeDelete; + struct CScale* scale; + struct CColorChange* colorChange; + struct CColorCollideDelete* colorCollideDelete; + struct CSprite* sprite; + u32* id; + + id = (u32*)vector_get(&orbit->objects, i); + + timeDelete = ecs_get(*id, ECS_C_TIME_DELETE); + scale = ecs_get(*id, ECS_C_SCALE); + colorChange = ecs_get(*id, ECS_C_COLOR_CHANGE); + sprite = ecs_get(*id, ECS_C_SPRITE); + colorCollideDelete = ecs_get(*id, ECS_C_COLOR_COLLIDE_DELETE); + + if (!timeDelete || !scale || !colorChange || !sprite || !colorCollideDelete) + continue; + + colorCollideDelete->isDisabled = true; + + c_scale_set + ( + scale, + C_PLAYER_DEATH_FOLLOWER_BASE_SCALE, + C_PLAYER_DEATH_FOLLOWER_SCALE, + C_PLAYER_DEATH_FOLLOWER_TIMER, + C_SCALE_TO + ); + + c_color_change_set + ( + colorChange, + sprite->color, + C_PLAYER_DEATH_FOLLOWER_COLOR, + C_PLAYER_DEATH_FOLLOWER_TIMER, + C_COLOR_CHANGE_TO + ); + + c_time_delete_set(timeDelete, C_PLAYER_DEATH_FOLLOWER_TIMER); + } + + state_set(self, C_PLAYER_DEATH_PULSATE); +} + +/* Adds a CPlayerDeath component. */ +static void +add(struct CPlayerDeath* self) +{ + state_set(self, C_PLAYER_DEATH_NONE); +} + +/* Draws a player_death component. */ +static void +update_f(struct CPlayerDeath* self) +{ + struct CHealth* health; + + health = ecs_get(self->id, ECS_C_HEALTH); + + if (!health || !health->isDead || self->state == C_PLAYER_DEATH_END) + return; + + if (self->state == C_PLAYER_DEATH_NONE) + begin(self); + + self->timer--; + + if (self->timer <= 0) + state_set(self, self->state + 1); +} + +/* Registers player_death component. */ +void +c_player_death_register(void) +{ + ecs_register + ( + ECS_C_PLAYER_DEATH, + sizeof(struct CPlayerDeath), + C_PLAYER_DEATH_LIMIT, + (ECSFunction)add, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_player_death.h b/src/game/ecs/c_player_death.h new file mode 100644 index 0000000..69cbf02 --- /dev/null +++ b/src/game/ecs/c_player_death.h @@ -0,0 +1,52 @@ +/* + * DESCRIPTION: + * c_player_death.c header. +*/ + +#pragma once + +#include "c_color_change.h" +#include "c_color_collide_delete.h" +#include "c_control.h" +#include "c_health.h" +#include "c_orbit.h" +#include "c_pulsate.h" +#include "c_scale.h" +#include "c_time_delete.h" + +#define C_PLAYER_DEATH_LIMIT 0xFF +#define C_PLAYER_DEATH_PULSATE_TIME 20 +#define C_PLAYER_DEATH_GROW_TIME 80 +#define C_PLAYER_DEATH_VANISH_TIME 80 +#define C_PLAYER_DEATH_GROW_SCALE_BASE_VALUE 1.0f +#define C_PLAYER_DEATH_GROW_SCALE_VALUE 3.0f +#define C_PLAYER_DEATH_VANISH_SCALE_BASE_VALUE 3.0f +#define C_PLAYER_DEATH_VANISH_SCALE_VALUE -3.0f +#define C_PLAYER_DEATH_FOLLOWER_SCALE 2.0f +#define C_PLAYER_DEATH_FOLLOWER_BASE_SCALE 1.0f +#define C_PLAYER_DEATH_FOLLOWER_TIMER 30 + +static const vec4 C_PLAYER_DEATH_FOLLOWER_COLOR = {1.0f, 1.0f, 1.0f, 0.0f}; +static const vec4 C_PLAYER_DEATH_GROW_COLOR_CHANGE_BASE_COLOR = {1.0f, 1.0f, 1.0f, 1.0f}; +static const vec4 C_PLAYER_DEATH_GROW_COLOR_CHANGE_COLOR = {1.0f, 0.0f, 0.0f, 0.5f}; +static const vec4 C_PLAYER_DEATH_VANISH_COLOR_CHANGE_BASE_COLOR = {1.0f, 0.0f, 0.0f, 0.5f}; +static const vec4 C_PLAYER_DEATH_VANISH_COLOR_CHANGE_COLOR = {0.0f, 0.0f, 0.0f, 0.0f}; + +#define C_PLAYER_DEATH_STATE_COUNT C_PLAYER_DEATH_END + 1 +enum CPlayerDeathState +{ + C_PLAYER_DEATH_NONE, + C_PLAYER_DEATH_PULSATE, + C_PLAYER_DEATH_GROW, + C_PLAYER_DEATH_VANISH, + C_PLAYER_DEATH_END +}; + +struct CPlayerDeath +{ + u32 id; + enum CPlayerDeathState state; + s32 timer; +}; + +void c_player_death_register(void); diff --git a/src/game/ecs/c_pulsate.c b/src/game/ecs/c_pulsate.c new file mode 100644 index 0000000..3f2f30b --- /dev/null +++ b/src/game/ecs/c_pulsate.c @@ -0,0 +1,62 @@ +/* + * DESCRIPTION: + * Pulsate component. +*/ + +#include "c_pulsate.h" + +static void update_f(struct CPulsate* self); + +/* Updates an pulsate component. */ +static void +update_f(struct CPulsate* self) +{ + struct CSprite* sprite; + f32 progress; + f32 scale; + + sprite = ecs_get(self->id, ECS_C_SPRITE); + + if (!sprite || self->isDisabled) + return; + + progress = (f32)self->timer / self->timerMax; + + sprite->scale = (sin(TAU * progress) * self->value) + self->baseScale; + + self->timer--; + + if (self->timer <= 0) + { + sprite->scale = self->baseScale; + self->timer = self->timerMax; + } +} + +/* Sets pulsate component. */ +void +c_pulsate_set(struct CPulsate* self, f32 baseScale, f32 value, s32 timerMax) +{ + self->baseScale = baseScale; + self->timerMax = timerMax; + self->value = value; + + self->timer = self->timerMax; +} + +/* Registers pulsate component. */ +void +c_pulsate_register(void) +{ + ecs_register + ( + ECS_C_PULSATE, + sizeof(struct CPulsate), + C_PULSATE_LIMIT, + NULL, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_pulsate.h b/src/game/ecs/c_pulsate.h new file mode 100644 index 0000000..19ff32e --- /dev/null +++ b/src/game/ecs/c_pulsate.h @@ -0,0 +1,23 @@ +/* + * DESCRIPTION: + * c_pulsate.c header. +*/ + +#pragma once + +#include "c_sprite.h" + +#define C_PULSATE_LIMIT 0xFF + +struct CPulsate +{ + u32 id; + f32 baseScale; + f32 value; + s32 timer; + s32 timerMax; + bool isDisabled; +}; + +void c_pulsate_set(struct CPulsate* self, f32 baseScale, f32 value, s32 timerMax); +void c_pulsate_register(void); diff --git a/src/game/ecs/c_rotation.c b/src/game/ecs/c_rotation.c new file mode 100644 index 0000000..aa469e2 --- /dev/null +++ b/src/game/ecs/c_rotation.c @@ -0,0 +1,74 @@ +/* + * DESCRIPTION: + * Rotation component. +*/ + +#include "c_rotation.h" + +static void update_f(struct CRotation* self); + +/* Adds a rotation component. */ +static void +add(struct CRotation* self) +{ + self->angle = C_ROTATION_ANGLE_DEFAULT; + self->velocity = C_ROTATION_VELOCITY_DEFAULT; +} + +/* Draws a rotation component. */ +static void +update_f(struct CRotation* self) +{ + if (self->isDisabled) + return; + + if + ( + keyboard_held(&game.keyboard, KEYBOARD_LEFT) || + keyboard_held(&game.keyboard, KEYBOARD_A) + ) + self->velocity += self->speed; + + if + ( + keyboard_held(&game.keyboard, KEYBOARD_RIGHT) || + keyboard_held(&game.keyboard, KEYBOARD_D) + ) + self->velocity -= self->speed; + + self->velocity *= self->friction; + + self->velocity = self->velocity > self->velocityMax ? self->velocityMax : self->velocity; + self->velocity = self->velocity < -self->velocityMax ? -self->velocityMax : self->velocity; + + self->angle += self->velocity; + + self->angle = self->angle > RADIANS_MAX ? RADIANS_MIN : self->angle; + self->angle = self->angle < RADIANS_MIN ? RADIANS_MAX : self->angle; +} + +/* Sets rotation component values. */ +void +c_rotation_set(struct CRotation* self, f32 speed, f32 velocityMax, f32 friction) +{ + self->speed = speed; + self->velocityMax = velocityMax; + self->friction = friction; +} + +/* Registers rotation component. */ +void +c_rotation_register(void) +{ + ecs_register + ( + ECS_C_ROTATION, + sizeof(struct CRotation), + C_ROTATION_LIMIT, + (ECSFunction)add, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_rotation.h b/src/game/ecs/c_rotation.h new file mode 100644 index 0000000..7bfbac6 --- /dev/null +++ b/src/game/ecs/c_rotation.h @@ -0,0 +1,27 @@ +/* + * DESCRIPTION: + * c_rotation.c header. +*/ + +#pragma once + +#include "entity.h" + +#define C_ROTATION_ANGLE_DEFAULT (PI / 2) +#define C_ROTATION_VELOCITY_DEFAULT -2.5f + +#define C_ROTATION_LIMIT 0xFF + +struct CRotation +{ + u32 id; + bool isDisabled; + f32 velocity; + f32 friction; + f32 angle; + f32 speed; + f32 velocityMax; +}; + +void c_rotation_set(struct CRotation* self, f32 speed, f32 speedMax, f32 friction); +void c_rotation_register(void); diff --git a/src/game/ecs/c_scale.c b/src/game/ecs/c_scale.c new file mode 100644 index 0000000..fb6b34c --- /dev/null +++ b/src/game/ecs/c_scale.c @@ -0,0 +1,103 @@ +/* + * DESCRIPTION: + * Scale component. +*/ + +#include "c_scale.h" + +static void add(struct CScale* self); +static void update_f(struct CScale* self); + +static void +add(struct CScale* self) +{ + self->isFinished = true; +} + +/* Updates an scale component. */ +static void +update_f(struct CScale* self) +{ + struct CSprite* sprite; + struct CText* text; + f32 progress; + f32* scale; + + sprite = ecs_get(self->id, ECS_C_SPRITE); + text = ecs_get(self->id, ECS_C_TEXT); + + if (self->isFinished) + return; + + if (sprite) + scale = &sprite->scale; + else if (text) + scale = &text->scale; + else + return; + + progress = (f32)self->timer / self->timerMax; + + switch (self->type) + { + case C_SCALE_TO: + case C_SCALE_TO_STICK: + *scale = self->baseValue + (self->value * (1.0f - progress)); + break; + case C_SCALE_FROM: + case C_SCALE_FROM_STICK: + *scale = self->baseValue + (self->value * progress); + break; + default: + break; + } + + self->timer--; + + if (self->timer <= 0) + { + switch (self->type) + { + case C_SCALE_TO: + case C_SCALE_FROM: + *scale = self->baseValue; + break; + case C_SCALE_TO_STICK: + case C_SCALE_FROM_STICK: + default: + break; + } + + self->isFinished = true; + } +} + +/* Sets scale component. */ +void +c_scale_set(struct CScale* self, f32 baseValue, f32 value, s32 timerMax, enum CScaleType type) +{ + self->value = value; + self->baseValue = baseValue; + self->timerMax = timerMax; + self->type = type; + + self->timer = self->timerMax; + self->isFinished = false; +} + +/* Registers scale component. */ +void +c_scale_register(void) +{ + ecs_register + ( + ECS_C_SCALE, + sizeof(struct CScale), + C_SCALE_LIMIT, + (ECSFunction)add, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_scale.h b/src/game/ecs/c_scale.h new file mode 100644 index 0000000..503803c --- /dev/null +++ b/src/game/ecs/c_scale.h @@ -0,0 +1,35 @@ +/* + * DESCRIPTION: + * c_scale.c header. +*/ + +#pragma once + +#include "c_sprite.h" +#include "c_text.h" + +#define C_SCALE_LIMIT 0xFF +#define C_SCALE_DEFAULT 1.0f + +#define C_SCALE_COUNT C_SCALE_FROM_STICK + 1 +enum CScaleType +{ + C_SCALE_TO, + C_SCALE_FROM, + C_SCALE_TO_STICK, + C_SCALE_FROM_STICK, +}; + +struct CScale +{ + u32 id; + f32 value; + f32 baseValue; + s32 timer; + s32 timerMax; + bool isFinished; + enum CScaleType type; +}; + +void c_scale_set(struct CScale* self, f32 baseValue, f32 value, s32 timerMax, enum CScaleType type); +void c_scale_register(void); diff --git a/src/game/ecs/c_spin.c b/src/game/ecs/c_spin.c new file mode 100644 index 0000000..e418e10 --- /dev/null +++ b/src/game/ecs/c_spin.c @@ -0,0 +1,46 @@ +/* + * DESCRIPTION: + * Spin component. +*/ + +#include "c_spin.h" + +static void update_f(struct CSpin* self); + +/* Updates an spin component. */ +static void +update_f(struct CSpin* self) +{ + struct CSprite* sprite; + + sprite = ecs_get(self->id, ECS_C_SPRITE); + + if (!sprite) + return; + + sprite->rotation += self->speed; +} + +/* Sets spin component. */ +void +c_spin_set(struct CSpin* self, f32 speed) +{ + self->speed = speed; +} + +/* Registers spin component. */ +void +c_spin_register(void) +{ + ecs_register + ( + ECS_C_SPIN, + sizeof(struct CSpin), + C_SPIN_LIMIT, + NULL, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_spin.h b/src/game/ecs/c_spin.h new file mode 100644 index 0000000..1ae9aa9 --- /dev/null +++ b/src/game/ecs/c_spin.h @@ -0,0 +1,19 @@ +/* + * DESCRIPTION: + * c_spin.c header. +*/ + +#pragma once + +#include "c_sprite.h" + +#define C_SPIN_LIMIT 0xFF + +struct CSpin +{ + u32 id; + f32 speed; +}; + +void c_spin_set(struct CSpin* self, f32 speed); +void c_spin_register(void); diff --git a/src/game/ecs/c_sprite.c b/src/game/ecs/c_sprite.c new file mode 100644 index 0000000..ec09457 --- /dev/null +++ b/src/game/ecs/c_sprite.c @@ -0,0 +1,153 @@ +/* + * DESCRIPTION: + * Sprite component. +*/ + +#include "c_sprite.h" + +static void c_sprite_size_get(struct CSprite* self, vec2 size); + +static void add(struct CSprite* self); +static void draw(struct CSprite* self); +static void update_f(struct CSprite* self); + +/* Obtains sprite draw size. */ +static void +c_sprite_size_get(struct CSprite* self, vec2 size) +{ + glm_vec2_copy(self->size, size); + glm_vec2_scale(size, self->scale, size); +} + +/* Adds sprite component. */ +static void +add(struct CSprite* self) +{ + glm_vec4_copy(COLOR_OPAQUE, self->color); + self->scale = C_SPRITE_SCALE_DEFAULT; +} + +/* Updates (fixed) sprite component. */ +static void +update_f(struct CSprite* self) +{ + self->rotation = self->rotation > RADIANS_MAX ? RADIANS_MIN : self->rotation; + self->rotation = self->rotation < RADIANS_MIN ? RADIANS_MAX : self->rotation; +} + +/* Draws a sprite component. */ +static void +draw(struct CSprite* self) +{ + mat4 model; + vec2 size; + vec2 origin; + vec3 position; + vec3 modelOrigin; + + c_sprite_size_get(self, size); + origin_2d_get(self->origin, size, origin); + + position[0] = self->position[0] - origin[0]; + position[1] = self->position[1] - origin[1]; + position[2] = self->position[2]; + + modelOrigin[0] = origin[0]; + modelOrigin[1] = origin[1]; + modelOrigin[2] = 0.0f; + + glm_mat4_identity(model); + glm_translate(model, position); + glm_rotate_at(model, modelOrigin, self->rotation, C_SPRITE_ROTATION_AXIS); + + shader_texture_quad_draw(&self->atlas, self->shader, model, size, self->color); +} + +/* Returns the sprite's containing rectangle. */ +void +c_sprite_rectangle_get(struct CSprite* self, vec4 rectangle) +{ + vec2 size; + vec2 origin; + + c_sprite_size_get(self, size); + origin_2d_get(self->origin, size, origin); + + rectangle[0] = self->position[0] - origin[0]; + rectangle[1] = self->position[1] - origin[1]; + rectangle[2] = rectangle[0] + self->size[0]; + rectangle[3] = rectangle[1] + self->size[1]; +} + +/* Sets sprite component info. */ +void +c_sprite_set +( + struct CSprite* self, + struct Texture texture, + enum ShaderType shader, + enum OriginType origin, + vec2 size, + vec4 color, + vec3 position +) +{ + c_sprite_atlas_set + ( + self, + texture, + shader, + origin, + texture.w, + texture.h, + 1, + 1, + size, + color, + position + ); +} + +/* Sets sprite component info, additionally given atlas rows/columns. */ +void +c_sprite_atlas_set +( + struct CSprite* self, + struct Texture texture, + enum ShaderType shader, + enum OriginType origin, + s32 frameW, + s32 frameH, + s32 rows, + s32 cols, + vec2 size, + vec4 color, + vec3 position +) +{ + self->shader = shader; + self->origin = origin; + + atlas_init(&self->atlas, texture, frameW, frameH, rows, cols); + + glm_vec2_copy(size, self->size); + glm_vec3_copy(position, self->position); + glm_vec4_copy(color, self->color); +} + +/* Registers sprite component. */ +void +c_sprite_register(void) +{ + ecs_register + ( + ECS_C_SPRITE, + sizeof(struct CSprite), + C_SPRITE_LIMIT, + (ECSFunction)add, + NULL, + (ECSFunction)update_f, + NULL, + (ECSFunction)draw + ); +} diff --git a/src/game/ecs/c_sprite.h b/src/game/ecs/c_sprite.h new file mode 100644 index 0000000..7440543 --- /dev/null +++ b/src/game/ecs/c_sprite.h @@ -0,0 +1,58 @@ +/* + * DESCRIPTION: + * c_sprite.c header. +*/ + +#pragma once + +#include "../shader/shader_texture_quad.h" + +#include "entity.h" + +#define C_SPRITE_LIMIT 0xFF +#define C_SPRITE_SCALE_DEFAULT 1.0f + +struct CSprite +{ + u32 id; + struct Atlas atlas; + enum ShaderType shader; + enum OriginType origin; + vec2 size; + vec3 position; + vec4 color; + f32 scale; + f32 rotation; +}; + +static const vec3 C_SPRITE_ROTATION_AXIS = {0.0f, 0.0f, 1.0f}; + +void c_sprite_rectangle_get(struct CSprite* self, vec4 rectangle); + +void c_sprite_set +( + struct CSprite* self, + struct Texture texture, + enum ShaderType shader, + enum OriginType origin, + vec2 size, + vec4 color, + vec3 position +); + +void c_sprite_atlas_set +( + struct CSprite* self, + struct Texture texture, + enum ShaderType shader, + enum OriginType origin, + s32 frameW, + s32 frameH, + s32 rows, + s32 cols, + vec2 size, + vec4 color, + vec3 position +); + +void c_sprite_register(void); diff --git a/src/game/ecs/c_stun.c b/src/game/ecs/c_stun.c new file mode 100644 index 0000000..1a839da --- /dev/null +++ b/src/game/ecs/c_stun.c @@ -0,0 +1,66 @@ +/* + * DESCRIPTION: + * Stun component. +*/ + +#include "c_stun.h" + +static void update_f(struct CStun* self); + +/* Draws a stun component. */ +static void +update_f(struct CStun* self) +{ + struct CPhysics* physics; + struct CControl* control; + struct CRotation* rotation; + struct CHealth* health; + + physics = ecs_get(self->id, ECS_C_PHYSICS); + control = ecs_get(self->id, ECS_C_CONTROL); + rotation = ecs_get(self->id, ECS_C_ROTATION); + health = ecs_get(self->id, ECS_C_HEALTH); + + if (health->isDead || !control || !rotation || !physics || !self->isStun) + return; + + control->isDisabled = true; + rotation->isDisabled = true; + + glm_vec3_zero(physics->velocity); + + self->timer--; + + if (self->timer <= 0) + { + control->isDisabled = false; + rotation->isDisabled = false; + self->isStun = false; + } +} + +/* Sets stun component. */ +void +c_stun_set(struct CStun* self, s32 timerMax) +{ + self->timerMax = timerMax; + self->timer = self->timerMax; + self->isStun = true; +} + +/* Registers stun component. */ +void +c_stun_register(void) +{ + ecs_register + ( + ECS_C_STUN, + sizeof(struct CStun), + C_STUN_LIMIT, + NULL, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_stun.h b/src/game/ecs/c_stun.h new file mode 100644 index 0000000..aff9610 --- /dev/null +++ b/src/game/ecs/c_stun.h @@ -0,0 +1,24 @@ +/* + * DESCRIPTION: + * c_stun.c header. +*/ + +#pragma once + +#include "c_control.h" +#include "c_health.h" +#include "c_physics.h" +#include "c_rotation.h" + +#define C_STUN_LIMIT 0xFF + +struct CStun +{ + u32 id; + s32 timer; + s32 timerMax; + bool isStun; +}; + +void c_stun_set(struct CStun* self, s32 timerMax); +void c_stun_register(void); diff --git a/src/game/ecs/c_text.c b/src/game/ecs/c_text.c new file mode 100644 index 0000000..38c537f --- /dev/null +++ b/src/game/ecs/c_text.c @@ -0,0 +1,284 @@ +/* + * DESCRIPTION: + * Text component. +*/ + +#include "c_text.h" + +static void c_text_free(struct CText* self); +static void c_text_glyph_draw(struct CText* self, struct Texture, vec3 position); + +static void add(struct CText* self); +static void draw(struct CText* self); + +/* Obtains the size of the glyph. */ +static void +c_text_glyph_size_get(struct CText* self, struct Texture texture, vec2 size) +{ + size[0] = texture.w; + size[1] = texture.h; + glm_vec2_scale(size, self->scale, size); +} + +/* Frees glyph textures. */ +static void +c_text_free(struct CText* self) +{ + for (s32 i = 0; i < self->length; i++) + { + struct Texture* texture; + + texture = &self->glyphTextures[i]; + + if (texture->isInit) + texture_free(texture); + } + + memset(&self->glyphTextures, '\0', sizeof(self->glyphTextures)); +} + +/* Draws a glyph. */ +static void +c_text_glyph_draw(struct CText* self, struct Texture texture, vec3 position) +{ + struct Atlas atlas; + mat4 model; + vec2 size; + + c_text_glyph_size_get(self, texture, size); + + glm_mat4_identity(model); + glm_translate(model, position); + + atlas_init(&atlas, texture, texture.w, texture.h, 1, 1); + + shader_texture_quad_draw(&atlas, self->shader, model, size, self->color); +} + +/* Adds text component. */ +static void +add(struct CText* self) +{ + glm_vec4_copy(COLOR_OPAQUE, self->color); + self->scale = C_TEXT_SCALE_DEFAULT; +} + +/* Deletes text component. */ +static void +delete(struct CText* self) +{ + c_text_free(self); +} + +/* Draws a text component. */ +static void +draw(struct CText* self) +{ + char glyph; + char nextGlyph; + f32 advance; + f32 lineW; + f32 offsetX; + f32 kerning; + struct GlyphMetrics glyphMetrics; + vec3 position; + vec4 rectangle; + vec2 origin; + vec2 size; + f32 lineSkip; + f32 lineBegin; + + c_text_rectangle_get(self, rectangle); + + size[0] = rectangle[2] - rectangle[0]; + size[1] = rectangle[3] - rectangle[1]; + + origin_2d_get(self->origin, size, origin); + + position[0] = self->position[0] - origin[0]; + position[1] = self->position[1] - origin[1]; + position[2] = self->position[2]; + + offsetX = 0.0f; + lineW = 0.0f; + + lineBegin = position[0]; + + lineSkip = font_line_skip_get(&self->font) * self->scale; + + for (s32 i = 0; i < self->length; i++) + { + glyph = self->string[i]; + + if + ( + glyph == '\n' || + (glyph == ' ' && (lineW > self->wrap && self->wrap != -1)) + ) + { + position[0] = lineBegin; + position[1] += lineSkip; + + lineW = 0.0f; + + if (glyph == '\n') + continue; + } + + if (i < self->length) + { + nextGlyph = self->string[i + 1]; + kerning = (f32)glyph_kerning_get(&self->font, glyph, nextGlyph); + } + else + kerning = 0.0; + + glyph_metrics_get(&glyphMetrics, &self->font, glyph); + + c_text_glyph_draw(self, self->glyphTextures[i], position); + + advance = glyphMetrics.advance; + + offsetX = advance + kerning; + offsetX *= self->scale; + + position[0] += offsetX; + lineW += offsetX; + } +} + +/* Gets a rectangle the size of all glyphs. */ +void +c_text_rectangle_get(struct CText* self, vec4 rectangle) +{ + char glyph; + char nextGlyph; + f32 lineW; + f32 offsetX; + f32 prevY; + struct GlyphMetrics glyphMetrics; + vec2 origin; + vec2 size; + f32 lineSkip; + f32 kerning; + f32 advance; + + if (self->length <= 0 || self->length > 255) + return; + + lineSkip = font_line_skip_get(&self->font); + lineSkip *= self->scale; + + glyph_metrics_get(&glyphMetrics, &self->font, self->string[0]); + + lineW = 0.0f; + + size[0] = 0.0f; + size[1] = (f32)glyphMetrics.maxY - glyphMetrics.minY; + + for (s32 i = 0; i < self->length; i++) + { + glyph = self->string[i]; + + if + ( + glyph == '\n' || + (glyph == ' ' && (lineW > self->wrap && self->wrap != -1)) + ) + { + size[1] += lineSkip; + lineW = 0.0f; + + if (glyph == '\n') + continue; + } + + if (i < self->length) + { + nextGlyph = self->string[i + 1]; + kerning = (f32)glyph_kerning_get(&self->font, glyph, nextGlyph); + } + else + kerning = 0.0; + + glyph_metrics_get(&glyphMetrics, &self->font, glyph); + + advance = glyphMetrics.advance; + + offsetX = advance + kerning; + offsetX *= self->scale; + + lineW += offsetX; + + if (lineW > size[0]) + size[0] = lineW; + } + + origin_2d_get(self->origin, size, origin); + + rectangle[0] = self->position[0] - origin[0]; + rectangle[1] = self->position[1] - origin[1]; + rectangle[2] = rectangle[0] + size[0]; + rectangle[3] = rectangle[1] + size[1]; +} + +/* Given a string and its length, generates textures for the string. */ +void +c_text_string_set(struct CText* self, char* string, s32 length) +{ + c_text_free(self); + + if (length > C_TEXT_STRING_LIMIT) + return; + + self->length = length; + + memset(self->string, '\0', sizeof(char) * C_TEXT_STRING_LIMIT); + memcpy(self->string, string, sizeof(char) * self->length); + + for (s32 i = 0; i < self->length; i++) + glyph_texture_init(&self->glyphTextures[i], &self->font, (char)string[i]); +} + +/* Sets text component info. */ +void +c_text_set +( + struct CText* self, + enum ShaderType shader, + enum OriginType origin, + struct Font font, + char* string, + s32 length, + s32 wrap, + vec4 color, + vec3 position +) +{ + self->font = font; + self->shader = shader; + self->wrap = wrap; + self->origin = origin; + + glm_vec3_copy(position, self->position); + glm_vec4_copy(color, self->color); + + c_text_string_set(self, string, length); +} + +/* Registers text component. */ +void +c_text_register(void) +{ + ecs_register + ( + ECS_C_TEXT, + sizeof(struct CText), + C_TEXT_LIMIT, + (ECSFunction)add, + (ECSFunction)delete, + NULL, + NULL, + (ECSFunction)draw + ); +} diff --git a/src/game/ecs/c_text.h b/src/game/ecs/c_text.h new file mode 100644 index 0000000..c947598 --- /dev/null +++ b/src/game/ecs/c_text.h @@ -0,0 +1,47 @@ +/* + * DESCRIPTION: + * c_text.c header. +*/ + +#pragma once + +#include "../shader/shader_texture_quad.h" + +#include "entity.h" + +#define C_TEXT_LIMIT 0xFF +#define C_TEXT_STRING_LIMIT 0xFF +#define C_TEXT_SCALE_DEFAULT 1.0f + +struct CText +{ + u32 id; + struct Font font; + struct Texture glyphTextures[C_TEXT_STRING_LIMIT]; + char string[C_TEXT_STRING_LIMIT]; + enum ShaderType shader; + enum OriginType origin; + s32 length; + s32 wrap; + vec3 position; + vec4 color; + f32 scale; +}; + +void c_text_rectangle_get(struct CText* self, vec4 rectangle); +void c_text_string_set(struct CText* self, char* string, s32 length); + +void c_text_set +( + struct CText* self, + enum ShaderType shader, + enum OriginType origin, + struct Font font, + char* string, + s32 length, + s32 wrap, + vec4 color, + vec3 position +); + +void c_text_register(void); diff --git a/src/game/ecs/c_time_delete.c b/src/game/ecs/c_time_delete.c new file mode 100644 index 0000000..62197f2 --- /dev/null +++ b/src/game/ecs/c_time_delete.c @@ -0,0 +1,55 @@ +/* + * DESCRIPTION: + * Time delete component. + * Deletes an entity when the timer elapses. +*/ + +#include "c_time_delete.h" + +static void add(struct CTimeDelete* self); +static void update_f(struct CTimeDelete* self); + +/* Adds a time_delete component. */ +static void +add(struct CTimeDelete* self) +{ + self->isDisabled = true; +} + +/* Draws a time_delete component. */ +static void +update_f(struct CTimeDelete* self) +{ + if (self->isDisabled) + return; + + self->timer--; + + if (self->timer <= 0) + entity_delete(self->id); +} + +/* Sets TimeDelete component. */ +void +c_time_delete_set(struct CTimeDelete* self, s32 timer) +{ + self->timer = timer; + self->isDisabled = false; +} + +/* Registers time_delete component. */ +void +c_time_delete_register(void) +{ + ecs_register + ( + ECS_C_TIME_DELETE, + sizeof(struct CTimeDelete), + C_TIME_DELETE_LIMIT, + (ECSFunction)add, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_time_delete.h b/src/game/ecs/c_time_delete.h new file mode 100644 index 0000000..0f6c2f7 --- /dev/null +++ b/src/game/ecs/c_time_delete.h @@ -0,0 +1,20 @@ +/* + * DESCRIPTION: + * c_time_delete.c header. +*/ + +#pragma once + +#include "entity.h" + +#define C_TIME_DELETE_LIMIT 0xFF + +struct CTimeDelete +{ + u32 id; + s32 timer; + bool isDisabled; +}; + +void c_time_delete_set(struct CTimeDelete* self, s32 timer); +void c_time_delete_register(void); diff --git a/src/game/ecs/c_ui_button.c b/src/game/ecs/c_ui_button.c new file mode 100644 index 0000000..b00d398 --- /dev/null +++ b/src/game/ecs/c_ui_button.c @@ -0,0 +1,106 @@ +/* + * DESCRIPTION: + * UI button component. +*/ + +#include "c_ui_button.h" + +static void update_f(struct CUIButton* self); + +/* Draws a ui_button component. */ +static void +update_f(struct CUIButton* self) +{ + struct CSprite* sprite; + struct CText* text; + struct CColorChange* colorChange; + vec4 rectangle; + + sprite = ecs_get(self->id, ECS_C_SPRITE); + text = ecs_get(self->id, ECS_C_TEXT); + colorChange = ecs_get(self->id, ECS_C_COLOR_CHANGE); + + if (self->isDisabled) + return; + + if (sprite) + c_sprite_rectangle_get(sprite, rectangle); + else if (text) + c_text_rectangle_get(text, rectangle); + else + return; + + if (rectangle_has_point(rectangle, game.mouse.position)) + { + if (self->state != C_UI_BUTTON_HOVER) + { + c_color_change_set + ( + colorChange, + self->selectColor, + self->baseColor, + 1, + C_COLOR_CHANGE_TO_STICK + ); + + if (self->state != C_UI_BUTTON_HELD) + sound_play(&game.sounds[SOUND_HOVER], -1); + + } + + self->state = C_UI_BUTTON_HOVER; + + if (mouse_held(&game.mouse, MOUSE_LEFT)) + { + if (!self->isPressed) + { + sound_play(&game.sounds[SOUND_SELECT], -1); + self->isPressed = true; + } + + self->state = C_UI_BUTTON_HELD; + } + } + else + { + if (self->state != C_UI_BUTTON_IDLE) + { + c_color_change_set + ( + colorChange, + self->baseColor, + self->selectColor, + 1, + C_COLOR_CHANGE_TO_STICK + ); + + self->isPressed = false; + } + self->state = C_UI_BUTTON_IDLE; + } +} + +/* Sets ui button component. */ +void +c_ui_button_set(struct CUIButton* self, vec4 baseColor, vec4 selectColor) +{ + glm_vec4_copy(baseColor, self->baseColor); + glm_vec4_copy(selectColor, self->selectColor); +} + +/* Registers ui_button component. */ +void +c_ui_button_register(void) +{ + ecs_register + ( + ECS_C_UI_BUTTON, + sizeof(struct CUIButton), + C_UI_BUTTON_LIMIT, + NULL, + NULL, + (ECSFunction)update_f, + NULL, + NULL + ); +} diff --git a/src/game/ecs/c_ui_button.h b/src/game/ecs/c_ui_button.h new file mode 100644 index 0000000..ef88fdd --- /dev/null +++ b/src/game/ecs/c_ui_button.h @@ -0,0 +1,30 @@ +/* + * DESCRIPTION: + * c_ui_button.c header. +*/ + +#pragma once + +#include "c_color_change.h" + +#define C_UI_BUTTON_LIMIT 0xFF + +enum CUIButtonState +{ + C_UI_BUTTON_IDLE, + C_UI_BUTTON_HOVER, + C_UI_BUTTON_HELD +}; + +struct CUIButton +{ + u32 id; + vec4 baseColor; + vec4 selectColor; + bool isDisabled; + bool isPressed; + enum CUIButtonState state; +}; + +void c_ui_button_set(struct CUIButton* self, vec4 baseColor, vec4 selectColor); +void c_ui_button_register(void); diff --git a/src/game/ecs/e_enemy.c b/src/game/ecs/e_enemy.c new file mode 100644 index 0000000..d14e378 --- /dev/null +++ b/src/game/ecs/e_enemy.c @@ -0,0 +1,43 @@ +/* + * DESCRIPTION: + * Enemy code. +*/ + +#include "e_enemy.h" + +/* Initializes an enemy. */ +void +enemy_init(u32 id, u32 targetID, enum CColorType colorType, vec3 position, f32 speed) +{ + struct CGameObject* object; + struct CChase* chase; + struct CSpin* spin; + struct CColor* color; + + object = ecs_add(id, ECS_C_GAME_OBJECT); + chase = ecs_add(id, ECS_C_CHASE); + spin = ecs_add(id, ECS_C_SPIN); + color = ecs_add(id, ECS_C_COLOR); + ecs_add(id, ECS_C_CONTACT_DAMAGE); + ecs_add(id, ECS_C_PARTICLE_SPAWN); + + c_game_object_set + ( + object, + game.textures[TEXTURE_ENEMY], + ENEMY_SHADER, + ENEMY_ORIGIN, + ENEMY_SIZE, + position, + C_COLOR_VALUES[colorType], + ENEMY_FRICTION, + ENEMY_VELOCITY_MAX, + ENEMY_RADIUS + ); + + c_chase_set(chase, targetID, speed); + + c_spin_set(spin, ENEMY_SPIN_SPEED); + + c_color_set(color, colorType); +} diff --git a/src/game/ecs/e_enemy.h b/src/game/ecs/e_enemy.h new file mode 100644 index 0000000..1bcc4fa --- /dev/null +++ b/src/game/ecs/e_enemy.h @@ -0,0 +1,24 @@ +/* + * DESCRIPTION: + * e_enemy.c header. +*/ + +#pragma once + +#include "c_chase.h" +#include "c_color.h" +#include "c_game_object.h" +#include "c_spin.h" + +#define ENEMY_FRICTION 0.95f +#define ENEMY_ALPHA_TIMER_MAX 60 +#define ENEMY_RADIUS 16.0f +#define ENEMY_SPIN_SPEED 0.05f +#define ENEMY_VELOCITY_MAX 20.0f +#define ENEMY_CHASE_SPEED 0.015f +#define ENEMY_SHADER SHADER_TEXTURE_QUAD +#define ENEMY_ORIGIN ORIGIN_CENTER + +static const vec2 ENEMY_SIZE = {25.0f, 25.0f}; + +void enemy_init(u32 id, u32 targetID, enum CColorType colorType, vec3 position, f32 speed); diff --git a/src/game/ecs/e_follower.c b/src/game/ecs/e_follower.c new file mode 100644 index 0000000..599dcf1 --- /dev/null +++ b/src/game/ecs/e_follower.c @@ -0,0 +1,57 @@ +/* + * DESCRIPTION: + * Follower code. +*/ + +#include "e_follower.h" + +/* Initialize a player. */ +void +follower_init(u32 id, enum CColorType colorType) +{ + struct CGameObject* object; + struct CColorChange* colorChange; + struct CColor* color; + struct CScale* scale; + + color = ecs_add(id, ECS_C_COLOR); + colorChange = ecs_add(id, ECS_C_COLOR_CHANGE); + object = ecs_add(id, ECS_C_GAME_OBJECT); + scale = ecs_add(id, ECS_C_SCALE); + ecs_add(id, ECS_C_COLOR_COLLIDE_DELETE); + ecs_add(id, ECS_C_TIME_DELETE); + + c_game_object_set + ( + object, + game.textures[TEXTURE_FOLLOWER], + FOLLOWER_SHADER, + FOLLOWER_ORIGIN, + FOLLOWER_SIZE, + FOLLOWER_POSITION, + C_COLOR_VALUES[colorType], + FOLLOWER_FRICTION, + FOLLOWER_VELOCITY_MAX, + FOLLOWER_RADIUS + ); + + c_color_change_set + ( + colorChange, + C_COLOR_VALUES[colorType], + FOLLOWER_COLOR_CHANGE_COLOR, + FOLLOWER_COLOR_CHANGE_TIMER_MAX, + C_COLOR_CHANGE_FROM + ); + + c_scale_set + ( + scale, + FOLLOWER_SCALE_BASE_VALUE, + FOLLOWER_SCALE_VALUE, + FOLLOWER_SCALE_TIMER_MAX, + FOLLOWER_SCALE_TYPE + ); + + c_color_set(color, colorType); +} diff --git a/src/game/ecs/e_follower.h b/src/game/ecs/e_follower.h new file mode 100644 index 0000000..0e68962 --- /dev/null +++ b/src/game/ecs/e_follower.h @@ -0,0 +1,27 @@ +/* + * DESCRIPTION: + * e_follower.c header. +*/ + +#pragma once + +#include "c_color_change.h" +#include "c_color_collide_delete.h" +#include "c_game_object.h" + +#define FOLLOWER_FRICTION 0.95f +#define FOLLOWER_VELOCITY_MAX 5.0f +#define FOLLOWER_COLOR_CHANGE_TIMER_MAX 60 +#define FOLLOWER_RADIUS 30.0f +#define FOLLOWER_SCALE_TIMER_MAX 30 +#define FOLLOWER_SCALE_VALUE -1.0f +#define FOLLOWER_SCALE_BASE_VALUE 1.0f +#define FOLLOWER_SCALE_TYPE C_SCALE_FROM +#define FOLLOWER_SHADER SHADER_TEXTURE_QUAD +#define FOLLOWER_ORIGIN ORIGIN_CENTER + +static const vec2 FOLLOWER_SIZE = {30.0f, 30.0f}; +static const vec3 FOLLOWER_POSITION = {0.0f, 0.0f, 0.0f}; +static const vec4 FOLLOWER_COLOR_CHANGE_COLOR = {1.0f, 1.0f, 1.0f, 0.0f}; + +void follower_init(u32 id, enum CColorType colorType); diff --git a/src/game/ecs/e_logo.c b/src/game/ecs/e_logo.c new file mode 100644 index 0000000..e7aa56a --- /dev/null +++ b/src/game/ecs/e_logo.c @@ -0,0 +1,48 @@ +/* + * DESCRIPTION: + * Menu screen logo. +*/ + +#include "e_logo.h" + +/* Initializes logo. */ +void +logo_init(u32 id) +{ + struct CSprite* sprite; + struct CMove* move; + struct CColorChange* colorChange; + + sprite = ecs_add(id, ECS_C_SPRITE); + move = ecs_add(id, ECS_C_MOVE); + colorChange = ecs_add(id, ECS_C_COLOR_CHANGE); + + c_sprite_set + ( + sprite, + game.textures[TEXTURE_LOGO], + LOGO_SHADER, + LOGO_ORIGIN, + LOGO_SIZE, + LOGO_COLOR_CHANGE_BASE_COLOR, + LOGO_MOVE_START + ); + + c_color_change_set + ( + colorChange, + LOGO_COLOR_CHANGE_BASE_COLOR, + LOGO_COLOR_CHANGE_COLOR, + LOGO_TIMER, + C_COLOR_CHANGE_TO_STICK + ); + + c_move_set + ( + move, + LOGO_MOVE_START, + LOGO_MOVE_END, + LOGO_TIMER, + C_MOVE_TO_STICK + ); +} diff --git a/src/game/ecs/e_logo.h b/src/game/ecs/e_logo.h new file mode 100644 index 0000000..7d162a1 --- /dev/null +++ b/src/game/ecs/e_logo.h @@ -0,0 +1,21 @@ +/* + * DESCRIPTION: + * e_logo.c header. +*/ + +#pragma once + +#include "c_color_change.h" +#include "c_move.h" + +#define LOGO_SHADER SHADER_TEXTURE_QUAD +#define LOGO_ORIGIN ORIGIN_CENTER +#define LOGO_COLOR_CHANGE_BASE_COLOR COLOR_TRANSPARENT +#define LOGO_COLOR_CHANGE_COLOR COLOR_OPAQUE +#define LOGO_TIMER 60 + +static const vec3 LOGO_MOVE_START = {640.0f, 360.0f, 0.0f}; +static const vec3 LOGO_MOVE_END = {640.0f, 300.0f, 0.0f}; +static const vec2 LOGO_SIZE = {512.0f, 512.0f}; + +void logo_init(u32 id); diff --git a/src/game/ecs/e_particle.c b/src/game/ecs/e_particle.c new file mode 100644 index 0000000..01f11c9 --- /dev/null +++ b/src/game/ecs/e_particle.c @@ -0,0 +1,59 @@ +/* + * DESCRIPTION: + * Enemy code. +*/ + +#include "e_particle.h" + +/* Initializes an particle. */ +void +particle_init +( + u32 id, + vec3 position, + vec4 baseColor, + vec4 color, + vec2 size, + f32 scaleValue, + f32 spinSpeed, + s32 timer +) +{ + struct CColorChange* colorChange; + struct CSprite* sprite; + struct CScale* scale; + struct CSpin* spin; + struct CTimeDelete* timeDelete; + + colorChange = ecs_add(id, ECS_C_COLOR_CHANGE); + sprite = ecs_add(id, ECS_C_SPRITE); + scale = ecs_add(id, ECS_C_SCALE); + spin = ecs_add(id, ECS_C_SPIN); + timeDelete = ecs_add(id, ECS_C_TIME_DELETE); + + c_sprite_set + ( + sprite, + game.textures[TEXTURE_PARTICLE], + PARTICLE_SHADER, + PARTICLE_ORIGIN, + size, + COLOR_OPAQUE, + position + ); + + c_spin_set(spin, spinSpeed); + + c_time_delete_set(timeDelete, timer); + + c_scale_set(scale, PARTICLE_SCALE_BASE_VALUE, scaleValue, timer, PARTICLE_SCALE_MODE); + + c_color_change_set + ( + colorChange, + baseColor, + color, + timer, + C_COLOR_CHANGE_TO_STICK + ); +} diff --git a/src/game/ecs/e_particle.h b/src/game/ecs/e_particle.h new file mode 100644 index 0000000..c9cd345 --- /dev/null +++ b/src/game/ecs/e_particle.h @@ -0,0 +1,35 @@ +/* + * DESCRIPTION: + * e_particle.c header. +*/ + +#pragma once + +#include "c_game_object.h" +#include "c_spin.h" +#include "c_time_delete.h" +#include "c_scale.h" +#include "c_color_change.h" + +#define PARTICLE_FRICTION 1.00f +#define PARTICLE_VELOCITY_MAX 1.0f +#define PARTICLE_RADIUS 0.0f +#define PARTICLE_SPIN_SPEED_MIN -0.05f +#define PARTICLE_SPIN_SPEED_MAX 0.05f +#define PARTICLE_SCALE_VALUE 2.0f +#define PARTICLE_SCALE_MODE C_SCALE_TO +#define PARTICLE_SHADER SHADER_TEXTURE_QUAD +#define PARTICLE_SCALE_BASE_VALUE 1.0f +#define PARTICLE_ORIGIN ORIGIN_CENTER + +void particle_init +( + u32 id, + vec3 position, + vec4 baseColor, + vec4 color, + vec2 size, + f32 scaleValue, + f32 spinSpeed, + s32 timer +); diff --git a/src/game/ecs/e_player.c b/src/game/ecs/e_player.c new file mode 100644 index 0000000..30c5e44 --- /dev/null +++ b/src/game/ecs/e_player.c @@ -0,0 +1,76 @@ +/* + * DESCRIPTION: + * Player code. +*/ + +#include "e_player.h" + +/* Adds a follower to orbit the player. */ +void +player_follower_add(u32 id) +{ + struct COrbit* orbit; + u32 followerID; + + orbit = ecs_get(id, ECS_C_ORBIT); + + followerID = entity_add(); + + follower_init(followerID, (enum CColorType)orbit->objects.count); + + c_orbit_object_add(orbit, followerID); +} + +/* Initialize a player. */ +void +player_init(u32 id, vec3 position) +{ + struct CGameObject* object; + struct CControl* control; + struct CRotation* rotation; + struct CHealth* health; + struct COrbit* orbit; + struct CPulsate* pulsate; + + control = ecs_add(id, ECS_C_CONTROL); + health = ecs_add(id, ECS_C_HEALTH); + object = ecs_add(id, ECS_C_GAME_OBJECT); + orbit = ecs_add(id, ECS_C_ORBIT); + pulsate = ecs_add(id, ECS_C_PULSATE); + rotation = ecs_add(id, ECS_C_ROTATION); + ecs_add(id, ECS_C_COLOR_CHANGE); + ecs_add(id, ECS_C_DAMAGE); + ecs_add(id, ECS_C_FLASH); + ecs_add(id, ECS_C_PLAYER_ATLAS_HEALTH); + ecs_add(id, ECS_C_PLAYER_DEATH); + ecs_add(id, ECS_C_SCALE); + ecs_add(id, ECS_C_STUN); + + c_game_object_atlas_set + ( + object, + game.textures[TEXTURE_PLAYER], + PLAYER_SHADER, + PLAYER_ORIGIN, + PLAYER_ATLAS_FRAME_WIDTH, + PLAYER_ATLAS_FRAME_HEIGHT, + PLAYER_ATLAS_ROWS, + PLAYER_ATLAS_COLUMNS, + PLAYER_SIZE, + position, + PLAYER_COLOR, + PLAYER_FRICTION, + PLAYER_VELOCITY_MAX, + PLAYER_RADIUS + ); + + c_control_set(control, PLAYER_CONTROL_SPEED, PLAYER_CONTROL_MOVE_MINIMUM); + + c_rotation_set(rotation, PLAYER_ROTATION_SPEED, PLAYER_ROTATION_SPEED_MAX, PLAYER_ROTATION_FRICTION); + + c_health_set(health, PLAYER_HEALTH_MAX); + + c_orbit_set(orbit, PLAYER_ORBIT_OFFSET); + + c_pulsate_set(pulsate, PLAYER_PULSATE_BASE_SCALE, PLAYER_PULSATE_VALUE, PLAYER_PULSATE_TIMER_MAX); +} diff --git a/src/game/ecs/e_player.h b/src/game/ecs/e_player.h new file mode 100644 index 0000000..0a2457f --- /dev/null +++ b/src/game/ecs/e_player.h @@ -0,0 +1,47 @@ +/* + * DESCRIPTION: + * e_player.c header. +*/ + +#pragma once + +#include "c_control.h" +#include "c_damage.h" +#include "c_flash.h" +#include "c_health.h" +#include "c_orbit.h" +#include "c_player_atlas_health.h" +#include "c_player_death.h" +#include "c_pulsate.h" +#include "c_rotation.h" +#include "c_stun.h" +#include "e_follower.h" + +#define PLAYER_FRICTION 0.70f +#define PLAYER_CONTROL_SPEED 0.01f +#define PLAYER_CONTROL_MOVE_MINIMUM 0.01f +#define PLAYER_VELOCITY_MAX 5.0f +#define PLAYER_ROTATION_SPEED 0.0025f +#define PLAYER_ROTATION_SPEED_MAX 0.05f +#define PLAYER_ROTATION_FRICTION 0.975f +#define PLAYER_FOLLOWER_COUNT 6 +#define PLAYER_RADIUS 20.0f +#define PLAYER_COLOR COLOR_OPAQUE +#define PLAYER_HEALTH_MAX 3 +#define PLAYER_ORBIT_OFFSET 100.0f +#define PLAYER_PULSATE_BASE_SCALE 1.0f +#define PLAYER_PULSATE_VALUE 0.1f +#define PLAYER_PULSATE_TIMER_MAX 20 +#define PLAYER_SHADER SHADER_TEXTURE_QUAD +#define PLAYER_ORIGIN ORIGIN_CENTER + +#define PLAYER_ATLAS_ROWS 1 +#define PLAYER_ATLAS_COLUMNS 4 +#define PLAYER_ATLAS_FRAME_WIDTH 64 +#define PLAYER_ATLAS_FRAME_HEIGHT 64 + +static const vec2 PLAYER_SIZE = {40.0f, 40.0f}; + +void player_follower_add(u32 id); + +void player_init(u32 id, vec3 position); diff --git a/src/game/ecs/e_text.c b/src/game/ecs/e_text.c new file mode 100644 index 0000000..9989cdd --- /dev/null +++ b/src/game/ecs/e_text.c @@ -0,0 +1,40 @@ +/* + * DESCRIPTION: + * Menu screen text. +*/ + +#include "e_text.h" + +/* Initializes text. */ +void +text_init +( + u32 id, + enum OriginType origin, + struct Font font, + char* string, + s32 length, + s32 wrap, + vec4 color, + vec3 position +) +{ + struct CText* text; + + text = ecs_add(id, ECS_C_TEXT); + ecs_add(id, ECS_C_COLOR_CHANGE); + ecs_add(id, ECS_C_SCALE); + + c_text_set + ( + text, + TEXT_SHADER, + origin, + font, + string, + length, + wrap, + color, + position + ); +} diff --git a/src/game/ecs/e_text.h b/src/game/ecs/e_text.h new file mode 100644 index 0000000..dfc871d --- /dev/null +++ b/src/game/ecs/e_text.h @@ -0,0 +1,22 @@ +/* + * DESCRIPTION: + * e_text.c header. +*/ + +#pragma once + +#include "c_text.h" + +#define TEXT_SHADER SHADER_TEXTURE_QUAD + +void text_init +( + u32 id, + enum OriginType origin, + struct Font font, + char* string, + s32 length, + s32 wrap, + vec4 color, + vec3 position +); diff --git a/src/game/ecs/e_ui_button.c b/src/game/ecs/e_ui_button.c new file mode 100644 index 0000000..352fed7 --- /dev/null +++ b/src/game/ecs/e_ui_button.c @@ -0,0 +1,34 @@ +/* + * DESCRIPTION: + * UI button entity. +*/ + +#include "e_ui_button.h" + +/* Initializes UI Button entity. */ +void +ui_button_init +( + u32 id, + enum OriginType origin, + struct Font font, + char* string, + s32 length, + vec4 color, + vec4 selectColor, + vec3 position +) +{ + struct CUIButton* uiButton; + + uiButton = ecs_add(id, ECS_C_UI_BUTTON); + + text_init(id, origin, font, string, length, UI_BUTTON_WRAP, color, position); + + c_ui_button_set + ( + uiButton, + color, + selectColor + ); +} diff --git a/src/game/ecs/e_ui_button.h b/src/game/ecs/e_ui_button.h new file mode 100644 index 0000000..16ca910 --- /dev/null +++ b/src/game/ecs/e_ui_button.h @@ -0,0 +1,25 @@ +/* + * DESCRIPTION: + * e_ui_button.c header. +*/ + +#pragma once + +#include "c_ui_button.h" +#include "e_text.h" + +#define UI_BUTTON_WRAP -1 +#define UI_BUTTON_SHADER SHADER_TEXTURE_QUAD + +void +ui_button_init +( + u32 id, + enum OriginType origin, + struct Font font, + char* string, + s32 length, + vec4 color, + vec4 selectColor, + vec3 position +); diff --git a/src/game/ecs/e_warning.c b/src/game/ecs/e_warning.c new file mode 100644 index 0000000..50953c1 --- /dev/null +++ b/src/game/ecs/e_warning.c @@ -0,0 +1,41 @@ +/* + * DESCRIPTION: + * Warning code. +*/ + +#include "e_warning.h" + +/* Initializes a warning. */ +void +warning_init(u32 id, vec3 position, enum CColorType color) +{ + struct CColorChange* colorChange; + struct CSprite* sprite; + struct CTimeDelete* timeDelete; + + colorChange = ecs_add(id, ECS_C_COLOR_CHANGE); + sprite = ecs_add(id, ECS_C_SPRITE); + timeDelete = ecs_add(id, ECS_C_TIME_DELETE); + + c_sprite_set + ( + sprite, + game.textures[TEXTURE_WARNING], + WARNING_SHADER, + WARNING_ORIGIN, + WARNING_SIZE, + C_COLOR_VALUES[color], + position + ); + + c_color_change_set + ( + colorChange, + C_COLOR_VALUES[color], + COLOR_TRANSPARENT, + WARNING_TIMER, + C_COLOR_CHANGE_TO_STICK + ); + + c_time_delete_set(timeDelete, WARNING_TIMER); +} diff --git a/src/game/ecs/e_warning.h b/src/game/ecs/e_warning.h new file mode 100644 index 0000000..fa20d0a --- /dev/null +++ b/src/game/ecs/e_warning.h @@ -0,0 +1,21 @@ +/* + * DESCRIPTION: + * e_warning.c header. +*/ + +#pragma once + +#include "c_color.h" +#include "c_color_change.h" +#include "c_time_delete.h" + +#define WARNING_FRICTION 1.00f +#define WARNING_VELOCITY_MAX 1.0f +#define WARNING_RADIUS 0.0f +#define WARNING_TIMER 60 +#define WARNING_SHADER SHADER_TEXTURE_QUAD +#define WARNING_ORIGIN ORIGIN_CENTER + +static const vec2 WARNING_SIZE = {32.0f, 32.0f}; + +void warning_init(u32 id, vec3 position, enum CColorType color); diff --git a/src/game/ecs/ecs.c b/src/game/ecs/ecs.c new file mode 100644 index 0000000..cec9651 --- /dev/null +++ b/src/game/ecs/ecs.c @@ -0,0 +1,209 @@ +/* + * DESCRIPTION: + * Entity component system (ECS) functions. +*/ + +#include "entity.h" + +static void ecs_component_function(struct ECSComponentList* list, ECSFunction function); +static void ecs_function(enum ECSFunctionType type); + +/* Uses a function on a component list. */ +static void +ecs_component_function(struct ECSComponentList* list, ECSFunction function) +{ + for (s32 i = 0; i < (s32)list->components.count; i++) + { + void* component; + + component = vector_get(&list->components, i); + + if (!component) + return; + + function(component); + } +} + +/* Executes the specified function on all components. */ +static void +ecs_function(enum ECSFunctionType type) +{ + for (s32 i = 0; i < ECS_C_COUNT; i++) + { + ECSFunction function; + struct ECSComponentList* list; + + list = &game.ecs.lists[i]; + + function = list->system.functions[type]; + + if (function) + ecs_component_function(list, function); + } +} + +/* Registers a component. */ +void +ecs_register +( + enum ECSComponentType type, + size_t size, + u32 limit, + ECSFunction add, + ECSFunction delete, + ECSFunction update_f, + ECSFunction update_v, + ECSFunction draw +) +{ + struct ECSComponentList* list; + + list = &game.ecs.lists[type]; + + memset(list, '\0', sizeof(struct ECSComponentList)); + + list->type = type; + + list->system.functions[ECS_FUNCTION_ADD] = add; + list->system.functions[ECS_FUNCTION_DELETE] = delete; + list->system.functions[ECS_FUNCTION_UPDATE_F] = update_f; + list->system.functions[ECS_FUNCTION_UPDATE_V] = update_v; + list->system.functions[ECS_FUNCTION_DRAW] = draw; + + vector_init(&list->components, size, limit); +} + +/* Unregisters a component. */ +void +ecs_unregister(enum ECSComponentType type) +{ + struct ECSComponentList* list; + + list = &game.ecs.lists[type]; + + vector_free(&list->components); + + memset(list, '\0', sizeof(struct ECSComponentList)); +} + +/* Adds a component to the ECS. */ +void* +ecs_add(u32 id, enum ECSComponentType type) +{ + ECSFunction add; + struct ECSComponentList* list; + void* component; + + list = &game.ecs.lists[type]; + + component = vector_push(&list->components, NULL); + + add = list->system.functions[ECS_FUNCTION_ADD]; + + if (add) + add(component); + + memcpy(component, &id, sizeof(u32)); + + return component; +} + +/* Deletes a component from an ECS. */ +void +ecs_delete(u32 id, enum ECSComponentType type) +{ + ECSFunction delete; + struct ECSComponentList* list; + void* component; + + component = ecs_get(id, type); + + if (!component) + return; + + list = &game.ecs.lists[type]; + + delete = list->system.functions[ECS_FUNCTION_DELETE]; + + if (delete) + delete(component); + + vector_remove_from_data(&list->components, component); +} + +/* Gets a component based on an ID. */ +void* +ecs_get(u32 id, enum ECSComponentType type) +{ + struct ECSComponentList* list; + + list = &game.ecs.lists[type]; + + for (s32 i = 0; i < (s32)list->components.count; i++) + { + u32 componentID; + void* component; + + component = vector_get(&list->components, i); + + /* All components have an ID as the first member of their struct. */ + memcpy(&componentID, component, sizeof(u32)); + + if (componentID == id) + return component; + } + + return NULL; +} + +/* Gets component based on an index instead. */ +void* +ecs_from_index_get(u32 index, enum ECSComponentType type) +{ + struct ECSComponentList* list; + + list = &game.ecs.lists[type]; + + return vector_get(&list->components, index); +} + +/* Removes all components from a given system. */ +void +ecs_clear(enum ECSComponentType type) +{ + struct ECSComponentList* list; + + list = &game.ecs.lists[type]; + + vector_clear(&list->components); +} + +/* Clears all components in the ECS (but does not remove the systems). */ +void +ecs_clear_all(void) +{ + for (s32 i = 0; i < (s32)ECS_C_COUNT; i++) + ecs_clear((enum ECSComponentType)i); +} + +/* Updates (fixed) ECS. */ +void +ecs_update_f(void) +{ + ecs_function(ECS_FUNCTION_UPDATE_F); +} + +/* Updates (variable) ECS. */ +void +ecs_update_v(void) +{ + ecs_function(ECS_FUNCTION_UPDATE_V); +} + +/* Draws ECS. */ +void +ecs_draw(void) +{ + ecs_function(ECS_FUNCTION_DRAW); +} diff --git a/src/game/ecs/ecs.h b/src/game/ecs/ecs.h new file mode 100644 index 0000000..ddf9d42 --- /dev/null +++ b/src/game/ecs/ecs.h @@ -0,0 +1,32 @@ +/* + * DESCRIPTION: + * ecs.c header. +*/ + +#pragma once + +#include "../../GAME.h" + +void ecs_register +( + enum ECSComponentType type, + size_t size, + u32 limit, + ECSFunction add, + ECSFunction delete, + ECSFunction update_f, + ECSFunction update_v, + ECSFunction draw +); + +void ecs_unregister(enum ECSComponentType type); + +void ecs_clear(enum ECSComponentType type); +void ecs_delete(u32 id, enum ECSComponentType type); +void ecs_draw(void); +void ecs_update_f(void); +void ecs_update_v(void); +void* ecs_add(u32 id, enum ECSComponentType type); +void* ecs_from_index_get(u32 index, enum ECSComponentType type); +void* ecs_get(u32 id, enum ECSComponentType type); +void ecs_clear_all(void); diff --git a/src/game/ecs/ecs_register.c b/src/game/ecs/ecs_register.c new file mode 100644 index 0000000..358e777 --- /dev/null +++ b/src/game/ecs/ecs_register.c @@ -0,0 +1,37 @@ +/* + * DESCRIPTION: + * Registers ECS components. +*/ + +#include "ecs_register.h" + +static void ecs_register_all(void); + +/* Registers all components into the ECS. */ +static void +ecs_register_all(void) +{ + for (s32 i = 0; i < ECS_C_COUNT; i++) + { + ECSRegister r; + + r = ECS_REGISTERS[i]; + + r(); + } +} + +/* Initializes ECS. */ +void +ecs_init(void) +{ + ecs_register_all(); +} + +/* Frees ECS. */ +void +ecs_free(void) +{ + for (s32 i = 0; i < ECS_C_COUNT; i++) + ecs_unregister((enum ECSComponentType)i); +} diff --git a/src/game/ecs/ecs_register.h b/src/game/ecs/ecs_register.h new file mode 100644 index 0000000..b642c9a --- /dev/null +++ b/src/game/ecs/ecs_register.h @@ -0,0 +1,66 @@ +/* + * DESCRIPTION: + * ecs_register.c header. +*/ + +#include "c_chase.h" +#include "c_circle.h" +#include "c_circle_collide.h" +#include "c_color.h" +#include "c_color_change.h" +#include "c_color_collide_delete.h" +#include "c_contact_damage.h" +#include "c_control.h" +#include "c_damage.h" +#include "c_flash.h" +#include "c_game_object.h" +#include "c_health.h" +#include "c_move.h" +#include "c_orbit.h" +#include "c_particle_spawn.h" +#include "c_physics.h" +#include "c_player_atlas_health.h" +#include "c_player_death.h" +#include "c_pulsate.h" +#include "c_rotation.h" +#include "c_scale.h" +#include "c_spin.h" +#include "c_sprite.h" +#include "c_stun.h" +#include "c_text.h" +#include "c_time_delete.h" +#include "c_ui_button.h" + +static const ECSRegister ECS_REGISTERS[ECS_C_COUNT] = +{ + c_chase_register, + c_circle_collide_register, + c_circle_register, + c_color_register, + c_color_change_register, + c_color_collide_delete_register, + c_contact_damage_register, + c_control_register, + c_damage_register, + c_flash_register, + c_game_object_register, + c_health_register, + c_move_register, + c_orbit_register, + c_particle_spawn_register, + c_physics_register, + c_player_atlas_health_register, + c_player_death_register, + c_pulsate_register, + c_rotation_register, + c_scale_register, + c_spin_register, + c_sprite_register, + c_stun_register, + c_text_register, + c_time_delete_register, + c_ui_button_register +}; + +void ecs_free(void); +void ecs_init(void); diff --git a/src/game/ecs/entity.c b/src/game/ecs/entity.c new file mode 100644 index 0000000..851ca49 --- /dev/null +++ b/src/game/ecs/entity.c @@ -0,0 +1,28 @@ +/* + * DESCRIPTION: + * Entity functions. +*/ + +#include "entity.h" + +/* Returns a new entity ID. */ +u32 +entity_add(void) +{ + u32 id; + + id = game.ecs.nextID; + + game.ecs.nextID++; + + return id; +} + +/* Removes all components with the specified entity. */ +void +entity_delete(u32 id) +{ + /* Will fail if NULL. */ + for (s32 i = 0; i < ECS_C_COUNT; i++) + ecs_delete(id, (enum ECSComponentType)i); +} diff --git a/src/game/ecs/entity.h b/src/game/ecs/entity.h new file mode 100644 index 0000000..1974708 --- /dev/null +++ b/src/game/ecs/entity.h @@ -0,0 +1,11 @@ +/* + * DESCRIPTION: + * entity.c header. +*/ + +#pragma once + +#include "ecs.h" + +u32 entity_add(void); +void entity_delete(u32 id); diff --git a/src/game/game.c b/src/game/game.c new file mode 100644 index 0000000..a006472 --- /dev/null +++ b/src/game/game.c @@ -0,0 +1,118 @@ +/* + * DESCRIPTION: + * Main game functions. +*/ + +#include "game.h" + +static void game_update_f(void); +static void game_update_v(void); +static void game_draw(void); + +/* Updates the game on a f timestep. */ +static void +game_update_f(void) +{ + if (event_press(&game.event, EVENT_QUIT)) + game.isQuit = true; + + if (keyboard_press(&game.keyboard, KEYBOARD_M)) + { + if (game.isMute) + music_pause(); + else + music_resume(); + + game.isMute = !game.isMute; + } + + event_update(&game.event); + mouse_update(&game.mouse); + keyboard_update(&game.keyboard); + + game_state_update_f(); + + if (game.isPaused) + return; + + ecs_update_f(); +} + +/* Updates game on a variable timestep. */ +static void +game_update_v(void) +{ + window_update(&game.window); + + renderer_update(&game.renderer); + + ecs_update_v(); +} + +/* Draws the game. */ +static void +game_draw(void) +{ + renderer_clear(&game.renderer); + + ecs_draw(); + + renderer_present(&game.renderer); +} +/* Initializes game. */ +void +game_init(void) +{ + memset(&game, '\0', sizeof(struct Game)); + + RANDOM_SEED_SET(time(NULL)); + + glm_vec4_copy(GAME_BOUNDS, game.bounds); + + game_shader_data_init(); + + sdl_init(); + + window_init(&game.window, WINDOW_MENU, WINDOW_SIZE, WINDOW_FLAGS); + + renderer_init(&game.renderer, &game.window, CAMERA_ORTHOGRAPHIC); + renderer_clear_color_set(&game.renderer, RENDERER_CLEAR_COLOR); + + ecs_init(); + + game.state = STATE_MENU; + + game_state_data_init(); + game_state_init(); +} + +/* Frees game resources. */ +void +game_free(void) +{ + game_state_free(); + game_state_data_free(); + + ecs_free(); + + renderer_free(&game.renderer); + window_free(&game.window); + + sdl_quit(); +} + +/* Main game loop. */ +void +game_loop(void) +{ + tick_update(&game.tick); + + while (game.tick.cum > FRAME_DELAY) + { + game_update_f(); + game.tick.cum -= FRAME_DELAY; + } + + game_update_v(); + game_draw(); +} diff --git a/src/game/game.h b/src/game/game.h new file mode 100644 index 0000000..ff4e3fb --- /dev/null +++ b/src/game/game.h @@ -0,0 +1,26 @@ +/* + * DESCRIPTION: + * game.c header. +*/ + +#pragma once + +#include "../engine/sdl.h" + +#include "ecs/ecs_register.h" + +#include "game_state.h" + +#define WINDOW_FLAGS SDL_WINDOW_OPENGL +#define WINDOW_MENU "Orbit+" +#define RENDERER_FLAGS SDL_RENDERER_ACCELERATED +#define FRAME_DELAY 16 + +static const vec4 RENDERER_CLEAR_COLOR = {0.0f, 0.0f, 0.0f, 0.0f}; +static const vec3 CAMERA_POSITION_DEFAULT = {0.0f, 0.0f, 0.0f}; +static const vec2 WINDOW_SIZE = {1280.0f, 720.0f}; +static const vec4 GAME_BOUNDS = {0.0f, 0.0f, 1280.0f, 720.0f}; + +void game_init(void); +void game_free(void); +void game_loop(void); diff --git a/src/game/game_font.c b/src/game/game_font.c new file mode 100644 index 0000000..e471ab1 --- /dev/null +++ b/src/game/game_font.c @@ -0,0 +1,25 @@ +/* + * DESCRIPTION: + * Handles loading/freeing game fonts. +*/ + +#include "game_font.h" + +/* Initializes a game font. */ +void +game_font_init(enum FontType font) +{ + if (font_init(&game.fonts[font], FONT_PATHS[font], FONT_SIZES[font])) + printf("LOADED: %s\n", FONT_PATHS[font]); + else + printf("FAILED: %s\n", FONT_PATHS[font]); +} + +/* Frees a game font. */ +void +game_font_free(enum FontType font) +{ + font_free(&game.fonts[font]); + + printf("FREED: %s\n", FONT_PATHS[font]); +} diff --git a/src/game/game_font.h b/src/game/game_font.h new file mode 100644 index 0000000..45b2fb5 --- /dev/null +++ b/src/game/game_font.h @@ -0,0 +1,23 @@ +/* + * DESCRIPTION: + * game_font.c header. +*/ + +#pragma once + +#include "../GAME.h" + +static const char* FONT_PATHS[FONT_COUNT] = +{ + "res/font/catv.ttf", + "res/font/catv.ttf", +}; + +static const s32 FONT_SIZES[FONT_COUNT] = +{ + 24, + 48 +}; + +void game_font_init(enum FontType font); +void game_font_free(enum FontType font); diff --git a/src/game/game_music.c b/src/game/game_music.c new file mode 100644 index 0000000..fdd160f --- /dev/null +++ b/src/game/game_music.c @@ -0,0 +1,25 @@ +/* + * DESCRIPTION: + * Handles loading/freeing game music. +*/ + +#include "game_music.h" + +/* Initializes a game music. */ +void +game_music_init(enum MusicType music) +{ + if(music_init(&game.music[music], MUSIC_PATHS[music])) + printf("LOADED: %s\n", MUSIC_PATHS[music]); + else + printf("FAILED: %s\n", MUSIC_PATHS[music]); +} + +/* Frees a game music. */ +void +game_music_free(enum MusicType music) +{ + music_free(&game.music[music]); + + printf("FREED: %s\n", MUSIC_PATHS[music]); +} diff --git a/src/game/game_music.h b/src/game/game_music.h new file mode 100644 index 0000000..be187e1 --- /dev/null +++ b/src/game/game_music.h @@ -0,0 +1,16 @@ +/* + * DESCRIPTION: + * game_music.c header. +*/ + +#pragma once + +#include "../GAME.h" + +static const char* MUSIC_PATHS[MUSIC_COUNT] = +{ + "res/mus/ethnica.ogg" +}; + +void game_music_init(enum MusicType music); +void game_music_free(enum MusicType music); diff --git a/src/game/game_shader.c b/src/game/game_shader.c new file mode 100644 index 0000000..d2a42f4 --- /dev/null +++ b/src/game/game_shader.c @@ -0,0 +1,60 @@ +/* + * DESCRIPTION: + * Handles loading/freeing game shaders. +*/ + +#include "game_shader.h" + +static struct ShaderData shaderData[SHADER_COUNT]; + +/* Gets all shader paths and copies their data. */ +void +game_shader_data_init(void) +{ + for (s32 i = 0; i < SHADER_COUNT; i++) + { + if ( + + file_read + ( + (char*)SHADER_PATHS[i].vertexPath, + (char*)shaderData[i].vertex, + SHADER_BUFFER_SIZE + ) + ) + printf("LOADED: %s\n", SHADER_PATHS[i].vertexPath); + else + printf("FAILED: %s\n", SHADER_PATHS[i].vertexPath); + + if ( + file_read + ( + (char*)SHADER_PATHS[i].fragmentPath, + (char*)shaderData[i].fragment, + SHADER_BUFFER_SIZE + ) + ) + printf("LOADED: %s\n", SHADER_PATHS[i].fragmentPath); + else + printf("FAILED: %s\n", SHADER_PATHS[i].fragmentPath); + } +} + +/* Initializes a game shader. */ +void +game_shader_init(enum ShaderType shader) +{ + if (shader_init(&game.shaders[shader], (char*)shaderData[shader].vertex, (char*)shaderData[shader].fragment)) + printf("LOADED: Shader #%i\n", shader); + else + printf("FAILED: Shader #%i\n", shader); +} + +/* Frees a game shader. */ +void +game_shader_free(enum ShaderType shader) +{ + shader_free(&game.shaders[shader]); + + printf("FREED: Shader #%i\n", shader); +} diff --git a/src/game/game_shader.h b/src/game/game_shader.h new file mode 100644 index 0000000..263446c --- /dev/null +++ b/src/game/game_shader.h @@ -0,0 +1,40 @@ +/* + * DESCRIPTION: + * game_shader.c header. +*/ + +#pragma once + +#include "../GAME.h" + +#define SHADER_PATH_SIZE 64 +#define SHADER_BUFFER_SIZE 2048 + +struct ShaderPaths +{ + const char* vertexPath; + const char* fragmentPath; +}; + +struct ShaderData +{ + char vertex[SHADER_BUFFER_SIZE]; + char fragment[SHADER_BUFFER_SIZE]; +}; + +#define SHADER_TEXTURE_QUAD_UNIFORM_MODEL "uModel" +#define SHADER_TEXTURE_QUAD_UNIFORM_PROJECTION "uProjection" +#define SHADER_TEXTURE_QUAD_UNIFORM_VIEW "uView" +#define SHADER_TEXTURE_QUAD_UNIFORM_COLOR "uColor" +#define SHADER_TEXTURE_QUAD_UNIFORM_TEXTURE "uTexture" +static const struct ShaderPaths SHADER_PATHS[SHADER_COUNT] = +{ + { + .vertexPath = "res/shader/textureQuad.vs", + .fragmentPath = "res/shader/textureQuad.fs" + }, +}; + +void game_shader_data_init(void); +void game_shader_init(enum ShaderType shader); +void game_shader_free(enum ShaderType shader); diff --git a/src/game/game_sound.c b/src/game/game_sound.c new file mode 100644 index 0000000..2aaa93e --- /dev/null +++ b/src/game/game_sound.c @@ -0,0 +1,25 @@ +/* + * DESCRIPTION: + * Handles loading/freeing game sounds. +*/ + +#include "game_sound.h" + +/* Initializes a game sound. */ +void +game_sound_init(enum SoundType sound) +{ + if (sound_init(&game.sounds[sound], SOUND_PATHS[sound])) + printf("LOADED: %s\n", SOUND_PATHS[sound]); + else + printf("FAILED: %s\n", SOUND_PATHS[sound]); +} + +/* Frees a game sound. */ +void +game_sound_free(enum SoundType sound) +{ + sound_free(&game.sounds[sound]); + + printf("FREED: %s\n", SOUND_PATHS[sound]); +} diff --git a/src/game/game_sound.h b/src/game/game_sound.h new file mode 100644 index 0000000..008daed --- /dev/null +++ b/src/game/game_sound.h @@ -0,0 +1,21 @@ +/* + * DESCRIPTION: + * game_sound.c header. +*/ + +#pragma once + +#include "../GAME.h" + +static const char* SOUND_PATHS[SOUND_COUNT] = +{ + "res/sfx/collide.ogg", + "res/sfx/hurt.ogg", + "res/sfx/level.ogg", + "res/sfx/warning.ogg", + "res/sfx/hover.ogg", + "res/sfx/select.ogg", +}; + +void game_sound_init(enum SoundType sound); +void game_sound_free(enum SoundType sound); diff --git a/src/game/game_state.c b/src/game/game_state.c new file mode 100644 index 0000000..c5bb2b1 --- /dev/null +++ b/src/game/game_state.c @@ -0,0 +1,277 @@ +/* + * DESCRIPTION: + * Handles game state. +*/ + +#include "game_state.h" + +static void game_state_change(enum StateType state); +static void game_state_texture_init(struct StateData* stateData); +static void game_state_texture_free(struct StateData* stateData); +static void game_state_sound_init(struct StateData* stateData); +static void game_state_sound_free(struct StateData* stateData); +static void game_state_music_init(struct StateData* stateData); +static void game_state_music_free(struct StateData* stateData); +static void game_state_shader_init(struct StateData* stateData); +static void game_state_shader_free(struct StateData* stateData); +static void game_state_font_init(struct StateData* stateData); +static void game_state_font_free(struct StateData* stateData); + +/* Inits state shaders. */ +static void +game_state_shader_init(struct StateData* stateData) +{ + for (s32 i = 0; i < stateData->shaderCount; i++) + { + enum ShaderType type; + + type = stateData->shaders[i]; + + game_shader_init(type); + } +} + +/* Frees state shaders. */ +static void +game_state_shader_free(struct StateData* stateData) +{ + for (s32 i = 0; i < stateData->shaderCount; i++) + { + enum ShaderType type; + + type = stateData->shaders[i]; + + game_shader_free(type); + } +} + +/* Inits state textures. */ +static void +game_state_texture_init(struct StateData* stateData) +{ + for (s32 i = 0; i < stateData->textureCount; i++) + { + enum TextureType type; + + type = stateData->textures[i]; + + game_texture_init(type); + } +} + +/* Frees state textures. */ +static void +game_state_texture_free(struct StateData* stateData) +{ + for (s32 i = 0; i < stateData->textureCount; i++) + { + enum TextureType type; + + type = stateData->textures[i]; + + game_texture_free(type); + } +} + +/* Inits state sounds. */ +static void +game_state_sound_init(struct StateData* stateData) +{ + for (s32 i = 0; i < stateData->soundCount; i++) + { + enum SoundType type; + + type = stateData->sounds[i]; + + game_sound_init(type); + } +} + +/* Frees state sounds. */ +static void +game_state_sound_free(struct StateData* stateData) +{ + for (s32 i = 0; i < stateData->soundCount; i++) + { + enum SoundType type; + + type = stateData->sounds[i]; + + game_sound_free(type); + } +} + +/* Inits state music. */ +static void +game_state_music_init(struct StateData* stateData) +{ + for (s32 i = 0; i < stateData->musicCount; i++) + { + enum MusicType type; + + type = stateData->music[i]; + + game_music_init(type); + } +} + +/* Frees state music. */ +static void +game_state_music_free(struct StateData* stateData) +{ + for (s32 i = 0; i < stateData->musicCount; i++) + { + enum MusicType type; + + type = stateData->music[i]; + + game_music_free(type); + } +} + +/* Inits state font. */ +static void +game_state_font_init(struct StateData* stateData) +{ + for (s32 i = 0; i < stateData->fontCount; i++) + { + enum FontType type; + + type = stateData->fonts[i]; + + game_font_init(type); + } +} + +/* Frees state font. */ +static void +game_state_font_free(struct StateData* stateData) +{ + for (s32 i = 0; i < stateData->fontCount; i++) + { + enum FontType type; + + type = stateData->fonts[i]; + + game_font_free(type); + } +} + +/* Changes state. */ +void +game_state_change(enum StateType state) +{ + game_state_free(); + game_state_data_free(); + ecs_clear_all(); + + game.state = state; + + game_state_data_init(); + game_state_init(); +} + +/* Initializes state data. */ +void +game_state_data_init(void) +{ + struct StateData stateData; + + stateData = STATE_DATA[game.state]; + + game_state_shader_init(&stateData); + game_state_texture_init(&stateData); + game_state_sound_init(&stateData); + game_state_music_init(&stateData); + game_state_font_init(&stateData); +} + +/* Initializes state data. */ +void +game_state_data_free(void) +{ + struct StateData stateData; + + stateData = STATE_DATA[game.state]; + + game_state_shader_free(&stateData); + game_state_texture_free(&stateData); + game_state_sound_free(&stateData); + game_state_music_free(&stateData); + game_state_font_free(&stateData); +} + +/* Initializes the specified game state. */ +void +game_state_init(void) +{ + switch (game.state) + { + case STATE_MENU: + menu_init(&game.menu); + break; + case STATE_PLAY: + play_init(&game.play); + break; + case STATE_RESULTS: + results_init(&game.results); + break; + default: + break; + } +} + +/* Updates game state. */ +void +game_state_update_f(void) +{ + switch (game.state) + { + case STATE_MENU: + menu_update_f(&game.menu); + + if (game.menu.isStart) + game_state_change(STATE_PLAY); + + break; + case STATE_PLAY: + play_update_f(&game.play); + + if (game.play.isOver) + { + game.score = game.play.score; + game_state_change(STATE_RESULTS); + } + + break; + case STATE_RESULTS: + results_update_f(&game.results); + + if (game.results.isMenu) + game_state_change(STATE_MENU); + + break; + default: + break; + } +} + +/* Frees game state. */ +void +game_state_free(void) +{ + switch (game.state) + { + case STATE_MENU: + menu_free(&game.menu); + break; + case STATE_PLAY: + play_free(&game.play); + break; + case STATE_RESULTS: + results_free(&game.results); + break; + default: + break; + } +} diff --git a/src/game/game_state.h b/src/game/game_state.h new file mode 100644 index 0000000..0a2106b --- /dev/null +++ b/src/game/game_state.h @@ -0,0 +1,76 @@ +/* + * DESCRIPTION: + * game_state.c header. +*/ + +#pragma once + +#include "state/s_play.h" +#include "state/s_menu.h" +#include "state/s_results.h" + +#include "game_font.h" +#include "game_music.h" +#include "game_shader.h" +#include "game_sound.h" +#include "game_texture.h" + +struct StateData +{ + enum FontType* fonts; + enum MusicType* music; + enum ShaderType* shaders; + enum SoundType* sounds; + enum TextureType* textures; + s32 fontCount; + s32 musicCount; + s32 shaderCount; + s32 soundCount; + s32 textureCount; +}; + +static const struct StateData STATE_DATA[STATE_COUNT] = +{ + { + .textures = STATE_MENU_TEXTURES, + .textureCount = STATE_MENU_TEXTURE_COUNT, + .sounds = STATE_MENU_SOUNDS, + .soundCount = STATE_MENU_SOUND_COUNT, + .music = NULL, + .musicCount = 0, + .shaders = STATE_MENU_SHADERS, + .shaderCount = STATE_MENU_SHADER_COUNT, + .fonts = STATE_MENU_FONTS, + .fontCount = STATE_MENU_FONT_COUNT + }, + { + .textures = STATE_PLAY_TEXTURES, + .textureCount = STATE_PLAY_TEXTURE_COUNT, + .sounds = STATE_PLAY_SOUNDS, + .soundCount = STATE_PLAY_SOUND_COUNT, + .music = STATE_PLAY_MUSIC, + .musicCount = STATE_PLAY_MUSIC_COUNT, + .shaders = STATE_PLAY_SHADERS, + .shaderCount = STATE_PLAY_SHADER_COUNT, + .fonts = STATE_PLAY_FONTS, + .fontCount = STATE_PLAY_FONT_COUNT + }, + { + .textures = NULL, + .textureCount = 0, + .sounds = STATE_RESULTS_SOUNDS, + .soundCount = STATE_RESULTS_SOUND_COUNT, + .music = NULL, + .musicCount = 0, + .shaders = STATE_RESULTS_SHADERS, + .shaderCount = STATE_RESULTS_SHADER_COUNT, + .fonts = STATE_RESULTS_FONTS, + .fontCount = STATE_RESULTS_FONT_COUNT + } +}; + +void game_state_data_init(void); +void game_state_data_free(void); +void game_state_init(void); +void game_state_free(void); +void game_state_update_f(void); diff --git a/src/game/game_texture.c b/src/game/game_texture.c new file mode 100644 index 0000000..643dabf --- /dev/null +++ b/src/game/game_texture.c @@ -0,0 +1,25 @@ +/* + * DESCRIPTION: + * Handles loading/freeing game textures. +*/ + +#include "game_texture.h" + +/* Initializes a game texture. */ +void +game_texture_init(enum TextureType texture) +{ + if (texture_init(&game.textures[texture], TEXTURE_PATHS[texture])) + printf("LOADED: %s\n", TEXTURE_PATHS[texture]); + else + printf("FAILED: %s\n", TEXTURE_PATHS[texture]); +} + +/* Frees a game texture. */ +void +game_texture_free(enum TextureType texture) +{ + texture_free(&game.textures[texture]); + + printf("FREED: %s\n", TEXTURE_PATHS[texture]); +} diff --git a/src/game/game_texture.h b/src/game/game_texture.h new file mode 100644 index 0000000..17e6d48 --- /dev/null +++ b/src/game/game_texture.h @@ -0,0 +1,21 @@ +/* + * DESCRIPTION: + * game_texture.c header. +*/ + +#pragma once + +#include "../GAME.h" + +static const char* TEXTURE_PATHS[TEXTURE_COUNT] = +{ + "res/gfx/player.png", + "res/gfx/follower.png", + "res/gfx/enemy.png", + "res/gfx/particle.png", + "res/gfx/warning.png", + "res/gfx/logo.png" +}; + +void game_texture_init(enum TextureType texture); +void game_texture_free(enum TextureType texture); diff --git a/src/game/shader/shader_texture_quad.c b/src/game/shader/shader_texture_quad.c new file mode 100644 index 0000000..3d056a2 --- /dev/null +++ b/src/game/shader/shader_texture_quad.c @@ -0,0 +1,63 @@ +/* + * DESCRIPTION: + * Rendering with SHADER_TEXTER_QUAD. +*/ + +#include "shader_texture_quad.h" + +/* Draw function for. */ +void +shader_texture_quad_draw(struct Atlas* atlas, enum ShaderType type, mat4 model, vec2 size, vec4 color) +{ + struct Shader* shader; + struct Renderer* renderer; + vec2 uvMin; + vec2 uvMax; + + shader = &game.shaders[type]; + renderer = &game.renderer; + + atlas_uv_get(atlas, uvMin, uvMax); + + f32 verticies[4][5] = + { + {0.0f , 0.0f , 0.0f, uvMin[0], uvMin[1]}, + {0.0f , size[1], 0.0f, uvMin[0], uvMax[1]}, + {size[0], size[1], 0.0f, uvMax[0], uvMax[1]}, + {size[0], 0.0f , 0.0f, uvMax[0], uvMin[1]}, + }; + + u32 indices[2][3] = + { + {1, 2, 3}, + {0, 1, 3} + }; + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + renderer_shader_use(&game.renderer, shader); + + shader_uniform_mat4_set(shader, SHADER_TEXTURE_QUAD_UNIFORM_VIEW, renderer->camera.view); + shader_uniform_mat4_set(shader, SHADER_TEXTURE_QUAD_UNIFORM_PROJECTION, renderer->camera.projection); + shader_uniform_mat4_set(shader, SHADER_TEXTURE_QUAD_UNIFORM_MODEL, model); + shader_uniform_vec4_set(shader, SHADER_TEXTURE_QUAD_UNIFORM_COLOR, color); + shader_uniform_texture_set(shader, SHADER_TEXTURE_QUAD_UNIFORM_TEXTURE, &atlas->texture, 0); + + vao_bind(&game.renderer.vao); + + vbo_bind(&game.renderer.vbo); + vbo_buffer(&game.renderer.vbo, sizeof(verticies), verticies); + + vbo_bind(&game.renderer.ebo); + vbo_buffer(&game.renderer.ebo, sizeof(indices), indices); + + vertex_attribute_set(0, 3, GL_FLOAT, 5 * sizeof(f32), 0); + vertex_attribute_set(1, 2, GL_FLOAT, 5 * sizeof(f32), 3 * sizeof(f32)); + + vao_bind(&game.renderer.vao); + + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + + vao_unbind(); +} diff --git a/src/game/shader/shader_texture_quad.h b/src/game/shader/shader_texture_quad.h new file mode 100644 index 0000000..f954207 --- /dev/null +++ b/src/game/shader/shader_texture_quad.h @@ -0,0 +1,8 @@ +/* + * DESCRIPTION: + * shader_draw.c header. +*/ + +#include "../game_shader.h" + +void shader_texture_quad_draw(struct Atlas* atlas, enum ShaderType type, mat4 model, vec2 size, vec4 color); diff --git a/src/game/state/STATE_TYPES.h b/src/game/state/STATE_TYPES.h new file mode 100644 index 0000000..085b060 --- /dev/null +++ b/src/game/state/STATE_TYPES.h @@ -0,0 +1,51 @@ +/* + * DESCRIPTION: + * Game state types. +*/ + +#pragma once + +#include "../../util/UTIL.h" + +#define STATE_COUNT STATE_RESULTS + 1 +enum StateType +{ + STATE_MENU, + STATE_PLAY, + STATE_RESULTS +}; + +struct Play +{ + u32 playerID; + u32 scoreID; + u32 levelID; + u32 messageID; + struct Vector enemies; /* entity id */ + u32 score; + u32 levelTimer; + u32 level; + s32 spawnTimer; + s32 startTimer; + vec4 bounds; + bool isOver; + bool isSpawn; + bool isStart; +}; + +struct Menu +{ + u32 logoID; + u32 startID; + u32 creditsID; + bool isMenuDone; + bool isLogoDone; + bool isStart; +}; + +struct Results +{ + u32 scoreID; + u32 menuID; + bool isMenu; +}; diff --git a/src/game/state/s_menu.c b/src/game/state/s_menu.c new file mode 100644 index 0000000..e614370 --- /dev/null +++ b/src/game/state/s_menu.c @@ -0,0 +1,141 @@ +/* + * DESCRIPTION: + * Menu game state. +*/ + +#include "s_menu.h" + +static void menu_text_color_change(struct Menu* self, struct CText* text); +static void menu_button_color_update(struct Menu* self); +static void menu_button_update(struct Menu* self); + +/* Changes the color of each text entity on the menu. */ +static void +menu_text_color_change(struct Menu* self, struct CText* text) +{ + struct CColorChange* colorChange; + + colorChange = ecs_get(text->id, ECS_C_COLOR_CHANGE); + + c_color_change_set + ( + colorChange, + MENU_TEXT_COLOR_CHANGE_BASE_COLOR, + MENU_TEXT_COLOR, + MENU_TEXT_COLOR_CHANGE_TIMER, + MENU_TEXT_COLOR_CHANGE_TYPE + ); +} + +/* Updates menu buttons. */ +static void +menu_button_color_update(struct Menu* self) +{ + if (self->isMenuDone) + return; + + struct CColorChange* colorChange; + + colorChange = ecs_get(self->logoID, ECS_C_COLOR_CHANGE); + + if (colorChange->isFinished) + self->isLogoDone = true; + + if (self->isLogoDone) + { + struct CText* startText; + struct CText* creditsText; + struct CUIButton* startUIButton; + startText = ecs_get(self->startID, ECS_C_TEXT); + creditsText = ecs_get(self->creditsID, ECS_C_TEXT); + startUIButton = ecs_get(self->startID, ECS_C_UI_BUTTON); + + menu_text_color_change(self, startText); + menu_text_color_change(self, creditsText); + + startUIButton->isDisabled = false; + + self->isMenuDone = true; + } +} + +/* Updates buttons. */ +static void +menu_button_update(struct Menu* self) +{ + struct CUIButton* startUIButton; + + startUIButton = ecs_get(self->startID, ECS_C_UI_BUTTON); + + if (startUIButton->isPressed) + self->isStart = true; + + if (keyboard_press(&game.keyboard, KEYBOARD_SPACE)) + self->isStart = true; +} + +/* Initializes menu. */ +void +menu_init(struct Menu* self) +{ + struct CUIButton* startUIButton; + struct CText* startText; + struct CText* creditsText; + + memset(self, '\0', sizeof(struct Menu)); + + self->logoID = entity_add(); + self->startID = entity_add(); + self->creditsID = entity_add(); + + logo_init(self->logoID); + + ui_button_init + ( + self->startID, + MENU_START_ORIGIN, + game.fonts[FONT_BIG], + MENU_START_STRING, + strlen(MENU_START_STRING), + MENU_TEXT_COLOR, + MENU_TEXT_SELECT_COLOR, + MENU_START_POSITION + ); + + text_init + ( + self->creditsID, + MENU_CREDITS_ORIGIN, + game.fonts[FONT_SMALL], + MENU_CREDITS_STRING, + strlen(MENU_CREDITS_STRING), + MENU_CREDITS_WRAP, + MENU_TEXT_COLOR, + MENU_CREDITS_POSITION + ); + + startUIButton = ecs_get(self->startID, ECS_C_UI_BUTTON); + startText = ecs_get(self->startID, ECS_C_TEXT); + creditsText = ecs_get(self->creditsID, ECS_C_TEXT); + + startText->color[3] = 0.0f; + creditsText->color[3] = 0.0f; + + startUIButton->isDisabled = true; +} + +/* Updates menu. */ +void +menu_update_f(struct Menu* self) +{ + menu_button_color_update(self); + menu_button_update(self); +} + +/* Frees menu. */ +void +menu_free(struct Menu* self) +{ + entity_delete(self->startID); + entity_delete(self->logoID); +} diff --git a/src/game/state/s_menu.h b/src/game/state/s_menu.h new file mode 100644 index 0000000..844af21 --- /dev/null +++ b/src/game/state/s_menu.h @@ -0,0 +1,55 @@ +/* + * DESCRIPTION: + * s_menu.c header. +*/ + +#pragma once + +#include "../ecs/c_color.h" +#include "../ecs/e_logo.h" +#include "../ecs/e_ui_button.h" + +#define MENU_TEXT_SELECT_COLOR COLOR_OPAQUE +#define MENU_TEXT_COLOR C_COLOR_VALUES[0] +#define MENU_TEXT_COLOR_CHANGE_BASE_COLOR COLOR_TRANSPARENT +#define MENU_TEXT_COLOR_CHANGE_TIMER 60 +#define MENU_TEXT_COLOR_CHANGE_TYPE C_COLOR_CHANGE_TO_STICK + +#define MENU_START_ORIGIN ORIGIN_CENTER +#define MENU_START_STRING "Start" +static const vec3 MENU_START_POSITION = {640.0f, 650.0f, 0.0f}; + +#define MENU_CREDITS_STRING "programming/art: Shweet\nconcept/sound: Jiggmin\nmusic: \"Ethnica\" by NemesisTheory" +#define MENU_CREDITS_ORIGIN ORIGIN_BOTTOM_LEFT +#define MENU_CREDITS_WRAP -1 +static const vec3 MENU_CREDITS_POSITION = {20.0f, 700.0f, 0.0f}; + +#define STATE_MENU_TEXTURE_COUNT 1 +static const enum TextureType STATE_MENU_TEXTURES[STATE_MENU_TEXTURE_COUNT] = +{ + TEXTURE_LOGO +}; + +#define STATE_MENU_SOUND_COUNT 2 +static const enum SoundType STATE_MENU_SOUNDS[STATE_MENU_SOUND_COUNT] = +{ + SOUND_HOVER, + SOUND_SELECT +}; + +#define STATE_MENU_FONT_COUNT 2 +static const enum FontType STATE_MENU_FONTS[STATE_MENU_FONT_COUNT] = +{ + FONT_SMALL, + FONT_BIG +}; + +#define STATE_MENU_SHADER_COUNT 1 +static const enum ShaderType STATE_MENU_SHADERS[STATE_MENU_SHADER_COUNT] = +{ + SHADER_TEXTURE_QUAD +}; + +void menu_init(struct Menu* self); +void menu_update_f(struct Menu* self); +void menu_free(struct Menu* self); diff --git a/src/game/state/s_play.c b/src/game/state/s_play.c new file mode 100644 index 0000000..d462f70 --- /dev/null +++ b/src/game/state/s_play.c @@ -0,0 +1,449 @@ +/* + * DESCRIPTION: + * Main gameplay state. +*/ + +#include "s_play.h" + +static s32 play_level_timer_get(struct Play* self); +static s32 play_spawn_timer_get(struct Play* self); +static void play_color_collide_delete_update(struct Play* self, struct CColorCollideDelete* colorCollideDelete); +static void play_damage_update(struct Play* self); +static void play_death_update(struct Play* self); +static void play_enemy_add(struct Play* self); +static void play_enemy_clear(struct Play* self, bool isParticle); +static void play_level_increment(struct Play* self); +static void play_score_set(struct Play* self, enum CColorType type); +static void play_score_update(struct Play* self); +static void play_spawn_update(struct Play* self); +static void play_start_update(struct Play* self); + +/* Updates score graphic. */ +static void +play_score_set(struct Play* self, enum CColorType type) +{ + struct CScale* scale; + struct CColorChange* colorChange; + struct CText* text; + char scoreBuffer[PLAY_SCORE_BUFFER_SIZE]; + + memset(scoreBuffer, '\0', sizeof(char) * PLAY_SCORE_BUFFER_SIZE); + + scale = ecs_get(self->scoreID, ECS_C_SCALE); + colorChange = ecs_get(self->scoreID, ECS_C_COLOR_CHANGE); + text = ecs_get(self->scoreID, ECS_C_TEXT); + + snprintf(scoreBuffer, sizeof(char) * PLAY_SCORE_BUFFER_SIZE, "%u", self->score); + + c_text_string_set(text, (char*)scoreBuffer, strlen(scoreBuffer)); + + c_scale_set + ( + scale, + PLAY_SCORE_SCALE_BASE, + PLAY_SCORE_SCALE_VALUE, + PLAY_SCORE_SCALE_TIMER, + PLAY_SCORE_SCALE_TYPE + ); + + c_color_change_set + ( + colorChange, + text->color, + C_COLOR_VALUES[type], + PLAY_SCORE_COLOR_CHANGE_TIMER, + PLAY_SCORE_COLOR_CHANGE_TYPE + ); +} + +/* What happens when a follower collides with an enemy? */ +static void +play_color_collide_delete_update(struct Play* self, struct CColorCollideDelete* colorCollideDelete) +{ + struct CColor* color; + enum CColorType type; + + color = ecs_get(colorCollideDelete->id, ECS_C_COLOR); + type = color->type; + + for (s32 i = 0; i < (s32)self->enemies.count; i++) + { + u32* id; + + id = (u32*)vector_get(&self->enemies, i); + + if (*id == colorCollideDelete->collideID) + vector_remove_from_data(&self->enemies, id); + } + + self->score += self->level; + play_score_set(self, type); +} + +/* Increment the level. */ +static void +play_level_increment(struct Play* self) +{ + struct CHealth* playerHealth; + struct CText* text; + char levelBuffer[PLAY_LEVEL_BUFFER_SIZE]; + vec4 color; + + memset(levelBuffer, '\0', sizeof(char) * PLAY_LEVEL_BUFFER_SIZE); + + playerHealth = ecs_get(self->playerID, ECS_C_HEALTH); + text = ecs_get(self->levelID, ECS_C_TEXT); + + if (playerHealth->isDead) + return; + + if (self->level > 0) + sound_play(&game.sounds[SOUND_LEVEL], -1); + + self->level++; + + if (self->level <= C_COLOR_COUNT) + player_follower_add(self->playerID); + + self->levelTimer = play_level_timer_get(self); + + if (!text) + return; + + snprintf(levelBuffer, sizeof(char) * PLAY_LEVEL_BUFFER_SIZE, "x%u", self->level); + + c_text_string_set(text, (char*)levelBuffer, strlen(levelBuffer)); +} + +/* Updates play start state. */ +static void +play_start_update(struct Play* self) +{ + self->startTimer--; + + if (self->startTimer <= 0) + { + self->isStart = false; + self->isSpawn = true; + } +} + +/* Get level up timer. */ +static s32 +play_level_timer_get(struct Play* self) +{ + return PLAY_LEVEL_TIMER_BASE; +} + +/* Update play score. */ +static void +play_score_update(struct Play* self) +{ + /* Check each of the player's followers, did they collide with an enemy? */ + struct COrbit* orbit; + + orbit = ecs_get(self->playerID, ECS_C_ORBIT); + + for (s32 i = 0; i < (s32)orbit->objects.count; i++) + { + struct CColorCollideDelete* colorCollideDelete; + u32 id; + + id = *(u32*)vector_get(&orbit->objects, i); + + colorCollideDelete = ecs_get(id, ECS_C_COLOR_COLLIDE_DELETE); + + if (!colorCollideDelete) + continue; + + if (colorCollideDelete->isCollided) + play_color_collide_delete_update(self, colorCollideDelete); + } +} + +/* Update play level. */ +static void +play_level_update(struct Play* self) +{ + self->levelTimer--; + + if (self->levelTimer <= 0) + play_level_increment(self); +} + +/* Gets current spawn timer. */ +static s32 +play_spawn_timer_get(struct Play* self) +{ + s32 timer; + + timer = PLAY_SPAWN_TIMER_BASE; + + timer -= (s32)(self->level * PLAY_LEVEL_SPAWN_TIMER_MULTIPLIER); + + timer *= RANDOM_F32(PLAY_SPAWN_TIMER_MULTIPLIER_MIN, PLAY_SPAWN_TIMER_MULTIPLIER_MAX); + + timer = MIN(timer, PLAY_SPAWN_TIMER_MIN); + + return timer; +} + +/* Updates spawn timer. */ +static void +play_spawn_update(struct Play* self) +{ + struct CStun* stun; + + stun = ecs_get(self->playerID, ECS_C_STUN); + + if (stun->isStun) + { + self->spawnTimer = PLAY_SPAWN_TIMER_STUN_TIME; + return; + } + + self->spawnTimer--; + + if (self->spawnTimer <= 0) + { + play_enemy_add(self); + self->spawnTimer = play_spawn_timer_get(self); + } +} + +/* Updates damage; if player is damaged, remove all enemies. */ +static void +play_damage_update(struct Play* self) +{ + struct CDamage* damage; + struct CHealth* health; + + damage = ecs_get(self->playerID, ECS_C_DAMAGE); + health = ecs_get(self->playerID, ECS_C_HEALTH); + + if (damage->isDamageUpdate && !health->isDead) + play_enemy_clear(self, true); +} + +/* Adds an enemy. */ +static void +play_enemy_add(struct Play* self) +{ + u32 enemyID; + u32 warningID; + vec3 position; + vec3 warningPosition; + enum CColorType color; + enum Direction direction; + u32 colorMax; + f32 speed; + + enemyID = entity_add(); + warningID = entity_add(); + + direction = (enum Direction)RANDOM_S32(0, DIRECTION_2D_COUNT - 1); + + glm_vec3_zero(position); + glm_vec3_zero(warningPosition); + + switch (direction) + { + case LEFT: + position[0] = game.bounds[0] - ENEMY_SIZE[0]; + position[1] = RANDOM_F32(game.bounds[1] + ENEMY_SIZE[1], game.bounds[3] - ENEMY_SIZE[1]); + warningPosition[0] = game.bounds[0] + WARNING_SIZE[0]; + warningPosition[1] = position[1]; + break; + case RIGHT: + position[0] = game.bounds[2] + ENEMY_SIZE[0]; + position[1] = RANDOM_F32(game.bounds[1] + ENEMY_SIZE[1], game.bounds[3] - ENEMY_SIZE[1]); + warningPosition[0] = game.bounds[2] - WARNING_SIZE[0]; + warningPosition[1] = position[1]; + break; + case UP: + position[0] = RANDOM_F32(game.bounds[0] + ENEMY_SIZE[0], game.bounds[2] - ENEMY_SIZE[0]); + position[1] = game.bounds[1] - ENEMY_SIZE[0]; + warningPosition[0] = position[0]; + warningPosition[1] = game.bounds[1] + WARNING_SIZE[0]; + break; + case DOWN: + position[0] = RANDOM_F32(game.bounds[0] + ENEMY_SIZE[0], game.bounds[2] - ENEMY_SIZE[0]); + position[1] = game.bounds[3] + ENEMY_SIZE[0]; + warningPosition[0] = position[0]; + warningPosition[1] = game.bounds[3] - WARNING_SIZE[0]; + break; + default: + break; + } + + colorMax = self->level - 1; + colorMax = MAX(colorMax, C_COLOR_COUNT - 1); + + color = (enum CColorType)RANDOM_S32(0, colorMax); + + speed = PLAY_ENEMY_SPEED + ((self->level - 1) * PLAY_ENEMY_SPEED_LEVEL_MULTIPLIER); + + enemy_init(enemyID, self->playerID, color, position, speed); + warning_init(warningID, warningPosition, color); + + sound_play(&game.sounds[SOUND_WARNING], -1); + + vector_push(&self->enemies, &enemyID); +} + +/* Removes all enemies. */ +static void +play_enemy_clear(struct Play* self, bool isSpawnParticle) +{ + for (s32 i = 0; i < (s32)self->enemies.count; i++) + { + u32 id; + + id = *(u32*)vector_get(&self->enemies, i); + + if (isSpawnParticle) + { + struct CParticleSpawn* particleSpawn; + struct CPhysics* physics; + vec3 position; + + particleSpawn = ecs_get(id, ECS_C_PARTICLE_SPAWN); + physics = ecs_get(id, ECS_C_PHYSICS); + + if (!particleSpawn || !physics) + continue; + + glm_vec3_copy(physics->position, position); + + c_particle_spawn(particleSpawn, position); + } + + entity_delete(id); + } +} + +/* Check if the player's death animation has ended. */ +static void +play_death_update(struct Play* self) +{ + struct CPlayerDeath* playerDeath; + + playerDeath = ecs_get(self->playerID, ECS_C_PLAYER_DEATH); + + if (playerDeath->state == C_PLAYER_DEATH_END) + self->isOver = true; +} + +/* Initialize play. */ +void +play_init(struct Play* self) +{ + struct CColorChange* messageColorChange; + + memset(self, '\0', sizeof(struct Play)); + + self->playerID = entity_add(); + + self->scoreID = entity_add(); + self->levelID = entity_add(); + self->messageID = entity_add(); + + player_init(self->playerID, PLAY_PLAYER_POSITION); + + text_init + ( + self->scoreID, + PLAY_SCORE_ORIGIN, + game.fonts[PLAY_SCORE_FONT], + PLAY_SCORE_STRING, + strlen(PLAY_SCORE_STRING), + PLAY_SCORE_WRAP, + PLAY_SCORE_COLOR, + PLAY_SCORE_POSITION + ); + + play_score_set(self, C_COLOR_GREEN); + + text_init + ( + self->levelID, + PLAY_LEVEL_ORIGIN, + game.fonts[PLAY_LEVEL_FONT], + PLAY_LEVEL_STRING, + strlen(PLAY_LEVEL_STRING), + PLAY_LEVEL_WRAP, + PLAY_LEVEL_COLOR, + PLAY_LEVEL_POSITION + ); + + play_level_increment(self); + + text_init + ( + self->messageID, + PLAY_MESSAGE_ORIGIN, + game.fonts[PLAY_MESSAGE_FONT], + PLAY_MESSAGE_STRING, + strlen(PLAY_MESSAGE_STRING), + PLAY_MESSAGE_WRAP, + PLAY_MESSAGE_COLOR, + PLAY_MESSAGE_POSITION + ); + + messageColorChange = ecs_get(self->messageID, ECS_C_COLOR_CHANGE); + + c_color_change_set + ( + messageColorChange, + C_COLOR_VALUES[0], + COLOR_TRANSPARENT, + PLAY_START_TIMER_DEFAULT, + C_COLOR_CHANGE_TO_STICK + ); + + vector_init(&self->enemies, sizeof(u32), PLAY_ENEMY_LIMIT); + + self->spawnTimer = PLAY_SPAWN_TIMER_DEFAULT; + self->startTimer = PLAY_START_TIMER_DEFAULT; + self->isSpawn = false; + self->isStart = true; + + music_play(&game.music[MUSIC_ETHNICA], true); +} + +/* Frees play. */ +void +play_free(struct Play* self) +{ + play_enemy_clear(self, false); + + entity_delete(self->playerID); + entity_delete(self->scoreID); + entity_delete(self->levelID); + entity_delete(self->messageID); +} + +/* Update play. */ +void +play_update_f(struct Play* self) +{ + if (keyboard_press(&game.keyboard, KEYBOARD_P)) + { + game.isPaused = !game.isPaused; + printf("???\n"); + } + + if (game.isPaused) + return; + + if (self->isStart) + play_start_update(self); + + if (self->isSpawn) + play_spawn_update(self); + + play_damage_update(self); + play_score_update(self); + play_level_update(self); + play_death_update(self); +} diff --git a/src/game/state/s_play.h b/src/game/state/s_play.h new file mode 100644 index 0000000..de9ee09 --- /dev/null +++ b/src/game/state/s_play.h @@ -0,0 +1,101 @@ +/* + * DESCRIPTION: + * play.c header. +*/ + +#pragma once + +#include "../ecs/e_enemy.h" +#include "../ecs/e_player.h" +#include "../ecs/e_text.h" +#include "../ecs/e_warning.h" + +#define PLAY_ENEMY_LIMIT 64 +#define PLAY_ENEMY_SPEED 0.1f +#define PLAY_ENEMY_SPEED_LEVEL_MULTIPLIER 0.025f + +#define PLAY_LEVEL_SPAWN_TIMER_MULTIPLIER 2 +#define PLAY_LEVEL_TIMER_BASE 1200 + +#define PLAY_SPAWN_TIMER_BASE 60 +#define PLAY_SPAWN_TIMER_DEFAULT 0 +#define PLAY_SPAWN_TIMER_MIN 5 +#define PLAY_SPAWN_TIMER_MULTIPLIER_MAX 0.95 +#define PLAY_SPAWN_TIMER_MULTIPLIER_MIN 0.05 +#define PLAY_SPAWN_TIMER_STUN_TIME 180 + +#define PLAY_START_TIMER_DEFAULT 420 + +#define PLAY_LEVEL_BUFFER_SIZE 16 +#define PLAY_LEVEL_FONT FONT_BIG +#define PLAY_LEVEL_ORIGIN ORIGIN_TOP_RIGHT +#define PLAY_LEVEL_STRING "x0" +#define PLAY_LEVEL_WRAP -1 +static const vec3 PLAY_LEVEL_POSITION = {1264.0f, 16.0f, 0.0f}; +static const vec4 PLAY_LEVEL_COLOR = {1.0f, 1.0f, 1.0f, 1.0f}; + +#define PLAY_SCORE_BUFFER_SIZE 16 +#define PLAY_SCORE_COLOR C_COLOR_VALUES[0] +#define PLAY_SCORE_COLOR_CHANGE_TYPE C_COLOR_CHANGE_TO_STICK +#define PLAY_SCORE_FONT FONT_BIG +#define PLAY_SCORE_ORIGIN ORIGIN_TOP_LEFT +#define PLAY_SCORE_SCALE_BASE 1.0f +#define PLAY_SCORE_SCALE_TYPE C_SCALE_FROM +#define PLAY_SCORE_SCALE_VALUE 1.5f +#define PLAY_SCORE_STRING "0" +#define PLAY_SCORE_COLOR_CHANGE_TIMER 16 +#define PLAY_SCORE_SCALE_TIMER 16 +#define PLAY_SCORE_WRAP -1 +static const vec3 PLAY_SCORE_POSITION = {16.0f, 16.0f, 0.0f}; + +#define PLAY_MESSAGE_STRING "Don't let anything touch your white center.\nDestroy attackers by touching them with their color.\n\nMove with your mouse.\nSpin with WASD/arrow keys.\n\nSurvive.\n" +#define PLAY_MESSAGE_ORIGIN ORIGIN_CENTER +#define PLAY_MESSAGE_WRAP -1 +#define PLAY_MESSAGE_COLOR C_COLOR_VALUES[0] +#define PLAY_MESSAGE_FONT FONT_SMALL +static const vec3 PLAY_MESSAGE_POSITION = {640.0f, 360.0f, 0.0f}; + +static const vec3 PLAY_PLAYER_POSITION = {640.0f, 360.0f, 0.0f}; + + +#define STATE_PLAY_TEXTURE_COUNT 5 +static const enum TextureType STATE_PLAY_TEXTURES[STATE_PLAY_TEXTURE_COUNT] = +{ + TEXTURE_PLAYER, + TEXTURE_FOLLOWER, + TEXTURE_ENEMY, + TEXTURE_PARTICLE, + TEXTURE_WARNING +}; + +#define STATE_PLAY_SOUND_COUNT 4 +static const enum SoundType STATE_PLAY_SOUNDS[STATE_PLAY_SOUND_COUNT] = +{ + SOUND_COLLIDE, + SOUND_LEVEL, + SOUND_HURT, + SOUND_WARNING +}; + +#define STATE_PLAY_MUSIC_COUNT 1 +static const enum MusicType STATE_PLAY_MUSIC[STATE_PLAY_MUSIC_COUNT] = +{ + MUSIC_ETHNICA +}; + +#define STATE_PLAY_SHADER_COUNT 1 +static const enum ShaderType STATE_PLAY_SHADERS[STATE_PLAY_SHADER_COUNT] = +{ + SHADER_TEXTURE_QUAD +}; + +#define STATE_PLAY_FONT_COUNT 2 +static const enum FontType STATE_PLAY_FONTS[STATE_PLAY_FONT_COUNT] = +{ + FONT_SMALL, + FONT_BIG +}; + +void play_init(struct Play* self); +void play_update_f(struct Play* self); +void play_free(struct Play* self); diff --git a/src/game/state/s_results.c b/src/game/state/s_results.c new file mode 100644 index 0000000..fe87261 --- /dev/null +++ b/src/game/state/s_results.c @@ -0,0 +1,75 @@ +/* + * DESCRIPTION: + * Results game state. +*/ + +#include "s_results.h" + +/* Updates buttons. */ +static void +results_button_update(struct Results* self) +{ + struct CUIButton* menuUIButton; + + menuUIButton = ecs_get(self->menuID, ECS_C_UI_BUTTON); + + if (menuUIButton->isPressed) + self->isMenu = true; + + if (keyboard_press(&game.keyboard, KEYBOARD_SPACE)) + self->isMenu = true; +} + +/* Initializes results. */ +void +results_init(struct Results* self) +{ + char scoreBuffer[RESULTS_SCORE_BUFFER_SIZE]; + + memset(self, '\0', sizeof(struct Results)); + + memset(scoreBuffer, '\0', sizeof(char) * RESULTS_SCORE_BUFFER_SIZE); + snprintf(scoreBuffer, sizeof(char) * RESULTS_SCORE_BUFFER_SIZE, "Your Score: %u", game.score); + + self->scoreID = entity_add(); + self->menuID = entity_add(); + + text_init + ( + self->scoreID, + RESULTS_SCORE_ORIGIN, + game.fonts[RESULTS_SCORE_FONT], + scoreBuffer, + strlen(scoreBuffer), + RESULTS_SCORE_WRAP, + RESULTS_SCORE_COLOR, + RESULTS_SCORE_POSITION + ); + + ui_button_init + ( + self->menuID, + RESULTS_MENU_ORIGIN, + game.fonts[RESULTS_MENU_FONT], + RESULTS_MENU_STRING, + strlen(RESULTS_MENU_STRING), + RESULTS_MENU_COLOR, + RESULTS_MENU_SELECT_COLOR, + RESULTS_MENU_POSITION + ); +} + +/* Updates results. */ +void +results_update_f(struct Results* self) +{ + results_button_update(self); +} + +/* Frees results. */ +void +results_free(struct Results* self) +{ + entity_delete(self->scoreID); + entity_delete(self->menuID); +} diff --git a/src/game/state/s_results.h b/src/game/state/s_results.h new file mode 100644 index 0000000..ed26516 --- /dev/null +++ b/src/game/state/s_results.h @@ -0,0 +1,48 @@ +/* + * DESCRIPTION: + * s_results.c header. +*/ + +#pragma once + +#include "../ecs/c_color.h" + +#include "../ecs/e_text.h" +#include "../ecs/e_ui_button.h" + +#define RESULTS_SCORE_BUFFER_SIZE 0xFF +#define RESULTS_SCORE_COLOR C_COLOR_VALUES[0] +#define RESULTS_SCORE_ORIGIN ORIGIN_CENTER +#define RESULTS_SCORE_WRAP -1 +#define RESULTS_SCORE_FONT FONT_BIG +static const vec3 RESULTS_SCORE_POSITION = {640.0f, 200.0f, 0.0f}; + +#define RESULTS_MENU_COLOR C_COLOR_VALUES[0] +#define RESULTS_MENU_FONT FONT_BIG +#define RESULTS_MENU_ORIGIN ORIGIN_CENTER +#define RESULTS_MENU_SELECT_COLOR COLOR_OPAQUE +#define RESULTS_MENU_STRING "Menu" +static const vec3 RESULTS_MENU_POSITION = {640.0f, 600.0f, 0.0f}; + +#define STATE_RESULTS_SOUND_COUNT 2 +static const enum SoundType STATE_RESULTS_SOUNDS[STATE_RESULTS_SOUND_COUNT] = +{ + SOUND_HOVER, + SOUND_SELECT +}; + +#define STATE_RESULTS_FONT_COUNT 1 +static const enum FontType STATE_RESULTS_FONTS[STATE_RESULTS_FONT_COUNT] = +{ + FONT_BIG +}; + +#define STATE_RESULTS_SHADER_COUNT 1 +static const enum ShaderType STATE_RESULTS_SHADERS[STATE_RESULTS_SHADER_COUNT] = +{ + SHADER_TEXTURE_QUAD +}; + +void results_init(struct Results* self); +void results_update_f(struct Results* self); +void results_free(struct Results* self); diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..e353b97 --- /dev/null +++ b/src/main.c @@ -0,0 +1,50 @@ +/* + * DESCRIPTION: + * Main file. +*/ + +#include "main.h" + +static void loop(void); +static void init(void); +static void quit(void); + +struct Game game; + +/* Initializes the program. */ +static void +init(void) +{ + game_init(); +} + +/* Quits the program. */ +static void +quit(void) +{ + game_free(); + + exit(EXIT_SUCCESS); +} + +/* Main loop. */ +static void +loop(void) +{ + game_loop(); + + if (game.isQuit) + quit(); +} + +/* main(). */ +s32 +main(s32 argc, char* argv[]) +{ + init(); + + while (true) + loop(); + + return EXIT_SUCCESS; +} diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..9c92e17 --- /dev/null +++ b/src/main.h @@ -0,0 +1,8 @@ +/* + * DESCRIPTION: + * main.c header. +*/ + +#pragma once + +#include "game/game.h" diff --git a/src/util/COLOR.h b/src/util/COLOR.h new file mode 100644 index 0000000..9c07bc6 --- /dev/null +++ b/src/util/COLOR.h @@ -0,0 +1,11 @@ +/* + * DESCRIPTION: + * COLOR header. +*/ + +#pragma once + +#include "TYPES.h" + +static const vec4 COLOR_OPAQUE = {1.0f, 1.0f, 1.0f, 1.0f}; +static const vec4 COLOR_TRANSPARENT = {0.0f, 0.0f, 0.0f, 0.0f}; diff --git a/src/util/DIRECTION.h b/src/util/DIRECTION.h new file mode 100644 index 0000000..d0e8b1b --- /dev/null +++ b/src/util/DIRECTION.h @@ -0,0 +1,18 @@ +/* + * DESCRIPTION: + * Direction enumerator. +*/ + +#pragma once + +#define DIRECTION_2D_COUNT DOWN + 1 +#define DIRECTION_3D_COUNT BACKWARD + 1 +enum Direction +{ + LEFT, + RIGHT, + UP, + DOWN, + FORWARD, + BACKWARD +}; diff --git a/src/util/MATH.h b/src/util/MATH.h new file mode 100644 index 0000000..53f5fa6 --- /dev/null +++ b/src/util/MATH.h @@ -0,0 +1,28 @@ +/* + * DESCRIPTION: + * Mathematical constants and macros. +*/ + +#pragma once + +#include + +#define PI (GLM_PI) +#define TAU (GLM_PI * 2) +#define RADIANS(x) (x * (PI / 180)) +#define DEGREES(x) (x * (180 / PI)) +#define RADIANS_MIN (0) +#define RADIANS_MAX (TAU) + +#define MIN(x, min) (x < min ? min : x) +#define MAX(x, max) (x > max ? max : x) +#define CLAMP(x, min, max) (MIN(MAX(x, max), min)) + +#define RANDOM_SEED_SET(seed) (srand(seed)) +#define RANDOM ((f32)rand() / (f32)RAND_MAX) +#define RANDOM_F32(min, max) ((f32)((RANDOM * (max - min + 1)) + min)) +#define RANDOM_S32(min, max) ((s32)((RANDOM * (max - min + 1)) + min)) +#define RANDOM_BOOL() (RANDOM_S32(0, 2)) + +#define DISTANCE_2D(x1, x2, y1, y2) (sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2))) +#define ATAN(x1, x2, y1, y2) (atan2(y2 - y1, x2 - x1)) diff --git a/src/util/TIME.h b/src/util/TIME.h new file mode 100644 index 0000000..024cbdb --- /dev/null +++ b/src/util/TIME.h @@ -0,0 +1,11 @@ +/* + * DESCRIPTION: + * Common time constants/macros. +*/ + +#pragma once + +#include + +#define SECOND (1000) +#define MINUTE (60000) diff --git a/src/util/TYPES.h b/src/util/TYPES.h new file mode 100644 index 0000000..2437bc5 --- /dev/null +++ b/src/util/TYPES.h @@ -0,0 +1,24 @@ +/* + * DESCRIPTION: + * Common typedefs. +*/ + +#pragma once + +#include +#include + +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef float f32; +typedef double f64; diff --git a/src/util/UTIL.h b/src/util/UTIL.h new file mode 100644 index 0000000..6fda0e6 --- /dev/null +++ b/src/util/UTIL.h @@ -0,0 +1,20 @@ +/* + * DESCRIPTION: + * Common utilities. +*/ + +#pragma once + +#include +#include +#include + +#include "COLOR.h" +#include "DIRECTION.h" +#include "TYPES.h" +#include "MATH.h" +#include "TIME.h" + +#include "rectangle.h" +#include "origin.h" +#include "vector.h" diff --git a/src/util/origin.c b/src/util/origin.c new file mode 100644 index 0000000..5bf7e5a --- /dev/null +++ b/src/util/origin.c @@ -0,0 +1,36 @@ +/* + * DESCRIPTION: + * Origin functions. +*/ + +#include "origin.h" + +/* Fetches the origin offset of...whatever it is. */ +void +origin_2d_get(enum OriginType type, vec2 size, vec2 origin) +{ + switch (type) + { + case ORIGIN_CENTER: + default: + origin[0] = (size[0] / 2); + origin[1] = (size[1] / 2); + break; + case ORIGIN_TOP_LEFT: + origin[0] = 0.0f; + origin[1] = 0.0f; + break; + case ORIGIN_TOP_RIGHT: + origin[0] = size[0]; + origin[1] = 0.0f; + break; + case ORIGIN_BOTTOM_LEFT: + origin[0] = 0.0f; + origin[1] = size[1]; + break; + case ORIGIN_BOTTOM_RIGHT: + origin[0] = size[0]; + origin[1] = size[1]; + break; + } +} diff --git a/src/util/origin.h b/src/util/origin.h new file mode 100644 index 0000000..137463f --- /dev/null +++ b/src/util/origin.h @@ -0,0 +1,20 @@ +/* + * DESCRIPTION: + * origin.c header. +*/ + +#pragma once + +#include "TYPES.h" + +#define ORIGIN_TYPE_COUNT ORIGIN_BOTTOM_RIGHT + 1 +enum OriginType +{ + ORIGIN_CENTER, + ORIGIN_TOP_LEFT, + ORIGIN_TOP_RIGHT, + ORIGIN_BOTTOM_LEFT, + ORIGIN_BOTTOM_RIGHT +}; + +void origin_2d_get(enum OriginType type, vec2 size, vec2 origin); diff --git a/src/util/rectangle.c b/src/util/rectangle.c new file mode 100644 index 0000000..4f8139c --- /dev/null +++ b/src/util/rectangle.c @@ -0,0 +1,21 @@ +/* + * DESCRIPTION: + * Rectangle functions. +*/ + +#include "rectangle.h" + +/* Does the rectangle have the specified point? */ +bool +rectangle_has_point(vec4 rectangle, vec2 point) +{ + if + ( + point[0] >= rectangle[0] && + point[1] >= rectangle[1] && + point[0] <= rectangle[2] && + point[1] <= rectangle[3] + ) + return true; + return false; +} diff --git a/src/util/rectangle.h b/src/util/rectangle.h new file mode 100644 index 0000000..f91a256 --- /dev/null +++ b/src/util/rectangle.h @@ -0,0 +1,8 @@ +/* + * DESCRIPTION: + * rectangle.c header. +*/ + +#include "TYPES.h" + +bool rectangle_has_point(vec4 rectangle, vec2 point); diff --git a/src/util/vector.c b/src/util/vector.c new file mode 100644 index 0000000..92b4172 --- /dev/null +++ b/src/util/vector.c @@ -0,0 +1,204 @@ +/* + * DESCRIPTION: + * Dynamic array/vector implementation. +*/ + +#include "vector.h" + +static void vector_realloc(struct Vector* self); + +/* Reallocates the vector to a specified size. */ +static void +vector_realloc(struct Vector* self) +{ + if (self->count == 0) + { + self->data = NULL; + return; + } + + self->data = realloc(self->data, vector_size_get(self)); +} + +/* Pushes all elements past an index forward (<-). */ +static void +vector_forward(struct Vector* self, s32 index) +{ + s32 length; + + length = ((self->count - 1) - index); + + for (s32 i = 0; i < length; i++) + { + void* data; + void* nextData; + s32 currentIndex; + + currentIndex = index + i; + + data = self->data + (currentIndex * self->itemSize); + nextData = data + self->itemSize; + + memcpy(data, nextData, self->itemSize); + } + +} + +/* Pushes all elements past an index backward (->).*/ +static void +vector_backward(struct Vector* self, s32 index) +{ + s32 length; + + length = ((self->count - 1) - index); + + for (s32 i = 0; i < length; i++) + { + void* data; + void* prevData; + s32 index; + + index = (self->count - 1) - i; + + data = self->data + (index * self->itemSize); + prevData = data - self->itemSize; + + memcpy(data, prevData, self->itemSize); + } +} + +/* Returns total size of vector. */ +size_t +vector_size_get(struct Vector* self) +{ + return self->count * self->itemSize; +} + +/* Initializes a vector, given a size of an element. */ +void +vector_init(struct Vector* self, size_t size, s32 limit) +{ + memset(self, '\0', sizeof(struct Vector)); + + self->itemSize = size; + self->count = 0; + self->limit = limit; + + vector_realloc(self); + + memset(self->data, '\0', vector_size_get(self)); +} + +/* Frees a vector. */ +void +vector_free(struct Vector* self) +{ + if (self->data) + free(self->data); + + self->count = 0; +} + +/* Adds an element to the end of the vector. */ +void* +vector_push(struct Vector* self, void* data) +{ + void* p; + + self->count++; + + if (self->count > self->limit) + { + self->count = self->limit; + return NULL; + } + + vector_realloc(self); + + p = self->data + (vector_size_get(self) - self->itemSize); + + if (data) + memcpy(p, data, self->itemSize); + else + memset(p, '\0', self->itemSize); + + return p; +} + +/* Removes the last element of the vector. */ +void +vector_pop(struct Vector* self) +{ + self->count--; + + vector_realloc(self); +} + +/* Removes all elements of a vector (but does not dealloc the data). */ +void +vector_clear(struct Vector* self) +{ + self->count = 0; + + vector_realloc(self); +} + +/* Inserts an element at the specified index, putting successive elements back. */ +void* +vector_insert(struct Vector* self, void* data, s32 index) +{ + void* p; + + self->count++; + + if (self->count > self->limit) + { + self->count = self->limit; + return NULL; + } + + vector_realloc(self); + + vector_backward(self, index); + + p = self->data + (index * self->itemSize); + + memcpy(p, data, self->itemSize); + + return p; +} + +/* Removes an element in a vector at the specified index, bringing successive elements forward. */ +void +vector_remove(struct Vector* self, s32 index) +{ + vector_forward(self, index); + + vector_pop(self); +} + +/* Returns the address of the element at the specified index. */ +void* +vector_get(struct Vector* self, s32 index) +{ + return self->data + (index * self->itemSize); +} + +/* Returns the index of an element, given it is valid. */ +s32 +vector_index_get(struct Vector* self, void* data) +{ + s32 index; + + index = (data - (void*)self->data) / self->itemSize; + + return index; +} + +/* Removes an element within a vector, given its data, provided it is valid. */ +void +vector_remove_from_data(struct Vector* self, void* data) +{ + vector_remove(self, vector_index_get(self, data)); + data = NULL; +} diff --git a/src/util/vector.h b/src/util/vector.h new file mode 100644 index 0000000..cb3d973 --- /dev/null +++ b/src/util/vector.h @@ -0,0 +1,29 @@ +/* + * DESCRIPTION: + * Header file for vector.c. +*/ + +#pragma once + +#include "UTIL.h" + +struct Vector +{ + u32 count; + u32 limit; + size_t itemSize; + void* data; +}; + +s32 vector_index_get(struct Vector* self, void* data); +size_t vector_size_get(struct Vector* self); +void vector_free(struct Vector* self); +void vector_init(struct Vector* self, size_t size, s32 limit); +void vector_pop(struct Vector* self); +void vector_remove(struct Vector* self, s32 index); +void vector_clear(struct Vector* self); +void vector_remove_from_data(struct Vector* self, void* data); +void* vector_get(struct Vector* self, s32 index); +void* vector_insert(struct Vector* self, void* data, s32 index); +void* vector_push(struct Vector* self, void* data); +void vector_print(struct Vector* self);