commit f6ef842a28e5d181880111ea35b624f3c5f25b31 Author: shweet Date: Sat Aug 24 00:47:58 2024 -0400 first commit diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..1de276b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,59 @@ +cmake_minimum_required(VERSION 3.10) + +project(frillrun) + +include_directories(include) +include_directories(${PROJECT_SOURCE_DIR}/src) + +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/ecs/component/*.c" + "${PROJECT_SOURCE_DIR}/src/game/ecs/component/animation/*.c" + "${PROJECT_SOURCE_DIR}/src/game/ecs/component/game/*.c" + "${PROJECT_SOURCE_DIR}/src/game/ecs/component/physics/*.c" + "${PROJECT_SOURCE_DIR}/src/game/ecs/component/ui/*.c" + "${PROJECT_SOURCE_DIR}/src/game/ecs/component/utility/*.c" + "${PROJECT_SOURCE_DIR}/src/game/ecs/component/visual/*.c" + "${PROJECT_SOURCE_DIR}/src/game/ecs/entity/*.c" + "${PROJECT_SOURCE_DIR}/src/game/ecs/entity/game/*.c" + "${PROJECT_SOURCE_DIR}/src/game/ecs/entity/ui/*.c" + "${PROJECT_SOURCE_DIR}/src/game/ecs/entity/utility/*.c" + "${PROJECT_SOURCE_DIR}/src/game/ecs/entity/visual/*.c" + "${PROJECT_SOURCE_DIR}/src/game/input/*.c" + "${PROJECT_SOURCE_DIR}/src/game/render/*.c" + "${PROJECT_SOURCE_DIR}/src/game/resource/*.c" + "${PROJECT_SOURCE_DIR}/src/game/state/*.c" + "${PROJECT_SOURCE_DIR}/src/game/state/level/*.c" + "${PROJECT_SOURCE_DIR}/src/game/state/title/*.c" + "${PROJECT_SOURCE_DIR}/src/game/state/cutscene/*.c" + "${PROJECT_SOURCE_DIR}/src/game/state/ending/*.c" +) + +add_executable(${PROJECT_NAME} ${src}) + +set (CMAKE_C_FLAGS "-O2 -Wall -Wextra -pedantic -Wno-unused-variable -Wno-unused-parameter -Wno-discarded-qualifiers") + +if (EMSCRIPTEN) + set(CMAKE_EXECUTABLE_SUFFIX ".html") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 -sFULL_ES2 -sFULL_ES3 -sUSE_SDL=2 -sUSE_SDL_IMAGE=2 -sSDL2_IMAGE_FORMATS='['png']' -sUSE_SDL_MIXER=2 -sSDL2_MIXER_FORMATS='['ogg']' -sUSE_SDL_TTF=2") + add_link_options(" --preload-file res --use-preload-plugins sNO_DYNAMIC_EXECUTION=1 -sALLOW_MEMORY_GROWTH=1 -sASSERTIONS=1 -sDISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0") +elseif (WIN32) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mwindows") + target_link_libraries(${PROJECT_NAME} mingw32 m SDL2main SDL2 SDL2_image SDL2_mixer SDL2_ttf opengl32 glew32) +elseif (UNIX) + target_link_libraries(${PROJECT_NAME} m SDL2 SDL2_image SDL2_mixer SDL2_ttf GL GLEW) +endif() + +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEBUG -g") +else() + set(CMAKE_BUILD_TYPE "Release") +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 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/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/COMMON.h b/src/COMMON.h new file mode 100644 index 0000000..5d8493c --- /dev/null +++ b/src/COMMON.h @@ -0,0 +1,68 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#define CGLM_DEFINE_PRINTS + +#include + +#define PI (GLM_PI) +#define PI_FOURTH (PI / 4) +#define PI_EIGHTH (PI / 8) +#define PI_HALF (PI / 2) +#define TAU (PI * 2) +#define RADIANS(x) (x * (PI / 180)) +#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)) /* [min, max] */ +#define RANDOM_S32(min, max) ((s32)((RANDOM * (max - min + 1)) + min)) /* [min, max] */ +#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) (fmod((atan2(y2 - y1, x2 - x1) + TAU), TAU)) /* [0, 2PI] */ + +#define MILLISECOND_TICK 600 +#define SECOND_TICK 60 +#define MINUTE_TICK 3600 +#define HOUR_TICK 216000 + +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; + +typedef s32 (*SortCompareFunction)(const void*, const void*); + +#define DIRECTION_COUNT 4 +typedef enum Direction +{ + DIRECTION_LEFT, + DIRECTION_RIGHT, + DIRECTION_UP, + DIRECTION_DOWN +} Direction; + +static const vec4 OPAQUE = {1.0f, 1.0f, 1.0f, 1.0f}; +static const vec4 BLACK = {0.0f, 0.0f, 0.0f, 1.0f}; +static const vec4 TRANSPARENT = {0.0f, 0.0f, 0.0f, 0.0f}; diff --git a/src/engine/camera.c b/src/engine/camera.c new file mode 100644 index 0000000..25cacd4 --- /dev/null +++ b/src/engine/camera.c @@ -0,0 +1,83 @@ +#include "camera.h" + +void +camera_orthographic_init(Camera* self, vec2 size) +{ + memset(self, '\0', sizeof(Camera)); + + self->type = CAMERA_ORTHOGRAPHIC; + + glm_vec2_copy(size, self->orthographic.size); + + self->zoom = 1.0f; +} + +void +camera_view_get(Camera* self, mat4 view) +{ + vec3 glPosition; + vec3 zoom; + vec3 center; + + glm_mat4_identity(view); + + glPosition[0] = -self->position[0] / (f32)self->orthographic.size[0]; + glPosition[1] = self->position[1] / (f32)self->orthographic.size[1]; + glPosition[2] = 0.0f; + + zoom[0] = self->zoom; + zoom[1] = self->zoom; + zoom[2] = 0.0f; + + switch (self->type) + { + case CAMERA_ORTHOGRAPHIC: + glm_mat4_identity(view); + glm_translate(view, glPosition); + glm_scale(view, zoom); + break; + default: + break; + } +} + +void +camera_projection_get(Camera* self, mat4 projection) +{ + glm_mat4_identity(projection); + + switch (self->type) + { + case CAMERA_ORTHOGRAPHIC: + glm_ortho + ( + 0.0f, + self->orthographic.size[0], + self->orthographic.size[1], + 0.0f, + CAMERA_ORTHOGRAPHIC_NEAR, + CAMERA_ORTHOGRAPHIC_FAR, + projection + ); + break; + default: + break; + } +} + +void +camera_position_set(Camera* self, vec3 position) +{ + glm_vec3_copy(position, self->position); +} + +void +camera_orthographic_window_set(Camera* self, Window* window) +{ + ivec2 size; + + window_size_get(window, size); + + self->orthographic.size[0] = (f32)size[0]; + self->orthographic.size[1] = (f32)size[1]; +} diff --git a/src/engine/camera.h b/src/engine/camera.h new file mode 100644 index 0000000..b0ca5b9 --- /dev/null +++ b/src/engine/camera.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include + +#include "window.h" + +#define CAMERA_ORTHOGRAPHIC_FAR -1.0f +#define CAMERA_ORTHOGRAPHIC_NEAR 1.0f + +typedef enum CameraType +{ + CAMERA_PERSPECTIVE, // unsupported + CAMERA_ORTHOGRAPHIC +} CameraType; + +typedef struct Camera +{ + CameraType type; + vec3 position; + f32 yaw; + f32 pitch; + f32 zoom; + union + { + struct + { + vec2 size; + } orthographic; + struct + { + f32 fov; + f32 aspect; + } perspective; + }; +} Camera; + +void camera_orthographic_init(Camera* self, vec2 size); +void camera_orthographic_window_set(Camera* self, Window* window); +void camera_position_set(Camera* self, vec3 position); +void camera_projection_get(Camera* self, mat4 projection); +void camera_view_get(Camera* self, mat4 view); diff --git a/src/engine/circle.c b/src/engine/circle.c new file mode 100644 index 0000000..a3d9f9e --- /dev/null +++ b/src/engine/circle.c @@ -0,0 +1,42 @@ +#include "circle.h" + +bool +circle_collide_check(Circle* a, Circle* b) +{ + f32 sum; + f32 distance; + + distance = DISTANCE_2D + ( + a->position[0], + b->position[0], + a->position[1], + b->position[1] + ); + + sum = a->radius + b->radius; + + if (distance < sum) + return true; + + return false; +} + +bool +circle_has_point_check(Circle* self, vec2 point) +{ + f32 distance; + + distance = DISTANCE_2D + ( + point[0], + self->position[0], + point[1], + self->position[1] + ); + + if (distance <= self->radius) + return true; + + return false; +} diff --git a/src/engine/circle.h b/src/engine/circle.h new file mode 100644 index 0000000..8e1979a --- /dev/null +++ b/src/engine/circle.h @@ -0,0 +1,12 @@ +#pragma once + +#include "../COMMON.h" + +typedef struct Circle +{ + f32 radius; + vec2 position; +} Circle; + +bool circle_collide_check(Circle* a, Circle* b); +bool circle_has_point_check(Circle* self, vec2 point); diff --git a/src/engine/event.c b/src/engine/event.c new file mode 100644 index 0000000..46d1d31 --- /dev/null +++ b/src/engine/event.c @@ -0,0 +1,44 @@ +#include "event.h" + +/* Updates events. */ +void +event_update(Event* self) +{ + SDL_Event event; + + memcpy(&self->previous, &self->current, sizeof(bool) * EVENT_COUNT); + memset(&self->current, '\0', sizeof(bool) * EVENT_COUNT); + + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_QUIT: + self->current[EVENT_QUIT] = true; + break; + default: + break; + } + } +} + +/* Is a given event pressed? */ +bool +event_press(Event* self, EventType type) +{ + return (self->current[type] && !self->previous[type]); +} + +/* Is a given event held? */ +bool +event_held(Event* self, EventType type) +{ + return (self->current[type] && self->previous[type]); +} + +/* Is a given event released? */ +bool +event_release(Event* self, EventType type) +{ + return (!self->current[type] && self->previous[type]); +} diff --git a/src/engine/event.h b/src/engine/event.h new file mode 100644 index 0000000..bdd651d --- /dev/null +++ b/src/engine/event.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include "../COMMON.h" + +#define EVENT_COUNT (EVENT_QUIT + 1) +typedef enum EventType +{ + EVENT_QUIT +} EventType; + +typedef struct Event +{ + bool current[EVENT_COUNT]; + bool previous[EVENT_COUNT]; +} Event; + +void event_update(Event* self); +bool event_press(Event* self, EventType type); +bool event_held(Event* self, EventType type); +bool event_release(Event* self, EventType type); diff --git a/src/engine/fbo.c b/src/engine/fbo.c new file mode 100644 index 0000000..a4fa5bf --- /dev/null +++ b/src/engine/fbo.c @@ -0,0 +1,38 @@ +#include "fbo.h" + +void +fbo_init(FBO* self) +{ + glGenFramebuffers(1, &self->handle); +} + +void +fbo_bind(FBO* self) +{ + glBindFramebuffer(GL_FRAMEBUFFER, self->handle); +} + +void +fbo_unbind(void) +{ + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +void +fbo_rbo_set(RBO* rbo) +{ + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo->handle); +} + +void +fbo_texture_set(Texture* texture) +{ + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->handle, 0); +} + +void +fbo_free(FBO* self) +{ + glDeleteFramebuffers(1, &self->handle); + memset(self, '\0', sizeof(FBO)); +} diff --git a/src/engine/fbo.h b/src/engine/fbo.h new file mode 100644 index 0000000..649b629 --- /dev/null +++ b/src/engine/fbo.h @@ -0,0 +1,16 @@ +#pragma once + +#include "rbo.h" +#include "texture.h" + +typedef struct FBO +{ + GLuint handle; +} FBO; + +void fbo_init(FBO* self); +void fbo_bind(FBO* self); +void fbo_unbind(void); +void fbo_free(FBO* self); +void fbo_rbo_set(RBO* rbo); +void fbo_texture_set(Texture* texture); diff --git a/src/engine/file.c b/src/engine/file.c new file mode 100644 index 0000000..41b0532 --- /dev/null +++ b/src/engine/file.c @@ -0,0 +1,53 @@ +#include "file.h" + +bool +file_read(const char* path, void* buffer, size_t size, const char* mode) +{ + SDL_RWops* io; + + printf(STRING_FILE_READ_OPEN, path); + + io = SDL_RWFromFile(path, mode); + + if (!io) + { + printf(STRING_FILE_READ_ERROR, path); + return false; + } + + SDL_RWread(io, buffer, size, 1); + + printf(STRING_FILE_READ_SUCCESS, path); + + SDL_RWclose(io); + + printf(STRING_FILE_CLOSED, path); + + return true; +} + +bool +file_write(const char* path, void* data, size_t size, const char* mode) +{ + SDL_RWops* io; + + printf(STRING_FILE_WRITE_OPEN, path); + + io = SDL_RWFromFile(path, mode); + + if (!io) + { + printf(STRING_FILE_WRITE_ERROR, path); + return false; + } + + SDL_RWwrite(io, data, size, 1); + + printf(STRING_FILE_WRITE_SUCCESS, path); + + SDL_RWclose(io); + + printf(STRING_FILE_CLOSED, path); + + return true; +} diff --git a/src/engine/file.h b/src/engine/file.h new file mode 100644 index 0000000..2fd0e21 --- /dev/null +++ b/src/engine/file.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include "../COMMON.h" + +#define STRING_FILE_READ_OPEN "[INFO] Opened file to read: %s\n" +#define STRING_FILE_CLOSED "[INFO] Closed file: %s\n" +#define STRING_FILE_READ_SUCCESS "[INFO] Read from file: %s\n" +#define STRING_FILE_READ_ERROR "[ERROR] Unable to read from file: %s\n" +#define STRING_FILE_WRITE_OPEN "[INFO] Opened file to write: %s\n" +#define STRING_FILE_WRITE_ERROR "[ERROR] Unable to write to file: %s\n" +#define STRING_FILE_WRITE_SUCCESS "[INFO] Wrote to file: %s\n" + +bool file_read(const char* path, void* buffer, size_t size, const char* mode); +bool file_write(const char* path, void* data, size_t size, const char* mode); diff --git a/src/engine/font.c b/src/engine/font.c new file mode 100644 index 0000000..f6b3c2f --- /dev/null +++ b/src/engine/font.c @@ -0,0 +1,104 @@ +#include "font.h" + +void +font_glyph_metrics_init(Font* self, GlyphMetrics* glyphMetrics, char glyph) +{ + TTF_GlyphMetrics + ( + self->ttf, + glyph, + &glyphMetrics->minX, + &glyphMetrics->maxX, + &glyphMetrics->minY, + &glyphMetrics->maxY, + &glyphMetrics->advance + ); +} + +s32 +font_glyph_width_get(Font* self, char glyph) +{ + GlyphMetrics glyphMetrics; + + font_glyph_metrics_init(self, &glyphMetrics, glyph); + + return glyphMetrics.maxX - glyphMetrics.minX; +} + +s32 +font_glyph_kerning_get(Font* self, char glyph, char nextGlyph) +{ + return TTF_GetFontKerningSizeGlyphs(self->ttf, glyph, nextGlyph); +} + +void +font_glyph_texture_init(Font* self, Texture* texture, char glyph) +{ + SDL_Surface* surface; + SDL_Surface* textSurface; + ivec2 size; + + size[0] = font_glyph_width_get(self, glyph); + + size[1] = font_height_get(self); + + surface_rgba_init(&surface, size); + + textSurface = TTF_RenderGlyph_Blended(self->ttf, glyph, GLYPH_COLOR); + + SDL_BlitSurface(textSurface, NULL, surface, NULL); + + SDL_FreeSurface(textSurface); + + texture_surface_init(texture, surface); + + SDL_FreeSurface(surface); +} + +s32 +font_line_skip_get(Font* self) +{ + return TTF_FontLineSkip(self->ttf); +} + +s32 +font_height_get(Font* self) +{ + return TTF_FontHeight(self->ttf); +} + +bool +font_init(Font* self, const char* path, u32 size) +{ + self->ttf = TTF_OpenFont(path, size); + + if (!self->ttf) + { + printf(STRING_SDL_TTF_FONT_ERROR, path, TTF_GetError()); + return false; + } + + printf(STRING_SDL_TTF_FONT_SUCCESS, path); + + self->size = size; + self->isInit = true; + + for (s32 i = 0; i < FONT_GLYPH_MAX; i++) + font_glyph_texture_init(self, &self->glyphTextures[i], (char)i); + + return true; +} + +void +font_free(Font* self) +{ + if (self->isInit) + { + TTF_CloseFont(self->ttf); + + for (s32 i = 0; i < FONT_GLYPH_MAX; i++) + texture_free(&self->glyphTextures[i]); + + self->isInit = false; + } +} diff --git a/src/engine/font.h b/src/engine/font.h new file mode 100644 index 0000000..35f5905 --- /dev/null +++ b/src/engine/font.h @@ -0,0 +1,39 @@ +#pragma once + +#include + +#include "texture.h" +#include "surface.h" + +#define FONT_GLYPH_MAX 128 + +#define STRING_SDL_TTF_FONT_SUCCESS "[INFO] Loaded font: %s\n" +#define STRING_SDL_TTF_FONT_ERROR "[ERROR] Unable to load font: %s | %s\n" + +typedef struct Font +{ + TTF_Font* ttf; + Texture glyphTextures[FONT_GLYPH_MAX]; + u32 size; + bool isInit; +} Font; + +typedef struct GlyphMetrics +{ + s32 minX; + s32 minY; + s32 maxX; + s32 maxY; + s32 advance; +} GlyphMetrics; + +bool font_init(Font* self, const char* path, u32 size); +s32 font_glyph_kerning_get(Font* self, char glyph, char nextGlyph); +s32 font_glyph_width_get(Font* self, char glyph); +s32 font_height_get(Font* self); +s32 font_line_skip_get(Font* self); +void font_free(Font* self); +void font_glyph_metrics_init(Font* self, GlyphMetrics* glyphMetrics, char glyph); +void font_glyph_texture_init(Font* self, Texture* texture, char glyph); + +static const SDL_Color GLYPH_COLOR = {255, 255, 255, 255}; diff --git a/src/engine/fullscreen.c b/src/engine/fullscreen.c new file mode 100644 index 0000000..4c6aacd --- /dev/null +++ b/src/engine/fullscreen.c @@ -0,0 +1,22 @@ +#include "fullscreen.h" + +/* Sets window to fullscreen. */ +void +fullscreen_set(Window* self, Renderer* renderer) +{ + SDL_SetWindowSize(self->sdl, self->expectedSize[0], self->expectedSize[1]); + + renderer_update(renderer); + + SDL_SetWindowFullscreen(self->sdl, SDL_WINDOW_FULLSCREEN_DESKTOP); +} + +/* Exits fullscreen. */ +void +fullscreen_exit(Window* self, Renderer* renderer) +{ + SDL_SetWindowFullscreen(self->sdl, 0); + SDL_SetWindowSize(self->sdl, self->expectedSize[0], self->expectedSize[1]); + renderer_update(renderer); +} + diff --git a/src/engine/fullscreen.h b/src/engine/fullscreen.h new file mode 100644 index 0000000..610c42e --- /dev/null +++ b/src/engine/fullscreen.h @@ -0,0 +1,7 @@ +#pragma once + +#include "window.h" +#include "renderer.h" + +void fullscreen_set(Window* window, Renderer* renderer); +void fullscreen_exit(Window* window, Renderer* renderer); diff --git a/src/engine/glew.c b/src/engine/glew.c new file mode 100644 index 0000000..01d0ce0 --- /dev/null +++ b/src/engine/glew.c @@ -0,0 +1,9 @@ +#include "glew.h" + +void +glew_init(void) +{ + glewInit(); + + printf(STRING_GLEW_INIT); +} diff --git a/src/engine/glew.h b/src/engine/glew.h new file mode 100644 index 0000000..80d5991 --- /dev/null +++ b/src/engine/glew.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +#include "../COMMON.h" + +#define STRING_GLEW_INIT "[INFO] Initialized GLEW\n" + +void glew_init(void); diff --git a/src/engine/keyboard.c b/src/engine/keyboard.c new file mode 100644 index 0000000..c50c480 --- /dev/null +++ b/src/engine/keyboard.c @@ -0,0 +1,32 @@ +#include "keyboard.h" + +void +keyboard_update(Keyboard* self) +{ + const u8* state; + + memcpy(&self->previous, &self->current, sizeof(u8) * KEYBOARD_KEY_COUNT); + memset(&self->current, '\0', sizeof(u8) * KEYBOARD_KEY_COUNT); + + state = SDL_GetKeyboardState(NULL); + + memcpy(&self->current, state, KEYBOARD_KEY_COUNT); +} + +bool +keyboard_press(Keyboard* self, KeyboardKeyType type) +{ + return (self->current[type] && !self->previous[type]); +} + +bool +keyboard_held(Keyboard* self, KeyboardKeyType type) +{ + return (self->current[type] && self->previous[type]); +} + +bool +keyboard_release(Keyboard* self, KeyboardKeyType type) +{ + return (!self->current[type] && self->previous[type]); +} diff --git a/src/engine/keyboard.h b/src/engine/keyboard.h new file mode 100644 index 0000000..ae6a384 --- /dev/null +++ b/src/engine/keyboard.h @@ -0,0 +1,240 @@ +#pragma once + +#include + +#include "../COMMON.h" + +#define KEYBOARD_KEY_COUNT (255) +typedef enum KeyboardKeyType +{ + KEYBOARD_KEY_UNKNOWN = 0, + KEYBOARD_KEY_UNKNOWN_TWO = 1, + KEYBOARD_KEY_UNKNOWN_THREE = 2, + KEYBOARD_KEY_UNKNOWN_FOUR = 3, + KEYBOARD_KEY_A = 4, + KEYBOARD_KEY_B = 5, + KEYBOARD_KEY_C = 6, + KEYBOARD_KEY_D = 7, + KEYBOARD_KEY_E = 8, + KEYBOARD_KEY_F = 9, + KEYBOARD_KEY_G = 10, + KEYBOARD_KEY_H = 11, + KEYBOARD_KEY_I = 12, + KEYBOARD_KEY_J = 13, + KEYBOARD_KEY_K = 14, + KEYBOARD_KEY_L = 15, + KEYBOARD_KEY_M = 16, + KEYBOARD_KEY_N = 17, + KEYBOARD_KEY_O = 18, + KEYBOARD_KEY_P = 19, + KEYBOARD_KEY_Q = 20, + KEYBOARD_KEY_R = 21, + KEYBOARD_KEY_S = 22, + KEYBOARD_KEY_T = 23, + KEYBOARD_KEY_U = 24, + KEYBOARD_KEY_V = 25, + KEYBOARD_KEY_W = 26, + KEYBOARD_KEY_X = 27, + KEYBOARD_KEY_Y = 28, + KEYBOARD_KEY_Z = 29, + KEYBOARD_KEY_1 = 30, + KEYBOARD_KEY_2 = 31, + KEYBOARD_KEY_3 = 32, + KEYBOARD_KEY_4 = 33, + KEYBOARD_KEY_5 = 34, + KEYBOARD_KEY_6 = 35, + KEYBOARD_KEY_7 = 36, + KEYBOARD_KEY_8 = 37, + KEYBOARD_KEY_9 = 38, + KEYBOARD_KEY_0 = 39, + KEYBOARD_KEY_RETURN = 40, + KEYBOARD_KEY_ESCAPE = 41, + KEYBOARD_KEY_BACKSPACE = 42, + KEYBOARD_KEY_TAB = 43, + KEYBOARD_KEY_SPACE = 44, + KEYBOARD_KEY_MINUS = 45, + KEYBOARD_KEY_EQUALS = 46, + KEYBOARD_KEY_LEFTBRACKET = 47, + KEYBOARD_KEY_RIGHTBRACKET = 48, + KEYBOARD_KEY_BACKSLASH = 49, + KEYBOARD_KEY_NONUSHASH = 50, + KEYBOARD_KEY_SEMICOLON = 51, + KEYBOARD_KEY_APOSTROPHE = 52, + KEYBOARD_KEY_GRAVE = 53, + KEYBOARD_KEY_COMMA = 54, + KEYBOARD_KEY_PERIOD = 55, + KEYBOARD_KEY_SLASH = 56, + KEYBOARD_KEY_CAPSLOCK = 57, + KEYBOARD_KEY_F1 = 58, + KEYBOARD_KEY_F2 = 59, + KEYBOARD_KEY_F3 = 60, + KEYBOARD_KEY_F4 = 61, + KEYBOARD_KEY_F5 = 62, + KEYBOARD_KEY_F6 = 63, + KEYBOARD_KEY_F7 = 64, + KEYBOARD_KEY_F8 = 65, + KEYBOARD_KEY_F9 = 66, + KEYBOARD_KEY_F10 = 67, + KEYBOARD_KEY_F11 = 68, + KEYBOARD_KEY_F12 = 69, + KEYBOARD_KEY_PRINTSCREEN = 70, + KEYBOARD_KEY_SCROLLLOCK = 71, + KEYBOARD_KEY_PAUSE = 72, + KEYBOARD_KEY_INSERT = 73, + KEYBOARD_KEY_HOME = 74, + KEYBOARD_KEY_PAGEUP = 75, + KEYBOARD_KEY_DELETE = 76, + KEYBOARD_KEY_END = 77, + KEYBOARD_KEY_PAGEDOWN = 78, + KEYBOARD_KEY_RIGHT = 79, + KEYBOARD_KEY_LEFT = 80, + KEYBOARD_KEY_DOWN = 81, + KEYBOARD_KEY_UP = 82, + KEYBOARD_KEY_NUMLOCKCLEAR = 83, + KEYBOARD_KEY_KP_DIVIDE = 84, + KEYBOARD_KEY_KP_MULTIPLY = 85, + KEYBOARD_KEY_KP_MINUS = 86, + KEYBOARD_KEY_KP_PLUS = 87, + KEYBOARD_KEY_KP_ENTER = 88, + KEYBOARD_KEY_KP_1 = 89, + KEYBOARD_KEY_KP_2 = 90, + KEYBOARD_KEY_KP_3 = 91, + KEYBOARD_KEY_KP_4 = 92, + KEYBOARD_KEY_KP_5 = 93, + KEYBOARD_KEY_KP_6 = 94, + KEYBOARD_KEY_KP_7 = 95, + KEYBOARD_KEY_KP_8 = 96, + KEYBOARD_KEY_KP_9 = 97, + KEYBOARD_KEY_KP_0 = 98, + KEYBOARD_KEY_KP_PERIOD = 99, + KEYBOARD_KEY_NONUSBACKSLASH = 100, + KEYBOARD_KEY_APPLICATION = 101, + KEYBOARD_KEY_POWER = 102, + KEYBOARD_KEY_KP_EQUALS = 103, + KEYBOARD_KEY_F13 = 104, + KEYBOARD_KEY_F14 = 105, + KEYBOARD_KEY_F15 = 106, + KEYBOARD_KEY_F16 = 107, + KEYBOARD_KEY_F17 = 108, + KEYBOARD_KEY_F18 = 109, + KEYBOARD_KEY_F19 = 110, + KEYBOARD_KEY_F20 = 111, + KEYBOARD_KEY_F21 = 112, + KEYBOARD_KEY_F22 = 113, + KEYBOARD_KEY_F23 = 114, + KEYBOARD_KEY_F24 = 115, + KEYBOARD_KEY_EXECUTE = 116, + KEYBOARD_KEY_HELP = 117, + KEYBOARD_KEY_MENU = 118, + KEYBOARD_KEY_SELECT = 119, + KEYBOARD_KEY_STOP = 120, + KEYBOARD_KEY_AGAIN = 121, + KEYBOARD_KEY_UNDO = 122, + KEYBOARD_KEY_CUT = 123, + KEYBOARD_KEY_COPY = 124, + KEYBOARD_KEY_PASTE = 125, + KEYBOARD_KEY_FIND = 126, + KEYBOARD_KEY_MUTE = 127, + KEYBOARD_KEY_VOLUMEUP = 128, + KEYBOARD_KEY_VOLUMEDOWN = 129, + KEYBOARD_KEY_LOCKINGCAPSLOCK = 130, + KEYBOARD_KEY_LOCKINGNUMLOCK = 131, + KEYBOARD_KEY_LOCKINGSCROLLLOCK = 132, + KEYBOARD_KEY_KP_COMMA = 133, + KEYBOARD_KEY_KP_EQUALSAS400 = 134, + KEYBOARD_KEY_INTERNATIONAL1 = 135, + KEYBOARD_KEY_INTERNATIONAL2 = 136, + KEYBOARD_KEY_INTERNATIONAL3 = 137, + KEYBOARD_KEY_INTERNATIONAL4 = 138, + KEYBOARD_KEY_INTERNATIONAL5 = 139, + KEYBOARD_KEY_INTERNATIONAL6 = 140, + KEYBOARD_KEY_INTERNATIONAL7 = 141, + KEYBOARD_KEY_INTERNATIONAL8 = 142, + KEYBOARD_KEY_INTERNATIONAL9 = 143, + KEYBOARD_KEY_LANG1 = 144, + KEYBOARD_KEY_LANG2 = 145, + KEYBOARD_KEY_LANG3 = 146, + KEYBOARD_KEY_LANG4 = 147, + KEYBOARD_KEY_LANG5 = 148, + KEYBOARD_KEY_LANG6 = 149, + KEYBOARD_KEY_LANG7 = 150, + KEYBOARD_KEY_LANG8 = 151, + KEYBOARD_KEY_LANG9 = 152, + KEYBOARD_KEY_ALTERASE = 153, + KEYBOARD_KEY_SYSREQ = 154, + KEYBOARD_KEY_CANCEL = 155, + KEYBOARD_KEY_CLEAR = 156, + KEYBOARD_KEY_PRIOR = 157, + KEYBOARD_KEY_RETURN2 = 158, + KEYBOARD_KEY_SEPARATOR = 159, + KEYBOARD_KEY_OUT = 160, + KEYBOARD_KEY_OPER = 161, + KEYBOARD_KEY_CLEARAGAIN = 162, + KEYBOARD_KEY_CRSEL = 163, + KEYBOARD_KEY_EXSEL = 164, + KEYBOARD_KEY_KP_00 = 176, + KEYBOARD_KEY_KP_000 = 177, + KEYBOARD_KEY_THOUSANDSSEPARATOR = 178, + KEYBOARD_KEY_DECIMALSEPARATOR = 179, + KEYBOARD_KEY_CURRENCYUNIT = 180, + KEYBOARD_KEY_CURRENCYSUBUNIT = 181, + KEYBOARD_KEY_KP_LEFTPAREN = 182, + KEYBOARD_KEY_KP_RIGHTPAREN = 183, + KEYBOARD_KEY_KP_LEFTBRACE = 184, + KEYBOARD_KEY_KP_RIGHTBRACE = 185, + KEYBOARD_KEY_KP_TAB = 186, + KEYBOARD_KEY_KP_BACKSPACE = 187, + KEYBOARD_KEY_KP_A = 188, + KEYBOARD_KEY_KP_B = 189, + KEYBOARD_KEY_KP_C = 190, + KEYBOARD_KEY_KP_D = 191, + KEYBOARD_KEY_KP_E = 192, + KEYBOARD_KEY_KP_F = 193, + KEYBOARD_KEY_KP_XOR = 194, + KEYBOARD_KEY_KP_POWER = 195, + KEYBOARD_KEY_KP_PERCENT = 196, + KEYBOARD_KEY_KP_LESS = 197, + KEYBOARD_KEY_KP_GREATER = 198, + KEYBOARD_KEY_KP_AMPERSAND = 199, + KEYBOARD_KEY_KP_DBLAMPERSAND = 200, + KEYBOARD_KEY_KP_VERTICALBAR = 201, + KEYBOARD_KEY_KP_DBLVERTICALBAR = 202, + KEYBOARD_KEY_KP_COLON = 203, + KEYBOARD_KEY_KP_HASH = 204, + KEYBOARD_KEY_KP_SPACE = 205, + KEYBOARD_KEY_KP_AT = 206, + KEYBOARD_KEY_KP_EXCLAM = 207, + KEYBOARD_KEY_KP_MEMSTORE = 208, + KEYBOARD_KEY_KP_MEMRECALL = 209, + KEYBOARD_KEY_KP_MEMCLEAR = 210, + KEYBOARD_KEY_KP_MEMADD = 211, + KEYBOARD_KEY_KP_MEMSUBTRACT = 212, + KEYBOARD_KEY_KP_MEMMULTIPLY = 213, + KEYBOARD_KEY_KP_MEMDIVIDE = 214, + KEYBOARD_KEY_KP_PLUSMINUS = 215, + KEYBOARD_KEY_KP_CLEAR = 216, + KEYBOARD_KEY_KP_CLEARENTRY = 217, + KEYBOARD_KEY_KP_BINARY = 218, + KEYBOARD_KEY_KP_OCTAL = 219, + KEYBOARD_KEY_KP_DECIMAL = 220, + KEYBOARD_KEY_KP_HEXADECIMAL = 221, + KEYBOARD_KEY_LCTRL = 224, + KEYBOARD_KEY_LSHIFT = 225, + KEYBOARD_KEY_LALT = 226, + KEYBOARD_KEY_LGUI = 227, + KEYBOARD_KEY_RCTRL = 228, + KEYBOARD_KEY_RSHIFT = 229, + KEYBOARD_KEY_RALT = 230, + KEYBOARD_KEY_RGUI = 231 +} KeyboardKeyType; + +typedef struct Keyboard +{ + u8 current[KEYBOARD_KEY_COUNT]; + u8 previous[KEYBOARD_KEY_COUNT]; +} Keyboard; + +void keyboard_update(Keyboard* self); +bool keyboard_press(Keyboard* self, KeyboardKeyType type); +bool keyboard_held(Keyboard* self, KeyboardKeyType type); +bool keyboard_release(Keyboard* self, KeyboardKeyType type); diff --git a/src/engine/mouse.c b/src/engine/mouse.c new file mode 100644 index 0000000..fbff3fc --- /dev/null +++ b/src/engine/mouse.c @@ -0,0 +1,74 @@ +#include "mouse.h" + +void +mouse_update(Mouse* self) +{ + s32 state; + s32 x; + s32 y; + + memcpy(&self->previous, &self->current, sizeof(bool) * MOUSE_BUTTON_COUNT); + memset(&self->current, '\0', sizeof(bool) * MOUSE_BUTTON_COUNT); + + state = SDL_GetMouseState(NULL, NULL); + + if ((state & SDL_BUTTON_LMASK) != 0) + self->current[MOUSE_BUTTON_LEFT] = true; + + if ((state & SDL_BUTTON_MMASK) != 0) + self->current[MOUSE_BUTTON_MIDDLE] = true; + + if ((state & SDL_BUTTON_RMASK) != 0) + self->current[MOUSE_BUTTON_RIGHT] = true; + + if ((state & SDL_BUTTON_X1) != 0) + self->current[MOUSE_BUTTON_X1] = true; + + if ((state & SDL_BUTTON_X2) != 0) + self->current[MOUSE_BUTTON_X2] = true; + + SDL_GetMouseState(&x, &y); + + self->position[0] = x; + self->position[1] = y; +} + +bool +mouse_press(Mouse* self, MouseButtonType type) +{ + return (self->current[type] && !self->previous[type]); +} + +bool +mouse_held(Mouse* self, MouseButtonType type) +{ + return (self->current[type] && self->previous[type]); +} + +bool +mouse_release(Mouse* self, MouseButtonType type) +{ + return (!self->current[type] && self->previous[type]); +} + +void +mouse_buffer_position_get(Mouse* self, RendererBuffer buffer, Renderer* renderer, vec2 position) +{ + vec2 mousePosition; + + mousePosition[0] = (f32)self->position[0]; + mousePosition[1] = (f32)self->position[1]; + + renderer_buffer_position_from_window_position(renderer, buffer, mousePosition, position); +} + +f32 +mouse_angle_from_buffer_position_get(Mouse* self, RendererBuffer buffer, Renderer* renderer, vec2 position) +{ + vec2 mousePosition; + f32 angle; + + mouse_buffer_position_get(self, buffer, renderer, mousePosition); + + return ATAN(position[0], mousePosition[0], position[1], mousePosition[1]); +} diff --git a/src/engine/mouse.h b/src/engine/mouse.h new file mode 100644 index 0000000..c6c6227 --- /dev/null +++ b/src/engine/mouse.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include "renderer.h" + +#define MOUSE_BUTTON_COUNT (MOUSE_BUTTON_X2 + 1) +typedef enum MouseButtonType +{ + MOUSE_BUTTON_NONE, + MOUSE_BUTTON_LEFT, + MOUSE_BUTTON_MIDDLE, + MOUSE_BUTTON_RIGHT, + MOUSE_BUTTON_X1, + MOUSE_BUTTON_X2 +} MouseButtonType; + +typedef struct Mouse +{ + ivec2 position; + bool current[MOUSE_BUTTON_COUNT]; + bool previous[MOUSE_BUTTON_COUNT]; +} Mouse; + +void mouse_update(Mouse* self); +bool mouse_press(Mouse* self, MouseButtonType type); +bool mouse_held(Mouse* self, MouseButtonType type); +bool mouse_release(Mouse* self, MouseButtonType type); +void mouse_buffer_position_get(Mouse* mouse, RendererBuffer buffer, Renderer* renderer, vec2 position); +f32 mouse_angle_from_buffer_position_get(Mouse* self, RendererBuffer buffer, Renderer* renderer, vec2 position); diff --git a/src/engine/music.c b/src/engine/music.c new file mode 100644 index 0000000..1cc1069 --- /dev/null +++ b/src/engine/music.c @@ -0,0 +1,62 @@ +#include "music.h" + +bool +music_init(Music* self, const char* path) +{ + self->chunk = Mix_LoadMUS(path); + + if (!self->chunk) + { + printf(STRING_SDL_MIXER_MUSIC_ERROR, path, Mix_GetError()); + return false; + } + + printf(STRING_SDL_MIXER_MUSIC_SUCCESS, path); + + self->isInit = true; + + return true; +} + +void +music_free(Music* self) +{ + if (self->isInit) + { + Mix_FreeMusic(self->chunk); + self->isInit = false; + } +} + +void +music_play(Music* self, bool isLoop) +{ + if (isLoop) + Mix_PlayMusic(self->chunk, -1); + else + Mix_PlayMusic(self->chunk, 0); +} + +void +music_resume(void) +{ + Mix_ResumeMusic(); +} + +void +music_pause(void) +{ + Mix_PauseMusic(); +} + +void +music_stop(void) +{ + Mix_HaltMusic(); +} + +bool +music_is_playing_check(void) +{ + return Mix_PlayingMusic(); +} diff --git a/src/engine/music.h b/src/engine/music.h new file mode 100644 index 0000000..a4fe255 --- /dev/null +++ b/src/engine/music.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include "../COMMON.h" + +#define STRING_SDL_MIXER_MUSIC_SUCCESS "[INFO] Loaded music: %s\n" +#define STRING_SDL_MIXER_MUSIC_ERROR "[ERROR] Unable to load music: %s | %s\n" + +typedef struct Music +{ + Mix_Music* chunk; + bool isInit; +} Music; + +bool music_is_playing_check(void); +void music_free(Music* self); +bool music_init(Music* self, const char* path); +void music_pause(void); +void music_play(Music* self, bool isLoop); +void music_resume(void); +void music_stop(void); diff --git a/src/engine/rbo.c b/src/engine/rbo.c new file mode 100644 index 0000000..c64b4c3 --- /dev/null +++ b/src/engine/rbo.c @@ -0,0 +1,32 @@ +#include "rbo.h" + +void +rbo_init(RBO* self) +{ + glGenRenderbuffers(1, &self->handle); +} + +void +rbo_bind(RBO* self) +{ + glBindRenderbuffer(GL_FRAMEBUFFER, self->handle); +} + +void +rbo_unbind(void) +{ + glBindRenderbuffer(GL_FRAMEBUFFER, 0); +} + +void +rbo_storage_set(RBO* self, ivec2 size) +{ + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, size[0], size[1]); +} + +void +rbo_free(RBO* self) +{ + glDeleteRenderbuffers(1, &self->handle); + memset(self, '\0', sizeof(RBO)); +} diff --git a/src/engine/rbo.h b/src/engine/rbo.h new file mode 100644 index 0000000..6c0aef2 --- /dev/null +++ b/src/engine/rbo.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +#include "../COMMON.h" + +typedef struct RBO +{ + GLuint handle; +} RBO; + +void rbo_init(RBO* self); +void rbo_bind(RBO* self); +void rbo_unbind(void); +void rbo_free(RBO* self); +void rbo_storage_set(RBO* self, ivec2 size); diff --git a/src/engine/rectangle.c b/src/engine/rectangle.c new file mode 100644 index 0000000..9044c0e --- /dev/null +++ b/src/engine/rectangle.c @@ -0,0 +1,24 @@ +#include "rectangle.h" + +bool +rectangle_collide_intersection(Rectangle* a, Rectangle* b, Rectangle* intersection) +{ + return SDL_IntersectFRect(a, b, intersection); +} + +bool +rectangle_collide(Rectangle* a, Rectangle* b) +{ + return SDL_HasIntersectionF(a, b); +} + +bool +rectangle_has_point(Rectangle* self, vec2 point) +{ + SDL_FPoint sdlPoint; + + sdlPoint.x = point[0]; + sdlPoint.y = point[1]; + + return SDL_PointInFRect(&sdlPoint, self); +} diff --git a/src/engine/rectangle.h b/src/engine/rectangle.h new file mode 100644 index 0000000..ec80daf --- /dev/null +++ b/src/engine/rectangle.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +#include "../COMMON.h" + +typedef SDL_FRect Rectangle; + +bool rectangle_collide(Rectangle* a, Rectangle* b); +bool rectangle_collide_intersection(Rectangle* a, Rectangle* b, Rectangle* intersection); +bool rectangle_has_point(Rectangle* self, vec2 point); diff --git a/src/engine/renderer.c b/src/engine/renderer.c new file mode 100644 index 0000000..ae4b3ca --- /dev/null +++ b/src/engine/renderer.c @@ -0,0 +1,174 @@ +#include "renderer.h" + +static void _renderer_viewport_window_set(Renderer* self); + +void +renderer_buffer_init(Renderer* self, RendererBuffer buffer) +{ + ivec2 size; + + window_size_get(self->window, size); + + fbo_init(&self->fbos[buffer]); + + fbo_bind(&self->fbos[buffer]); + + texture_init(&self->fboTextures[buffer], size, NULL); + + texture_bind(&self->fboTextures[buffer]); + + fbo_texture_set(&self->fboTextures[buffer]); + + rbo_init(&self->rbos[buffer]); + + rbo_bind(&self->rbos[buffer]); + + rbo_storage_set(&self->rbos[buffer], size); + + fbo_rbo_set(&self->rbos[buffer]); + + rbo_unbind(); + fbo_unbind(); +} + +void +renderer_buffer_free(Renderer* self, RendererBuffer buffer) +{ + texture_free(&self->fboTextures[buffer]); + rbo_free(&self->rbos[buffer]); + fbo_free(&self->fbos[buffer]); +} + +static void +_renderer_viewport_window_set(Renderer* self) +{ + ivec4 viewport; + + window_ivec4_get(self->window, viewport); + + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); +} + +void +renderer_init(Renderer* self, Window* window, CameraType type, const ivec2* bufferSizes) +{ + + memset(self, '\0', sizeof(Renderer)); + + 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); + + for (s32 i = 0; i < RENDERER_BUFFER_COUNT; i++) + { + vec2 cameraSize; + + renderer_buffer_init(self, (RendererBuffer)i); + + glm_ivec2_copy((s32*)bufferSizes[i], self->bufferSizes[i]); + + cameraSize[0] = bufferSizes[i][0]; + cameraSize[1] = bufferSizes[i][1]; + + switch (type) + { + case CAMERA_ORTHOGRAPHIC: + camera_orthographic_init(&self->camera[i], cameraSize); + break; + default: + break; + } + } + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +} + +void +renderer_free(Renderer* self) +{ + for (s32 i = 0; i < RENDERER_BUFFER_COUNT; i++) + renderer_buffer_free(self, (RendererBuffer)i); + + vao_free(&self->vao); + vbo_free(&self->vbo); + vbo_free(&self->ebo); + + memset(self, '\0', sizeof(Renderer)); + SDL_GL_DeleteContext(self->glContext); +} + +void +renderer_shader_use(Renderer* self, Shader* shader) +{ + shader_use(shader); +} + +void +renderer_clear_color_set(Renderer* self, vec4 color) +{ + glClearColor(color[0], color[1], color[2], color[3]); +} + +void +renderer_clear(Renderer* self) +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void +renderer_present(Renderer* self) +{ + SDL_GL_SwapWindow(self->window->sdl); +} + +void +renderer_update(Renderer* self) +{ + _renderer_viewport_window_set(self); +} + +void +renderer_buffer_use(Renderer* self, RendererBuffer buffer) +{ + fbo_bind(&self->fbos[buffer]); +} + +void +renderer_buffer_unbind(void) +{ + fbo_unbind(); +} + +void +renderer_buffer_position_from_window_position +( + Renderer* self, + RendererBuffer buffer, + vec2 windowPosition, + vec2 rendererPosition +) +{ + ivec2 windowSize; + + window_size_get(self->window, windowSize); + + rendererPosition[0] = windowPosition[0] / windowSize[0]; + rendererPosition[1] = windowPosition[1] / windowSize[1]; + + rendererPosition[0] *= self->camera[buffer].orthographic.size[0]; + rendererPosition[1] *= self->camera[buffer].orthographic.size[1]; + + rendererPosition[0] += (self->camera[buffer].orthographic.size[0] / 2) * (1 - self->camera[buffer].zoom); + rendererPosition[1] += (self->camera[buffer].orthographic.size[1] / 2) * (1 - self->camera[buffer].zoom); + + rendererPosition[0] += self->camera[buffer].position[0]; + rendererPosition[1] += self->camera[buffer].position[1]; + +} diff --git a/src/engine/renderer.h b/src/engine/renderer.h new file mode 100644 index 0000000..abdb1dc --- /dev/null +++ b/src/engine/renderer.h @@ -0,0 +1,55 @@ +#pragma once + +#include "camera.h" +#include "glew.h" +#include "window.h" +#include "shader.h" +#include "vao.h" +#include "fbo.h" +#include "rbo.h" +#include "vbo.h" +#include "vertexattribute.h" + +#define RENDERER_BUFFER_COUNT RENDERER_BUFFER_CURSOR + 1 +typedef enum RendererBuffer +{ + RENDERER_BUFFER_BACKGROUND, + RENDERER_BUFFER_WORLD, + RENDERER_BUFFER_UI, + RENDERER_BUFFER_META, + RENDERER_BUFFER_CURSOR +} RendererBuffer; + +typedef struct Renderer +{ + SDL_GLContext glContext; + Window* window; + Camera camera[RENDERER_BUFFER_COUNT]; + ivec2 bufferSizes[RENDERER_BUFFER_COUNT]; + Texture fboTextures[RENDERER_BUFFER_COUNT]; + FBO fbos[RENDERER_BUFFER_COUNT]; + RBO rbos[RENDERER_BUFFER_COUNT]; + VBO vbo; + VBO ebo; + VAO vao; +} Renderer; + +void renderer_init(Renderer* self, Window* window, CameraType type, const ivec2* bufferSizes); +void renderer_clear_color_set(Renderer* self, vec4 color); +void renderer_clear(Renderer* self); +void renderer_shader_use(Renderer* self, Shader* shader); +void renderer_buffer_use(Renderer* self, RendererBuffer buffer); +void renderer_buffer_init(Renderer* self, RendererBuffer buffer); +void renderer_buffer_free(Renderer* self, RendererBuffer buffer); +void renderer_free(Renderer* self); +void renderer_update(Renderer* self); +void renderer_present(Renderer* self); +void renderer_buffer_unbind(void); + +void renderer_buffer_position_from_window_position +( + Renderer* self, + RendererBuffer buffer, + vec2 windowPosition, + vec2 rendererPosition +); diff --git a/src/engine/sdl.c b/src/engine/sdl.c new file mode 100644 index 0000000..efcc9b9 --- /dev/null +++ b/src/engine/sdl.c @@ -0,0 +1,63 @@ +#include "sdl.h" + +/* Initializes SDL. */ +void +sdl_init(void) +{ + if (SDL_INIT_VIDEO < 0) + { + printf(STRING_SDL2_VIDEO_ERROR); + exit(EXIT_FAILURE); + } + else + printf(STRING_SDL2_VIDEO_INIT); + + if (SDL_INIT_TIMER < 0) + { + printf(STRING_SDL2_TIMER_ERROR); + exit(EXIT_FAILURE); + } + else + printf(STRING_SDL2_TIMER_INIT); + + if (IMG_Init(IMG_FLAGS) < 0) + { + printf(STRING_SDL_IMAGE_ERROR); + exit(EXIT_FAILURE); + } + else + printf(STRING_SDL_IMAGE_INIT); + + if (TTF_Init() < 0) + { + printf(STRING_SDL_TTF_ERROR); + exit(EXIT_FAILURE); + } + else + printf(STRING_SDL_TTF_INIT); + + if (Mix_OpenAudio(MIX_FREQUENCY, MIX_DEFAULT_FORMAT, MIX_CHANNELS, MIX_SAMPLE_SIZE) < 0) + { + printf(STRING_SDL_MIXER_ERROR); + exit(EXIT_FAILURE); + } + else + printf(STRING_SDL_MIXER_INIT); + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); +} + +/* Quits SDL. */ +void +sdl_quit(void) +{ + printf(STRING_SDL2_QUIT); + SDL_Quit(); +} diff --git a/src/engine/sdl.h b/src/engine/sdl.h new file mode 100644 index 0000000..d89599b --- /dev/null +++ b/src/engine/sdl.h @@ -0,0 +1,29 @@ +#pragma once + +#define SDL_MAIN_HANDLED + +#include +#include +#include +#include +#include "../COMMON.h" + +#define STRING_SDL2_VIDEO_ERROR "[ERROR] Unable to initialize SDL2 (Video): %s\n", SDL_GetError() +#define STRING_SDL2_VIDEO_INIT "[INFO] Initialized SDL2 (Video)\n" +#define STRING_SDL2_TIMER_ERROR "[ERROR] Unable to initialize SDL2 (Timer): %s\n", SDL_GetError() +#define STRING_SDL2_TIMER_INIT "[INFO] Initialized SDL2 (Timer)\n" +#define STRING_SDL_IMAGE_ERROR "[ERROR] Unable to initialize SDL_image: %s\n", IMG_GetError() +#define STRING_SDL_IMAGE_INIT "[INFO] Initialized SDL_image\n" +#define STRING_SDL_MIXER_ERROR "[ERROR] Unable to initialize SDL_mixer: %s\n", Mix_GetError() +#define STRING_SDL_MIXER_INIT "[INFO] Initialized SDL_mixer\n" +#define STRING_SDL_TTF_ERROR "[ERROR] Unable to initialize SDL_ttf: %s\n", TTF_GetError() +#define STRING_SDL_TTF_INIT "[INFO] Initialized SDL_ttf\n" +#define STRING_SDL2_QUIT "[INFO] Quitting SDL2\n" + +#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..62762c1 --- /dev/null +++ b/src/engine/shader.c @@ -0,0 +1,128 @@ +#include "shader.h" + +static bool _shader_compile(u32 handle); + +static bool +_shader_compile(u32 handle) +{ + s32 success; + char log[SHADER_LOG_BUFFER_SIZE]; + + glCompileShader(handle); + glGetShaderiv(handle, GL_COMPILE_STATUS, &success); + + if (!success) + { + glGetShaderInfoLog(handle, SHADER_LOG_BUFFER_SIZE, NULL, log); + printf(STRING_SHADER_COMPILE_ERROR, handle, log); + return false; + } + else + printf(STRING_SHADER_COMPILE_SUCCESS, handle); + + return true; +} + +bool +shader_init(Shader* self, const char* vertex, const char* fragment) +{ + GLuint vertexHandle; + GLuint fragmentHandle; + + memset(self, '\0', sizeof(struct Shader)); + + vertexHandle = glCreateShader(GL_VERTEX_SHADER); + fragmentHandle = glCreateShader(GL_FRAGMENT_SHADER); + + glShaderSource(vertexHandle, 1, &vertex, NULL); + glShaderSource(fragmentHandle, 1, &fragment, NULL); + + if (!_shader_compile(vertexHandle) || !_shader_compile(fragmentHandle)) + return false; + + self->handle = glCreateProgram(); + + glAttachShader(self->handle, vertexHandle); + glAttachShader(self->handle, fragmentHandle); + + glLinkProgram(self->handle); + + glDeleteShader(vertexHandle); + glDeleteShader(fragmentHandle); + + self->isInit = true; + + return true; +} + +void +shader_use(Shader* self) +{ + glUseProgram(self->handle); +} + +void +shader_free(Shader* self) +{ + if (self->isInit) + { + glDeleteProgram(self->handle); + self->isInit = false; + } +} + +void +shader_uniform_s32_set(Shader* self, const char* name, s32 value) +{ + glUniform1i(glGetUniformLocation(self->handle, name), value); +} + +void +shader_uniform_u32_set(Shader* self, const char* name, u32 value) +{ + glUniform1ui(glGetUniformLocation(self->handle, name), value); +} + +void +shader_uniform_bool_set(Shader* self, const char* name, bool value) +{ + glUniform1i(glGetUniformLocation(self->handle, name), value); +} + +void +shader_uniform_f32_set(Shader* self, const char* name, f32 value) +{ + glUniform1f(glGetUniformLocation(self->handle, name), value); +} + +void +shader_uniform_vec2_set(Shader* self, const char* name, vec2 value) +{ + glUniform2fv(glGetUniformLocation(self->handle, name), 1, value); +} + +void +shader_uniform_vec3_set(Shader* self, const char* name, vec3 value) +{ + glUniform3fv(glGetUniformLocation(self->handle, name), 1, value); +} + +void +shader_uniform_vec4_set(Shader* self, const char* name, vec4 value) +{ + glUniform4fv(glGetUniformLocation(self->handle, name), 1, value); +} + +void +shader_uniform_mat4_set(Shader* self, const char* name, mat4 value) +{ + glUniformMatrix4fv(glGetUniformLocation(self->handle, name), 1, GL_FALSE, (f32*)value); +} + +void +shader_uniform_texture_set(Shader* self, const char* name, 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..b0dc27f --- /dev/null +++ b/src/engine/shader.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +#include "texture.h" + +#define SHADER_LOG_BUFFER_SIZE 1024 + +#define STRING_SHADER_COMPILE_SUCCESS "[INFO] Compiled shader: #%i\n" +#define STRING_SHADER_COMPILE_ERROR "[ERROR] Unable to compile shader: #%i, %s\n" + +typedef struct Shader +{ + GLuint handle; + bool isInit; +} Shader; + +bool shader_init(struct Shader* self, const char* vertex, const char* fragment); +void shader_use(struct Shader* self); +void shader_free(struct Shader* self); +void shader_uniform_f32_set(struct Shader* self, const char* name, f32 value); +void shader_uniform_s32_set(struct Shader* self, const char* name, s32 value); +void shader_uniform_u32_set(struct Shader* self, const char* name, u32 value); +void shader_uniform_bool_set(struct Shader* self, const char* name, bool value); +void shader_uniform_mat4_set(struct Shader* self, const char* name, mat4 value); +void shader_uniform_vec2_set(struct Shader* self, const char* name, vec2 value); +void shader_uniform_vec3_set(struct Shader* self, const char* name, vec3 value); +void shader_uniform_vec4_set(struct Shader* self, const char* name, vec4 value); +void shader_uniform_texture_set(struct Shader* self, const char* name, Texture* texture, s32 index); diff --git a/src/engine/sound.c b/src/engine/sound.c new file mode 100644 index 0000000..f3fc8c1 --- /dev/null +++ b/src/engine/sound.c @@ -0,0 +1,45 @@ +#include "sound.h" + +/* Initializes a sound. */ +bool +sound_init(Sound* self, const char* path) +{ + self->chunk = Mix_LoadWAV(path); + + if (!self->chunk) + { + printf(STRING_SDL_MIXER_SOUND_ERROR, path, Mix_GetError()); + return false; + } + + printf(STRING_SDL_MIXER_SOUND_SUCCESS, path); + + self->isInit = true; + + return true; +} + +/* Frees a sound. */ +void +sound_free(Sound* self) +{ + if (self->isInit) + { + Mix_FreeChunk(self->chunk); + self->isInit = false; + } +} + +/* Plays a sound, specifying a channel. */ +void +sound_play(Sound* self) +{ + Mix_PlayChannel(-1, self->chunk, 0); +} + +/* Stops a channel. */ +void +sound_channel_stop(s32 channel) +{ + Mix_HaltChannel(channel); +} diff --git a/src/engine/sound.h b/src/engine/sound.h new file mode 100644 index 0000000..f3186d7 --- /dev/null +++ b/src/engine/sound.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include "../COMMON.h" + +#define SOUND_NO_PRIORITY -1 + +#define STRING_SDL_MIXER_SOUND_SUCCESS "[INFO] Loaded sound: %s\n" +#define STRING_SDL_MIXER_SOUND_ERROR "[ERROR] Unable to load sound: %s | %s\n" + +typedef struct Sound +{ + Mix_Chunk* chunk; + bool isInit; +} Sound; + +bool sound_init(Sound* self, const char* path); +void sound_free(Sound* self); +void sound_play(Sound* self); +void sound_channel_stop(s32 channel); diff --git a/src/engine/surface.c b/src/engine/surface.c new file mode 100644 index 0000000..58057b3 --- /dev/null +++ b/src/engine/surface.c @@ -0,0 +1,17 @@ +#include "surface.h" + +void +surface_rgba_init(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..5e82630 --- /dev/null +++ b/src/engine/surface.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "../COMMON.h" + +void surface_rgba_init(SDL_Surface** self, ivec2 size); diff --git a/src/engine/texture.c b/src/engine/texture.c new file mode 100644 index 0000000..ab580d7 --- /dev/null +++ b/src/engine/texture.c @@ -0,0 +1,84 @@ +#include "texture.h" + +void +texture_surface_init(Texture* self, SDL_Surface* surface) +{ + ivec2 size; + + size[0] = surface->w; + size[1] = surface->h; + + texture_init(self, size, surface->pixels); +} + +bool +texture_from_path_init(Texture* self, const char* path) +{ + SDL_Surface* surface; + + memset(self, '\0', sizeof(Texture)); + + surface = IMG_Load(path); + + if (!surface) + { + printf(STRING_SDL_IMAGE_LOAD_ERROR, path, IMG_GetError()); + return false; + } + + printf(STRING_SDL_IMAGE_LOAD_SUCCESS, path); + + texture_surface_init(self, surface); + + SDL_FreeSurface(surface); + + return true; +} + +void +texture_init(Texture* self, ivec2 size, void* data) +{ + glGenTextures(1, &self->handle); + + texture_bind(self); + + glm_ivec2_copy(size, self->size); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self->size[0], self->size[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + + texture_parameter_set(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + texture_parameter_set(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + texture_parameter_set(GL_TEXTURE_MIN_FILTER, GL_NEAREST); + texture_parameter_set(GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glGenerateMipmap(GL_TEXTURE_2D); + + self->isInit = true; + + texture_unbind(); +} + +void +texture_bind(Texture* self) +{ + glBindTexture(GL_TEXTURE_2D, self->handle); +} + +void +texture_parameter_set(GLenum pname, GLint parameter) +{ + glTexParameteri(GL_TEXTURE_2D, pname, parameter); +} + +void +texture_unbind(void) +{ + glBindTexture(GL_TEXTURE_2D, 0); +} + +void +texture_free(Texture* self) +{ + glDeleteTextures(1, &self->handle); + memset(self, '\0', sizeof(Texture)); +} diff --git a/src/engine/texture.h b/src/engine/texture.h new file mode 100644 index 0000000..d425655 --- /dev/null +++ b/src/engine/texture.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include +#include + +#include "../COMMON.h" + +#define STRING_SDL_IMAGE_LOAD_ERROR "[ERROR] Unable to load image: %s | %s\n" +#define STRING_SDL_IMAGE_LOAD_SUCCESS "[INFO] Loaded image: %s\n" + +typedef struct Texture +{ + GLuint handle; + ivec2 size; + bool isInit; +} Texture; + +bool texture_from_path_init(Texture* self, const char* path); +void texture_init(Texture* self, ivec2 size, void* data); +void texture_surface_init(Texture* self, SDL_Surface* surface); +void texture_parameter_set(GLenum pname, GLint parameter); +void texture_bind(Texture* self); +void texture_unbind(void); +void texture_free(Texture* self); diff --git a/src/engine/tick.c b/src/engine/tick.c new file mode 100644 index 0000000..5d7acfa --- /dev/null +++ b/src/engine/tick.c @@ -0,0 +1,10 @@ +#include "tick.h" + +void +tick_update(Tick* self) +{ + self->previous = self->current; + self->current = SDL_GetTicks64(); + self->delta = self->current - self->previous; + self->cumulative += self->delta; +} diff --git a/src/engine/tick.h b/src/engine/tick.h new file mode 100644 index 0000000..ee32469 --- /dev/null +++ b/src/engine/tick.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include "../COMMON.h" + +typedef struct Tick +{ + u64 current; + u64 previous; + u64 delta; + u64 cumulative; +} Tick; + +void tick_update(Tick* self); diff --git a/src/engine/time.c b/src/engine/time.c new file mode 100644 index 0000000..3110dae --- /dev/null +++ b/src/engine/time.c @@ -0,0 +1,9 @@ +#include "time.h" + +void +time_formatted_get(u32 value, u32* minutes, u32* seconds, u32* milliseconds) +{ + *minutes = (u32)((f32)value / MINUTE_TICK); + *seconds = (u32)((f32)value / SECOND_TICK) % SECOND_TICK; + *milliseconds = (((f32)value - ((*minutes * MINUTE_TICK) + (*seconds * SECOND_TICK))) / SECOND_TICK) * 100; +} diff --git a/src/engine/time.h b/src/engine/time.h new file mode 100644 index 0000000..7c1c6d2 --- /dev/null +++ b/src/engine/time.h @@ -0,0 +1,5 @@ +#pragma once + +#include "../COMMON.h" + +void time_formatted_get(u32 value, u32* minutes, u32* seconds, u32* milliseconds); diff --git a/src/engine/vao.c b/src/engine/vao.c new file mode 100644 index 0000000..5882bff --- /dev/null +++ b/src/engine/vao.c @@ -0,0 +1,26 @@ +#include "vao.h" + +void +vao_init(VAO* self) +{ + glGenVertexArrays(1, &self->handle); +} + +void +vao_bind(VAO* self) +{ + glBindVertexArray(self->handle); +} + +void +vao_unbind(void) +{ + glBindVertexArray(0); +} + +void +vao_free(VAO* self) +{ + glDeleteVertexArrays(1, &self->handle); + memset(self, '\0', sizeof(VAO)); +} diff --git a/src/engine/vao.h b/src/engine/vao.h new file mode 100644 index 0000000..1a063b9 --- /dev/null +++ b/src/engine/vao.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +#include "../COMMON.h" + +typedef struct VAO +{ + GLuint handle; +} VAO; + +void vao_init(VAO* self); +void vao_bind(VAO* self); +void vao_unbind(void); +void vao_free(VAO* self); diff --git a/src/engine/vbo.c b/src/engine/vbo.c new file mode 100644 index 0000000..9cb13db --- /dev/null +++ b/src/engine/vbo.c @@ -0,0 +1,29 @@ +#include "vbo.h" + +void +vbo_init(VBO* self, GLint type, bool isDynamic) +{ + self->isDynamic = isDynamic; + self->type = type; + + glGenBuffers(1, &self->handle); +} + +void +vbo_bind(VBO* self) +{ + glBindBuffer(self->type, self->handle); +} + +void +vbo_free(VBO* self) +{ + glDeleteBuffers(1, &self->handle); + memset(self, '\0', sizeof(VBO)); +} + +void +vbo_buffer(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..1a7c96a --- /dev/null +++ b/src/engine/vbo.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +#include "../COMMON.h" + +typedef struct VBO +{ + GLuint handle; + GLint type; + bool isDynamic; +} VBO; + +void vbo_buffer(VBO* self, size_t size, void* data); +void vbo_bind(VBO* self); +void vbo_free(VBO* self); +void vbo_init(VBO* self, GLint type, bool isDynamic); diff --git a/src/engine/vector.c b/src/engine/vector.c new file mode 100644 index 0000000..1dd5af5 --- /dev/null +++ b/src/engine/vector.c @@ -0,0 +1,192 @@ +#include "vector.h" + +static void _vector_realloc(Vector* self); +static void _vector_forward(Vector* self, s32 index); +static void _vector_backward(Vector* self, s32 index); + +static void +_vector_realloc(Vector* self) +{ + if (self->count == 0) + { + self->data = NULL; + return; + } + + self->data = realloc(self->data, vector_size_get(self)); +} + +static void +_vector_forward(Vector* self, s32 index) +{ + s32 length; + + length = ((self->count - 1) - index); + + for (s32 i = 0; i < length; i++) + { + u8* data; + u8* nextData; + s32 currentIndex; + + currentIndex = index + i; + + data = (u8*)self->data + (currentIndex * self->itemSize); + nextData = data + self->itemSize; + + memcpy((void*)data, (void*)nextData, self->itemSize); + } + +} + +static void +_vector_backward(Vector* self, s32 index) +{ + s32 length; + + if (self->count == 0) + return; + + length = ((self->count - 1) - index); + + for (s32 i = 0; i < length; i++) + { + u8* data; + u8* prevData; + s32 index; + + index = (self->count - 1) - i; + + data = (u8*)self->data + (index * self->itemSize); + prevData = (u8*)data - self->itemSize; + + memcpy((void*)data, (void*)prevData, self->itemSize); + } +} + +size_t +vector_size_get(Vector* self) +{ + return self->count * self->itemSize; +} + +void +vector_init(Vector* self, size_t size) +{ + memset(self, '\0', sizeof(Vector)); + + self->itemSize = size; + + _vector_realloc(self); + + memset(self->data, '\0', vector_size_get(self)); +} + +void +vector_free(Vector* self) +{ + if (self->data) + free(self->data); + + self->count = 0; +} + +void* +vector_push(Vector* self, void* data) +{ + u8* pointer; + + self->count++; + + _vector_realloc(self); + + pointer = (u8*)self->data + (vector_size_get(self) - self->itemSize); + + if (data) + memcpy((void*)pointer, data, self->itemSize); + else + memset((void*)pointer, '\0', self->itemSize); + + return pointer; +} + +void +vector_pop(Vector* self) +{ + self->count--; + + _vector_realloc(self); +} + +void +vector_clear(Vector* self) +{ + self->count = 0; + + _vector_realloc(self); +} + +void* +vector_insert(Vector* self, void* data, s32 index) +{ + u8* pointer; + + _vector_backward(self, index); + + self->count++; + + _vector_realloc(self); + + pointer = (u8*)self->data + (index * self->itemSize); + + memcpy((void*)pointer, data, self->itemSize); + + return pointer; +} + +void +vector_remove(Vector* self, s32 index) +{ + _vector_forward(self, index); + + vector_pop(self); +} + +void* +vector_get(Vector* self, s32 index) +{ + return (void*)((u8*)self->data + (index * self->itemSize)); +} + +s32 +vector_index_get(Vector* self, void* data) +{ + s32 index; + + index = ((u8*)data - (u8*)self->data) / self->itemSize; + + return index; +} + +void +vector_remove_from_data(Vector* self, void* data) +{ + for (s32 i = 0; i < (s32)self->count; i++) + { + void* pointer; + s32 result; + + pointer = vector_get(self, i); + + result = memcmp(pointer, data, self->itemSize); + + if (result == 0) + vector_remove(self, i); + } +} + +void +vector_sort(Vector* self, SortCompareFunction function) +{ + qsort(self->data, self->count, self->itemSize, function); +} diff --git a/src/engine/vector.h b/src/engine/vector.h new file mode 100644 index 0000000..b985ff3 --- /dev/null +++ b/src/engine/vector.h @@ -0,0 +1,26 @@ +#pragma once + +#include "../COMMON.h" + +typedef struct Vector +{ + u32 count; + u32 limit; + size_t itemSize; + void* data; +} Vector; + +s32 vector_index_get(Vector* self, void* data); +size_t vector_size_get(Vector* self); +void vector_free(Vector* self); +void vector_init(Vector* self, size_t size); +void vector_pop(Vector* self); +void vector_remove(Vector* self, s32 index); +void vector_clear(Vector* self); +void vector_remove_from_data(Vector* self, void* data); +void* vector_get(Vector* self, s32 index); +void* vector_insert(Vector* self, void* data, s32 index); +void* vector_push(Vector* self, void* data); +void vector_print(Vector* self); +void vector_sort(Vector* self, SortCompareFunction function); +void vector_remove_from_data(Vector* self, void* data); diff --git a/src/engine/vertexattribute.c b/src/engine/vertexattribute.c new file mode 100644 index 0000000..3b2d7a5 --- /dev/null +++ b/src/engine/vertexattribute.c @@ -0,0 +1,24 @@ +#include "vertexattribute.h" + +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..ddfb405 --- /dev/null +++ b/src/engine/vertexattribute.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include + +#include "../COMMON.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..a156905 --- /dev/null +++ b/src/engine/window.c @@ -0,0 +1,49 @@ +#include "window.h" + +void +window_init(Window* self, char* name, ivec2 size, u32 flags) +{ + memset(self, '\0', sizeof(Window)); + + glm_ivec2_copy(size, self->expectedSize); + + self->sdl = SDL_CreateWindow + ( + name, + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + size[0], + size[1], + flags + ); + + SDL_ShowCursor(SDL_DISABLE); +} + +void +window_ivec4_get(struct Window* self, ivec4 value) +{ + ivec2 size; + + window_size_get(self, size); + + value[0] = 0; + value[1] = 0; + value[2] = size[0]; + value[3] = size[1]; +} + +void +window_size_get(Window* self, ivec2 size) +{ + SDL_GetWindowSize(self->sdl, &size[0], &size[1]); +} + +void +window_free(Window* self) +{ + SDL_DestroyWindow(self->sdl); + + memset(self, '\0', sizeof(Window)); +} + diff --git a/src/engine/window.h b/src/engine/window.h new file mode 100644 index 0000000..46aede3 --- /dev/null +++ b/src/engine/window.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +#include "../COMMON.h" + +typedef struct Window +{ + SDL_Window* sdl; + ivec2 expectedSize; +} Window; + +void window_init(Window* self, char* name, ivec2 size, u32 flags); +void window_free(Window* self); +void window_ivec4_get(Window* self, ivec4 size); +void window_size_get(Window* self, ivec2 size); + diff --git a/src/game/GAME_COMMON.h b/src/game/GAME_COMMON.h new file mode 100644 index 0000000..90139b5 --- /dev/null +++ b/src/game/GAME_COMMON.h @@ -0,0 +1,22 @@ +#pragma once + +#include "state/state.h" + +#include "../engine/tick.h" +#include "../engine/sdl.h" + +#include "render/buffer.h" + +typedef struct Game +{ + ECS ecs; + Input input; + Control control; + Renderer renderer; + Resources resources; + State state; + Tick tick; + Window window; + Postprocessing postprocessing[RENDERER_BUFFER_COUNT]; + bool isPaused; +} Game; diff --git a/src/game/ecs/ECS_COMMON.h b/src/game/ecs/ECS_COMMON.h new file mode 100644 index 0000000..1453d83 --- /dev/null +++ b/src/game/ecs/ECS_COMMON.h @@ -0,0 +1,66 @@ +#pragma once + +#include "component/COMPONENT_COMMON.h" + +#include "../../engine/vector.h" + +#define ECS_FUNCTION_COUNT ECS_FUNCTION_DRAW + 1 +typedef enum ECSFunctionType +{ + ECS_FUNCTION_ADD, + ECS_FUNCTION_DELETE, + ECS_FUNCTION_TICK, + ECS_FUNCTION_UPDATE, + ECS_FUNCTION_DRAW +} ECSFunctionType; + +typedef struct ECS ECS; +typedef struct Control Control; +typedef struct Input Input; +typedef struct Renderer Renderer; +typedef struct Postprocessing Postprocessing; +typedef struct Resources Resources; +typedef u32 EntityID; + +typedef void (*ECSFunction)(void*, ECS*); + +typedef struct ECSSystem +{ + ECSFunction functions[ECS_FUNCTION_COUNT]; +} ECSSystem; + +typedef struct Component +{ + EntityID id; + bool isDisabled; + bool isFunctionDisabled[ECS_FUNCTION_COUNT]; +} Component; + +typedef struct ComponentInfo +{ + ECSSystem system; + ComponentType type; + size_t size; +} ComponentInfo; + +typedef struct ComponentList +{ + ECS* ecs; + ECSSystem system; + ComponentType type; + Vector components; +} ComponentList; + +typedef struct ECS +{ + Input* input; + Control* control; + Renderer* renderer; + Resources* resources; + Postprocessing* postprocessing; + ComponentList lists[COMPONENT_COUNT]; + bool isFunctionDisabled[ECS_FUNCTION_COUNT]; + bool isLog; + EntityID nextID; +} ECS; + diff --git a/src/game/ecs/component/COMPONENT_COMMON.h b/src/game/ecs/component/COMPONENT_COMMON.h new file mode 100644 index 0000000..60a1c27 --- /dev/null +++ b/src/game/ecs/component/COMPONENT_COMMON.h @@ -0,0 +1,52 @@ +#pragma once + +#include "../../../COMMON.h" + +#define COMPONENT_COUNT COMPONENT_PULSATE + 1 +typedef enum ComponentType +{ + /* Utility */ + COMPONENT_TIMER, + COMPONENT_COUNTER, + COMPONENT_DELETE_ON_TIMER, + /* Physics */ + COMPONENT_PHYSICS, + COMPONENT_COPY_MOUSE_POSITION, + COMPONENT_CIRCLE_COLLIDER, + /* Game */ + COMPONENT_GAME_OBJECT, + COMPONENT_PLANE_OBJECT, + COMPONENT_WORLD_OBJECT, + COMPONENT_SOLID, + COMPONENT_LEVITATE, + COMPONENT_COLLIDE_SLOW, + COMPONENT_COLLECTIBLE, + COMPONENT_COLLECT, + COMPONENT_HOMING, + COMPONENT_FOOD, + COMPONENT_THRESHOLD, + COMPONENT_TAKE_FOOD, + COMPONENT_STAGE, + COMPONENT_STAMINA, + COMPONENT_POWER, + COMPONENT_PLAYER_CONTROL, + /* Animation */ + COMPONENT_ANIMATION, + COMPONENT_ANIMATION_PLAYER, + COMPONENT_ANIMATION_TARGET, + /* UI */ + COMPONENT_BUTTON, + /* Visual */ + COMPONENT_DROP_SHADOW, + COMPONENT_TEXTURE_QUAD, + COMPONENT_TEXT, + COMPONENT_DIALOGUE, + COMPONENT_VALUE_TEXT, + COMPONENT_ATLAS, + COMPONENT_CAMERA_FOCUS, + COMPONENT_COLOR_CHANGE, + COMPONENT_COLOR_MATCH, + COMPONENT_SCALE_VALUE, + COMPONENT_ROTATE, + COMPONENT_PULSATE +} ComponentType; diff --git a/src/game/ecs/component/animation/component_animation.c b/src/game/ecs/component/animation/component_animation.c new file mode 100644 index 0000000..4b4e48b --- /dev/null +++ b/src/game/ecs/component/animation/component_animation.c @@ -0,0 +1,87 @@ +#include "component_animation.h" + +void _component_animation_frame_set(ComponentAnimation* self, ECS* ecs); + +void +_component_animation_frame_set(ComponentAnimation* self, ECS* ecs) +{ + ComponentTimer* timer; + + if (self->isFinished) + return; + + timer = ecs_component_get(ecs, COMPONENT_TIMER, self->timer); + + if (timer->isFinished) + { + ComponentAtlas* atlas; + + if (self->frame >= self->animation.count) + { + if (!self->animation.isLoop) + { + self->isFinished = true; + return; + } + + self->frame = 0; + } + + atlas = ecs_component_get(ecs, COMPONENT_ATLAS, self->component.id); + + atlas->index = self->animation.frameIndices[self->frame]; + + component_timer_init(timer, ecs, self->animation.length); + + self->frame++; + } +} + +void +component_animation_add(ComponentAnimation* self, ECS* ecs) +{ + ComponentTimer* timer; + + self->timer = entity_timer_add(ecs, -1); + + timer = ecs_component_get(ecs, COMPONENT_TIMER, self->timer); + + timer->component.isDisabled = true; +} + +void +component_animation_delete(ComponentAnimation* self, ECS* ecs) +{ + ecs_entity_delete(ecs, self->timer); +} + +void +component_animation_set(ComponentAnimation* self, ECS* ecs, Animation* animation) +{ + ComponentTimer* timer; + + timer = ecs_component_get(ecs, COMPONENT_TIMER, self->timer); + + memcpy(&self->animation, animation, sizeof(Animation)); + + self->frame = 0; + self->isFinished = false; + + component_timer_init(timer, ecs, self->animation.length); + timer->component.isDisabled = false; + timer->isFinished = true; + + _component_animation_frame_set(self, ecs); +} + +void +component_animation_init(ComponentAnimation* self, ECS* ecs, Animation* animation) +{ + component_animation_set(self, ecs, animation); +} + +void +component_animation_tick(ComponentAnimation* self, ECS* ecs) +{ + _component_animation_frame_set(self, ecs); +} diff --git a/src/game/ecs/component/animation/component_animation.h b/src/game/ecs/component/animation/component_animation.h new file mode 100644 index 0000000..2a46c42 --- /dev/null +++ b/src/game/ecs/component/animation/component_animation.h @@ -0,0 +1,44 @@ +#pragma once + +#include "../../entity/utility/entity_timer.h" +#include "../../component/visual/component_atlas.h" + +typedef struct Animation +{ + u32* frameIndices; + u32 count; + u32 length; + bool isLoop; +} Animation; + +typedef struct ComponentAnimation +{ + Component component; + EntityID timer; + u32 frame; + bool isFinished; + Animation animation; +} ComponentAnimation; + +void component_animation_add(ComponentAnimation* self, ECS* ecs); +void component_animation_delete(ComponentAnimation* self, ECS* ecs); +void component_animation_tick(ComponentAnimation* self, ECS* ecs); +void component_animation_set(ComponentAnimation* self, ECS* ecs, Animation* animation); +void component_animation_init(ComponentAnimation* self, ECS* ecs, Animation* animation); + +static const ComponentInfo COMPONENT_ANIMATION_INFO = +{ + .system = + { + .functions = + { + (ECSFunction)component_animation_add, + (ECSFunction)component_animation_delete, + (ECSFunction)component_animation_tick, + NULL, + NULL + } + }, + .type = COMPONENT_ANIMATION, + .size = sizeof(ComponentAnimation) +}; diff --git a/src/game/ecs/component/animation/component_animation_player.c b/src/game/ecs/component/animation/component_animation_player.c new file mode 100644 index 0000000..aa0465c --- /dev/null +++ b/src/game/ecs/component/animation/component_animation_player.c @@ -0,0 +1,87 @@ +#include "component_animation_player.h" + +void _component_animation_player_set(ComponentAnimationPlayer* self, ECS* ecs, AnimationPlayerType type); +void _component_animation_player_determine(ComponentAnimationPlayer* self, ECS* ecs); + +void +_component_animation_player_set(ComponentAnimationPlayer* self, ECS* ecs, AnimationPlayerType type) +{ + ComponentAnimation* animation; + + if (type == self->type) + return; + + self->type = type; + + animation = ecs_component_get(ecs, COMPONENT_ANIMATION, self->component.id); + + component_animation_set(animation, ecs, &ANIMATION_PLAYER_STRUCTS[type]); +} + +void +_component_animation_player_determine(ComponentAnimationPlayer* self, ECS* ecs) +{ + AnimationPlayerType type; + ComponentWorldObject* worldObject; + + worldObject = ecs_component_get(ecs, COMPONENT_WORLD_OBJECT, self->component.id); + + type = (AnimationPlayerType)(self->action + ((ANIMATION_PLAYER_ACTION_COUNT) * worldObject->direction)); + + _component_animation_player_set(self, ecs, type); +} + +void +component_animation_player_init(ComponentAnimationPlayer* self, ECS* ecs, AnimationPlayerType type) +{ + self->type = -1; + self->action = ANIMATION_PLAYER_ACTION_IDLE; + + _component_animation_player_set(self, ecs, type); +} + +void +component_animation_player_tick(ComponentAnimationPlayer* self, ECS* ecs) +{ + ComponentWorldObject* worldObject; + ComponentPlayerControl* playerControl; + ComponentPhysics* physics; + ComponentAnimation* animation; + ComponentTimer* animationTimer; + f32 nextPositionDistance; + s32 newTimer; + + worldObject = ecs_component_get(ecs, COMPONENT_WORLD_OBJECT, self->component.id); + + if (worldObject->isAirborne && self->action == ANIMATION_PLAYER_ACTION_LUNGE) + return; + + playerControl = ecs_component_get(ecs, COMPONENT_PLAYER_CONTROL, self->component.id); + physics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->component.id); + + self->action = ANIMATION_PLAYER_ACTION_IDLE; + + if (playerControl->isLunge) + { + self->action = ANIMATION_PLAYER_ACTION_LUNGE; + sound_play(&ecs->resources->sounds[SOUND_LUNGE + RANDOM_S32(0, SOUND_LUNGE_COUNT - 1)]); + } + else if (physics->isMoving) + { + self->action = ANIMATION_PLAYER_ACTION_RUN; + + animation = ecs_component_get(ecs, COMPONENT_ANIMATION, self->component.id); + animationTimer = ecs_component_get(ecs, COMPONENT_TIMER, animation->timer); + + nextPositionDistance = component_physics_next_position_distance_get(physics, ecs); + + newTimer = ANIMATION_PLAYER_RUN_TIMER - (s32)((nextPositionDistance / ANIMATION_PLAYER_RUN_DISTANCE_MAX) * ANIMATION_PLAYER_RUN_TIMER); + + newTimer = MIN(newTimer, (s32)ANIMATION_PLAYER_RUN_TIMER_MIN); + + if (animationTimer->value > (s32)ANIMATION_PLAYER_RUN_TIMER_MIN) + animationTimer->value = (s32)(CLAMP((s32)animationTimer->value, (s32)ANIMATION_PLAYER_RUN_TIMER_MIN, (s32)newTimer)); + } + + _component_animation_player_determine(self, ecs); +} diff --git a/src/game/ecs/component/animation/component_animation_player.h b/src/game/ecs/component/animation/component_animation_player.h new file mode 100644 index 0000000..cdbe35c --- /dev/null +++ b/src/game/ecs/component/animation/component_animation_player.h @@ -0,0 +1,199 @@ +#pragma once + +#include "component_animation.h" +#include "../game/component_world_object.h" +#include "../game/component_player_control.h" + +static const f32 ANIMATION_PLAYER_RUN_DISTANCE_MAX = 50.0f; +static const u32 ANIMATION_PLAYER_RUN_TIMER = 20; +static const u32 ANIMATION_PLAYER_RUN_TIMER_MIN = 5; + +#define ANIMATION_PLAYER_COUNT ANIMATION_PLAYER_LUNGE_DOWN + 1 +typedef enum AnimationPlayerType +{ + ANIMATION_PLAYER_IDLE_LEFT, + ANIMATION_PLAYER_RUN_LEFT, + ANIMATION_PLAYER_LUNGE_LEFT, + ANIMATION_PLAYER_IDLE_RIGHT, + ANIMATION_PLAYER_RUN_RIGHT, + ANIMATION_PLAYER_LUNGE_RIGHT, + ANIMATION_PLAYER_IDLE_UP, + ANIMATION_PLAYER_RUN_UP, + ANIMATION_PLAYER_LUNGE_UP, + ANIMATION_PLAYER_IDLE_DOWN, + ANIMATION_PLAYER_RUN_DOWN, + ANIMATION_PLAYER_LUNGE_DOWN +} AnimationPlayerType; + +#define ANIMATION_PLAYER_ACTION_COUNT (ANIMATION_PLAYER_ACTION_LUNGE + 1) +typedef enum AnimationPlayerActionType +{ + ANIMATION_PLAYER_ACTION_IDLE, + ANIMATION_PLAYER_ACTION_RUN, + ANIMATION_PLAYER_ACTION_LUNGE +} AnimationPlayerActionType; + +#define ANIMATION_PLAYER_IDLE_LEFT_COUNT 1 +static const u32 ANIMATION_PLAYER_IDLE_LEFT_FRAME_INDICES[ANIMATION_PLAYER_IDLE_LEFT_COUNT] = {0}; +static const struct Animation ANIMATION_PLAYER_IDLE_LEFT_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_PLAYER_IDLE_LEFT_FRAME_INDICES, + .count = ANIMATION_PLAYER_IDLE_LEFT_COUNT, + .length = 0, + .isLoop = true +}; + +#define ANIMATION_PLAYER_RUN_LEFT_COUNT 3 +static const u32 ANIMATION_PLAYER_RUN_LEFT_FRAME_INDICES[ANIMATION_PLAYER_RUN_LEFT_COUNT] = {1, 2, 3}; +static const struct Animation ANIMATION_PLAYER_RUN_LEFT_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_PLAYER_RUN_LEFT_FRAME_INDICES, + .count = ANIMATION_PLAYER_RUN_LEFT_COUNT, + .length = 20, + .isLoop = true +}; + + +#define ANIMATION_PLAYER_LUNGE_LEFT_COUNT 1 +static const u32 ANIMATION_PLAYER_LUNGE_LEFT_FRAME_INDICES[ANIMATION_PLAYER_LUNGE_LEFT_COUNT] = {4}; +static const struct Animation ANIMATION_PLAYER_LUNGE_LEFT_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_PLAYER_LUNGE_LEFT_FRAME_INDICES, + .count = ANIMATION_PLAYER_LUNGE_LEFT_COUNT, + .length = 0, + .isLoop = true +}; + +#define ANIMATION_PLAYER_IDLE_RIGHT_COUNT 1 +static const u32 ANIMATION_PLAYER_IDLE_RIGHT_FRAME_INDICES[ANIMATION_PLAYER_IDLE_RIGHT_COUNT] = {5}; +static const struct Animation ANIMATION_PLAYER_IDLE_RIGHT_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_PLAYER_IDLE_RIGHT_FRAME_INDICES, + .count = ANIMATION_PLAYER_IDLE_RIGHT_COUNT, + .length = 0, + .isLoop = true +}; + +#define ANIMATION_PLAYER_RUN_RIGHT_COUNT 3 +static const u32 ANIMATION_PLAYER_RUN_RIGHT_FRAME_INDICES[ANIMATION_PLAYER_RUN_RIGHT_COUNT] = {6, 7, 8}; +static const struct Animation ANIMATION_PLAYER_RUN_RIGHT_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_PLAYER_RUN_RIGHT_FRAME_INDICES, + .count = ANIMATION_PLAYER_RUN_RIGHT_COUNT, + .length = 20, + .isLoop = true +}; + +#define ANIMATION_PLAYER_LUNGE_RIGHT_COUNT 1 +static const u32 ANIMATION_PLAYER_LUNGE_RIGHT_FRAME_INDICES[ANIMATION_PLAYER_LUNGE_RIGHT_COUNT] = {9}; +static const struct Animation ANIMATION_PLAYER_LUNGE_RIGHT_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_PLAYER_LUNGE_RIGHT_FRAME_INDICES, + .count = ANIMATION_PLAYER_LUNGE_RIGHT_COUNT, + .length = 0, + .isLoop = true +}; + + +#define ANIMATION_PLAYER_IDLE_UP_COUNT 1 +static const u32 ANIMATION_PLAYER_IDLE_UP_FRAME_INDICES[ANIMATION_PLAYER_IDLE_UP_COUNT] = {10}; +static const struct Animation ANIMATION_PLAYER_IDLE_UP_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_PLAYER_IDLE_UP_FRAME_INDICES, + .count = ANIMATION_PLAYER_IDLE_UP_COUNT, + .length = 0, + .isLoop = true +}; + +#define ANIMATION_PLAYER_RUN_UP_COUNT 3 +static const u32 ANIMATION_PLAYER_RUN_UP_FRAME_INDICES[ANIMATION_PLAYER_RUN_UP_COUNT] = {11, 12, 13}; +static const struct Animation ANIMATION_PLAYER_RUN_UP_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_PLAYER_RUN_UP_FRAME_INDICES, + .count = ANIMATION_PLAYER_RUN_UP_COUNT, + .length = 20, + .isLoop = true +}; + +#define ANIMATION_PLAYER_LUNGE_UP_COUNT 1 +static const u32 ANIMATION_PLAYER_LUNGE_UP_FRAME_INDICES[ANIMATION_PLAYER_LUNGE_UP_COUNT] = {14}; +static const struct Animation ANIMATION_PLAYER_LUNGE_UP_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_PLAYER_LUNGE_UP_FRAME_INDICES, + .count = ANIMATION_PLAYER_LUNGE_UP_COUNT, + .length = 0, + .isLoop = true +}; + +#define ANIMATION_PLAYER_IDLE_DOWN_COUNT 1 +static const u32 ANIMATION_PLAYER_IDLE_DOWN_FRAME_INDICES[ANIMATION_PLAYER_IDLE_DOWN_COUNT] = {15}; +static const struct Animation ANIMATION_PLAYER_IDLE_DOWN_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_PLAYER_IDLE_DOWN_FRAME_INDICES, + .count = ANIMATION_PLAYER_IDLE_DOWN_COUNT, + .length = 0, + .isLoop = true +}; + +#define ANIMATION_PLAYER_RUN_DOWN_COUNT 3 +static const u32 ANIMATION_PLAYER_RUN_DOWN_FRAME_INDICES[ANIMATION_PLAYER_RUN_DOWN_COUNT] = {16, 17, 18}; +static const struct Animation ANIMATION_PLAYER_RUN_DOWN_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_PLAYER_RUN_DOWN_FRAME_INDICES, + .count = ANIMATION_PLAYER_RUN_DOWN_COUNT, + .length = 20, + .isLoop = true +}; + +#define ANIMATION_PLAYER_LUNGE_DOWN_COUNT 1 +static const u32 ANIMATION_PLAYER_LUNGE_DOWN_FRAME_INDICES[ANIMATION_PLAYER_LUNGE_DOWN_COUNT] = {19}; +static const struct Animation ANIMATION_PLAYER_LUNGE_DOWN_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_PLAYER_LUNGE_DOWN_FRAME_INDICES, + .count = ANIMATION_PLAYER_LUNGE_DOWN_COUNT, + .length = 0, + .isLoop = true +}; + +static const struct Animation ANIMATION_PLAYER_STRUCTS[ANIMATION_PLAYER_COUNT] = +{ + ANIMATION_PLAYER_IDLE_LEFT_STRUCT, + ANIMATION_PLAYER_RUN_LEFT_STRUCT, + ANIMATION_PLAYER_LUNGE_LEFT_STRUCT, + ANIMATION_PLAYER_IDLE_RIGHT_STRUCT, + ANIMATION_PLAYER_RUN_RIGHT_STRUCT, + ANIMATION_PLAYER_LUNGE_RIGHT_STRUCT, + ANIMATION_PLAYER_IDLE_UP_STRUCT, + ANIMATION_PLAYER_RUN_UP_STRUCT, + ANIMATION_PLAYER_LUNGE_UP_STRUCT, + ANIMATION_PLAYER_IDLE_DOWN_STRUCT, + ANIMATION_PLAYER_RUN_DOWN_STRUCT, + ANIMATION_PLAYER_LUNGE_DOWN_STRUCT +}; + +typedef struct ComponentAnimationPlayer +{ + Component component; + AnimationPlayerType type; + AnimationPlayerActionType action; +} ComponentAnimationPlayer; + +void component_animation_player_init(ComponentAnimationPlayer* self, ECS* ecs, AnimationPlayerType type); +void component_animation_player_tick(ComponentAnimationPlayer* self, ECS* ecs); + +static const ComponentInfo COMPONENT_ANIMATION_PLAYER_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_animation_player_tick, + NULL, + NULL + } + }, + .type = COMPONENT_ANIMATION_PLAYER, + .size = sizeof(ComponentAnimationPlayer) +}; diff --git a/src/game/ecs/component/animation/component_animation_target.c b/src/game/ecs/component/animation/component_animation_target.c new file mode 100644 index 0000000..9ae1b5b --- /dev/null +++ b/src/game/ecs/component/animation/component_animation_target.c @@ -0,0 +1,107 @@ +#include "component_animation_target.h" + +void _component_animation_target_set(ComponentAnimationTarget* self, ECS* ecs, AnimationTargetType type); +void _component_animation_target_determine(ComponentAnimationTarget* self, ECS* ecs); + +void +_component_animation_target_set(ComponentAnimationTarget* self, ECS* ecs, AnimationTargetType type) +{ + ComponentAnimation* animation; + + if (type == self->type) + return; + + self->type = type; + + animation = ecs_component_get(ecs, COMPONENT_ANIMATION, self->component.id); + + component_animation_set(animation, ecs, &ANIMATION_TARGET_STRUCTS[type]); +} + +void +_component_animation_target_determine(ComponentAnimationTarget* self, ECS* ecs) +{ + ComponentStage* stage; + AnimationTargetType type; + + stage = ecs_component_get(ecs, COMPONENT_STAGE, self->component.id); + + type = (AnimationTargetType)(self->action + ((ANIMATION_TARGET_ACTION_COUNT) * stage->value)); + + _component_animation_target_set(self, ecs, type); +} + +void +component_animation_target_init(ComponentAnimationTarget* self, ECS* ecs, AnimationTargetType type, EntityID playerID) +{ + self->type = -1; + self->action = ANIMATION_TARGET_ACTION_IDLE; + self->playerID = playerID; + + _component_animation_target_set(self, ecs, type); +} + +void +component_animation_target_tick(ComponentAnimationTarget* self, ECS* ecs) +{ + ComponentFood* playerFood; + ComponentTakeFood* takeFood; + ComponentAnimation* animation; + + animation = ecs_component_get(ecs, COMPONENT_ANIMATION, self->component.id); + + if + ( + (self->action == ANIMATION_TARGET_ACTION_GULP || self->action == ANIMATION_TARGET_ACTION_BURP) && + !animation->isFinished + ) + return; + + if (self->action == ANIMATION_TARGET_ACTION_GULP && animation->isFinished) + { + self->action = ANIMATION_TARGET_ACTION_BURP; + + sound_play(&ecs->resources->sounds[SOUND_BURP + RANDOM_S32(0, SOUND_BURP_COUNT - 1)]); + + _component_animation_target_determine(self, ecs); + + return; + } + + playerFood = ecs_component_get(ecs, COMPONENT_FOOD, self->playerID); + takeFood = ecs_component_get(ecs, COMPONENT_TAKE_FOOD, self->component.id); + + if (self->action == ANIMATION_TARGET_ACTION_BURP && animation->isFinished) + { + sound_play(&ecs->resources->sounds[SOUND_GURGLE + RANDOM_S32(0, SOUND_GURGLE_COUNT - 1)]); + takeFood->component.isDisabled = false; + } + + self->action = ANIMATION_TARGET_ACTION_IDLE; + + if (takeFood->isTakeFood) + { + self->action = ANIMATION_TARGET_ACTION_GULP; + + takeFood->isTakeFood = false; + takeFood->component.isDisabled = true; + + sound_play(&ecs->resources->sounds[SOUND_GULP + RANDOM_S32(0, SOUND_GULP_COUNT - 1)]); + } + else if (playerFood->value > 0) + { + ComponentPhysics* playerPhysics; + ComponentPhysics* physics; + f32 distance; + + playerPhysics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->playerID); + physics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->component.id); + + distance = DISTANCE_2D(playerPhysics->position[0], physics->position[0], playerPhysics->position[1], physics->position[1]); + + if (distance <= ANIMATION_TARGET_POINT_RADIUS && !self->isPointDisabled) + self->action = ANIMATION_TARGET_ACTION_POINT; + } + + _component_animation_target_determine(self, ecs); +} diff --git a/src/game/ecs/component/animation/component_animation_target.h b/src/game/ecs/component/animation/component_animation_target.h new file mode 100644 index 0000000..c0121fc --- /dev/null +++ b/src/game/ecs/component/animation/component_animation_target.h @@ -0,0 +1,296 @@ +#pragma once + +#include "component_animation.h" +#include "../game/component_food.h" +#include "../game/component_take_food.h" +#include "../game/component_stage.h" +#include "../game/component_world_object.h" + +static const f32 ANIMATION_TARGET_POINT_RADIUS = 1500.0f; + +#define ANIMATION_TARGET_COUNT (ANIMATION_TARGET_BURP_STAGE_FIVE + 1) +typedef enum AnimationTargetType +{ + ANIMATION_TARGET_IDLE_STAGE_ONE, + ANIMATION_TARGET_POINT_STAGE_ONE, + ANIMATION_TARGET_GULP_STAGE_ONE, + ANIMATION_TARGET_BURP_STAGE_ONE, + ANIMATION_TARGET_IDLE_STAGE_TWO, + ANIMATION_TARGET_POINT_STAGE_TWO, + ANIMATION_TARGET_GULP_STAGE_TWO, + ANIMATION_TARGET_BURP_STAGE_TWO, + ANIMATION_TARGET_IDLE_STAGE_THREE, + ANIMATION_TARGET_POINT_STAGE_THREE, + ANIMATION_TARGET_GULP_STAGE_THREE, + ANIMATION_TARGET_BURP_STAGE_THREE, + ANIMATION_TARGET_IDLE_STAGE_FOUR, + ANIMATION_TARGET_POINT_STAGE_FOUR, + ANIMATION_TARGET_GULP_STAGE_FOUR, + ANIMATION_TARGET_BURP_STAGE_FOUR, + ANIMATION_TARGET_IDLE_STAGE_FIVE, + ANIMATION_TARGET_POINT_STAGE_FIVE, + ANIMATION_TARGET_GULP_STAGE_FIVE, + ANIMATION_TARGET_BURP_STAGE_FIVE +} AnimationTargetType; + +#define ANIMATION_TARGET_ACTION_COUNT (ANIMATION_TARGET_ACTION_BURP + 1) +typedef enum AnimationTargetActionType +{ + ANIMATION_TARGET_ACTION_IDLE, + ANIMATION_TARGET_ACTION_POINT, + ANIMATION_TARGET_ACTION_GULP, + ANIMATION_TARGET_ACTION_BURP +} AnimationTargetActionType; + +#define ANIMATION_TARGET_IDLE_STAGE_ONE_COUNT 2 +static const u32 ANIMATION_TARGET_IDLE_STAGE_ONE_FRAME_INDICES[ANIMATION_TARGET_IDLE_STAGE_ONE_COUNT] = {0, 1}; +static const struct Animation ANIMATION_TARGET_IDLE_STAGE_ONE_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_IDLE_STAGE_ONE_FRAME_INDICES, + .count = ANIMATION_TARGET_IDLE_STAGE_ONE_COUNT, + .length = 30, + .isLoop = true +}; + +#define ANIMATION_TARGET_POINT_STAGE_ONE_COUNT 1 +static const u32 ANIMATION_TARGET_POINT_STAGE_ONE_FRAME_INDICES[ANIMATION_TARGET_POINT_STAGE_ONE_COUNT] = {2}; +static const struct Animation ANIMATION_TARGET_POINT_STAGE_ONE_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_POINT_STAGE_ONE_FRAME_INDICES, + .count = ANIMATION_TARGET_POINT_STAGE_ONE_COUNT, + .length = 0, + .isLoop = true +}; + +#define ANIMATION_TARGET_GULP_STAGE_ONE_COUNT 1 +static const u32 ANIMATION_TARGET_GULP_STAGE_ONE_FRAME_INDICES[ANIMATION_TARGET_GULP_STAGE_ONE_COUNT] = {3}; +static const struct Animation ANIMATION_TARGET_GULP_STAGE_ONE_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_GULP_STAGE_ONE_FRAME_INDICES, + .count = ANIMATION_TARGET_GULP_STAGE_ONE_COUNT, + .length = 60, + .isLoop = false +}; + +#define ANIMATION_TARGET_BURP_STAGE_ONE_COUNT 1 +static const u32 ANIMATION_TARGET_BURP_STAGE_ONE_FRAME_INDICES[ANIMATION_TARGET_BURP_STAGE_ONE_COUNT] = {4}; +static const struct Animation ANIMATION_TARGET_BURP_STAGE_ONE_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_BURP_STAGE_ONE_FRAME_INDICES, + .count = ANIMATION_TARGET_BURP_STAGE_ONE_COUNT, + .length = 60, + .isLoop = false +}; + +#define ANIMATION_TARGET_IDLE_STAGE_TWO_COUNT 2 +static const u32 ANIMATION_TARGET_IDLE_STAGE_TWO_FRAME_INDICES[ANIMATION_TARGET_IDLE_STAGE_TWO_COUNT] = {5, 6}; +static const struct Animation ANIMATION_TARGET_IDLE_STAGE_TWO_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_IDLE_STAGE_TWO_FRAME_INDICES, + .count = ANIMATION_TARGET_IDLE_STAGE_TWO_COUNT, + .length = 30, + .isLoop = true +}; + +#define ANIMATION_TARGET_POINT_STAGE_TWO_COUNT 1 +static const u32 ANIMATION_TARGET_POINT_STAGE_TWO_FRAME_INDICES[ANIMATION_TARGET_POINT_STAGE_TWO_COUNT] = {7}; +static const struct Animation ANIMATION_TARGET_POINT_STAGE_TWO_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_POINT_STAGE_TWO_FRAME_INDICES, + .count = ANIMATION_TARGET_POINT_STAGE_TWO_COUNT, + .length = 0, + .isLoop = true +}; + +#define ANIMATION_TARGET_GULP_STAGE_TWO_COUNT 1 +static const u32 ANIMATION_TARGET_GULP_STAGE_TWO_FRAME_INDICES[ANIMATION_TARGET_GULP_STAGE_TWO_COUNT] = {8}; +static const struct Animation ANIMATION_TARGET_GULP_STAGE_TWO_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_GULP_STAGE_TWO_FRAME_INDICES, + .count = ANIMATION_TARGET_GULP_STAGE_TWO_COUNT, + .length = 60, + .isLoop = false +}; + +#define ANIMATION_TARGET_BURP_STAGE_TWO_COUNT 1 +static const u32 ANIMATION_TARGET_BURP_STAGE_TWO_FRAME_INDICES[ANIMATION_TARGET_BURP_STAGE_TWO_COUNT] = {9}; +static const struct Animation ANIMATION_TARGET_BURP_STAGE_TWO_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_BURP_STAGE_TWO_FRAME_INDICES, + .count = ANIMATION_TARGET_BURP_STAGE_TWO_COUNT, + .length = 60, + .isLoop = false +}; + +#define ANIMATION_TARGET_IDLE_STAGE_THREE_COUNT 2 +static const u32 ANIMATION_TARGET_IDLE_STAGE_THREE_FRAME_INDICES[ANIMATION_TARGET_IDLE_STAGE_THREE_COUNT] = {10, 11}; +static const struct Animation ANIMATION_TARGET_IDLE_STAGE_THREE_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_IDLE_STAGE_THREE_FRAME_INDICES, + .count = ANIMATION_TARGET_IDLE_STAGE_THREE_COUNT, + .length = 30, + .isLoop = true +}; + +#define ANIMATION_TARGET_POINT_STAGE_THREE_COUNT 1 +static const u32 ANIMATION_TARGET_POINT_STAGE_THREE_FRAME_INDICES[ANIMATION_TARGET_POINT_STAGE_THREE_COUNT] = {12}; +static const struct Animation ANIMATION_TARGET_POINT_STAGE_THREE_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_POINT_STAGE_THREE_FRAME_INDICES, + .count = ANIMATION_TARGET_POINT_STAGE_THREE_COUNT, + .length = 0, + .isLoop = true +}; + +#define ANIMATION_TARGET_GULP_STAGE_THREE_COUNT 1 +static const u32 ANIMATION_TARGET_GULP_STAGE_THREE_FRAME_INDICES[ANIMATION_TARGET_GULP_STAGE_THREE_COUNT] = {13}; +static const struct Animation ANIMATION_TARGET_GULP_STAGE_THREE_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_GULP_STAGE_THREE_FRAME_INDICES, + .count = ANIMATION_TARGET_GULP_STAGE_THREE_COUNT, + .length = 60, + .isLoop = false +}; + +#define ANIMATION_TARGET_BURP_STAGE_THREE_COUNT 1 +static const u32 ANIMATION_TARGET_BURP_STAGE_THREE_FRAME_INDICES[ANIMATION_TARGET_BURP_STAGE_THREE_COUNT] = {14}; +static const struct Animation ANIMATION_TARGET_BURP_STAGE_THREE_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_BURP_STAGE_THREE_FRAME_INDICES, + .count = ANIMATION_TARGET_BURP_STAGE_THREE_COUNT, + .length = 60, + .isLoop = false +}; + +#define ANIMATION_TARGET_IDLE_STAGE_FOUR_COUNT 2 +static const u32 ANIMATION_TARGET_IDLE_STAGE_FOUR_FRAME_INDICES[ANIMATION_TARGET_IDLE_STAGE_FOUR_COUNT] = {15, 16}; +static const struct Animation ANIMATION_TARGET_IDLE_STAGE_FOUR_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_IDLE_STAGE_FOUR_FRAME_INDICES, + .count = ANIMATION_TARGET_IDLE_STAGE_FOUR_COUNT, + .length = 30, + .isLoop = true +}; + +#define ANIMATION_TARGET_POINT_STAGE_FOUR_COUNT 1 +static const u32 ANIMATION_TARGET_POINT_STAGE_FOUR_FRAME_INDICES[ANIMATION_TARGET_POINT_STAGE_FOUR_COUNT] = {17}; +static const struct Animation ANIMATION_TARGET_POINT_STAGE_FOUR_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_POINT_STAGE_FOUR_FRAME_INDICES, + .count = ANIMATION_TARGET_POINT_STAGE_FOUR_COUNT, + .length = 0, + .isLoop = true +}; + +#define ANIMATION_TARGET_GULP_STAGE_FOUR_COUNT 1 +static const u32 ANIMATION_TARGET_GULP_STAGE_FOUR_FRAME_INDICES[ANIMATION_TARGET_GULP_STAGE_FOUR_COUNT] = {18}; +static const struct Animation ANIMATION_TARGET_GULP_STAGE_FOUR_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_GULP_STAGE_FOUR_FRAME_INDICES, + .count = ANIMATION_TARGET_GULP_STAGE_FOUR_COUNT, + .length = 60, + .isLoop = false +}; + +#define ANIMATION_TARGET_BURP_STAGE_FOUR_COUNT 1 +static const u32 ANIMATION_TARGET_BURP_STAGE_FOUR_FRAME_INDICES[ANIMATION_TARGET_BURP_STAGE_FOUR_COUNT] = {19}; +static const struct Animation ANIMATION_TARGET_BURP_STAGE_FOUR_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_BURP_STAGE_FOUR_FRAME_INDICES, + .count = ANIMATION_TARGET_BURP_STAGE_FOUR_COUNT, + .length = 60, + .isLoop = false +}; + +#define ANIMATION_TARGET_IDLE_STAGE_FIVE_COUNT 2 +static const u32 ANIMATION_TARGET_IDLE_STAGE_FIVE_FRAME_INDICES[ANIMATION_TARGET_IDLE_STAGE_FIVE_COUNT] = {20, 21}; +static const struct Animation ANIMATION_TARGET_IDLE_STAGE_FIVE_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_IDLE_STAGE_FIVE_FRAME_INDICES, + .count = ANIMATION_TARGET_IDLE_STAGE_FIVE_COUNT, + .length = 30, + .isLoop = true +}; + +#define ANIMATION_TARGET_POINT_STAGE_FIVE_COUNT 1 +static const u32 ANIMATION_TARGET_POINT_STAGE_FIVE_FRAME_INDICES[ANIMATION_TARGET_POINT_STAGE_FIVE_COUNT] = {22}; +static const struct Animation ANIMATION_TARGET_POINT_STAGE_FIVE_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_POINT_STAGE_FIVE_FRAME_INDICES, + .count = ANIMATION_TARGET_POINT_STAGE_FIVE_COUNT, + .length = 0, + .isLoop = true +}; + +#define ANIMATION_TARGET_GULP_STAGE_FIVE_COUNT 1 +static const u32 ANIMATION_TARGET_GULP_STAGE_FIVE_FRAME_INDICES[ANIMATION_TARGET_GULP_STAGE_FIVE_COUNT] = {23}; +static const struct Animation ANIMATION_TARGET_GULP_STAGE_FIVE_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_GULP_STAGE_FIVE_FRAME_INDICES, + .count = ANIMATION_TARGET_GULP_STAGE_FIVE_COUNT, + .length = 60, + .isLoop = false +}; + +#define ANIMATION_TARGET_BURP_STAGE_FIVE_COUNT 1 +static const u32 ANIMATION_TARGET_BURP_STAGE_FIVE_FRAME_INDICES[ANIMATION_TARGET_BURP_STAGE_FIVE_COUNT] = {24}; +static const struct Animation ANIMATION_TARGET_BURP_STAGE_FIVE_STRUCT = +{ + .frameIndices = (u32*)ANIMATION_TARGET_BURP_STAGE_FIVE_FRAME_INDICES, + .count = ANIMATION_TARGET_BURP_STAGE_FIVE_COUNT, + .length = 60, + .isLoop = false +}; + +static const struct Animation ANIMATION_TARGET_STRUCTS[ANIMATION_TARGET_COUNT] = +{ + ANIMATION_TARGET_IDLE_STAGE_ONE_STRUCT, + ANIMATION_TARGET_POINT_STAGE_ONE_STRUCT, + ANIMATION_TARGET_GULP_STAGE_ONE_STRUCT, + ANIMATION_TARGET_BURP_STAGE_ONE_STRUCT, + ANIMATION_TARGET_IDLE_STAGE_TWO_STRUCT, + ANIMATION_TARGET_POINT_STAGE_TWO_STRUCT, + ANIMATION_TARGET_GULP_STAGE_TWO_STRUCT, + ANIMATION_TARGET_BURP_STAGE_TWO_STRUCT, + ANIMATION_TARGET_IDLE_STAGE_THREE_STRUCT, + ANIMATION_TARGET_POINT_STAGE_THREE_STRUCT, + ANIMATION_TARGET_GULP_STAGE_THREE_STRUCT, + ANIMATION_TARGET_BURP_STAGE_THREE_STRUCT, + ANIMATION_TARGET_IDLE_STAGE_FOUR_STRUCT, + ANIMATION_TARGET_POINT_STAGE_FOUR_STRUCT, + ANIMATION_TARGET_GULP_STAGE_FOUR_STRUCT, + ANIMATION_TARGET_BURP_STAGE_FOUR_STRUCT, + ANIMATION_TARGET_IDLE_STAGE_FIVE_STRUCT, + ANIMATION_TARGET_POINT_STAGE_FIVE_STRUCT, + ANIMATION_TARGET_GULP_STAGE_FIVE_STRUCT, + ANIMATION_TARGET_BURP_STAGE_FIVE_STRUCT +}; + +typedef struct ComponentAnimationTarget +{ + Component component; + AnimationTargetType type; + AnimationTargetActionType action; + EntityID playerID; + bool isPointDisabled; +} ComponentAnimationTarget; + +void component_animation_target_init(ComponentAnimationTarget* self, ECS* ecs, AnimationTargetType type, EntityID playerID); +void component_animation_target_tick(ComponentAnimationTarget* self, ECS* ecs); + +static const ComponentInfo COMPONENT_ANIMATION_TARGET_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_animation_target_tick, + NULL, + NULL + } + }, + .type = COMPONENT_ANIMATION_TARGET, + .size = sizeof(ComponentAnimationTarget) +}; diff --git a/src/game/ecs/component/game/component_collect.c b/src/game/ecs/component/game/component_collect.c new file mode 100644 index 0000000..347794a --- /dev/null +++ b/src/game/ecs/component/game/component_collect.c @@ -0,0 +1,26 @@ +#include "component_collect.h" + +void _component_collect_circle_set(ComponentCollect* self, ECS* ecs); + +void +_component_collect_circle_set(ComponentCollect* self, ECS* ecs) +{ + ComponentCircleCollider* circleCollider; + + circleCollider = ecs_component_get(ecs, COMPONENT_CIRCLE_COLLIDER, self->component.id); + + self->circle.position[0] = circleCollider->circle.position[0]; + self->circle.position[1] = circleCollider->circle.position[1]; +} + +void +component_collect_init(ComponentCollect* self, ECS* ecs, f32 radius) +{ + self->circle.radius = radius; +} + +void +component_collect_tick(ComponentCollect* self, ECS* ecs) +{ + _component_collect_circle_set(self, ecs); +} diff --git a/src/game/ecs/component/game/component_collect.h b/src/game/ecs/component/game/component_collect.h new file mode 100644 index 0000000..faf6f7b --- /dev/null +++ b/src/game/ecs/component/game/component_collect.h @@ -0,0 +1,29 @@ +#pragma once + +#include "component_world_object.h" + +typedef struct ComponentCollect +{ + Component component; + Circle circle; +} ComponentCollect; + +void component_collect_tick(ComponentCollect* self, ECS* ecs); +void component_collect_init(ComponentCollect* self, ECS* ecs, f32 radius); + +static const ComponentInfo COMPONENT_COLLECT_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_collect_tick, + NULL, + NULL + } + }, + .type = COMPONENT_COLLECT, + .size = sizeof(ComponentCollect) +}; diff --git a/src/game/ecs/component/game/component_collectible.c b/src/game/ecs/component/game/component_collectible.c new file mode 100644 index 0000000..b2a9c80 --- /dev/null +++ b/src/game/ecs/component/game/component_collectible.c @@ -0,0 +1,169 @@ +#include "component_collectible.h" + +void _component_collectible_increment(ComponentCollectible* self, ECS* ecs, EntityID id); +void _component_collectible_collect(ComponentCollectible* self, ECS* ecs, EntityID id); + +void +_component_collectible_increment(ComponentCollectible* self, ECS* ecs, EntityID id) +{ + ComponentFood* food; + ComponentPower* power; + ComponentStamina* stamina; + ComponentColorChange* colorChange; + + switch (self->type) + { + case COLLECTIBLE_FOOD: + food = ecs_component_get(ecs, COMPONENT_FOOD, id); + if (!food) + return; + food->value += COMPONENT_COLLECTIBLE_FOOD_VALUE * food->multiplier; + sound_play(&ecs->resources->sounds[SOUND_FOOD_COLLECT]); + break; + case COLLECTIBLE_POWER: + colorChange = ecs_component_get(ecs, COMPONENT_COLOR_CHANGE, id); + power = ecs_component_get(ecs, COMPONENT_POWER, id); + if (!power) + return; + power->value += COMPONENT_COLLECTIBLE_POWER_VALUE; + sound_play(&ecs->resources->sounds[SOUND_POWER]); + + if (!colorChange) + return; + + component_color_change_init(colorChange, ecs, COMPONENT_COLLECTIBLE_POWER_COLOR,TRANSPARENT, COMPONENT_COLLECTIBLE_POWER_COLOR_CHANGE_TIME, true, false); + break; + case COLLECTIBLE_STAMINA: + stamina = ecs_component_get(ecs, COMPONENT_STAMINA, id); + colorChange = ecs_component_get(ecs, COMPONENT_COLOR_CHANGE, id); + if (!stamina) + return; + stamina->value += COMPONENT_COLLECTIBLE_STAMINA_VALUE; + sound_play(&ecs->resources->sounds[SOUND_STAMINA]); + + if (!colorChange) + return; + + component_color_change_init(colorChange, ecs, COMPONENT_COLLECTIBLE_STAMINA_COLOR,TRANSPARENT, COMPONENT_COLLECTIBLE_STAMINA_COLOR_CHANGE_TIME, true, false); + break; + case COLLECTIBLE_ROTTEN_FOOD: + food = ecs_component_get(ecs, COMPONENT_FOOD, id); + if (!food) + return; + food->value -= COMPONENT_COLLECTIBLE_FOOD_VALUE; + sound_play(&ecs->resources->sounds[SOUND_BLEH]); + break; + case COLLECTIBLE_AMULET: + sound_play(&ecs->resources->sounds[SOUND_POWER]); + break; + default: + break; + } +} + +void +_component_collectible_collect(ComponentCollectible* self, ECS* ecs, EntityID id) +{ + _component_collectible_increment(self, ecs, id); + ecs_entity_delete(ecs, self->component.id); +} + +void +component_collectible_add(ComponentCollectible* self, ECS* ecs) +{ + ecs_components_add + ( + ecs, + COMPONENT_COLLECTIBLE_DEPENDENCIES, + COMPONENT_COLLECTIBLE_DEPENDENCY_COUNT, + self->component.id + ); +} + +void +component_collectible_init +( + ComponentCollectible* self, + ECS* ecs, + Texture* texture, + const vec2 size, + const vec3 position, + CollectibleType type +) +{ + component_world_object_init + ( + ecs_component_get(ecs, COMPONENT_WORLD_OBJECT, self->component.id), + ecs, + texture, + size, + position, + COMPONENT_COLLECTIBLE_HEIGHT_OFFSET, + COMPONENT_COLLECTIBLE_RADIUS + ); + + component_levitate_init + ( + ecs_component_get(ecs, COMPONENT_LEVITATE, self->component.id), + ecs, + COMPONENT_COLLECTIBLE_LEVITATE_DISTANCE, + COMPONENT_COLLECTIBLE_LEVITATE_FREQUENCY + ); + + self->type = type; +} + +void +component_collectible_tick(ComponentCollectible* self, ECS* ecs) +{ + ComponentCircleCollider* circleCollider; + ComponentHoming* homing; + bool isTarget; + bool isAbleToBeCollected; + EntityID target; + + circleCollider = ecs_component_get(ecs, COMPONENT_CIRCLE_COLLIDER, self->component.id); + homing = ecs_component_get(ecs, COMPONENT_HOMING, self->component.id); + + isTarget = false; + isAbleToBeCollected = true; + + for (s32 i = 0; i < (s32)ecs->lists[COMPONENT_COLLECT].components.count; i++) + { + ComponentCollect* collect; + + collect = ecs_component_from_index_get(ecs, COMPONENT_COLLECT, i); + + if (circle_collide_check(&collect->circle, &circleCollider->circle)) + { + target = collect->component.id; + isTarget = true; + } + } + + if (!isTarget) + return; + + if (self->type == COLLECTIBLE_FOOD) + { + ComponentFood* food; + + food = ecs_component_get(ecs, COMPONENT_FOOD, target); + + if (food->value >= food->max) + { + homing->isHoming = false; + isAbleToBeCollected = false; + //sound_play(&ecs->resources->sounds[SOUND_CANT_CARRY]); + } + } + + if (isAbleToBeCollected) + { + if (!homing->isHoming) + component_homing_init(homing, ecs, target, COMPONENT_COLLECTIBLE_HOMING_SPEED); + + if (component_circle_collider_collide_check(circleCollider, ecs, target)) + _component_collectible_collect(self, ecs, target); + } +} diff --git a/src/game/ecs/component/game/component_collectible.h b/src/game/ecs/component/game/component_collectible.h new file mode 100644 index 0000000..06bea9b --- /dev/null +++ b/src/game/ecs/component/game/component_collectible.h @@ -0,0 +1,85 @@ +#pragma once + +#include "component_homing.h" +#include "component_collect.h" +#include "component_world_object.h" +#include "component_levitate.h" +#include "component_food.h" +#include "component_power.h" +#include "component_stamina.h" + +#include "../visual/component_color_change.h" + +static const f32 COMPONENT_COLLECTIBLE_HEIGHT_OFFSET = 1000.0f; +static const f32 COMPONENT_COLLECTIBLE_RADIUS = 64.0f; +static const u32 COMPONENT_COLLECTIBLE_FOOD_VALUE = 1; +static const f32 COMPONENT_COLLECTIBLE_POWER_VALUE = 10.0f; +static const f32 COMPONENT_COLLECTIBLE_STAMINA_VALUE = 50.0f; +static const u32 COMPONENT_COLLECTIBLE_HOMING_SPEED = 3.0f; + +static const f32 COMPONENT_COLLECTIBLE_LEVITATE_DISTANCE = 32.0f; +static const f32 COMPONENT_COLLECTIBLE_LEVITATE_FREQUENCY = 10.0f; + +static const u32 COMPONENT_COLLECTIBLE_STAMINA_COLOR_CHANGE_TIME = 30; +static const u32 COMPONENT_COLLECTIBLE_POWER_COLOR_CHANGE_TIME = 30; + +static const vec4 COMPONENT_COLLECTIBLE_POWER_COLOR = {0.60f, 1.0f, 0.80f, 0.0f}; +static const vec4 COMPONENT_COLLECTIBLE_STAMINA_COLOR = {1.0f, 0.2f, 0.40f, 0.0f}; + +typedef struct Vector Vector; + +#define COLLECTIBLE_TYPE_COUNT COLLECTIBLE_ROTTEN_FOOD + 1 +typedef enum CollectibleType +{ + COLLECTIBLE_FOOD, + COLLECTIBLE_STAMINA, + COLLECTIBLE_POWER, + COLLECTIBLE_LOREBOOK, + COLLECTIBLE_AMULET, + COLLECTIBLE_ROTTEN_FOOD +} CollectibleType; + +typedef struct ComponentCollectible +{ + Component component; + CollectibleType type; +} ComponentCollectible; + +void +component_collectible_init +( + ComponentCollectible* self, + ECS* ecs, + Texture* texture, + const vec2 size, + const vec3 position, + CollectibleType type +); + +void component_collectible_add(ComponentCollectible* self, ECS* ecs); +void component_collectible_tick(ComponentCollectible* self, ECS* ecs); + +#define COMPONENT_COLLECTIBLE_DEPENDENCY_COUNT 3 +static const ComponentType COMPONENT_COLLECTIBLE_DEPENDENCIES[COMPONENT_COLLECTIBLE_DEPENDENCY_COUNT] = +{ + COMPONENT_WORLD_OBJECT, + COMPONENT_HOMING, + COMPONENT_LEVITATE +}; + +static const ComponentInfo COMPONENT_COLLECTIBLE_INFO = +{ + .system = + { + .functions = + { + (ECSFunction)component_collectible_add, + NULL, + (ECSFunction)component_collectible_tick, + NULL, + NULL + } + }, + .type = COMPONENT_COLLECTIBLE, + .size = sizeof(ComponentCollectible) +}; diff --git a/src/game/ecs/component/game/component_collide_slow.c b/src/game/ecs/component/game/component_collide_slow.c new file mode 100644 index 0000000..22cc9f3 --- /dev/null +++ b/src/game/ecs/component/game/component_collide_slow.c @@ -0,0 +1,52 @@ +#include "component_collide_slow.h" + +void _component_collide_slow_collisions_tick(ComponentCollideSlow* self, ECS* ecs); + +void +_component_collide_slow_collisions_tick(ComponentCollideSlow* self, ECS* ecs) +{ + ComponentCircleCollider* circleCollider; + + circleCollider = ecs_component_get(ecs, COMPONENT_CIRCLE_COLLIDER, self->component.id); + + self->isPreviousColliding = self->isColliding; + self->isColliding = false; + + ecs->isLog = false; + + for (s32 i = 0; i < (s32)circleCollider->collisions.count; i++) + { + ComponentPhysics* collidePhysics; + ComponentWorldObject* collideWorldObject; + EntityID* id; + f32 angle; + f32 distance; + + id = vector_get(&circleCollider->collisions, i); + + collidePhysics = ecs_component_get(ecs, COMPONENT_PHYSICS, *id); + collideWorldObject = ecs_component_get(ecs, COMPONENT_WORLD_OBJECT, *id); + + if (!collideWorldObject || !collidePhysics) + continue; + + if (!collideWorldObject->isAirborne) + { + collidePhysics->velocity[0] *= COMPONENT_COLLIDE_SLOW_VELOCITY_MULTIPLIER; + collidePhysics->velocity[1] *= COMPONENT_COLLIDE_SLOW_VELOCITY_MULTIPLIER; + + self->isColliding = true; + } + } + + if (self->isPreviousColliding != self->isColliding) + sound_play(&ecs->resources->sounds[SOUND_STICKY]); + + ecs->isLog = true; +} + +void +component_collide_slow_tick(ComponentCollideSlow* self, ECS* ecs) +{ + _component_collide_slow_collisions_tick(self, ecs); +} diff --git a/src/game/ecs/component/game/component_collide_slow.h b/src/game/ecs/component/game/component_collide_slow.h new file mode 100644 index 0000000..998d4d5 --- /dev/null +++ b/src/game/ecs/component/game/component_collide_slow.h @@ -0,0 +1,31 @@ +#pragma once + +#include "component_world_object.h" + +typedef struct ComponentCollideSlow +{ + Component component; + bool isColliding; + bool isPreviousColliding; +} ComponentCollideSlow; + +static const f32 COMPONENT_COLLIDE_SLOW_VELOCITY_MULTIPLIER = 0.5f; + +void component_collide_slow_tick(ComponentCollideSlow* self, ECS* ecs); + +static const ComponentInfo COMPONENT_COLLIDE_SLOW_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_collide_slow_tick, + NULL, + NULL + } + }, + .type = COMPONENT_COLLIDE_SLOW, + .size = sizeof(ComponentCollideSlow) +}; diff --git a/src/game/ecs/component/game/component_food.c b/src/game/ecs/component/game/component_food.c new file mode 100644 index 0000000..372ab22 --- /dev/null +++ b/src/game/ecs/component/game/component_food.c @@ -0,0 +1,26 @@ +#include "component_food.h" + +void +component_food_tick(ComponentFood* self, ECS* ecs) +{ + self->value = CLAMP(self->value, 0, self->max); + + if (self->value == self->max) + { + if (!self->isJustFull) + { + sound_play(&ecs->resources->sounds[SOUND_CANT_CARRY]); + self->isJustFull = true; + } + } + else + self->isJustFull = false; +} + +void +component_food_init(ComponentFood* self, ECS* ecs, s32 value, s32 max, s32 multiplier) +{ + self->value = value; + self->max = max; + self->multiplier = multiplier; +} diff --git a/src/game/ecs/component/game/component_food.h b/src/game/ecs/component/game/component_food.h new file mode 100644 index 0000000..150b0c9 --- /dev/null +++ b/src/game/ecs/component/game/component_food.h @@ -0,0 +1,32 @@ +#pragma once + +#include "component_world_object.h" + +typedef struct ComponentFood +{ + Component component; + s32 value; + s32 max; + s32 multiplier; + bool isJustFull; +} ComponentFood; + +void component_food_tick(ComponentFood* self, ECS* ecs); +void component_food_init(ComponentFood* self, ECS* ecs, s32 value, s32 max, s32 multiplier); + +static const ComponentInfo COMPONENT_FOOD_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_food_tick, + NULL, + NULL + } + }, + .type = COMPONENT_FOOD, + .size = sizeof(ComponentFood) +}; diff --git a/src/game/ecs/component/game/component_game_object.c b/src/game/ecs/component/game/component_game_object.c new file mode 100644 index 0000000..773282d --- /dev/null +++ b/src/game/ecs/component/game/component_game_object.c @@ -0,0 +1,62 @@ +#include "component_game_object.h" + +void +component_game_object_init +( + ComponentGameObject* self, + ECS* ecs, + Texture* texture, + RendererBuffer buffer, + Origin origin, + vec2 size, + vec3 position +) +{ + ComponentPhysics* physics; + + physics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->component.id); + + component_texture_quad_init + ( + ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->component.id), + ecs, + texture, + COMPONENT_TEXTURE_QUAD_FLIP_DEFAULT, + origin, + buffer, + COMPONENT_TEXTURE_QUAD_ROTATION_DEFAULT, + size, + COMPONENT_TEXTURE_QUAD_SCALE_DEFAULT, + COMPONENT_TEXTURE_QUAD_UV_MIN_DEFAULT, + COMPONENT_TEXTURE_QUAD_UV_MAX_DEFAULT, + COMPONENT_TEXTURE_QUAD_OFFSET_DEFAULT, + position, + COMPONENT_TEXTURE_QUAD_COLOR_DEFAULT + ); + + glm_vec3_copy(position, physics->position); +} + +void +component_game_object_add(ComponentGameObject* self, ECS* ecs) +{ + ecs_components_add + ( + ecs, + COMPONENT_GAME_OBJECT_DEPENDENCIES, + COMPONENT_GAME_OBJECT_DEPENDENCY_COUNT, + self->component.id + ); +} + +void +component_game_object_tick(ComponentGameObject* self, ECS* ecs) +{ + ComponentTextureQuad* textureQuad; + ComponentPhysics* physics; + + textureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->component.id); + physics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->component.id); + + glm_vec3_copy(physics->position, textureQuad->position); +} diff --git a/src/game/ecs/component/game/component_game_object.h b/src/game/ecs/component/game/component_game_object.h new file mode 100644 index 0000000..b41becc --- /dev/null +++ b/src/game/ecs/component/game/component_game_object.h @@ -0,0 +1,48 @@ +#pragma once + +#include "../visual/component_texture_quad.h" +#include "../physics/component_physics.h" + +typedef struct ComponentGameObject +{ + Component component; +} ComponentGameObject; + +void +component_game_object_init +( + ComponentGameObject* self, + ECS* ecs, + Texture* texture, + RendererBuffer buffer, + Origin origin, + vec2 size, + vec3 position +); + +void component_game_object_add(ComponentGameObject* self, ECS* ecs); +void component_game_object_tick(ComponentGameObject* self, ECS* ecs); + +#define COMPONENT_GAME_OBJECT_DEPENDENCY_COUNT 2 +static const ComponentType COMPONENT_GAME_OBJECT_DEPENDENCIES[COMPONENT_GAME_OBJECT_DEPENDENCY_COUNT] = +{ + COMPONENT_PHYSICS, + COMPONENT_TEXTURE_QUAD, +}; + +static const ComponentInfo COMPONENT_GAME_OBJECT_INFO = +{ + .system = + { + .functions = + { + (ECSFunction)component_game_object_add, + NULL, + (ECSFunction)component_game_object_tick, + NULL, + NULL + } + }, + .type = COMPONENT_GAME_OBJECT, + .size = sizeof(ComponentGameObject) +}; diff --git a/src/game/ecs/component/game/component_homing.c b/src/game/ecs/component/game/component_homing.c new file mode 100644 index 0000000..3f01a93 --- /dev/null +++ b/src/game/ecs/component/game/component_homing.c @@ -0,0 +1,31 @@ +#include "component_homing.h" + +void +component_homing_init(ComponentHoming* self, ECS* ecs, EntityID targetID, f32 speed) +{ + self->targetID = targetID; + self->speed = speed; + self->isHoming = true; +} + +void +component_homing_tick(ComponentHoming* self, ECS* ecs) +{ + if (!self->isHoming) + return; + + ComponentPhysics* physics; + ComponentPhysics* targetPhysics; + f32 angle; + + physics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->component.id); + targetPhysics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->targetID); + + if (!targetPhysics) + return; + + angle = ATAN(physics->position[0], targetPhysics->position[0], physics->position[1], targetPhysics->position[1]); + + physics->velocity[0] += self->speed * cos(angle); + physics->velocity[1] += self->speed * sin(angle); +} diff --git a/src/game/ecs/component/game/component_homing.h b/src/game/ecs/component/game/component_homing.h new file mode 100644 index 0000000..d5b87f8 --- /dev/null +++ b/src/game/ecs/component/game/component_homing.h @@ -0,0 +1,31 @@ +#pragma once + +#include "../physics/component_physics.h" + +typedef struct ComponentHoming +{ + Component component; + EntityID targetID; + f32 speed; + bool isHoming; +} ComponentHoming; + +void component_homing_tick(ComponentHoming* self, ECS* ecs); +void component_homing_init(ComponentHoming* self, ECS* ecs, EntityID targetID, f32 speed); + +static const ComponentInfo COMPONENT_HOMING_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_homing_tick, + NULL, + NULL + } + }, + .type = COMPONENT_HOMING, + .size = sizeof(ComponentHoming) +}; diff --git a/src/game/ecs/component/game/component_levitate.c b/src/game/ecs/component/game/component_levitate.c new file mode 100644 index 0000000..b3fd492 --- /dev/null +++ b/src/game/ecs/component/game/component_levitate.c @@ -0,0 +1,44 @@ +#include "component_levitate.h" + +void +component_levitate_add(ComponentLevitate* self, ECS* ecs) +{ + self->counterID = entity_counter_add(ecs); +} + +void +component_levitate_delete(ComponentLevitate* self, ECS* ecs) +{ + ecs_entity_delete(ecs, self->counterID); +} + +void +component_levitate_tick(ComponentLevitate* self, ECS* ecs) +{ + ComponentCounter* counter; + ComponentWorldObject* worldObject; + + counter = ecs_component_get(ecs, COMPONENT_COUNTER, self->counterID); + worldObject = ecs_component_get(ecs, COMPONENT_WORLD_OBJECT, self->component.id); + + worldObject->heightOffset = self->distance + ((self->distance / 2.0f) * cos((f32)counter->value / self->frequency)); +} + +void +component_levitate_init +( + ComponentLevitate* self, + ECS* ecs, + f32 distance, + f32 frequency +) +{ + ComponentWorldObject* worldObject; + + worldObject = ecs_component_get(ecs, COMPONENT_WORLD_OBJECT, self->component.id); + + self->frequency = frequency; + self->distance = distance; + + worldObject->isGravityAffected = false; +} diff --git a/src/game/ecs/component/game/component_levitate.h b/src/game/ecs/component/game/component_levitate.h new file mode 100644 index 0000000..8751f40 --- /dev/null +++ b/src/game/ecs/component/game/component_levitate.h @@ -0,0 +1,42 @@ +#pragma once + +#include "component_world_object.h" +#include "../../entity/utility/entity_counter.h" + +typedef struct ComponentLevitate +{ + Component component; + f32 distance; + f32 frequency; + EntityID counterID; +} ComponentLevitate; + +void component_levitate_add(ComponentLevitate* self, ECS* ecs); +void component_levitate_delete(ComponentLevitate* self, ECS* ecs); +void component_levitate_tick(ComponentLevitate* self, ECS* ecs); + +void +component_levitate_init +( + ComponentLevitate* self, + ECS* ecs, + f32 distance, + f32 frequency +); + +static const ComponentInfo COMPONENT_LEVITATE_INFO = +{ + .system = + { + .functions = + { + (ECSFunction)component_levitate_add, + (ECSFunction)component_levitate_delete, + (ECSFunction)component_levitate_tick, + NULL, + NULL + } + }, + .type = COMPONENT_LEVITATE, + .size = sizeof(ComponentLevitate) +}; diff --git a/src/game/ecs/component/game/component_plane_object.c b/src/game/ecs/component/game/component_plane_object.c new file mode 100644 index 0000000..15f7267 --- /dev/null +++ b/src/game/ecs/component/game/component_plane_object.c @@ -0,0 +1,111 @@ +#include "component_plane_object.h" + +void _component_plane_object_depth_set(ComponentPlaneObject* self, ECS* ecs); +void _component_plane_object_circle_collider_set(ComponentPlaneObject* self, ECS* ecs); + +void +_component_plane_object_circle_collider_set(ComponentPlaneObject* self, ECS* ecs) +{ + ComponentCircleCollider* circleCollider; + ComponentTextureQuad* textureQuad; + ComponentPhysics* physics; + + physics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->component.id); + textureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->component.id); + circleCollider = ecs_component_get(ecs, COMPONENT_CIRCLE_COLLIDER, self->component.id); + + circleCollider->circle.position[0] = physics->position[0]; + circleCollider->circle.position[1] = physics->position[1] + (textureQuad->size[1] / 2.0f); +} + +void +_component_plane_object_depth_set(ComponentPlaneObject* self, ECS* ecs) +{ + ComponentPhysics* physics; + ComponentTextureQuad* textureQuad; + f32 depth; + f32 yOffset; + + physics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->component.id); + textureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->component.id); + + yOffset = COMPONENT_PLANE_OBJECT_DEPTH_Y_OFFSET_MULTIPLIER * ((physics->position[1] + textureQuad->size[1]) / COMPONENT_PLANE_OBJECT_BOUNDS[3]); + + depth = COMPONENT_PLANE_OBJECT_DEPTH_MAX - yOffset; + depth += COMPONENT_PLANE_OBJECT_DEPTH_MIN; + + physics->position[2] = depth; +} + +void +_component_plane_object_bounds_set(ComponentPlaneObject* self, ECS* ecs) +{ + ComponentPhysics* physics; + + physics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->component.id); + + physics->position[0] = CLAMP(physics->position[0], COMPONENT_PLANE_OBJECT_BOUNDS[0], COMPONENT_PLANE_OBJECT_BOUNDS[2]); + physics->position[1] = CLAMP(physics->position[1], COMPONENT_PLANE_OBJECT_BOUNDS[1], COMPONENT_PLANE_OBJECT_BOUNDS[3]); +} + + +void +component_plane_object_init +( + ComponentPlaneObject* self, + ECS* ecs, + Texture* texture, + vec2 size, + vec3 position, + f32 radius +) +{ + component_game_object_init + ( + ecs_component_get(ecs, COMPONENT_GAME_OBJECT, self->component.id), + ecs, + texture, + COMPONENT_PLANE_OBJECT_BUFFER, + COMPONENT_PLANE_OBJECT_ORIGIN, + size, + position + ); + + component_circle_collider_init + ( + ecs_component_get(ecs, COMPONENT_CIRCLE_COLLIDER, self->component.id), + (f32*)position, + radius + ); + + component_physics_init + ( + ecs_component_get(ecs, COMPONENT_PHYSICS, self->component.id), + ecs, + position, + COMPONENT_PLANE_OBJECT_VELOCITY_MAX, + COMPONENT_PLANE_OBJECT_FRICTION + ); + + _component_plane_object_circle_collider_set(self, ecs); +} + +void +component_plane_object_add(ComponentPlaneObject* self, ECS* ecs) +{ + ecs_components_add + ( + ecs, + COMPONENT_PLANE_OBJECT_DEPENDENCIES, + COMPONENT_PLANE_OBJECT_DEPENDENCY_COUNT, + self->component.id + ); +} + +void +component_plane_object_tick(ComponentPlaneObject* self, ECS* ecs) +{ + _component_plane_object_bounds_set(self, ecs); + _component_plane_object_depth_set(self, ecs); + _component_plane_object_circle_collider_set(self, ecs); +} diff --git a/src/game/ecs/component/game/component_plane_object.h b/src/game/ecs/component/game/component_plane_object.h new file mode 100644 index 0000000..ad73363 --- /dev/null +++ b/src/game/ecs/component/game/component_plane_object.h @@ -0,0 +1,58 @@ +#pragma once + +#include "component_game_object.h" +#include "../physics/component_circle_collider.h" + +static const RendererBuffer COMPONENT_PLANE_OBJECT_BUFFER = RENDERER_BUFFER_WORLD; +static const f32 COMPONENT_PLANE_OBJECT_FRICTION = 0.985f; +static const f32 COMPONENT_PLANE_OBJECT_DEPTH_Y_OFFSET_MULTIPLIER = 0.1f; +static const f32 COMPONENT_PLANE_OBJECT_DEPTH_MIN = 0.3f; +static const f32 COMPONENT_PLANE_OBJECT_DEPTH_MAX = 0.4f; +static const vec3 COMPONENT_PLANE_OBJECT_VELOCITY_MAX = {0.0f, 0.0f, 0.0f}; +static const vec4 COMPONENT_PLANE_OBJECT_BOUNDS = {250.0f, 250.0f, 6300.0f, 3100.0f}; + +#define COMPONENT_PLANE_OBJECT_ORIGIN ORIGIN_CENTER + +typedef struct ComponentPlaneObject +{ + Component component; +} ComponentPlaneObject; + +void +component_plane_object_init +( + ComponentPlaneObject* self, + ECS* ecs, + Texture* texture, + vec2 size, + vec3 position, + f32 radius +); + +void component_plane_object_add(ComponentPlaneObject* self, ECS* ecs); +void component_plane_object_delete(ComponentPlaneObject* self, ECS* ecs); +void component_plane_object_tick(ComponentPlaneObject* self, ECS* ecs); + +#define COMPONENT_PLANE_OBJECT_DEPENDENCY_COUNT 2 +static const ComponentType COMPONENT_PLANE_OBJECT_DEPENDENCIES[COMPONENT_PLANE_OBJECT_DEPENDENCY_COUNT] = +{ + COMPONENT_GAME_OBJECT, + COMPONENT_CIRCLE_COLLIDER +}; + +static const ComponentInfo COMPONENT_PLANE_OBJECT_INFO = +{ + .system = + { + .functions = + { + (ECSFunction)component_plane_object_add, + NULL, + (ECSFunction)component_plane_object_tick, + NULL, + NULL + } + }, + .type = COMPONENT_PLANE_OBJECT, + .size = sizeof(ComponentPlaneObject) +}; diff --git a/src/game/ecs/component/game/component_player_control.c b/src/game/ecs/component/game/component_player_control.c new file mode 100644 index 0000000..2d5b75b --- /dev/null +++ b/src/game/ecs/component/game/component_player_control.c @@ -0,0 +1,148 @@ +#include "component_player_control.h" + +void _component_player_control_movement_tick(ComponentPlayerControl* self, ECS* ecs); +void _component_player_control_movement(ComponentPlayerControl* self, ECS* ecs); +void _component_player_control_lunge(ComponentPlayerControl* self, ECS* ecs); +void _component_player_control_lunge_tick(ComponentPlayerControl* self, ECS* ecs); + +static vec2 SIZE = {64.0f, 64.0f}; +static vec3 POSITION = {0.0f, 0.0f, 0.0f}; + +void +component_player_control_add(ComponentPlayerControl* self, ECS* ecs) +{ + ecs_components_add(ecs, COMPONENT_PLAYER_CONTROL_DEPENDENCIES, COMPONENT_PLAYER_CONTROL_DEPENDENCY_COUNT, self->component.id); + + self->lungeTimerID = entity_timer_add(ecs, COMPONENT_PLAYER_CONTROL_LUNGE_TIMER_MAX); +} + +void +component_player_control_delete(ComponentPlayerControl* self, ECS* ecs) +{ + ecs_entity_delete(ecs, self->lungeTimerID); +} + +void +_component_player_control_movement(ComponentPlayerControl* self, ECS* ecs) +{ + ComponentPhysics* physics; + ComponentWorldObject* worldObject; + vec2 mousePosition; + vec2 physicsPosition; + f32 velocityGain; + f32 distanceFromMouse; + + physics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->component.id); + worldObject = ecs_component_get(ecs, COMPONENT_WORLD_OBJECT, self->component.id); + + physicsPosition[0] = physics->position[0]; + physicsPosition[1] = physics->position[1]; + + mouse_buffer_position_get(&ecs->input->mouse, RENDERER_BUFFER_WORLD, ecs->renderer, mousePosition); + + worldObject->angle = mouse_angle_from_buffer_position_get(&ecs->input->mouse, RENDERER_BUFFER_WORLD, ecs->renderer, physicsPosition); + + velocityGain = COMPONENT_PLAYER_CONTROL_VELOCITY_DEFAULT; + + distanceFromMouse = DISTANCE_2D + ( + physicsPosition[0], + mousePosition[0], + physicsPosition[1], + mousePosition[1] + ); + + if (distanceFromMouse < COMPONENT_PLAYER_CONTROL_VELOCITY_DISTANCE_MAX) + { + f32 nextPositionDistance; + velocityGain *= (distanceFromMouse / COMPONENT_PLAYER_CONTROL_VELOCITY_DISTANCE_MAX); + + nextPositionDistance = component_physics_next_position_distance_get(physics, ecs); + + if (nextPositionDistance < COMPONENT_PLAYER_CONTROL_VELOCITY_STOP_THRESHOLD) + { + velocityGain = 0.0f; + glm_vec2_zero(physics->velocity); + } + } + + physics->velocity[0] += velocityGain * cos(worldObject->angle); + physics->velocity[1] += velocityGain * sin(worldObject->angle); +} + +void +_component_player_control_movement_tick(ComponentPlayerControl* self, ECS* ecs) +{ + ComponentWorldObject* worldObject; + + worldObject = ecs_component_get(ecs, COMPONENT_WORLD_OBJECT, self->component.id); + + if (!worldObject->isAirborne) + _component_player_control_movement(self, ecs); +} + +void +_component_player_control_lunge(ComponentPlayerControl* self, ECS* ecs) +{ + ComponentPhysics* physics; + ComponentWorldObject* worldObject; + vec2 physicsPosition; + + physics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->component.id); + worldObject = ecs_component_get(ecs, COMPONENT_WORLD_OBJECT, self->component.id); + + physicsPosition[0] = physics->position[0]; + physicsPosition[1] = physics->position[1]; + + worldObject->angle = mouse_angle_from_buffer_position_get(&ecs->input->mouse, RENDERER_BUFFER_WORLD, ecs->renderer, physicsPosition); + + physics->velocity[0] = COMPONENT_PLAYER_CONTROL_LUNGE_VELOCITY * cos(worldObject->angle); + physics->velocity[1] = COMPONENT_PLAYER_CONTROL_LUNGE_VELOCITY * sin(worldObject->angle); + + worldObject->heightOffsetVelocity += COMPONENT_PLAYER_CONTROL_LUNGE_HEIGHT_OFFSET_VELOCITY; + + worldObject->isAirborne = true; + + worldObject->heightOffset += COMPONENT_PLAYER_CONTROL_LUNGE_HEIGHT_OFFSET_VELOCITY; +} + +void +_component_player_control_lunge_tick(ComponentPlayerControl* self, ECS* ecs) +{ + self->isLunge = false; + + if (control_pressed(ecs->control, CONTROL_ACTION_SECONDARY)) + { + ComponentTimer* lungeTimer; + ComponentStamina* stamina; + ComponentWorldObject* worldObject; + + lungeTimer = ecs_component_get(ecs, COMPONENT_TIMER, self->lungeTimerID); + stamina = ecs_component_get(ecs, COMPONENT_STAMINA, self->component.id); + worldObject = ecs_component_get(ecs, COMPONENT_WORLD_OBJECT, self->component.id); + + if + ( + lungeTimer->isFinished && + stamina->value >= COMPONENT_PLAYER_CONTROL_LUNGE_STAMINA_COST && + !worldObject->isAirborne + ) + { + component_timer_init(lungeTimer, ecs, COMPONENT_PLAYER_CONTROL_LUNGE_TIMER_MAX); + + stamina->value -= COMPONENT_PLAYER_CONTROL_LUNGE_STAMINA_COST; + self->isLunge = true; + } + + } + + if (self->isLunge) + _component_player_control_lunge(self, ecs); +} + +void +component_player_control_tick(ComponentPlayerControl* self, ECS* ecs) +{ + _component_player_control_movement_tick(self, ecs); + _component_player_control_lunge_tick(self, ecs); +} diff --git a/src/game/ecs/component/game/component_player_control.h b/src/game/ecs/component/game/component_player_control.h new file mode 100644 index 0000000..2f1bf20 --- /dev/null +++ b/src/game/ecs/component/game/component_player_control.h @@ -0,0 +1,50 @@ +#pragma once + +#include "component_world_object.h" +#include "component_stamina.h" + +#include "../../entity/visual/entity_sprite.h" +#include "../../entity/utility/entity_timer.h" + +static const f32 COMPONENT_PLAYER_CONTROL_VELOCITY_DEFAULT = 1.0f; +static const f32 COMPONENT_PLAYER_CONTROL_VELOCITY_DISTANCE_MAX = 500.0f; +static const f32 COMPONENT_PLAYER_CONTROL_VELOCITY_IN_CIRCLE_MULTIPLIER = 0.9f; +static const f32 COMPONENT_PLAYER_CONTROL_VELOCITY_STOP_THRESHOLD = 3.0f; +static const f32 COMPONENT_PLAYER_CONTROL_LUNGE_VELOCITY = 50.0f; +static const f32 COMPONENT_PLAYER_CONTROL_LUNGE_HEIGHT_OFFSET_VELOCITY = 10.0f; +static const s32 COMPONENT_PLAYER_CONTROL_LUNGE_STAMINA_COST = 25; +static const s32 COMPONENT_PLAYER_CONTROL_LUNGE_TIMER_MAX = 10; + +typedef struct ComponentPlayerControl +{ + Component component; + bool isLunge; + EntityID lungeTimerID; +} ComponentPlayerControl; + +void component_player_control_add(ComponentPlayerControl* self, ECS* ecs); +void component_player_control_tick(ComponentPlayerControl* self, ECS* ecs); + +#define COMPONENT_PLAYER_CONTROL_DEPENDENCY_COUNT 2 +static const ComponentType COMPONENT_PLAYER_CONTROL_DEPENDENCIES[COMPONENT_PLAYER_CONTROL_DEPENDENCY_COUNT] = +{ + COMPONENT_WORLD_OBJECT, + COMPONENT_STAMINA, +}; + +static const ComponentInfo COMPONENT_PLAYER_CONTROL_INFO = +{ + .system = + { + .functions = + { + (ECSFunction)component_player_control_add, + NULL, + (ECSFunction)component_player_control_tick, + NULL, + NULL + } + }, + .type = COMPONENT_PLAYER_CONTROL, + .size = sizeof(ComponentPlayerControl) +}; diff --git a/src/game/ecs/component/game/component_power.c b/src/game/ecs/component/game/component_power.c new file mode 100644 index 0000000..4ba4f21 --- /dev/null +++ b/src/game/ecs/component/game/component_power.c @@ -0,0 +1,16 @@ +#include "component_power.h" + +void +component_power_init(ComponentPower* self, ECS* ecs, f32 max, f32 gain) +{ + self->value = max; + self->max = max; + self->gain = gain; +} + +void +component_power_tick(ComponentPower* self, ECS* ecs) +{ + self->value += self->gain; + self->value = MAX(self->value, self->max); +} diff --git a/src/game/ecs/component/game/component_power.h b/src/game/ecs/component/game/component_power.h new file mode 100644 index 0000000..61f5ae1 --- /dev/null +++ b/src/game/ecs/component/game/component_power.h @@ -0,0 +1,31 @@ +#pragma once + +#include "../../ecs_entity.h" + +typedef struct ComponentPower +{ + Component component; + f32 value; + f32 max; + f32 gain; +} ComponentPower; + +void component_power_tick(ComponentPower* self, ECS* ecs); +void component_power_init(ComponentPower* self, ECS* ecs, f32 max, f32 gain); + +static const ComponentInfo COMPONENT_POWER_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_power_tick, + NULL, + NULL + } + }, + .type = COMPONENT_POWER, + .size = sizeof(ComponentPower) +}; diff --git a/src/game/ecs/component/game/component_solid.c b/src/game/ecs/component/game/component_solid.c new file mode 100644 index 0000000..100fc8b --- /dev/null +++ b/src/game/ecs/component/game/component_solid.c @@ -0,0 +1,46 @@ +#include "component_solid.h" + +void _component_solid_collisions_tick(ComponentSolid* self, ECS* ecs); + +void +_component_solid_collisions_tick(ComponentSolid* self, ECS* ecs) +{ + ComponentCircleCollider* circleCollider; + ComponentPhysics* physics; + + circleCollider = ecs_component_get(ecs, COMPONENT_CIRCLE_COLLIDER, self->component.id); + physics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->component.id); + + for (s32 i = 0; i < (s32)circleCollider->collisions.count; i++) + { + ComponentPhysics* collidePhysics; + ComponentCircleCollider* collideCircleCollider; + EntityID* id; + f32 angle; + + id = vector_get(&circleCollider->collisions, i); + + collidePhysics = ecs_component_get(ecs, COMPONENT_PHYSICS, *id); + collideCircleCollider = ecs_component_get(ecs, COMPONENT_CIRCLE_COLLIDER, *id); + + angle = ATAN + ( + physics->position[0], + collidePhysics->position[0], + physics->position[1], + collidePhysics->position[1] + ); + + collidePhysics->position[0] = physics->position[0] + ((circleCollider->circle.radius * 2) * cos(angle)); + collidePhysics->position[1] = physics->position[1] + ((circleCollider->circle.radius * 2) * sin(angle)); + + collidePhysics->position[0] += (collideCircleCollider->circle.radius * 2) * cos(angle); + collidePhysics->position[1] += (collideCircleCollider->circle.radius * 2) * sin(angle); + } +} + +void +component_solid_tick(ComponentSolid* self, ECS* ecs) +{ + _component_solid_collisions_tick(self, ecs); +} diff --git a/src/game/ecs/component/game/component_solid.h b/src/game/ecs/component/game/component_solid.h new file mode 100644 index 0000000..fca3e8d --- /dev/null +++ b/src/game/ecs/component/game/component_solid.h @@ -0,0 +1,27 @@ +#pragma once + +#include "component_world_object.h" + +typedef struct ComponentSolid +{ + Component component; +} ComponentSolid; + +void component_solid_tick(ComponentSolid* self, ECS* ecs); + +static const ComponentInfo COMPONENT_SOLID_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_solid_tick, + NULL, + NULL + } + }, + .type = COMPONENT_SOLID, + .size = sizeof(ComponentSolid) +}; diff --git a/src/game/ecs/component/game/component_stage.c b/src/game/ecs/component/game/component_stage.c new file mode 100644 index 0000000..c660357 --- /dev/null +++ b/src/game/ecs/component/game/component_stage.c @@ -0,0 +1,13 @@ +#include "component_stage.h" + +void +component_stage_init(ComponentStage* self, ECS* ecs, u32 value) +{ + self->value = value; +} + +void +component_stage_tick(ComponentStage* self, ECS* ecs) +{ + +} diff --git a/src/game/ecs/component/game/component_stage.h b/src/game/ecs/component/game/component_stage.h new file mode 100644 index 0000000..81fe038 --- /dev/null +++ b/src/game/ecs/component/game/component_stage.h @@ -0,0 +1,29 @@ +#pragma once + +#include "../../ecs_entity.h" + +typedef struct ComponentStage +{ + Component component; + u32 value; +} ComponentStage; + +void component_stage_tick(ComponentStage* self, ECS* ecs); +void component_stage_init(ComponentStage* self, ECS* ecs, u32 value); + +static const ComponentInfo COMPONENT_STAGE_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_stage_tick, + NULL, + NULL + } + }, + .type = COMPONENT_STAGE, + .size = sizeof(ComponentStage) +}; diff --git a/src/game/ecs/component/game/component_stamina.c b/src/game/ecs/component/game/component_stamina.c new file mode 100644 index 0000000..91fd83b --- /dev/null +++ b/src/game/ecs/component/game/component_stamina.c @@ -0,0 +1,16 @@ +#include "component_stamina.h" + +void +component_stamina_init(ComponentStamina* self, ECS* ecs, f32 max, f32 gain) +{ + self->value = max; + self->max = max; + self->gain = gain; +} + +void +component_stamina_tick(ComponentStamina* self, ECS* ecs) +{ + self->value += self->gain; + self->value = MAX(self->value, self->max); +} diff --git a/src/game/ecs/component/game/component_stamina.h b/src/game/ecs/component/game/component_stamina.h new file mode 100644 index 0000000..661b77e --- /dev/null +++ b/src/game/ecs/component/game/component_stamina.h @@ -0,0 +1,31 @@ +#pragma once + +#include "../../ecs_entity.h" + +typedef struct ComponentStamina +{ + Component component; + f32 value; + f32 max; + f32 gain; +} ComponentStamina; + +void component_stamina_tick(ComponentStamina* self, ECS* ecs); +void component_stamina_init(ComponentStamina* self, ECS* ecs, f32 max, f32 gain); + +static const ComponentInfo COMPONENT_STAMINA_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_stamina_tick, + NULL, + NULL + } + }, + .type = COMPONENT_STAMINA, + .size = sizeof(ComponentStamina) +}; diff --git a/src/game/ecs/component/game/component_take_food.c b/src/game/ecs/component/game/component_take_food.c new file mode 100644 index 0000000..c702355 --- /dev/null +++ b/src/game/ecs/component/game/component_take_food.c @@ -0,0 +1,37 @@ +#include "component_take_food.h" + +void +component_take_food_tick(ComponentTakeFood* self, ECS* ecs) +{ + ComponentCircleCollider* circleCollider; + + circleCollider = ecs_component_get(ecs, COMPONENT_CIRCLE_COLLIDER, self->component.id); + + self->isTakeFood = false; + + ecs->isLog = false; + + for (s32 i = 0; i < (s32)circleCollider->collisions.count; i++) + { + ComponentFood* collideFood; + ComponentFood* food; + EntityID* id; + + id = vector_get(&circleCollider->collisions, i); + + collideFood = ecs_component_get(ecs, COMPONENT_FOOD, *id); + food = ecs_component_get(ecs, COMPONENT_FOOD, self->component.id); + + if (!collideFood) + continue; + + if (collideFood->value > 0) + { + food->value += (collideFood->value * food->multiplier); + collideFood->value = 0; + self->isTakeFood = true; + } + } + + ecs->isLog = true; +} diff --git a/src/game/ecs/component/game/component_take_food.h b/src/game/ecs/component/game/component_take_food.h new file mode 100644 index 0000000..17f3ea8 --- /dev/null +++ b/src/game/ecs/component/game/component_take_food.h @@ -0,0 +1,29 @@ +#pragma once + +#include "component_world_object.h" +#include "component_food.h" + +typedef struct ComponentTakeFood +{ + Component component; + bool isTakeFood; +} ComponentTakeFood; + +void component_take_food_tick(ComponentTakeFood* self, ECS* ecs); + +static const ComponentInfo COMPONENT_TAKE_FOOD_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_take_food_tick, + NULL, + NULL + } + }, + .type = COMPONENT_TAKE_FOOD, + .size = sizeof(ComponentTakeFood) +}; diff --git a/src/game/ecs/component/game/component_threshold.c b/src/game/ecs/component/game/component_threshold.c new file mode 100644 index 0000000..d08de2e --- /dev/null +++ b/src/game/ecs/component/game/component_threshold.c @@ -0,0 +1,12 @@ +#include "component_threshold.h" + +void +component_threshold_tick(ComponentThreshold* self, ECS* ecs) +{ +} + +void +component_threshold_init(ComponentThreshold* self, ECS* ecs, u32 value) +{ + self->value = value; +} diff --git a/src/game/ecs/component/game/component_threshold.h b/src/game/ecs/component/game/component_threshold.h new file mode 100644 index 0000000..d5b5b84 --- /dev/null +++ b/src/game/ecs/component/game/component_threshold.h @@ -0,0 +1,30 @@ +#pragma once + +#include "../../ecs_entity.h" + +typedef struct ComponentThreshold +{ + Component component; + s32 value; + s32 max; +} ComponentThreshold; + +void component_threshold_tick(ComponentThreshold* self, ECS* ecs); +void component_threshold_init(ComponentThreshold* self, ECS* ecs, u32 value); + +static const ComponentInfo COMPONENT_THRESHOLD_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_threshold_tick, + NULL, + NULL + } + }, + .type = COMPONENT_THRESHOLD, + .size = sizeof(ComponentThreshold) +}; diff --git a/src/game/ecs/component/game/component_world_object.c b/src/game/ecs/component/game/component_world_object.c new file mode 100644 index 0000000..cb4d303 --- /dev/null +++ b/src/game/ecs/component/game/component_world_object.c @@ -0,0 +1,213 @@ +#include "component_world_object.h" + +void _component_world_object_shadow_set(ComponentWorldObject* self, ECS* ecs); +void _component_world_object_height_offset_set(ComponentWorldObject* self, ECS* ecs); +void _component_world_object_depth_set(ComponentWorldObject* self, ECS* ecs); +void _component_world_object_circle_collider_set(ComponentWorldObject* self, ECS* ecs); +void _component_world_object_direction_set(ComponentWorldObject* self, ECS* ecs); + +void +_component_world_object_shadow_set(ComponentWorldObject* self, ECS* ecs) +{ + ComponentTextureQuad* shadowTextureQuad; + ComponentTextureQuad* textureQuad; + ComponentCircleCollider* circleCollider; + ComponentPhysics* physics; + f32 shadowScale; + + physics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->component.id); + circleCollider = ecs_component_get(ecs, COMPONENT_CIRCLE_COLLIDER, self->component.id); + textureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->component.id); + shadowTextureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->shadowID); + + shadowTextureQuad->size[0] = circleCollider->circle.radius; + shadowTextureQuad->size[1] = COMPONENT_WORLD_OBJECT_SHADOW_HEIGHT; + + shadowTextureQuad->position[0] = physics->position[0]; + shadowTextureQuad->position[1] = physics->position[1] + (textureQuad->size[1] / 2.0f); + shadowTextureQuad->position[2] = physics->position[2] + COMPONENT_WORLD_OBJECT_SHADOW_Z_OFFSET; + + shadowScale = 1 - (self->heightOffset * COMPONENT_WORLD_OBJECT_HEIGHT_OFFSET_SHADOW_SCALE_MULTIPLIER); + + shadowTextureQuad->scale[0] = shadowScale; + shadowTextureQuad->scale[1] = shadowScale; + + shadowTextureQuad->scale[0] = MIN(shadowTextureQuad->scale[0], 0); + shadowTextureQuad->scale[1] = MIN(shadowTextureQuad->scale[1], 0); +} + +void +_component_world_object_height_offset_set(ComponentWorldObject* self, ECS* ecs) +{ + ComponentTextureQuad* textureQuad; + + textureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->component.id); + + if (self->isGravityAffected) + self->heightOffsetVelocity -= COMPONENT_WORLD_OBJECT_GRAVITY; + + self->heightOffset += self->heightOffsetVelocity; + + if (self->heightOffset <= 0.0f) + { + self->isAirborne = false; + self->heightOffset = 0.0f; + self->heightOffsetVelocity = 0.0f; + } + else + self->isAirborne = true; + + textureQuad->offset[1] = -self->heightOffset; +} + +void +_component_world_object_circle_collider_set(ComponentWorldObject* self, ECS* ecs) +{ + ComponentCircleCollider* circleCollider; + ComponentTextureQuad* textureQuad; + ComponentPhysics* physics; + + physics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->component.id); + textureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->component.id); + circleCollider = ecs_component_get(ecs, COMPONENT_CIRCLE_COLLIDER, self->component.id); + + circleCollider->circle.position[0] = physics->position[0]; + circleCollider->circle.position[1] = physics->position[1] + (textureQuad->size[1] / 2.0f); +} + +void +_component_world_object_depth_set(ComponentWorldObject* self, ECS* ecs) +{ + ComponentPhysics* physics; + ComponentTextureQuad* textureQuad; + f32 depth; + f32 yOffset; + + physics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->component.id); + textureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->component.id); + + yOffset = COMPONENT_WORLD_OBJECT_DEPTH_Y_OFFSET_MULTIPLIER * ((physics->position[1] + textureQuad->size[1]) / COMPONENT_WORLD_OBJECT_BOUNDS[3]); + + depth = COMPONENT_WORLD_OBJECT_DEPTH_MAX - yOffset; + depth += COMPONENT_WORLD_OBJECT_DEPTH_MIN; + + physics->position[2] = depth; +} + +void +_component_world_object_bounds_set(ComponentWorldObject* self, ECS* ecs) +{ + ComponentPhysics* physics; + + physics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->component.id); + + physics->position[0] = CLAMP(physics->position[0], COMPONENT_WORLD_OBJECT_BOUNDS[0], COMPONENT_WORLD_OBJECT_BOUNDS[2]); + physics->position[1] = CLAMP(physics->position[1], COMPONENT_WORLD_OBJECT_BOUNDS[1], COMPONENT_WORLD_OBJECT_BOUNDS[3]); +} + + +void +_component_world_object_direction_set(ComponentWorldObject* self, ECS* ecs) +{ + if + ( + (self->angle >= 0.0f && self->angle < PI_FOURTH) || + (self->angle >= PI + PI_HALF + PI_FOURTH && self->angle < TAU) + ) + self->direction = DIRECTION_RIGHT; + + if (self->angle >= PI_FOURTH && self->angle < PI_HALF + PI_FOURTH) + self->direction = DIRECTION_DOWN; + + if (self->angle >= PI_HALF + PI_FOURTH && self->angle < PI + PI_FOURTH) + self->direction = DIRECTION_LEFT; + + if (self->angle >= PI + PI_FOURTH && self->angle < PI + PI_HALF + PI_FOURTH) + self->direction = DIRECTION_UP; +} + +void +component_world_object_init +( + ComponentWorldObject* self, + ECS* ecs, + Texture* texture, + vec2 size, + vec3 position, + f32 heightOffset, + f32 radius +) +{ + component_game_object_init + ( + ecs_component_get(ecs, COMPONENT_GAME_OBJECT, self->component.id), + ecs, + texture, + COMPONENT_WORLD_OBJECT_BUFFER, + COMPONENT_WORLD_OBJECT_ORIGIN, + size, + position + ); + + component_circle_collider_init + ( + ecs_component_get(ecs, COMPONENT_CIRCLE_COLLIDER, self->component.id), + (f32*)position, + radius + ); + + component_physics_init + ( + ecs_component_get(ecs, COMPONENT_PHYSICS, self->component.id), + ecs, + position, + COMPONENT_WORLD_OBJECT_VELOCITY_MAX, + COMPONENT_WORLD_OBJECT_FRICTION + ); + + self->shadowID = entity_sprite_add + ( + ecs, + &ecs->resources->textures[TEXTURE_SHADOW], + COMPONENT_WORLD_OBJECT_BUFFER, + COMPONENT_WORLD_OBJECT_ORIGIN, + (f32*)size, + (f32*)position + ); + + self->heightOffset = heightOffset; + self->isGravityAffected = true; + + _component_world_object_shadow_set(self, ecs); + _component_world_object_height_offset_set(self, ecs); + _component_world_object_circle_collider_set(self, ecs); +} + +void +component_world_object_add(ComponentWorldObject* self, ECS* ecs) +{ + ecs_components_add + ( + ecs, + COMPONENT_WORLD_OBJECT_DEPENDENCIES, + COMPONENT_WORLD_OBJECT_DEPENDENCY_COUNT, + self->component.id + ); +} + +void +component_world_object_delete(ComponentWorldObject* self, ECS* ecs) +{ + ecs_entity_delete(ecs, self->shadowID); +} + +void +component_world_object_tick(ComponentWorldObject* self, ECS* ecs) +{ + _component_world_object_depth_set(self, ecs); + _component_world_object_shadow_set(self, ecs); + _component_world_object_height_offset_set(self, ecs); + _component_world_object_bounds_set(self, ecs); + _component_world_object_direction_set(self, ecs); + _component_world_object_circle_collider_set(self, ecs); +} diff --git a/src/game/ecs/component/game/component_world_object.h b/src/game/ecs/component/game/component_world_object.h new file mode 100644 index 0000000..0312c36 --- /dev/null +++ b/src/game/ecs/component/game/component_world_object.h @@ -0,0 +1,72 @@ +#pragma once + +#include "component_game_object.h" +#include "../physics/component_circle_collider.h" + +#include "../../entity/visual/entity_sprite.h" + +static const RendererBuffer COMPONENT_WORLD_OBJECT_BUFFER = RENDERER_BUFFER_WORLD; +static const f32 COMPONENT_WORLD_OBJECT_SHADOW_Z_OFFSET = 0.001f; +static const f32 COMPONENT_WORLD_OBJECT_HEIGHT_OFFSET_SHADOW_SCALE_MULTIPLIER = 0.005f; +static const f32 COMPONENT_WORLD_OBJECT_FRICTION = 0.985f; +static const f32 COMPONENT_WORLD_OBJECT_SHADOW_HEIGHT = 32.0f; +static const f32 COMPONENT_WORLD_OBJECT_DEPTH_Y_OFFSET_MULTIPLIER = 0.1f; +static const f32 COMPONENT_WORLD_OBJECT_DEPTH_MIN = 0.1f; +static const f32 COMPONENT_WORLD_OBJECT_DEPTH_MAX = 0.2f; +static const f32 COMPONENT_WORLD_OBJECT_GRAVITY = 1.0f; +static const vec3 COMPONENT_WORLD_OBJECT_VELOCITY_MAX = {100.0f, 100.0f, 100.0f}; +static const vec4 COMPONENT_WORLD_OBJECT_BOUNDS = {250.0f, 250.0f, 6300.0f, 3100.0f}; + +#define COMPONENT_WORLD_OBJECT_ORIGIN ORIGIN_CENTER + +typedef struct ComponentWorldObject +{ + Component component; + EntityID shadowID; + f32 heightOffset; + f32 heightOffsetVelocity; + f32 angle; + Direction direction; + bool isAirborne; + bool isGravityAffected; +} ComponentWorldObject; + +void +component_world_object_init +( + ComponentWorldObject* self, + ECS* ecs, + Texture* texture, + vec2 size, + vec3 position, + f32 heightOffset, + f32 radius +); + +void component_world_object_add(ComponentWorldObject* self, ECS* ecs); +void component_world_object_delete(ComponentWorldObject* self, ECS* ecs); +void component_world_object_tick(ComponentWorldObject* self, ECS* ecs); + +#define COMPONENT_WORLD_OBJECT_DEPENDENCY_COUNT 2 +static const ComponentType COMPONENT_WORLD_OBJECT_DEPENDENCIES[COMPONENT_WORLD_OBJECT_DEPENDENCY_COUNT] = +{ + COMPONENT_GAME_OBJECT, + COMPONENT_CIRCLE_COLLIDER +}; + +static const ComponentInfo COMPONENT_WORLD_OBJECT_INFO = +{ + .system = + { + .functions = + { + (ECSFunction)component_world_object_add, + (ECSFunction)component_world_object_delete, + (ECSFunction)component_world_object_tick, + NULL, + NULL + } + }, + .type = COMPONENT_WORLD_OBJECT, + .size = sizeof(ComponentWorldObject) +}; diff --git a/src/game/ecs/component/physics/component_circle_collider.c b/src/game/ecs/component/physics/component_circle_collider.c new file mode 100644 index 0000000..6e0181c --- /dev/null +++ b/src/game/ecs/component/physics/component_circle_collider.c @@ -0,0 +1,66 @@ +#include "component_circle_collider.h" + +void _component_circle_collider_collisions_tick(ComponentCircleCollider* self, ECS* ecs); + +void +_component_circle_collider_collisions_tick(ComponentCircleCollider* self, ECS* ecs) +{ + vector_clear(&self->collisions); + + for (s32 i = 0; i < (s32)ecs->lists[COMPONENT_CIRCLE_COLLIDER].components.count; i++) + { + EntityID* id; + ComponentCircleCollider* circleCollider; + + id = vector_get(&ecs->lists[COMPONENT_CIRCLE_COLLIDER].components, i); + + if (*id == self->component.id) + continue; + + circleCollider = ecs_component_get(ecs, COMPONENT_CIRCLE_COLLIDER, *id); + + if (circle_collide_check(&self->circle, &circleCollider->circle)) + vector_push(&self->collisions, id); + } +} + +bool +component_circle_collider_collide_check(ComponentCircleCollider* self, ECS* ecs, EntityID id) +{ + for (s32 i = 0; i < (s32)self->collisions.count; i++) + { + EntityID* checkID; + + checkID = vector_get(&self->collisions, i); + + if (*checkID == id) + return true; + } + + return false; +} + +void +component_circle_collider_add(ComponentCircleCollider* self, ECS* ecs) +{ + vector_init(&self->collisions, sizeof(EntityID)); +} + +void +component_circle_collider_delete(ComponentCircleCollider* self, ECS* ecs) +{ + vector_free(&self->collisions); +} + +void +component_circle_collider_tick(ComponentCircleCollider* self, ECS* ecs) +{ + _component_circle_collider_collisions_tick(self, ecs); +} + +void +component_circle_collider_init(ComponentCircleCollider* self, vec2 position, f32 radius) +{ + glm_vec2_copy(position, self->circle.position); + self->circle.radius = radius; +} diff --git a/src/game/ecs/component/physics/component_circle_collider.h b/src/game/ecs/component/physics/component_circle_collider.h new file mode 100644 index 0000000..d45bc32 --- /dev/null +++ b/src/game/ecs/component/physics/component_circle_collider.h @@ -0,0 +1,42 @@ +#pragma once + +#include "../../ecs_entity.h" + +#include "../../../../engine/circle.h" + +typedef struct ComponentCircleCollider +{ + Component component; + Circle circle; + Vector collisions; /* EntityID */ +} ComponentCircleCollider; + +void component_circle_collider_add(ComponentCircleCollider* self, ECS* ecs); +void component_circle_collider_delete(ComponentCircleCollider* self, ECS* ecs); +void component_circle_collider_tick(ComponentCircleCollider* self, ECS* ecs); +bool component_circle_collider_collide_check(ComponentCircleCollider* self, ECS* ecs, EntityID id); + +void component_circle_collider_init +( + ComponentCircleCollider* self, + vec2 position, + f32 radius +); + +static const ComponentInfo COMPONENT_CIRCLE_COLLIDER_INFO = +{ + .system = + { + .functions = + { + + (ECSFunction)component_circle_collider_add, + (ECSFunction)component_circle_collider_delete, + (ECSFunction)component_circle_collider_tick, + NULL, + NULL + } + }, + .type = COMPONENT_CIRCLE_COLLIDER, + .size = sizeof(ComponentCircleCollider) +}; diff --git a/src/game/ecs/component/physics/component_copy_mouse_position.c b/src/game/ecs/component/physics/component_copy_mouse_position.c new file mode 100644 index 0000000..4e057e0 --- /dev/null +++ b/src/game/ecs/component/physics/component_copy_mouse_position.c @@ -0,0 +1,21 @@ +#include "component_copy_mouse_position.h" + +void +component_copy_mouse_position_add(ComponentCopyMousePosition* self, ECS* ecs) +{ + component_copy_mouse_position_tick(self, ecs); +} + +void +component_copy_mouse_position_tick(ComponentCopyMousePosition* self, ECS* ecs) +{ + ComponentPhysics* physics; + vec2 mousePosition; + + physics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->component.id); + + mouse_buffer_position_get(&ecs->input->mouse, RENDERER_BUFFER_CURSOR, ecs->renderer, mousePosition); + + physics->position[0] = mousePosition[0]; + physics->position[1] = mousePosition[1]; +} diff --git a/src/game/ecs/component/physics/component_copy_mouse_position.h b/src/game/ecs/component/physics/component_copy_mouse_position.h new file mode 100644 index 0000000..5e34b2c --- /dev/null +++ b/src/game/ecs/component/physics/component_copy_mouse_position.h @@ -0,0 +1,30 @@ +#pragma once + +#include "component_physics.h" + +#include "../../../input/input.h" + +typedef struct ComponentCopyMousePosition +{ + Component component; +} ComponentCopyMousePosition; + +void component_copy_mouse_position_add(ComponentCopyMousePosition* self, ECS* ecs); +void component_copy_mouse_position_tick(ComponentCopyMousePosition* self, ECS* ecs); + +static const ComponentInfo COMPONENT_COPY_MOUSE_POSITION_INFO = +{ + .system = + { + .functions = + { + (ECSFunction)component_copy_mouse_position_add, + NULL, + (ECSFunction)component_copy_mouse_position_tick, + NULL, + NULL + } + }, + .type = COMPONENT_COPY_MOUSE_POSITION, + .size = sizeof(ComponentCopyMousePosition) +}; diff --git a/src/game/ecs/component/physics/component_physics.c b/src/game/ecs/component/physics/component_physics.c new file mode 100644 index 0000000..50220c9 --- /dev/null +++ b/src/game/ecs/component/physics/component_physics.c @@ -0,0 +1,67 @@ +#include "component_physics.h" + +void +component_physics_tick(ComponentPhysics* self, ECS* ecs) +{ + glm_vec3_add(self->velocity, self->position, self->position); + + glm_vec3_scale(self->velocity, self->friction, self->velocity); + + self->velocity[0] = MAX(self->velocity[0], self->velocityMax[0]); + self->velocity[1] = MAX(self->velocity[1], self->velocityMax[1]); + self->velocity[2] = MAX(self->velocity[2], self->velocityMax[2]); + + if + ( + self->velocity[0] != 0.0f || + self->velocity[1] != 0.0f + ) + self->isMoving = true; + else + self->isMoving = false; +} + +void +component_physics_next_position_get(ComponentPhysics* self, ECS* ecs, vec2 position) +{ + position[0] = self->position[0] + self->velocity[0]; + position[1] = self->position[1] + self->velocity[1]; +} + +f32 +component_physics_next_position_distance_get(ComponentPhysics* self, ECS* ecs) +{ + vec2 position; + + component_physics_next_position_get(self, ecs, position); + + return DISTANCE_2D + ( + position[0], + self->position[0], + position[1], + self->position[1] + ); +} + +void +component_physics_add(ComponentPhysics* self, ECS* ecs) +{ + self->friction = COMPONENT_PHYSICS_FRICTION_DEFAULT; + glm_vec3_copy((f32*)COMPONENT_PHYSICS_VELOCITY_MAX_DEFAULT, self->velocityMax); +} + +void +component_physics_init +( + ComponentPhysics* self, + ECS* ecs, + const vec3 position, + const vec3 velocityMax, + f32 friction +) +{ + glm_vec3_copy((f32*)position, self->position); + glm_vec3_copy((f32*)velocityMax, self->velocityMax); + self->friction = friction; +} diff --git a/src/game/ecs/component/physics/component_physics.h b/src/game/ecs/component/physics/component_physics.h new file mode 100644 index 0000000..5a4128d --- /dev/null +++ b/src/game/ecs/component/physics/component_physics.h @@ -0,0 +1,48 @@ +#pragma once + +#include "../../ecs_entity.h" + +#include "../../../input/control.h" + +static const f32 COMPONENT_PHYSICS_FRICTION_DEFAULT = 1.0f; +static const vec3 COMPONENT_PHYSICS_VELOCITY_MAX_DEFAULT = {1000.0f, 1000.0f, 1000.0f}; + +typedef struct ComponentPhysics +{ + Component component; + vec3 position; + vec3 velocity; + vec3 velocityMax; + f32 friction; + bool isMoving; +} ComponentPhysics; + +void component_physics_tick(ComponentPhysics* self, ECS* ecs); +void component_physics_next_position_get(ComponentPhysics* self, ECS* ecs, vec2 position); +f32 component_physics_next_position_distance_get(ComponentPhysics* self, ECS* ecs); + +void component_physics_init +( + ComponentPhysics* self, + ECS* ecs, + const vec3 position, + const vec3 velocityMax, + f32 friction +); + +static const ComponentInfo COMPONENT_PHYSICS_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_physics_tick, + NULL, + NULL + } + }, + .type = COMPONENT_PHYSICS, + .size = sizeof(ComponentPhysics) +}; diff --git a/src/game/ecs/component/ui/component_button.c b/src/game/ecs/component/ui/component_button.c new file mode 100644 index 0000000..16862c2 --- /dev/null +++ b/src/game/ecs/component/ui/component_button.c @@ -0,0 +1,48 @@ +#include "component_button.h" + +void +component_button_add(ComponentButton* self, ECS* ecs) +{ + for (s32 i = 0; i < COMPONENT_BUTTON_DEPENDENCY_COUNT; i++) + ecs_component_add(ecs, COMPONENT_BUTTON_DEPENDENCIES[i], self->component.id); +} + +void +component_button_tick(ComponentButton* self, ECS* ecs) +{ + ComponentTextureQuad* textureQuad; + vec2 mousePosition; + Rectangle rectangle; + + textureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->component.id); + + mouse_buffer_position_get(&ecs->input->mouse, textureQuad->buffer, ecs->renderer, mousePosition); + + component_texture_quad_rectangle_get(textureQuad, &rectangle); + + if (rectangle_has_point(&rectangle, mousePosition)) + { + self->state = BUTTON_STATE_HOVER; + + glm_vec4_copy((f32*)COMPONENT_BUTTON_STATE_HOVER_COLOR, textureQuad->color); + + if (control_held(ecs->control, CONTROL_ACTION_PRIMARY)) + { + if (self->state != BUTTON_STATE_PRESSED) + { + self->isJustPressed = true; + sound_play(&ecs->resources->sounds[SOUND_SELECT]); + } + else + self->isJustPressed = false; + + glm_vec4_copy((f32*)COMPONENT_BUTTON_STATE_PRESSED_COLOR, textureQuad->color); + self->state = BUTTON_STATE_PRESSED; + } + } + else + { + glm_vec4_copy((f32*)COMPONENT_BUTTON_STATE_NONE_COLOR, textureQuad->color); + self->state = BUTTON_STATE_NONE; + } +} diff --git a/src/game/ecs/component/ui/component_button.h b/src/game/ecs/component/ui/component_button.h new file mode 100644 index 0000000..84ef2a1 --- /dev/null +++ b/src/game/ecs/component/ui/component_button.h @@ -0,0 +1,51 @@ +#pragma once + +#include "../visual/component_texture_quad.h" +#include "../physics/component_physics.h" + +#include "../../entity/utility/entity_timer.h" + +#define BUTTON_STATE_COUNT BUTTON_STATE_PRESSED + 1 +typedef enum ButtonState +{ + BUTTON_STATE_NONE, + BUTTON_STATE_HOVER, + BUTTON_STATE_PRESSED +} ButtonState; + +typedef struct ComponentButton +{ + Component component; + ButtonState state; + bool isJustPressed; +} ComponentButton; + +void component_button_add(ComponentButton* self, ECS* ecs); +void component_button_tick(ComponentButton* self, ECS* ecs); + +#define COMPONENT_BUTTON_DEPENDENCY_COUNT 1 +static const ComponentType COMPONENT_BUTTON_DEPENDENCIES[COMPONENT_BUTTON_DEPENDENCY_COUNT] = +{ + COMPONENT_TEXTURE_QUAD +}; + +static const ComponentInfo COMPONENT_BUTTON_INFO = +{ + .system = + { + .functions = + { + (ECSFunction)component_button_add, + NULL, + (ECSFunction)component_button_tick, + NULL, + NULL + } + }, + .type = COMPONENT_BUTTON, + .size = sizeof(ComponentButton) +}; + +static const vec4 COMPONENT_BUTTON_STATE_NONE_COLOR = {1.0f, 1.0f, 1.0f, 1.0f}; +static const vec4 COMPONENT_BUTTON_STATE_HOVER_COLOR = {0.75f, 0.75f, 0.75f, 1.0f}; +static const vec4 COMPONENT_BUTTON_STATE_PRESSED_COLOR = {0.5f, 0.5f, 0.5f, 1.0f}; diff --git a/src/game/ecs/component/utility/component_counter.c b/src/game/ecs/component/utility/component_counter.c new file mode 100644 index 0000000..ebb3900 --- /dev/null +++ b/src/game/ecs/component/utility/component_counter.c @@ -0,0 +1,13 @@ +#include "component_counter.h" + +void +component_counter_init(ComponentCounter* self, ECS* ecs) +{ + self->value = 0; +} + +void +component_counter_tick(ComponentCounter* self, ECS* ecs) +{ + self->value++; +} diff --git a/src/game/ecs/component/utility/component_counter.h b/src/game/ecs/component/utility/component_counter.h new file mode 100644 index 0000000..1479a89 --- /dev/null +++ b/src/game/ecs/component/utility/component_counter.h @@ -0,0 +1,29 @@ +#pragma once + +#include "../../ecs_entity.h" + +typedef struct ComponentCounter +{ + Component component; + s32 value; +} ComponentCounter; + +void component_counter_init(ComponentCounter* self, ECS* ecs); +void component_counter_tick(ComponentCounter* self, ECS* ecs); + +static const ComponentInfo COMPONENT_COUNTER_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_counter_tick, + NULL, + NULL, + } + }, + .type = COMPONENT_COUNTER, + .size = sizeof(ComponentCounter) +}; diff --git a/src/game/ecs/component/utility/component_delete_on_timer.c b/src/game/ecs/component/utility/component_delete_on_timer.c new file mode 100644 index 0000000..2928882 --- /dev/null +++ b/src/game/ecs/component/utility/component_delete_on_timer.c @@ -0,0 +1,43 @@ +#include "component_delete_on_timer.h" + +void +component_delete_on_timer_add(ComponentDeleteOnTimer* self, ECS* ecs) +{ + ComponentTimer* timer; + + self->timerID = entity_timer_add(ecs, -1); + + timer = ecs_component_get(ecs, COMPONENT_TIMER, self->timerID); + + timer->component.isDisabled = true; +} + + +void +component_delete_on_timer_delete(ComponentDeleteOnTimer* self, ECS* ecs) +{ + ecs_entity_delete(ecs, self->timerID); +} + +void +component_delete_on_timer_init(ComponentDeleteOnTimer* self, ECS* ecs, s32 value) +{ + ComponentTimer* timer; + + timer = ecs_component_get(ecs, COMPONENT_TIMER, self->timerID); + + component_timer_init(timer, ecs, value); + + timer->component.isDisabled = false; +} + +void +component_delete_on_timer_tick(ComponentDeleteOnTimer* self, ECS* ecs) +{ + ComponentTimer* timer; + + timer = ecs_component_get(ecs, COMPONENT_TIMER, self->timerID); + + if (timer->isFinished) + ecs_entity_delete(ecs, self->component.id); +} diff --git a/src/game/ecs/component/utility/component_delete_on_timer.h b/src/game/ecs/component/utility/component_delete_on_timer.h new file mode 100644 index 0000000..df5c3b5 --- /dev/null +++ b/src/game/ecs/component/utility/component_delete_on_timer.h @@ -0,0 +1,31 @@ +#pragma once + +#include "../../entity/utility/entity_timer.h" + +typedef struct ComponentDeleteOnTimer +{ + Component component; + EntityID timerID; +} ComponentDeleteOnTimer; + +void component_delete_on_timer_init(ComponentDeleteOnTimer* self, ECS* ecs, s32 value); +void component_delete_on_timer_add(ComponentDeleteOnTimer* self, ECS* ecs); +void component_delete_on_timer_delete(ComponentDeleteOnTimer* self, ECS* ecs); +void component_delete_on_timer_tick(ComponentDeleteOnTimer* self, ECS* ecs); + +static const ComponentInfo COMPONENT_DELETE_ON_TIMER_INFO = +{ + .system = + { + .functions = + { + (ECSFunction)component_delete_on_timer_add, + (ECSFunction)component_delete_on_timer_delete, + (ECSFunction)component_delete_on_timer_tick, + NULL, + NULL, + } + }, + .type = COMPONENT_DELETE_ON_TIMER, + .size = sizeof(ComponentDeleteOnTimer) +}; diff --git a/src/game/ecs/component/utility/component_timer.c b/src/game/ecs/component/utility/component_timer.c new file mode 100644 index 0000000..3cac20e --- /dev/null +++ b/src/game/ecs/component/utility/component_timer.c @@ -0,0 +1,25 @@ +#include "component_timer.h" + +void +component_timer_init(ComponentTimer* self, ECS* ecs, s32 value) +{ + self->value = value; + self->startValue = value; + self->isFinished = false; +} + +void +component_timer_tick(ComponentTimer* self, ECS* ecs) +{ + if (self->isFinished) + return; + + if (self->value <= 0) + { + self->isFinished = true; + self->value = 0; + return; + } + + self->value--; +} diff --git a/src/game/ecs/component/utility/component_timer.h b/src/game/ecs/component/utility/component_timer.h new file mode 100644 index 0000000..5ca79e6 --- /dev/null +++ b/src/game/ecs/component/utility/component_timer.h @@ -0,0 +1,31 @@ +#pragma once + +#include "../../ecs_entity.h" + +typedef struct ComponentTimer +{ + Component component; + s32 value; + s32 startValue; + bool isFinished; +} ComponentTimer; + +void component_timer_init(ComponentTimer* self, ECS* ecs, s32 value); +void component_timer_tick(ComponentTimer* self, ECS* ecs); + +static const ComponentInfo COMPONENT_TIMER_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_timer_tick, + NULL, + NULL, + } + }, + .type = COMPONENT_TIMER, + .size = sizeof(ComponentTimer) +}; diff --git a/src/game/ecs/component/visual/component_atlas.c b/src/game/ecs/component/visual/component_atlas.c new file mode 100644 index 0000000..4aa79ef --- /dev/null +++ b/src/game/ecs/component/visual/component_atlas.c @@ -0,0 +1,33 @@ +#include "component_atlas.h" + +void +component_atlas_uv_get(ComponentAtlas* self, Texture* texture, vec2 uvMin, vec2 uvMax) +{ + vec2 position; + + position[0] = (self->index % self->size[1]) * self->frameSize[0]; + position[1] = (s32)((f32)self->index / self->size[1]) * self->frameSize[1]; + + uvMin[0] = (f32)position[0] / texture->size[0]; + uvMin[1] = (f32)position[1] / texture->size[1]; + uvMax[0] = (f32)(position[0] + self->frameSize[0]) / texture->size[0]; + uvMax[1] = (f32)(position[1] + self->frameSize[1]) / texture->size[1]; +} + +void +component_atlas_init(ComponentAtlas* self, ECS* ecs, const ivec2 frameSize, const ivec2 size, u32 index) +{ + glm_ivec2_copy((s32*)frameSize, self->frameSize); + glm_ivec2_copy((s32*)size, self->size); + self->index = index; +} + +void +component_atlas_tick(ComponentAtlas* self, ECS* ecs) +{ + ComponentTextureQuad* textureQuad; + + textureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->component.id); + + component_atlas_uv_get(self, textureQuad->texture, textureQuad->uvMin, textureQuad->uvMax); +} diff --git a/src/game/ecs/component/visual/component_atlas.h b/src/game/ecs/component/visual/component_atlas.h new file mode 100644 index 0000000..e1b6cf3 --- /dev/null +++ b/src/game/ecs/component/visual/component_atlas.h @@ -0,0 +1,32 @@ +#pragma once + +#include "component_texture_quad.h" + +typedef struct ComponentAtlas +{ + Component component; + ivec2 frameSize; + ivec2 size; + u32 index; +} ComponentAtlas; + +void component_atlas_init(ComponentAtlas* self, ECS* ecs, const ivec2 frameSize, const ivec2 size, u32 index); +void component_atlas_tick(ComponentAtlas* self, ECS* ecs); +void component_atlas_uv_get(ComponentAtlas* self, Texture* texture, vec2 uvMin, vec2 uvMax); + +static const ComponentInfo COMPONENT_ATLAS_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_atlas_tick, + NULL, + NULL, + } + }, + .type = COMPONENT_ATLAS, + .size = sizeof(ComponentAtlas) +}; diff --git a/src/game/ecs/component/visual/component_camera_focus.c b/src/game/ecs/component/visual/component_camera_focus.c new file mode 100644 index 0000000..b9db4f6 --- /dev/null +++ b/src/game/ecs/component/visual/component_camera_focus.c @@ -0,0 +1,66 @@ +#include "component_camera_focus.h" + +void +component_camera_focus_tick(ComponentCameraFocus* self, ECS* ecs) +{ + ComponentPhysics* physics; + vec3 position; + //f32 velocityPercent; + //vec2 positionPercent; + + physics = ecs_component_get(ecs, COMPONENT_PHYSICS, self->entityID); + + if (!physics) + return; + + glm_vec3_copy(physics->position, position); + + /* + positionPercent[0] = (physics->position[0] + (physics->velocity[0] * COMPONENT_CAMERA_FOCUS_VELOCITY_MULTIPLIER)) / self->camera->orthographic.size[0]; + positionPercent[1] = (physics->position[1] + (physics->velocity[1] * COMPONENT_CAMERA_FOCUS_VELOCITY_MULTIPLIER)) / self->camera->orthographic.size[1]; + */ + + /* + position[0] += physics->velocity[0] * COMPONENT_CAMERA_FOCUS_VELOCITY_MULTIPLIER; + position[1] += physics->velocity[1] * COMPONENT_CAMERA_FOCUS_VELOCITY_MULTIPLIER; + */ + + position[0] -= self->camera->orthographic.size[0] / 2; + position[1] -= self->camera->orthographic.size[1] / 2; + + /* + position[0] += (physics->position[0]) - ((self->camera->orthographic.size[0] / 4) * (1 - self->camera->zoom)); + position[1] += (physics->position[1]) - ((self->camera->orthographic.size[1] / 4) * (1 - self->camera->zoom)); + */ + + position[2] = 0.0f; + + //velocityPercent = 0.0f; + + /* + if (fabs(physics->velocity[0]) >= fabs(physics->velocity[1])) + velocityPercent = fabs(physics->velocity[0]) / physics->velocityMax[0]; + else if (fabs(physics->velocity[1]) > fabs(physics->velocity[0])) + velocityPercent = fabs(physics->velocity[1]) / physics->velocityMax[1]; + + self->camera->zoom = COMPONENT_CAMERA_FOCUS_ZOOM_MIN; + self->camera->zoom += (velocityPercent * (COMPONENT_CAMERA_FOCUS_ZOOM_MAX - COMPONENT_CAMERA_FOCUS_ZOOM_MIN)); + */ + + //glm_vec3_print(position, stderr); + + camera_position_set(self->camera, position); +} + +void +component_camera_focus_init +( + ComponentCameraFocus* self, + ECS* ecs, + Camera* camera, + u32 entityID +) +{ + self->camera = camera; + self->entityID = entityID; +} diff --git a/src/game/ecs/component/visual/component_camera_focus.h b/src/game/ecs/component/visual/component_camera_focus.h new file mode 100644 index 0000000..24f02c6 --- /dev/null +++ b/src/game/ecs/component/visual/component_camera_focus.h @@ -0,0 +1,43 @@ +#pragma once + +#include "../physics/component_physics.h" + +static const f32 COMPONENT_CAMERA_FOCUS_VELOCITY_MULTIPLIER = 10.0f; +static const f32 COMPONENT_CAMERA_FOCUS_VELOCITY_ZOOM_MULTIPLIER = 0.1f; +static const f32 COMPONENT_CAMERA_FOCUS_ZOOM_MAX = 0.40f; +static const f32 COMPONENT_CAMERA_FOCUS_ZOOM_MIN = 0.25f; + +typedef struct ComponentCameraFocus +{ + Component component; + Camera* camera; + EntityID entityID; +} ComponentCameraFocus; + +void component_camera_focus_tick(ComponentCameraFocus* self, ECS* ecs); + +void +component_camera_focus_init +( + ComponentCameraFocus* self, + ECS* ecs, + Camera* camera, + EntityID entityID +); + +static const ComponentInfo COMPONENT_CAMERA_FOCUS_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_camera_focus_tick, + NULL, + NULL + } + }, + .type = COMPONENT_CAMERA_FOCUS, + .size = sizeof(ComponentCameraFocus) +}; diff --git a/src/game/ecs/component/visual/component_color_change.c b/src/game/ecs/component/visual/component_color_change.c new file mode 100644 index 0000000..c463faa --- /dev/null +++ b/src/game/ecs/component/visual/component_color_change.c @@ -0,0 +1,109 @@ +#include "component_color_change.h" + +void +component_color_change_add(ComponentColorChange* self, ECS* ecs) +{ + self->timerID = entity_timer_add(ecs, -1); + + self->component.isDisabled = true; +} + +void +component_color_change_delete(ComponentColorChange* self, ECS* ecs) +{ + ecs_entity_delete(ecs, self->timerID); +} + +void +component_color_change_tick(ComponentColorChange* self, ECS* ecs) +{ + ComponentTextureQuad* textureQuad; + ComponentText* text; + ComponentTimer* timer; + vec4 colorStep; + vec4* color; + vec4* colorCover; + + if (self->isFinished) + return; + + timer = ecs_component_get(ecs, COMPONENT_TIMER, self->timerID); + + ecs->isLog = false; + + textureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->component.id); + text = ecs_component_get(ecs, COMPONENT_TEXT, self->component.id); + + ecs->isLog = true; + + if (textureQuad) + { + color = &textureQuad->color; + colorCover = &textureQuad->colorCover; + } + else if (text) + { + color = &text->color; + colorCover = &text->colorCover; + } + else + return; + + if (self->isColorCover) + glm_vec4_scale(self->colorStep, timer->value, *colorCover); + else + glm_vec4_scale(self->colorStep, timer->value, *color); + + if (timer->isFinished) + { + self->isFinished = true; + + if (self->isReturn) + { + if (self->isColorCover) + glm_vec4_copy(self->returnColor, *colorCover); + else + glm_vec4_copy(self->returnColor, *color); + } + return; + } +} + +void +component_color_change_init(ComponentColorChange* self, ECS* ecs, const vec4 endColor, const vec4 beginColor, u32 length, bool isColorCover, bool isReturn) +{ + ComponentTimer* timer; + ComponentTextureQuad* textureQuad; + ComponentText* text; + vec4 colorDifference; + + ecs->isLog = false; + + textureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->component.id); + text = ecs_component_get(ecs, COMPONENT_TEXT, self->component.id); + + ecs->isLog = true; + + glm_vec4_copy((f32*)beginColor, self->beginColor); + glm_vec4_copy((f32*)endColor, self->endColor); + + if (textureQuad) + glm_vec4_copy((f32*)textureQuad->color, self->returnColor); + else if (text) + glm_vec4_copy((f32*)text->color, self->returnColor); + + timer = ecs_component_get(ecs, COMPONENT_TIMER, self->timerID); + + component_timer_init(timer, ecs, length); + + timer->component.isDisabled = false; + + glm_vec4_sub(self->endColor, self->beginColor, colorDifference); + glm_vec4_scale(colorDifference, (1.0f / length), self->colorStep); + + self->isColorCover = isColorCover; + self->isReturn = isReturn; + self->isFinished = false; + + self->component.isDisabled = false; +} diff --git a/src/game/ecs/component/visual/component_color_change.h b/src/game/ecs/component/visual/component_color_change.h new file mode 100644 index 0000000..5cfff3a --- /dev/null +++ b/src/game/ecs/component/visual/component_color_change.h @@ -0,0 +1,51 @@ +#pragma once + +#include "component_texture_quad.h" +#include "component_text.h" +#include "../../entity/utility/entity_timer.h" + +typedef struct ComponentColorChange +{ + Component component; + vec4 beginColor; + vec4 endColor; + vec4 returnColor; + vec4 colorStep; + bool isColorCover; + bool isReturn; + bool isFinished; + EntityID timerID; +} ComponentColorChange; + +void component_color_change_add(ComponentColorChange* self, ECS* ecs); +void component_color_change_delete(ComponentColorChange* self, ECS* ecs); +void component_color_change_tick(ComponentColorChange* self, ECS* ecs); + +void +component_color_change_init +( + ComponentColorChange* self, + ECS* ecs, + const vec4 endColor, + const vec4 beginColor, + u32 length, + bool isColorCover, + bool isReturn +); + +static const ComponentInfo COMPONENT_COLOR_CHANGE_INFO = +{ + .system = + { + .functions = + { + (ECSFunction)component_color_change_add, + (ECSFunction)component_color_change_delete, + (ECSFunction)component_color_change_tick, + NULL, + NULL + } + }, + .type = COMPONENT_COLOR_CHANGE, + .size = sizeof(ComponentColorChange) +}; diff --git a/src/game/ecs/component/visual/component_color_match.c b/src/game/ecs/component/visual/component_color_match.c new file mode 100644 index 0000000..d161dc2 --- /dev/null +++ b/src/game/ecs/component/visual/component_color_match.c @@ -0,0 +1,34 @@ +#include "component_color_match.h" + +void _component_color_match_set(ComponentColorMatch* self, ECS* ecs); + +void +_component_color_match_set(ComponentColorMatch* self, ECS* ecs) +{ + ComponentTextureQuad* matchTextureQuad; + ComponentTextureQuad* textureQuad; + + matchTextureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->matchID); + + if (matchTextureQuad == NULL) + return; + + textureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->component.id); + + glm_vec4_copy(matchTextureQuad->color, textureQuad->color); + glm_vec4_copy(matchTextureQuad->colorCover, textureQuad->colorCover); +} + +void +component_color_match_tick(ComponentColorMatch* self, ECS* ecs) +{ + _component_color_match_set(self, ecs); +} + +void +component_color_match_init(ComponentColorMatch* self, ECS* ecs, EntityID matchID) +{ + self->matchID = matchID; + + _component_color_match_set(self, ecs); +} diff --git a/src/game/ecs/component/visual/component_color_match.h b/src/game/ecs/component/visual/component_color_match.h new file mode 100644 index 0000000..0f65d9e --- /dev/null +++ b/src/game/ecs/component/visual/component_color_match.h @@ -0,0 +1,38 @@ +#pragma once + +#include "component_texture_quad.h" + +typedef struct ComponentColorMatch +{ + Component component; + EntityID matchID; +} ComponentColorMatch; + +void component_color_match_add(ComponentColorMatch* self, ECS* ecs); +void component_color_match_delete(ComponentColorMatch* self, ECS* ecs); +void component_color_match_tick(ComponentColorMatch* self, ECS* ecs); + +void +component_color_match_init +( + ComponentColorMatch* self, + ECS* ecs, + EntityID matchID +); + +static const ComponentInfo COMPONENT_COLOR_MATCH_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_color_match_tick, + NULL, + NULL + } + }, + .type = COMPONENT_COLOR_MATCH, + .size = sizeof(ComponentColorMatch) +}; diff --git a/src/game/ecs/component/visual/component_dialogue.c b/src/game/ecs/component/visual/component_dialogue.c new file mode 100644 index 0000000..80698bb --- /dev/null +++ b/src/game/ecs/component/visual/component_dialogue.c @@ -0,0 +1,108 @@ +#include "component_dialogue.h" + +static void _component_dialogue_string_set(ComponentDialogue* self, ECS* ecs); + +static void +_component_dialogue_string_set(ComponentDialogue* self, ECS* ecs) +{ + ComponentText* text; + char string[COMPONENT_TEXT_STRING_MAX]; + + memset(string, '\0', COMPONENT_TEXT_STRING_MAX); + memcpy(string, self->string, self->index + 1); + + text = ecs_component_get(ecs, COMPONENT_TEXT, self->component.id); + + component_text_string_set(text, ecs, string, self->index + 1); + + sound_play(&ecs->resources->sounds[SOUND_BLIP]); +} + +void +component_dialogue_add(ComponentDialogue* self, ECS* ecs) +{ + for (s32 i = 0 ; i < COMPONENT_DIALOGUE_DEPENDENCY_COUNT; i++) + ecs_component_add(ecs, COMPONENT_DIALOGUE_DEPENDENCIES[i], self->component.id); + + self->timerID = entity_timer_add(ecs, COMPONENT_DIALOGUE_SPEED_DEFAULT); + self->skipTimerID = entity_timer_add(ecs, COMPONENT_DIALOGUE_SKIP_TIMER_VALUE); +} + +void +component_dialogue_delete(ComponentDialogue* self, ECS* ecs) +{ + for (s32 i = 0 ; i < COMPONENT_DIALOGUE_DEPENDENCY_COUNT; i++) + ecs_component_delete(ecs, COMPONENT_DIALOGUE_DEPENDENCIES[i], self->component.id); + + ecs_entity_delete(ecs, self->timerID); + ecs_entity_delete(ecs, self->skipTimerID); +} + +void +component_dialogue_tick(ComponentDialogue* self, ECS* ecs) +{ + ComponentTimer* timer; + + if (self->isFinished) + return; + + timer = ecs_component_get(ecs, COMPONENT_TIMER, self->timerID); + + if (timer->isFinished) + { + self->index++; + + _component_dialogue_string_set(self, ecs); + + if (self->index >= self->length) + self->isFinished = true; + else + component_timer_init(timer, ecs, self->speed); + } + + if (control_released(ecs->control, CONTROL_ACTION_PRIMARY)) + { + ComponentTimer* skipTimer; + + skipTimer = ecs_component_get(ecs, COMPONENT_TIMER, self->skipTimerID); + + if (!skipTimer->isFinished) + return; + + self->index = self->length - 1; + timer->value = 0; + timer->isFinished = true; + + component_timer_init(timer, ecs, self->speed); + component_timer_init(skipTimer, ecs, COMPONENT_DIALOGUE_SKIP_TIMER_VALUE); + } +} + +void +component_dialogue_init +( + ComponentDialogue* self, + ECS* ecs, + const char* string, + u32 speed +) +{ + ComponentTimer* timer; + ComponentTimer* skipTimer; + + self->speed = speed; + + memcpy(self->string, string, COMPONENT_TEXT_STRING_MAX); + + timer = ecs_component_get(ecs, COMPONENT_TIMER, self->timerID); + skipTimer = ecs_component_get(ecs, COMPONENT_TIMER, self->skipTimerID); + + component_timer_init(timer, ecs, self->speed); + component_timer_init(skipTimer, ecs, COMPONENT_DIALOGUE_SKIP_TIMER_VALUE); + + self->length = strlen(self->string); + self->index = 0; + self->isFinished = false; + + _component_dialogue_string_set(self, ecs); +} diff --git a/src/game/ecs/component/visual/component_dialogue.h b/src/game/ecs/component/visual/component_dialogue.h new file mode 100644 index 0000000..63b6601 --- /dev/null +++ b/src/game/ecs/component/visual/component_dialogue.h @@ -0,0 +1,57 @@ +#pragma once + +#include "component_text.h" + +#include "../../entity/utility/entity_timer.h" + +static const u32 COMPONENT_DIALOGUE_SPEED_DEFAULT = 3; +static const u32 COMPONENT_DIALOGUE_SKIP_TIMER_VALUE = 1; + +typedef struct ComponentDialogue +{ + Component component; + char string[COMPONENT_TEXT_STRING_MAX]; + u32 speed; + u32 index; + u32 length; + bool isFinished; + EntityID timerID; + EntityID skipTimerID; +} ComponentDialogue; + +void component_dialogue_add(ComponentDialogue* self, ECS* ecs); +void component_dialogue_delete(ComponentDialogue* self, ECS* ecs); +void component_dialogue_tick(ComponentDialogue* self, ECS* ecs); +void component_dialogue_string_set(ComponentDialogue* self, ECS* ecs); + +void +component_dialogue_init +( + ComponentDialogue* self, + ECS* ecs, + const char* string, + u32 speed +); + +#define COMPONENT_DIALOGUE_DEPENDENCY_COUNT 1 +static const ComponentType COMPONENT_DIALOGUE_DEPENDENCIES[COMPONENT_DIALOGUE_DEPENDENCY_COUNT] = +{ + COMPONENT_TEXT +}; + +static const ComponentInfo COMPONENT_DIALOGUE_INFO = +{ + .system = + { + .functions = + { + (ECSFunction)component_dialogue_add, + (ECSFunction)component_dialogue_delete, + (ECSFunction)component_dialogue_tick, + NULL, + NULL + } + }, + .type = COMPONENT_DIALOGUE, + .size = sizeof(ComponentDialogue) +}; diff --git a/src/game/ecs/component/visual/component_drop_shadow.c b/src/game/ecs/component/visual/component_drop_shadow.c new file mode 100644 index 0000000..b4ee827 --- /dev/null +++ b/src/game/ecs/component/visual/component_drop_shadow.c @@ -0,0 +1,67 @@ +#include "component_drop_shadow.h" + +static void _component_drop_shadow_texture_quad_set(ComponentDropShadow* self, ECS* ecs); + +static void +_component_drop_shadow_texture_quad_set(ComponentDropShadow* self, ECS* ecs) +{ + ComponentTextureQuad* textureQuadDropShadow; + ComponentTextureQuad* textureQuad; + + textureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->component.id); + + if (!self->isSpriteInit) + { + self->spriteID = entity_sprite_add + ( + ecs, + textureQuad->texture, + textureQuad->buffer, + textureQuad->origin, + textureQuad->size, + textureQuad->position + ); + + self->isSpriteInit = true; + } + + textureQuadDropShadow = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->spriteID); + + memcpy(textureQuadDropShadow, textureQuad, sizeof(ComponentTextureQuad)); + + textureQuadDropShadow->component.id = self->spriteID; + glm_vec4_copy(self->color, textureQuadDropShadow->color); + + textureQuadDropShadow->position[0] += self->offset[0]; + textureQuadDropShadow->position[1] += self->offset[1]; + textureQuadDropShadow->position[2] += COMPONENT_DROP_SHADOW_Z_OFFSET; +} + +void +component_drop_shadow_add(ComponentDropShadow* self, ECS* ecs) +{ + self->spriteID = ecs_entity_add(ecs); +} + +void +component_drop_shadow_delete(ComponentDropShadow* self, ECS* ecs) +{ + ecs_entity_delete(ecs, self->spriteID); +} + +void +component_drop_shadow_tick(ComponentDropShadow* self, ECS* ecs) +{ + _component_drop_shadow_texture_quad_set(self, ecs); +} + +void +component_drop_shadow_init(ComponentDropShadow* self, ECS* ecs, vec4 color, vec2 offset) +{ + glm_vec4_copy(color, self->color); + glm_vec2_copy(offset, self->offset); + + _component_drop_shadow_texture_quad_set(self, ecs); +} + + diff --git a/src/game/ecs/component/visual/component_drop_shadow.h b/src/game/ecs/component/visual/component_drop_shadow.h new file mode 100644 index 0000000..2d7629a --- /dev/null +++ b/src/game/ecs/component/visual/component_drop_shadow.h @@ -0,0 +1,35 @@ +#pragma once + +#include "../../entity/visual/entity_sprite.h" + +static const f32 COMPONENT_DROP_SHADOW_Z_OFFSET = 0.001f; + +typedef struct ComponentDropShadow +{ + Component component; + vec4 color; + vec2 offset; + bool isSpriteInit; + EntityID spriteID; +} ComponentDropShadow; + +void component_drop_shadow_init(ComponentDropShadow* self, ECS* ecs, vec4 color, vec2 offset); +void component_drop_shadow_tick(ComponentDropShadow* self, ECS* ecs); +void component_drop_shadow_add(ComponentDropShadow* self, ECS* ecs); +void component_drop_shadow_delete(ComponentDropShadow* self, ECS* ecs); + +static const ComponentInfo COMPONENT_DROP_SHADOW_INFO = +{ + .system = + { + .functions = + { + (ECSFunction)component_drop_shadow_add, + (ECSFunction)component_drop_shadow_delete, + (ECSFunction)component_drop_shadow_tick, + NULL + } + }, + .type = COMPONENT_DROP_SHADOW, + .size = sizeof(ComponentDropShadow) +}; diff --git a/src/game/ecs/component/visual/component_pulsate.c b/src/game/ecs/component/visual/component_pulsate.c new file mode 100644 index 0000000..6c11001 --- /dev/null +++ b/src/game/ecs/component/visual/component_pulsate.c @@ -0,0 +1,42 @@ +#include "component_pulsate.h" + +void +component_pulsate_add(ComponentPulsate* self, ECS* ecs) +{ + self->counterID = entity_counter_add(ecs); +} + +void +component_pulsate_delete(ComponentPulsate* self, ECS* ecs) +{ + ecs_entity_delete(ecs, self->counterID); +} + +void +component_pulsate_tick(ComponentPulsate* self, ECS* ecs) +{ + ComponentCounter* counter; + ComponentTextureQuad* textureQuad; + + counter = ecs_component_get(ecs, COMPONENT_COUNTER, self->counterID); + textureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->component.id); + + textureQuad->scale[0] = 1 + ((self->maxScale[0] - self->minScale[0]) / 2.0f) * cos((f32)counter->value / self->frequency); + textureQuad->scale[1] = 1 + ((self->maxScale[1] - self->minScale[1]) / 2.0f) * cos((f32)counter->value / self->frequency); +} + +void +component_pulsate_init +( + ComponentPulsate* self, + ECS* ecs, + vec2 minScale, + vec2 maxScale, + f32 frequency +) +{ + self->frequency = frequency; + + glm_vec2_copy(minScale, self->minScale); + glm_vec2_copy(maxScale, self->maxScale); +} diff --git a/src/game/ecs/component/visual/component_pulsate.h b/src/game/ecs/component/visual/component_pulsate.h new file mode 100644 index 0000000..a8e76c9 --- /dev/null +++ b/src/game/ecs/component/visual/component_pulsate.h @@ -0,0 +1,47 @@ +#pragma once + +#include "../../ecs_entity.h" + +#include "component_texture_quad.h" + +#include "../../entity/utility/entity_counter.h" + +typedef struct ComponentPulsate +{ + Component component; + vec2 minScale; + vec2 maxScale; + f32 frequency; + EntityID counterID; +} ComponentPulsate; + +void component_pulsate_add(ComponentPulsate* self, ECS* ecs); +void component_pulsate_delete(ComponentPulsate* self, ECS* ecs); +void component_pulsate_tick(ComponentPulsate* self, ECS* ecs); + +void +component_pulsate_init +( + ComponentPulsate* self, + ECS* ecs, + vec2 minScale, + vec2 maxScale, + f32 frequency +); + +static const ComponentInfo COMPONENT_PULSATE_INFO = +{ + .system = + { + .functions = + { + (ECSFunction)component_pulsate_add, + (ECSFunction)component_pulsate_delete, + (ECSFunction)component_pulsate_tick, + NULL, + NULL + } + }, + .type = COMPONENT_PULSATE, + .size = sizeof(ComponentPulsate) +}; diff --git a/src/game/ecs/component/visual/component_rotate.c b/src/game/ecs/component/visual/component_rotate.c new file mode 100644 index 0000000..bdd0a63 --- /dev/null +++ b/src/game/ecs/component/visual/component_rotate.c @@ -0,0 +1,17 @@ +#include "component_rotate.h" + +void +component_rotate_tick(ComponentRotate* self, ECS* ecs) +{ + ComponentTextureQuad* textureQuad; + + textureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->component.id); + + textureQuad->rotation += self->speed; +} + +void +component_rotate_init(ComponentRotate* self, ECS* ecs, f32 speed) +{ + self->speed = speed; +} diff --git a/src/game/ecs/component/visual/component_rotate.h b/src/game/ecs/component/visual/component_rotate.h new file mode 100644 index 0000000..cec19e9 --- /dev/null +++ b/src/game/ecs/component/visual/component_rotate.h @@ -0,0 +1,38 @@ +#pragma once + +#include "component_texture_quad.h" + +typedef struct ComponentRotate +{ + Component component; + f32 speed; +} ComponentRotate; + +void component_rotate_add(ComponentRotate* self, ECS* ecs); +void component_rotate_delete(ComponentRotate* self, ECS* ecs); +void component_rotate_tick(ComponentRotate* self, ECS* ecs); + +void +component_rotate_init +( + ComponentRotate* self, + ECS* ecs, + f32 speed +); + +static const ComponentInfo COMPONENT_ROTATE_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_rotate_tick, + NULL, + NULL + } + }, + .type = COMPONENT_ROTATE, + .size = sizeof(ComponentRotate) +}; diff --git a/src/game/ecs/component/visual/component_scale_value.c b/src/game/ecs/component/visual/component_scale_value.c new file mode 100644 index 0000000..f99a792 --- /dev/null +++ b/src/game/ecs/component/visual/component_scale_value.c @@ -0,0 +1,45 @@ +#include "component_scale_value.h" + +void _component_scale_value_set(ComponentScaleValue* self, ECS* ecs); + +void +_component_scale_value_set(ComponentScaleValue* self, ECS* ecs) +{ + ComponentTextureQuad* textureQuad; + void* component; + f32 value; + f32 max; + f32 percent; + vec2 sizeDifference; + vec2 scaledSize; + + textureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, self->component.id); + component = ecs_component_get(ecs, self->type, self->id); + + memcpy(&value, (u8*)component + sizeof(Component), sizeof(f32)); + memcpy(&max, (u8*)component + sizeof(Component) + sizeof(f32), sizeof(f32)); + + percent = value / max; + + glm_vec2_sub(self->maxSize, self->minSize, sizeDifference); + glm_vec2_scale(sizeDifference, percent, scaledSize); + glm_vec2_copy(self->minSize, textureQuad->size); + glm_vec2_add(textureQuad->size, scaledSize, textureQuad->size); +} + +void +component_scale_value_init(ComponentScaleValue* self, ECS* ecs, vec2 minSize, vec2 maxSize, ComponentType type, EntityID id) +{ + self->id = id; + self->type = type; + glm_vec2_copy(minSize, self->minSize); + glm_vec2_copy(maxSize, self->maxSize); + + _component_scale_value_set(self, ecs); +} + +void +component_scale_value_tick(ComponentScaleValue* self, ECS* ecs) +{ + _component_scale_value_set(self, ecs); +} diff --git a/src/game/ecs/component/visual/component_scale_value.h b/src/game/ecs/component/visual/component_scale_value.h new file mode 100644 index 0000000..b55e6df --- /dev/null +++ b/src/game/ecs/component/visual/component_scale_value.h @@ -0,0 +1,33 @@ +#pragma once + +#include "component_texture_quad.h" + +typedef struct ComponentScaleValue +{ + Component component; + vec2 minSize; + vec2 maxSize; + ComponentType type; + EntityID id; +} ComponentScaleValue; + +void component_scale_value_init(ComponentScaleValue* self, ECS* ecs, vec2 minSize, vec2 maxSize, ComponentType type, EntityID id); +void component_scale_value_tick(ComponentScaleValue* self, ECS* ecs); + +static const ComponentInfo COMPONENT_SCALE_VALUE_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + (ECSFunction)component_scale_value_tick, + NULL, + NULL + } + }, + .type = COMPONENT_SCALE_VALUE, + .size = sizeof(ComponentScaleValue) +}; + diff --git a/src/game/ecs/component/visual/component_text.c b/src/game/ecs/component/visual/component_text.c new file mode 100644 index 0000000..c3f232b --- /dev/null +++ b/src/game/ecs/component/visual/component_text.c @@ -0,0 +1,236 @@ +#include "component_text.h" + +void _component_text_glyph_size_get(ComponentText* self, Texture* texture, vec2 size); +void _component_text_glyph_position_get(ComponentText* self, Texture* texture, vec3 position); +void _component_text_glyph_entities_init(ComponentText* self, ECS* ecs); +void _component_text_glyph_entities_free(ComponentText* self, ECS* ecs); +void _component_text_glyphs_position_set(ComponentText* self, ECS* ecs); +void _component_text_glyphs_color_set(ComponentText* self, ECS* ecs); + +void +_component_text_glyph_size_get(ComponentText* self, Texture* texture, vec2 size) +{ + size[0] = texture->size[0] * self->scale[0]; + size[1] = texture->size[1] * self->scale[1]; +} + +void +_component_text_glyph_entities_init(ComponentText* self, ECS* ecs) +{ + vec2 dropShadowOffset; + + glm_vec2_zero(dropShadowOffset); + + dropShadowOffset[1] = (s32)(self->font->size * COMPONENT_TEXT_DROP_SHADOW_FONT_SIZE_MULTIPLIER); + + for (s32 i = 0; i < (s32)self->length; i++) + { + EntityID glyphID; + vec2 glyphSize; + vec3 glyphPosition; + char glyph; + + glyph = self->string[i]; + + if (glyph == '\n') + glyph = ' '; + + _component_text_glyph_size_get(self, &self->font->glyphTextures[(s32)glyph], glyphSize); + + glyphID = entity_glyph_add + ( + ecs, + &self->font->glyphTextures[(s32)glyph], + self->buffer, + glyphSize, + self->position, + self->color, + self->dropShadowColor, + dropShadowOffset + ); + + vector_push(&self->glyphEntities, &glyphID); + } + + _component_text_glyphs_position_set(self, ecs); + + for (s32 i = 0; i < (s32)self->length; i++) + { + EntityID* glyphEntityID; + ComponentDropShadow* glyphEntityDropShadow; + + glyphEntityID = (EntityID*)vector_get(&self->glyphEntities, i); + + glyphEntityDropShadow = ecs_component_get(ecs, COMPONENT_DROP_SHADOW, *glyphEntityID); + + component_drop_shadow_tick(glyphEntityDropShadow, ecs); + } +} + +void +_component_text_glyph_entities_free(ComponentText* self, ECS* ecs) +{ + for (s32 i = 0; i < (s32)self->length; i++) + { + EntityID* glyphEntity; + + glyphEntity = (EntityID*)vector_get(&self->glyphEntities, i); + + ecs_entity_delete(ecs, *glyphEntity); + } + + vector_clear(&self->glyphEntities); +} + +void +_component_text_glyphs_position_set(ComponentText* self, ECS* ecs) +{ + GlyphMetrics glyphMetrics; + f32 currentLineWidth; + f32 increment; + f32 kerning; + f32 lineBegin; + f32 lineSkip; + f32 advance; + vec3 position; + + lineSkip = font_line_skip_get(self->font); + + glm_vec3_copy(self->position, position); + + currentLineWidth = 0.0f; + lineBegin = position[0]; + + for (s32 i = 0; i < (s32)self->length; i++) + { + EntityID* glyphEntityID; + ComponentTextureQuad* glyphEntityTextureQuad; + char glyph; + + glyph = self->string[i]; + glyphEntityID = (EntityID*)vector_get(&self->glyphEntities, i); + glyphEntityTextureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, *glyphEntityID); + + font_glyph_metrics_init(self->font, &glyphMetrics, glyph); + + advance = glyphMetrics.advance; + + if + ( + glyph == '\n' || + (glyph == ' ' && (currentLineWidth > self->wrap) && self->wrap != -1) + ) + { + position[0] = lineBegin; + position[1] += lineSkip * self->scale[1]; + + advance = 0.0f; + + currentLineWidth = 0.0f; + } + + if (i < (s32)self->length) + kerning = (f32)font_glyph_kerning_get(self->font, glyph, self->string[i + 1]); + else + kerning = 0.0f; + + glm_vec3_copy(position, glyphEntityTextureQuad->position); + + increment = advance + kerning; + + position[0] += increment; + position[2] -= COMPONENT_TEXT_Z_OFFSET_INCREMENT; + + currentLineWidth += increment; + } +} + +void +_component_text_glyphs_color_set(ComponentText* self, ECS* ecs) +{ + for (s32 i = 0; i < (s32)self->length; i++) + { + EntityID* glyphEntityID; + ComponentTextureQuad* glyphEntityTextureQuad; + ComponentDropShadow* glyphEntityDropShadow; + ComponentTextureQuad* glyphEntityDropShadowTextureQuad; + + glyphEntityID = (EntityID*)vector_get(&self->glyphEntities, i); + + glyphEntityTextureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, *glyphEntityID); + glyphEntityDropShadow = ecs_component_get(ecs, COMPONENT_DROP_SHADOW, *glyphEntityID); + glyphEntityDropShadowTextureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, glyphEntityDropShadow->spriteID); + + glm_vec4_copy(self->color, glyphEntityTextureQuad->color); + glm_vec4_copy(self->colorCover, glyphEntityTextureQuad->colorCover); + + glyphEntityDropShadowTextureQuad->color[3] = self->color[3]; + glm_vec4_copy(self->colorCover, glyphEntityDropShadowTextureQuad->colorCover); + } +} + +void +component_text_string_set(ComponentText* self, ECS* ecs, char* string, u32 length) +{ + _component_text_glyph_entities_free(self, ecs); + + if (length > COMPONENT_TEXT_STRING_MAX) + return; + + self->length = length; + + memset(self->string, '\0', sizeof(char) * COMPONENT_TEXT_STRING_MAX); + memcpy(self->string, string, sizeof(char) * self->length); + + _component_text_glyph_entities_init(self, ecs); +} + +void +component_text_add(ComponentText* self, ECS* ecs) +{ + glm_vec4_copy(COMPONENT_TEXT_COLOR_DEFAULT, self->color); + glm_vec4_copy(COMPONENT_TEXT_COLOR_COVER_DEFAULT, self->color); + glm_vec4_copy(COMPONENT_TEXT_DROP_SHADOW_COLOR_DEFAULT, self->dropShadowColor); + glm_vec2_copy(COMPONENT_TEXT_SCALE_DEFAULT, self->scale); + + self->wrap = COMPONENT_TEXT_WRAP_DEFAULT; + + vector_init(&self->glyphEntities, sizeof(EntityID)); +} + +void +component_text_delete(ComponentText* self, ECS* ecs) +{ + _component_text_glyph_entities_free(self, ecs); + + vector_free(&self->glyphEntities); +} + +void +component_text_tick(ComponentText* self, ECS* ecs) +{ + _component_text_glyphs_position_set(self, ecs); + _component_text_glyphs_color_set(self, ecs); +} + +void +component_text_init +( + ComponentText* self, + ECS* ecs, + Font* font, + RendererBuffer buffer, + char* string, + vec3 position, + u32 length, + s32 wrap +) +{ + self->font = font; + self->wrap = wrap; + self->buffer = buffer; + + glm_vec3_copy(position, self->position); + + component_text_string_set(self, ecs, string, length); +} diff --git a/src/game/ecs/component/visual/component_text.h b/src/game/ecs/component/visual/component_text.h new file mode 100644 index 0000000..8a9eacc --- /dev/null +++ b/src/game/ecs/component/visual/component_text.h @@ -0,0 +1,79 @@ +#pragma once + +#include "../../ecs_entity.h" + +#include "../../../../engine/rectangle.h" +#include "../../../../engine/font.h" +#include "../../../render/texture_quad.h" +#include "../../../resource/resource_shader.h" + +#include "../physics/component_physics.h" + +#include "../../entity/visual/entity_glyph.h" + +#define COMPONENT_TEXT_LIMIT 1024 +#define COMPONENT_TEXT_STRING_MAX 1024 + +#define COMPONENT_TEXT_COLOR_DEFAULT (f32*)OPAQUE +#define COMPONENT_TEXT_COLOR_COVER_DEFAULT (f32*)OPAQUE +#define COMPONENT_TEXT_DROP_SHADOW_COLOR_DEFAULT (f32*)BLACK +#define COMPONENT_TEXT_Z_OFFSET_INCREMENT 0.0001f + +#define COMPONENT_TEXT_DROP_SHADOW_FONT_SIZE_MULTIPLIER 0.125f + +static const vec2 COMPONENT_TEXT_SCALE_DEFAULT = {1.0f, 1.0f}; +static const f32 COMPONENT_TEXT_WRAP_DEFAULT = -1; +static const vec3 COMPONENT_TEXT_OFFSET_DEFAULT = {0.0f, 0.0f, 0.0f}; + +typedef struct ComponentText +{ + Component component; + Shader* shader; + RendererBuffer buffer; + Font* font; + Vector glyphEntities; /* EntityID */ + char string[COMPONENT_TEXT_STRING_MAX]; + s32 wrap; + u32 length; + vec2 scale; + vec3 offset; + vec3 position; + vec4 color; + vec4 colorCover; + vec4 dropShadowColor; +} ComponentText; + +void component_text_add(ComponentText* self, ECS* ecs); +void component_text_delete(ComponentText* self, ECS* ecs); +void component_text_string_set(ComponentText* self, ECS* ecs, char* string, u32 length); +void component_text_tick(ComponentText* self, ECS* ecs); + +void +component_text_init +( + ComponentText* self, + ECS* ecs, + Font* font, + RendererBuffer buffer, + char* string, + vec3 position, + u32 length, + s32 wrap +); + +static const ComponentInfo COMPONENT_TEXT_INFO = +{ + .system = + { + .functions = + { + (ECSFunction)component_text_add, + (ECSFunction)component_text_delete, + (ECSFunction)component_text_tick, + NULL, + NULL + } + }, + .type = COMPONENT_TEXT, + .size = sizeof(ComponentText) +}; diff --git a/src/game/ecs/component/visual/component_texture_quad.c b/src/game/ecs/component/visual/component_texture_quad.c new file mode 100644 index 0000000..d8f673e --- /dev/null +++ b/src/game/ecs/component/visual/component_texture_quad.c @@ -0,0 +1,176 @@ +#include "component_texture_quad.h" + +void +component_texture_quad_size_get(ComponentTextureQuad* self, vec2 size) +{ + glm_vec2_copy(self->size, size); + glm_vec2_mul(size, self->scale, size); +} + +void +component_texture_quad_position_get(ComponentTextureQuad* self, vec3 position) +{ + vec2 size; + + glm_vec3_copy(self->position, position); + glm_vec3_add(position, self->offset, position); + + component_texture_quad_size_get(self, size); + + switch (self->origin) + { + case ORIGIN_CENTER: + position[0] -= size[0] / 2; + position[1] -= size[1] / 2; + break; + case ORIGIN_TOP_LEFT: + default: + break; + } + +} + +void +component_texture_quad_origin_point_get(ComponentTextureQuad* self, vec3 originPoint) +{ + vec2 size; + + glm_vec3_zero(originPoint); + + switch (self->origin) + { + case ORIGIN_CENTER: + component_texture_quad_size_get(self, size); + originPoint[0] = size[0] / 2; + originPoint[1] = size[1] / 2; + case ORIGIN_TOP_LEFT: + default: + break; + } +} + +void +component_texture_quad_model_get(ComponentTextureQuad* self, mat4 model) +{ + vec3 position; + vec3 originPoint; + + component_texture_quad_position_get(self, position); + component_texture_quad_origin_point_get(self, originPoint); + + glm_mat4_identity(model); + glm_translate(model, position); + glm_rotate_at(model, originPoint, self->rotation, (f32*)COMPONENT_TEXTURE_QUAD_ROTATION_AXIS); +} + +void +component_texture_quad_rectangle_get(ComponentTextureQuad* self, Rectangle* rectangle) +{ + vec2 size; + vec2 difference; + + component_texture_quad_size_get(self, size); + + rectangle->x = (self->position[0] - (size[0] / 2)) + self->offset[0]; + rectangle->y = (self->position[1] - (size[1] / 2)) + self->offset[1]; + rectangle->w = size[0]; + rectangle->h = size[1]; +} + +s32 +component_texture_quad_sort(ComponentTextureQuad* a, ComponentTextureQuad* b) +{ + return a->position[2] > b->position[2] ? -1 : 1; +} + +void +component_texture_quad_init +( + ComponentTextureQuad* self, + ECS* ecs, + Texture* texture, + Flip flip, + Origin origin, + RendererBuffer buffer, + f32 rotation, + vec2 size, + vec2 scale, + vec2 uvMin, + vec2 uvMax, + vec3 offset, + vec3 position, + vec4 color +) +{ + + self->texture = texture; + self->flip = flip; + self->origin = origin; + self->buffer = buffer; + self->rotation = rotation; + glm_vec2_copy(size, self->size); + glm_vec2_copy(scale, self->scale); + glm_vec2_copy(uvMin, self->uvMin); + glm_vec2_copy(uvMax, self->uvMax); + glm_vec3_copy(COMPONENT_TEXTURE_QUAD_OFFSET_DEFAULT, self->offset); + glm_vec4_copy(COMPONENT_TEXTURE_QUAD_COLOR_COVER, self->colorCover); + glm_vec3_copy(position, self->position); + glm_vec4_copy(color, self->color); +} + +void +component_texture_quad_add(ComponentTextureQuad* self, ECS* ecs) +{ + component_texture_quad_init + ( + self, + ecs, + &ecs->resources->textures[COMPONENT_TEXTURE_QUAD_TEXTURE_DEFAULT], + COMPONENT_TEXTURE_QUAD_FLIP_DEFAULT, + COMPONENT_TEXTURE_QUAD_ORIGIN_DEFAULT, + COMPONENT_TEXTURE_QUAD_BUFFER_DEFAULT, + COMPONENT_TEXTURE_QUAD_ROTATION_DEFAULT, + COMPONENT_TEXTURE_QUAD_SIZE_DEFAULT, + COMPONENT_TEXTURE_QUAD_SCALE_DEFAULT, + COMPONENT_TEXTURE_QUAD_UV_MIN_DEFAULT, + COMPONENT_TEXTURE_QUAD_UV_MAX_DEFAULT, + COMPONENT_TEXTURE_QUAD_OFFSET_DEFAULT, + COMPONENT_TEXTURE_QUAD_POSITION_DEFAULT, + COMPONENT_TEXTURE_QUAD_COLOR_DEFAULT + ); +} + +void +component_texture_quad_draw(ComponentTextureQuad* self, ECS* ecs) +{ + mat4 model; + mat4 view; + mat4 projection; + vec2 size; + + component_texture_quad_model_get(self, model); + component_texture_quad_size_get(self, size); + + camera_view_get(&ecs->renderer->camera[self->buffer], view); + camera_projection_get(&ecs->renderer->camera[self->buffer], projection); + + renderer_buffer_use(ecs->renderer, self->buffer); + + texture_quad_draw + ( + self->texture, + ecs->renderer, + &ecs->resources->shaders[SHADER_TEXTURE_QUAD], + self->uvMin, + self->uvMax, + model, + view, + projection, + size, + self->color, + self->colorCover, + self->flip + ); + + renderer_buffer_unbind(); +} diff --git a/src/game/ecs/component/visual/component_texture_quad.h b/src/game/ecs/component/visual/component_texture_quad.h new file mode 100644 index 0000000..d1ae812 --- /dev/null +++ b/src/game/ecs/component/visual/component_texture_quad.h @@ -0,0 +1,85 @@ +#pragma once + +#include "../../ecs_entity.h" + +#include "../../../../engine/rectangle.h" +#include "../../../render/texture_quad.h" +#include "../../../resource/resource_shader.h" + +typedef struct ComponentTextureQuad +{ + Component component; + Flip flip; + Origin origin; + RendererBuffer buffer; + Texture* texture; + f32 rotation; + vec2 scale; + vec2 size; + vec2 uvMax; + vec2 uvMin; + vec3 offset; + vec3 position; + vec4 color; + vec4 colorCover; +} ComponentTextureQuad; + +void component_texture_quad_init +( + ComponentTextureQuad* self, + ECS* ecs, + Texture* texture, + Flip flip, + Origin origin, + RendererBuffer buffer, + f32 rotation, + vec2 size, + vec2 scale, + vec2 uvMin, + vec2 uvMax, + vec3 position, + vec3 offset, + vec4 color +); + +void component_texture_quad_size_get(ComponentTextureQuad* self, vec2 size); +void component_texture_quad_position_get(ComponentTextureQuad* self, vec3 position); +void component_texture_quad_origin_point_get(ComponentTextureQuad* self, vec3 originPoint); +void component_texture_quad_model_get(ComponentTextureQuad* self, mat4 model); +void component_texture_quad_rectangle_get(ComponentTextureQuad* self, Rectangle* rectangle); +s32 component_texture_quad_sort(ComponentTextureQuad* a, ComponentTextureQuad* b); +void component_texture_quad_draw(ComponentTextureQuad* self, ECS* ecs); + +static const ComponentInfo COMPONENT_TEXTURE_QUAD_INFO = +{ + .system = + { + .functions = + { + NULL, + NULL, + NULL, + NULL, + (ECSFunction)component_texture_quad_draw + } + }, + .type = COMPONENT_TEXTURE_QUAD, + .size = sizeof(ComponentTextureQuad) +}; + +#define COMPONENT_TEXTURE_QUAD_UV_MIN_DEFAULT TEXTURE_QUAD_UV_MIN_DEFAULT +#define COMPONENT_TEXTURE_QUAD_UV_MAX_DEFAULT TEXTURE_QUAD_UV_MAX_DEFAULT +#define COMPONENT_TEXTURE_QUAD_COLOR_DEFAULT TEXTURE_QUAD_COLOR_DEFAULT +#define COMPONENT_TEXTURE_QUAD_FLIP_DEFAULT TEXTURE_QUAD_FLIP_DEFAULT +#define COMPONENT_TEXTURE_QUAD_ORIGIN_DEFAULT TEXTURE_QUAD_ORIGIN_DEFAULT + +static const RendererBuffer COMPONENT_TEXTURE_QUAD_BUFFER_DEFAULT = RENDERER_BUFFER_WORLD; +static const ShaderType COMPONENT_TEXTURE_QUAD_SHADER_DEFAULT = SHADER_TEXTURE_QUAD; +static const TextureType COMPONENT_TEXTURE_QUAD_TEXTURE_DEFAULT = TEXTURE_DEFAULT; +static const f32 COMPONENT_TEXTURE_QUAD_ROTATION_DEFAULT = 0.0f; +static const vec2 COMPONENT_TEXTURE_QUAD_SCALE_DEFAULT = {1.0f, 1.0f}; +static const vec2 COMPONENT_TEXTURE_QUAD_SIZE_DEFAULT = {32.0f, 32.0f}; +static const vec3 COMPONENT_TEXTURE_QUAD_POSITION_DEFAULT = {0.0f, 0.0f, 0.0f}; +static const vec3 COMPONENT_TEXTURE_QUAD_OFFSET_DEFAULT = {0.0f, 0.0f, 0.0f}; +static const vec3 COMPONENT_TEXTURE_QUAD_ROTATION_AXIS = {0.0f, 0.0f, 1.0f}; +static const vec4 COMPONENT_TEXTURE_QUAD_COLOR_COVER = {0.0f, 0.0f, 0.0f, 1.0f}; diff --git a/src/game/ecs/component/visual/component_value_text.c b/src/game/ecs/component/visual/component_value_text.c new file mode 100644 index 0000000..fa6d786 --- /dev/null +++ b/src/game/ecs/component/visual/component_value_text.c @@ -0,0 +1,128 @@ +#include "component_value_text.h" + +s32 _component_value_text_value_get(ComponentValueText* self, ECS* ecs); +s32 _component_value_text_max_get(ComponentValueText* self, ECS* ecs); +void _component_value_text_set(ComponentValueText* self, ECS* ecs); + +s32 +_component_value_text_value_get(ComponentValueText* self, ECS* ecs) +{ + u8* component; + s32 value; + + component = (u8*)ecs_component_get(ecs, self->type, self->id); + + // Get first value of component, after the component struct. If it segfaults, not my problem. + memcpy(&value, component + sizeof(Component), sizeof(u32)); + + return value; +} + +s32 +_component_value_text_max_get(ComponentValueText* self, ECS* ecs) +{ + u8* component; + s32 max; + + component = (u8*)ecs_component_get(ecs, self->type, self->id); + + // Get second value of component, after the component struct and the value. If it segfaults, not my problem. + memcpy(&max, component + sizeof(Component) + sizeof(u32), sizeof(u32)); + + return max; +} + +void +_component_value_text_set(ComponentValueText* self, ECS* ecs) +{ + ComponentText* text; + u32 minutes; + u32 seconds; + u32 milliseconds; + u32 max; + + char string[COMPONENT_VALUE_TEXT_STRING_MAX]; + + text = ecs_component_get(ecs, COMPONENT_TEXT, self->component.id); + + memset(string, '\0', COMPONENT_VALUE_TEXT_STRING_MAX); + + switch (self->textType) + { + case COMPONENT_VALUE_TEXT_TYPE_TIMER: + time_formatted_get(self->value, &minutes, &seconds, &milliseconds); + snprintf(string, COMPONENT_VALUE_TEXT_STRING_MAX, self->format, minutes, seconds, milliseconds); + break; + case COMPONENT_VALUE_TEXT_TYPE_INTEGER_MAX: + max = _component_value_text_max_get(self, ecs); + snprintf(string, COMPONENT_VALUE_TEXT_STRING_MAX, self->format, self->value, max); + break; + case COMPONENT_VALUE_TEXT_TYPE_INTEGER: + default: + snprintf(string, COMPONENT_VALUE_TEXT_STRING_MAX, self->format, self->value); + break; + } + + component_text_string_set(text, ecs, string, strlen(string)); +} + +void +component_value_text_add(ComponentValueText* self, ECS* ecs) +{ + ecs_components_add + ( + ecs, + COMPONENT_VALUE_TEXT_DEPENDENCIES, + COMPONENT_VALUE_TEXT_DEPENDENCY_COUNT, + self->component.id + ); +} + +void +component_value_text_tick(ComponentValueText* self, ECS* ecs) +{ + self->value = _component_value_text_value_get(self, ecs); + + if (self->value != self->previousValue) + { + _component_value_text_set(self, ecs); + self->previousValue = self->value; + } +} + + +void +component_value_text_init +( + ComponentValueText* self, + ECS* ecs, + Font* font, + RendererBuffer buffer, + const vec3 position, + ComponentType type, + ComponentValueTextType textType, + const char* format, + EntityID id +) +{ + component_text_init + ( + ecs_component_get(ecs, COMPONENT_TEXT, self->component.id), + ecs, + font, + buffer, + "1", + position, + 0, + -1 + ); + + self->format = format; + self->type = type; + self->textType = textType; + self->id = id; + self->value = _component_value_text_value_get(self, ecs); + self->previousValue = self->value; + + _component_value_text_set(self, ecs); +} diff --git a/src/game/ecs/component/visual/component_value_text.h b/src/game/ecs/component/visual/component_value_text.h new file mode 100644 index 0000000..b6824e0 --- /dev/null +++ b/src/game/ecs/component/visual/component_value_text.h @@ -0,0 +1,64 @@ +#pragma once + +#include "component_text.h" +#include "../../../../engine/time.h" + +#define COMPONENT_VALUE_TEXT_STRING_MAX 64 + +typedef enum ComponentValueTextType +{ + COMPONENT_VALUE_TEXT_TYPE_INTEGER, + COMPONENT_VALUE_TEXT_TYPE_INTEGER_MAX, + COMPONENT_VALUE_TEXT_TYPE_TIMER, +} ComponentValueTextType; + +typedef struct ComponentValueText +{ + Component component; + ComponentType type; + ComponentValueTextType textType; + EntityID id; + const char* format; + s32 previousValue; + s32 value; +} ComponentValueText; + +void component_value_text_add(ComponentValueText* self, ECS* ecs); +void component_value_text_tick(ComponentValueText* self, ECS* ecs); + +void +component_value_text_init +( + ComponentValueText* self, + ECS* ecs, + Font* font, + RendererBuffer buffer, + const vec3 position, + ComponentType type, + ComponentValueTextType textType, + const char* format, + EntityID id +); + +#define COMPONENT_VALUE_TEXT_DEPENDENCY_COUNT 1 +static const ComponentType COMPONENT_VALUE_TEXT_DEPENDENCIES[COMPONENT_VALUE_TEXT_DEPENDENCY_COUNT] = +{ + COMPONENT_TEXT +}; + +static const ComponentInfo COMPONENT_VALUE_TEXT_INFO = +{ + .system = + { + .functions = + { + (ECSFunction)component_value_text_add, + NULL, + (ECSFunction)component_value_text_tick, + NULL, + NULL + } + }, + .type = COMPONENT_VALUE_TEXT, + .size = sizeof(ComponentText) +}; diff --git a/src/game/ecs/ecs.c b/src/game/ecs/ecs.c new file mode 100644 index 0000000..1bfc5ba --- /dev/null +++ b/src/game/ecs/ecs.c @@ -0,0 +1,71 @@ +#include "ecs.h" + +static void _ecs_function(ECS* self, ECSFunctionType type); + +static void +_ecs_function(ECS* self, ECSFunctionType type) +{ + for (s32 i = 0; i < COMPONENT_COUNT; i++) + { + ComponentList* list; + + list = &self->lists[i]; + + ecs_component_list_function(list, type); + } +} + +void +ecs_tick(ECS* self) +{ + if (!self->isFunctionDisabled[ECS_FUNCTION_TICK]) + _ecs_function(self, ECS_FUNCTION_TICK); +} + +void +ecs_update(ECS* self) +{ + if (!self->isFunctionDisabled[ECS_FUNCTION_UPDATE]) + _ecs_function(self, ECS_FUNCTION_UPDATE); +} + +void +ecs_draw(ECS* self) +{ + vector_sort(&self->lists[COMPONENT_TEXTURE_QUAD].components, (SortCompareFunction)component_texture_quad_sort); + + if (!self->isFunctionDisabled[ECS_FUNCTION_DRAW]) + _ecs_function(self, ECS_FUNCTION_DRAW); +} + +void +ecs_init(ECS* self, Renderer* renderer, Control* control, Input* input, Resources* resources, Postprocessing* postprocessing) +{ + self->renderer = renderer; + self->control = control; + self->input = input; + self->resources = resources; + self->postprocessing = postprocessing; + self->isLog = true; + + for (s32 i = 0 ; i < COMPONENT_COUNT; i++) + ecs_component_list_init(&self->lists[i], self, COMPONENT_INFO[i]); +} + +void +ecs_clear(ECS* self) +{ + for (s32 i = 0 ; i < COMPONENT_COUNT; i++) + ecs_component_list_clear(&self->lists[i]); + + self->nextID = 0; +} + +void +ecs_free(ECS* self) +{ + for (s32 i = 0 ; i < COMPONENT_COUNT; i++) + ecs_component_list_free(&self->lists[i]); + + memset(self, '\0', sizeof(ECS)); +} diff --git a/src/game/ecs/ecs.h b/src/game/ecs/ecs.h new file mode 100644 index 0000000..635a13d --- /dev/null +++ b/src/game/ecs/ecs.h @@ -0,0 +1,100 @@ +#pragma once + +#include "component/animation/component_animation.h" +#include "component/animation/component_animation_player.h" +#include "component/animation/component_animation_target.h" +#include "component/game/component_collect.h" +#include "component/game/component_collectible.h" +#include "component/game/component_collide_slow.h" +#include "component/game/component_food.h" +#include "component/game/component_threshold.h" +#include "component/game/component_game_object.h" +#include "component/game/component_homing.h" +#include "component/game/component_levitate.h" +#include "component/game/component_player_control.h" +#include "component/game/component_power.h" +#include "component/game/component_solid.h" +#include "component/game/component_stamina.h" +#include "component/game/component_take_food.h" +#include "component/game/component_stage.h" +#include "component/game/component_plane_object.h" +#include "component/game/component_world_object.h" +#include "component/physics/component_circle_collider.h" +#include "component/physics/component_copy_mouse_position.h" +#include "component/physics/component_physics.h" +#include "component/ui/component_button.h" +#include "component/utility/component_counter.h" +#include "component/utility/component_timer.h" +#include "component/utility/component_delete_on_timer.h" +#include "component/visual/component_atlas.h" +#include "component/visual/component_camera_focus.h" +#include "component/visual/component_dialogue.h" +#include "component/visual/component_drop_shadow.h" +#include "component/visual/component_color_change.h" +#include "component/visual/component_color_match.h" +#include "component/visual/component_scale_value.h" +#include "component/visual/component_pulsate.h" +#include "component/visual/component_rotate.h" +#include "component/visual/component_text.h" +#include "component/visual/component_texture_quad.h" +#include "component/visual/component_value_text.h" + +#include "../input/control.h" +#include "../../engine/renderer.h" +#include "../render/postprocessing.h" +#include "../resource/resources.h" + +static const struct ComponentInfo COMPONENT_INFO[COMPONENT_COUNT] = +{ + /* Utility */ + COMPONENT_TIMER_INFO, + COMPONENT_COUNTER_INFO, + COMPONENT_DELETE_ON_TIMER_INFO, + /* Physics */ + COMPONENT_PHYSICS_INFO, + COMPONENT_COPY_MOUSE_POSITION_INFO, + COMPONENT_CIRCLE_COLLIDER_INFO, + /* Game */ + COMPONENT_GAME_OBJECT_INFO, + COMPONENT_PLANE_OBJECT_INFO, + COMPONENT_WORLD_OBJECT_INFO, + COMPONENT_SOLID_INFO, + COMPONENT_LEVITATE_INFO, + COMPONENT_COLLIDE_SLOW_INFO, + COMPONENT_COLLECTIBLE_INFO, + COMPONENT_COLLECT_INFO, + COMPONENT_HOMING_INFO, + COMPONENT_FOOD_INFO, + COMPONENT_THRESHOLD_INFO, + COMPONENT_TAKE_FOOD_INFO, + COMPONENT_STAGE_INFO, + COMPONENT_STAMINA_INFO, + COMPONENT_POWER_INFO, + COMPONENT_PLAYER_CONTROL_INFO, + /* Animation */ + COMPONENT_ANIMATION_INFO, + COMPONENT_ANIMATION_PLAYER_INFO, + COMPONENT_ANIMATION_TARGET_INFO, + /* UI */ + COMPONENT_BUTTON_INFO, + /* Visual */ + COMPONENT_DROP_SHADOW_INFO, + COMPONENT_TEXTURE_QUAD_INFO, + COMPONENT_TEXT_INFO, + COMPONENT_DIALOGUE_INFO, + COMPONENT_VALUE_TEXT_INFO, + COMPONENT_ATLAS_INFO, + COMPONENT_CAMERA_FOCUS_INFO, + COMPONENT_COLOR_CHANGE_INFO, + COMPONENT_COLOR_MATCH_INFO, + COMPONENT_SCALE_VALUE_INFO, + COMPONENT_ROTATE_INFO, + COMPONENT_PULSATE_INFO +}; + +void ecs_tick(ECS* self); +void ecs_update(ECS* self); +void ecs_draw(ECS* self); +void ecs_init(ECS* self, Renderer* renderer, Control* control, Input* input, Resources* resources, Postprocessing* postprocessing); +void ecs_clear(ECS* self); +void ecs_free(ECS* self); diff --git a/src/game/ecs/ecs_component.c b/src/game/ecs/ecs_component.c new file mode 100644 index 0000000..bd7a09b --- /dev/null +++ b/src/game/ecs/ecs_component.c @@ -0,0 +1,104 @@ +#include "ecs_component.h" + +static bool isFirstTimeComponentAdded = false; + +void* +ecs_component_get(ECS* self, ComponentType type, EntityID id) +{ + void* component; + + component = ecs_component_list_get(&self->lists[type], id); + + if + ( + (!component && !isFirstTimeComponentAdded) && + self->isLog + ) + printf("%s Type: %i, ID: %u\n", STRING_ECS_COMPONENT_ID_ERROR, type, id); + + return component; +} + +void* +ecs_component_from_index_get(ECS* self, ComponentType type, u32 index) +{ + void* component; + + component = vector_get(&self->lists[type].components, index); + + if + ( + (!component && !isFirstTimeComponentAdded) && + self->isLog + ) + printf("%s Type: %i, ID: %i\n", STRING_ECS_COMPONENT_INDEX_ERROR, type, index); + + return component; +} + +void* +ecs_component_add(ECS* self, ComponentType type, EntityID id) +{ + void* component; + ECSFunction add; + + isFirstTimeComponentAdded = true; + + component = ecs_component_get(self, type, id); + + if (component) + return component; + + isFirstTimeComponentAdded = false; + + component = vector_push(&self->lists[type].components, NULL); + + memcpy(component, (void*)&id, sizeof(EntityID)); + + add = self->lists[type].system.functions[ECS_FUNCTION_ADD]; + + if (add) + add(component, self); + + return component; +} + +void +ecs_component_delete(ECS* self, ComponentType type, EntityID id) +{ + for (s32 i = 0; i < (s32)self->lists[type].components.count; i++) + { + EntityID checkID; + void* component; + + component = vector_get(&self->lists[type].components, i); + + memcpy(&checkID, component, sizeof(EntityID)); + + if (checkID == id) + { + ECSFunction delete; + + delete = self->lists[type].system.functions[ECS_FUNCTION_DELETE]; + + if (delete) + delete(component, self); + + vector_remove(&self->lists[type].components, i); + } + } +} + +void +ecs_components_add(ECS* self, const ComponentType* types, u32 count, EntityID id) +{ + for (s32 i = 0; i < (s32)count; i++) + ecs_component_add(self, types[i], id); +} + +void +ecs_components_delete(ECS* self, const ComponentType* types, u32 count, EntityID id) +{ + for (s32 i = 0; i < (s32)count; i++) + ecs_component_delete(self, types[i], id); +} diff --git a/src/game/ecs/ecs_component.h b/src/game/ecs/ecs_component.h new file mode 100644 index 0000000..8a1da12 --- /dev/null +++ b/src/game/ecs/ecs_component.h @@ -0,0 +1,13 @@ +#pragma once + +#include "ecs_component_list.h" + +#define STRING_ECS_COMPONENT_ID_ERROR "[ERROR] ECS component get failed! Invalid entity ID! |" +#define STRING_ECS_COMPONENT_INDEX_ERROR "[ERROR] ECS component get failed! Invalid index! |" + +void ecs_component_delete(ECS* self, ComponentType type, EntityID id); +void* ecs_component_add(ECS* self, ComponentType type, EntityID id); +void* ecs_component_get(ECS* self, ComponentType type, EntityID id); +void* ecs_component_from_index_get(ECS* self, ComponentType type, u32 index); +void ecs_components_add(ECS* self, const ComponentType* types, u32 count, EntityID id); +void ecs_components_delete(ECS* self, const ComponentType* types, u32 count, EntityID id); diff --git a/src/game/ecs/ecs_component_list.c b/src/game/ecs/ecs_component_list.c new file mode 100644 index 0000000..e69cd03 --- /dev/null +++ b/src/game/ecs/ecs_component_list.c @@ -0,0 +1,73 @@ +#include "ecs_component_list.h" + +void +ecs_component_list_init(ComponentList* self, ECS* ecs, ComponentInfo info) +{ + self->ecs = ecs; + self->type = info.type; + self->system = info.system; + + vector_init(&self->components, info.size); +} + +void +ecs_component_list_function(ComponentList* self, ECSFunctionType type) +{ + ECSFunction function; + + function = self->system.functions[type]; + + if (!function) + return; + + for (s32 i = 0; i < (s32)self->components.count; i++) + { + void* component; + Component ecsComponent; + + component = vector_get(&self->components, i); + + memcpy(&ecsComponent, component, sizeof(Component)); + + if + ( + ecsComponent.isDisabled || + ecsComponent.isFunctionDisabled[type] + ) + continue; + + function(component, self->ecs); + } +} + +void* +ecs_component_list_get(ComponentList* self, EntityID id) +{ + for (s32 i = 0; i < (s32)self->components.count; i++) + { + u32 checkID; + void* component; + + component = vector_get(&self->components, i); + + memcpy(&checkID, component, sizeof(u32)); + + if (checkID == id) + return component; + } + + return NULL; +} + +void +ecs_component_list_clear(ComponentList* self) +{ + vector_clear(&self->components); +} + +void +ecs_component_list_free(ComponentList* self) +{ + vector_free(&self->components); + memset(self, '\0', sizeof(ComponentList)); +} diff --git a/src/game/ecs/ecs_component_list.h b/src/game/ecs/ecs_component_list.h new file mode 100644 index 0000000..2ffc130 --- /dev/null +++ b/src/game/ecs/ecs_component_list.h @@ -0,0 +1,9 @@ +#pragma once + +#include "ECS_COMMON.h" + +void* ecs_component_list_get(ComponentList* self, EntityID id); +void ecs_component_list_init(ComponentList* self, ECS* ecs, ComponentInfo info); +void ecs_component_list_function(ComponentList* self, ECSFunctionType type); +void ecs_component_list_clear(ComponentList* self); +void ecs_component_list_free(ComponentList* self); diff --git a/src/game/ecs/ecs_entity.c b/src/game/ecs/ecs_entity.c new file mode 100644 index 0000000..7a56c9f --- /dev/null +++ b/src/game/ecs/ecs_entity.c @@ -0,0 +1,20 @@ +#include "ecs_entity.h" + +EntityID +ecs_entity_add(ECS* self) +{ + EntityID id; + + id = self->nextID; + + self->nextID++; + + return id; +} + +void +ecs_entity_delete(ECS* self, EntityID id) +{ + for (s32 i = 0; i < COMPONENT_COUNT; i++) + ecs_component_delete(self, (ComponentType)i, id); +} diff --git a/src/game/ecs/ecs_entity.h b/src/game/ecs/ecs_entity.h new file mode 100644 index 0000000..ec462df --- /dev/null +++ b/src/game/ecs/ecs_entity.h @@ -0,0 +1,6 @@ +#pragma once + +#include "ecs_component.h" + +u32 ecs_entity_add(ECS* ecs); +void ecs_entity_delete(ECS* ecs, EntityID id); diff --git a/src/game/ecs/entity/game/entity_collectible.c b/src/game/ecs/entity/game/entity_collectible.c new file mode 100644 index 0000000..d68f0d4 --- /dev/null +++ b/src/game/ecs/entity/game/entity_collectible.c @@ -0,0 +1,46 @@ +#include "entity_collectible.h" + +EntityID +entity_collectible_add(ECS* ecs, const vec3 position, CollectibleType type) +{ + EntityID id; + ComponentPhysics* physics; + vec3 smokePosition; + + id = ecs_entity_add(ecs); + + ecs_components_add(ecs, ENTITY_COLLECTIBLE_DEPENDENCIES, ENTITY_COLLECTIBLE_DEPENDENCY_COUNT, id); + + component_collectible_init + ( + ecs_component_get(ecs, COMPONENT_COLLECTIBLE, id), + ecs, + &ecs->resources->textures[TEXTURE_COLLECTIBLE], + ENTITY_COLLECTIBLE_SIZE, + position, + type + ); + + component_atlas_init + ( + ecs_component_get(ecs, COMPONENT_ATLAS, id), + ecs, + ENTITY_COLLECTIBLE_ATLAS_FRAME_SIZE, + ENTITY_COLLECTIBLE_ATLAS_SIZE, + (u32)type + ); + + physics = ecs_component_get(ecs, COMPONENT_PHYSICS, id); + + glm_vec3_copy(physics->position, smokePosition); + + smokePosition[2] += ENTITY_COLLECTIBLE_SMOKE_Z_OFFSET; + + entity_smoke_add + ( + ecs, + smokePosition + ); + + return id; +} diff --git a/src/game/ecs/entity/game/entity_collectible.h b/src/game/ecs/entity/game/entity_collectible.h new file mode 100644 index 0000000..8b5a1fe --- /dev/null +++ b/src/game/ecs/entity/game/entity_collectible.h @@ -0,0 +1,22 @@ +#pragma once + +#include "../../component/game/component_collectible.h" +#include "../../component/visual/component_rotate.h" +#include "../../component/visual/component_atlas.h" + +#include "entity_smoke.h" + +static const vec2 ENTITY_COLLECTIBLE_SIZE = {128.0f, 128.0f}; +static const ivec2 ENTITY_COLLECTIBLE_ATLAS_FRAME_SIZE = {32, 32}; +static const ivec2 ENTITY_COLLECTIBLE_ATLAS_SIZE = {1, 6}; +static const f32 ENTITY_COLLECTIBLE_SMOKE_Z_OFFSET = 0.01f; + +#define ENTITY_COLLECTIBLE_DEPENDENCY_COUNT 3 +static const ComponentType ENTITY_COLLECTIBLE_DEPENDENCIES[ENTITY_COLLECTIBLE_DEPENDENCY_COUNT] = +{ + COMPONENT_ATLAS, + COMPONENT_COLLECTIBLE, + COMPONENT_ROTATE +}; + +EntityID entity_collectible_add(ECS* ecs, const vec3 position, CollectibleType type); diff --git a/src/game/ecs/entity/game/entity_collectible_amulet.c b/src/game/ecs/entity/game/entity_collectible_amulet.c new file mode 100644 index 0000000..143e439 --- /dev/null +++ b/src/game/ecs/entity/game/entity_collectible_amulet.c @@ -0,0 +1,7 @@ +#include "entity_collectible_amulet.h" + +EntityID +entity_collectible_amulet_add(ECS* ecs, const vec3 position) +{ + return entity_collectible_add(ecs, position, COLLECTIBLE_AMULET); +} diff --git a/src/game/ecs/entity/game/entity_collectible_amulet.h b/src/game/ecs/entity/game/entity_collectible_amulet.h new file mode 100644 index 0000000..2f44cce --- /dev/null +++ b/src/game/ecs/entity/game/entity_collectible_amulet.h @@ -0,0 +1,5 @@ +#pragma once + +#include "entity_collectible.h" + +EntityID entity_collectible_amulet_add(ECS* ecs, const vec3 position); diff --git a/src/game/ecs/entity/game/entity_collectible_food.c b/src/game/ecs/entity/game/entity_collectible_food.c new file mode 100644 index 0000000..7905be4 --- /dev/null +++ b/src/game/ecs/entity/game/entity_collectible_food.c @@ -0,0 +1,7 @@ +#include "entity_collectible_food.h" + +EntityID +entity_collectible_food_add(ECS* ecs, const vec3 position) +{ + return entity_collectible_add(ecs, position, COLLECTIBLE_FOOD); +} diff --git a/src/game/ecs/entity/game/entity_collectible_food.h b/src/game/ecs/entity/game/entity_collectible_food.h new file mode 100644 index 0000000..f3e7c40 --- /dev/null +++ b/src/game/ecs/entity/game/entity_collectible_food.h @@ -0,0 +1,5 @@ +#pragma once + +#include "entity_collectible.h" + +EntityID entity_collectible_food_add(ECS* ecs, const vec3 position); diff --git a/src/game/ecs/entity/game/entity_collectible_power.c b/src/game/ecs/entity/game/entity_collectible_power.c new file mode 100644 index 0000000..fdbb401 --- /dev/null +++ b/src/game/ecs/entity/game/entity_collectible_power.c @@ -0,0 +1,11 @@ +#include "entity_collectible_power.h" + +EntityID +entity_collectible_power_add(ECS* ecs, const vec3 position) +{ + EntityID id; + + id = entity_collectible_add(ecs, position, COLLECTIBLE_POWER); + + return id; +} diff --git a/src/game/ecs/entity/game/entity_collectible_power.h b/src/game/ecs/entity/game/entity_collectible_power.h new file mode 100644 index 0000000..761185f --- /dev/null +++ b/src/game/ecs/entity/game/entity_collectible_power.h @@ -0,0 +1,5 @@ +#pragma once + +#include "entity_collectible.h" + +EntityID entity_collectible_power_add(ECS* ecs, const vec3 position); diff --git a/src/game/ecs/entity/game/entity_collectible_rotten_food.c b/src/game/ecs/entity/game/entity_collectible_rotten_food.c new file mode 100644 index 0000000..c7cea48 --- /dev/null +++ b/src/game/ecs/entity/game/entity_collectible_rotten_food.c @@ -0,0 +1,7 @@ +#include "entity_collectible_rotten_food.h" + +EntityID +entity_collectible_rotten_food_add(ECS* ecs, const vec3 position) +{ + return entity_collectible_add(ecs, position, COLLECTIBLE_ROTTEN_FOOD); +} diff --git a/src/game/ecs/entity/game/entity_collectible_rotten_food.h b/src/game/ecs/entity/game/entity_collectible_rotten_food.h new file mode 100644 index 0000000..23bb581 --- /dev/null +++ b/src/game/ecs/entity/game/entity_collectible_rotten_food.h @@ -0,0 +1,5 @@ +#pragma once + +#include "entity_collectible.h" + +EntityID entity_collectible_rotten_food_add(ECS* ecs, const vec3 position); diff --git a/src/game/ecs/entity/game/entity_collectible_stamina.c b/src/game/ecs/entity/game/entity_collectible_stamina.c new file mode 100644 index 0000000..41c4937 --- /dev/null +++ b/src/game/ecs/entity/game/entity_collectible_stamina.c @@ -0,0 +1,11 @@ +#include "entity_collectible_stamina.h" + +EntityID +entity_collectible_stamina_add(ECS* ecs, const vec3 position) +{ + EntityID id; + + id = entity_collectible_add(ecs, position, COLLECTIBLE_STAMINA); + + return id; +} diff --git a/src/game/ecs/entity/game/entity_collectible_stamina.h b/src/game/ecs/entity/game/entity_collectible_stamina.h new file mode 100644 index 0000000..9af5c27 --- /dev/null +++ b/src/game/ecs/entity/game/entity_collectible_stamina.h @@ -0,0 +1,5 @@ +#pragma once + +#include "entity_collectible.h" + +EntityID entity_collectible_stamina_add(ECS* ecs, const vec3 position); diff --git a/src/game/ecs/entity/game/entity_player.c b/src/game/ecs/entity/game/entity_player.c new file mode 100644 index 0000000..22b0eb7 --- /dev/null +++ b/src/game/ecs/entity/game/entity_player.c @@ -0,0 +1,83 @@ +#include "entity_player.h" + +EntityID +entity_player_add(ECS* ecs, const vec3 position) +{ + EntityID id; + ComponentWorldObject* worldObject; + ComponentColorChange* colorChange; + + id = ecs_entity_add(ecs); + + ecs_components_add(ecs, ENTITY_PLAYER_DEPENDENCIES, ENTITY_PLAYER_DEPENDENCY_COUNT, id); + + worldObject = ecs_component_get(ecs, COMPONENT_WORLD_OBJECT, id), + + component_world_object_init + ( + worldObject, + ecs, + &ecs->resources->textures[TEXTURE_PLAYER], + PLAYER_SIZE, + position, + PLAYER_HEIGHT_OFFSET, + PLAYER_RADIUS + ); + + worldObject->angle = PLAYER_ANGLE; + + component_atlas_init + ( + ecs_component_get(ecs, COMPONENT_ATLAS, id), + ecs, + PLAYER_ATLAS_FRAME_SIZE, + PLAYER_ATLAS_SIZE, + PLAYER_ATLAS_INDEX + ); + + component_camera_focus_init + ( + ecs_component_get(ecs, COMPONENT_CAMERA_FOCUS, id), + ecs, + &ecs->renderer->camera[RENDERER_BUFFER_WORLD], + id + ); + + component_stamina_init + ( + ecs_component_get(ecs, COMPONENT_STAMINA, id), + ecs, + PLAYER_STAMINA_MAX, + PLAYER_STAMINA_GAIN + ); + + component_power_init + ( + ecs_component_get(ecs, COMPONENT_POWER, id), + ecs, + PLAYER_POWER_MAX, + PLAYER_POWER_GAIN + ); + + component_collect_init + ( + ecs_component_get(ecs, COMPONENT_COLLECT, id), + ecs, + PLAYER_COLLECT_RADIUS + ); + + component_food_init + ( + ecs_component_get(ecs, COMPONENT_FOOD, id), + ecs, + 0, + PLAYER_FOOD_MAX, + PLAYER_FOOD_MULTIPLIER + ); + + colorChange = ecs_component_get(ecs, COMPONENT_COLOR_CHANGE, id); + + colorChange->component.isDisabled = true; + + return id; +} diff --git a/src/game/ecs/entity/game/entity_player.h b/src/game/ecs/entity/game/entity_player.h new file mode 100644 index 0000000..2854166 --- /dev/null +++ b/src/game/ecs/entity/game/entity_player.h @@ -0,0 +1,48 @@ +#pragma once + +#include "../../component/animation/component_animation.h" +#include "../../component/animation/component_animation_player.h" +#include "../../component/game/component_player_control.h" +#include "../../component/visual/component_atlas.h" +#include "../../component/visual/component_color_change.h" +#include "../../component/game/component_food.h" +#include "../../component/game/component_power.h" +#include "../../component/game/component_collect.h" +#include "../../component/game/component_stamina.h" +#include "../../component/game/component_world_object.h" +#include "../../component/visual/component_camera_focus.h" + +static const TextureType PLAYER_TEXTURE = TEXTURE_PLAYER; +static const vec2 PLAYER_SIZE = {384.0f, 256.0f}; +static const f32 PLAYER_HEIGHT_OFFSET = 0.0f; +static const f32 PLAYER_RADIUS = 128.0f; +static const f32 PLAYER_STAMINA_MAX = 100.0f; +static const f32 PLAYER_STAMINA_GAIN = 0.1f; +static const f32 PLAYER_POWER_MAX = 100.0f; +static const f32 PLAYER_POWER_GAIN = 0.01f; +static const f32 PLAYER_COLLECT_RADIUS = 300.0f; + +static const ivec2 PLAYER_ATLAS_FRAME_SIZE = {96, 64}; +static const ivec2 PLAYER_ATLAS_SIZE = {4, 5}; +static const s32 PLAYER_ATLAS_INDEX = 0; +static const f32 PLAYER_ANGLE = PI_HALF; +static const s32 PLAYER_FOOD_MAX = 25; +static const s32 PLAYER_FOOD_MULTIPLIER = 1; + +#define ENTITY_PLAYER_DEPENDENCY_COUNT 11 +static const ComponentType ENTITY_PLAYER_DEPENDENCIES[ENTITY_PLAYER_DEPENDENCY_COUNT] = +{ + COMPONENT_WORLD_OBJECT, + COMPONENT_ATLAS, + COMPONENT_CAMERA_FOCUS, + COMPONENT_COLLECT, + COMPONENT_FOOD, + COMPONENT_POWER, + COMPONENT_STAMINA, + COMPONENT_PLAYER_CONTROL, + COMPONENT_ANIMATION, + COMPONENT_ANIMATION_PLAYER, + COMPONENT_COLOR_CHANGE +}; + +EntityID entity_player_add(ECS* ecs, const vec3 position); diff --git a/src/game/ecs/entity/game/entity_smoke.c b/src/game/ecs/entity/game/entity_smoke.c new file mode 100644 index 0000000..605990c --- /dev/null +++ b/src/game/ecs/entity/game/entity_smoke.c @@ -0,0 +1,39 @@ +#include "entity_smoke.h" + +EntityID +entity_smoke_add(ECS* ecs, vec3 position) +{ + EntityID id; + f32 angle; + + id = entity_sprite_atlas_add + ( + ecs, + &ecs->resources->textures[TEXTURE_SMOKE], + RENDERER_BUFFER_WORLD, + ORIGIN_CENTER, + ENTITY_SMOKE_SIZE, + position, + ENTITY_SMOKE_ATLAS_FRAME_SIZE, + ENTITY_SMOKE_ATLAS_SIZE, + 0 + ); + + ecs_components_add(ecs, ENTITY_SMOKE_DEPENDENCIES, ENTITY_SMOKE_DEPENDENCY_COUNT, id); + + component_animation_init + ( + ecs_component_get(ecs, COMPONENT_ANIMATION, id), + ecs, + &ENTITY_SMOKE_ANIMATION + ); + + component_delete_on_timer_init + ( + ecs_component_get(ecs, COMPONENT_DELETE_ON_TIMER, id), + ecs, + ENTITY_SMOKE_TIMER + ); + + return id; +} diff --git a/src/game/ecs/entity/game/entity_smoke.h b/src/game/ecs/entity/game/entity_smoke.h new file mode 100644 index 0000000..83096c2 --- /dev/null +++ b/src/game/ecs/entity/game/entity_smoke.h @@ -0,0 +1,32 @@ +#pragma once + +#include "../visual/entity_sprite_atlas.h" + +#include "../../component/utility/component_delete_on_timer.h" +#include "../../component/animation/component_animation.h" + +#define ENTITY_SMOKE_ANIMATION_COUNT 8 +static const u32 ENTITY_SMOKE_ANIMATION_FRAME_INDICES[ENTITY_SMOKE_ANIMATION_COUNT] = {0, 1, 2, 3, 4, 5, 6, 7}; +static const struct Animation ENTITY_SMOKE_ANIMATION = +{ + .frameIndices = (u32*)ENTITY_SMOKE_ANIMATION_FRAME_INDICES, + .count = ENTITY_SMOKE_ANIMATION_COUNT, + .length = 5, + .isLoop = false +}; + +static const vec2 ENTITY_SMOKE_SIZE = {256.0f, 256.0f}; +static const ivec2 ENTITY_SMOKE_ATLAS_FRAME_SIZE = {128, 128}; +static const ivec2 ENTITY_SMOKE_ATLAS_SIZE = {1, 8}; +static const s32 ENTITY_SMOKE_TIMER = 45; + +static const f32 ENTITY_SMOKE_VELOCITY = 100.0f; + +#define ENTITY_SMOKE_DEPENDENCY_COUNT 2 +static const ComponentType ENTITY_SMOKE_DEPENDENCIES[ENTITY_SMOKE_DEPENDENCY_COUNT] = +{ + COMPONENT_DELETE_ON_TIMER, + COMPONENT_ANIMATION, +}; + +EntityID entity_smoke_add(ECS* ecs, vec3 position); diff --git a/src/game/ecs/entity/game/entity_smoke_big.c b/src/game/ecs/entity/game/entity_smoke_big.c new file mode 100644 index 0000000..e99328c --- /dev/null +++ b/src/game/ecs/entity/game/entity_smoke_big.c @@ -0,0 +1,39 @@ +#include "entity_smoke_big.h" + +EntityID +entity_smoke_big_add(ECS* ecs, vec3 position) +{ + EntityID id; + f32 angle; + + id = entity_sprite_atlas_add + ( + ecs, + &ecs->resources->textures[TEXTURE_SMOKE], + RENDERER_BUFFER_WORLD, + ORIGIN_CENTER, + ENTITY_SMOKE_BIG_SIZE, + position, + ENTITY_SMOKE_ATLAS_FRAME_SIZE, + ENTITY_SMOKE_ATLAS_SIZE, + 0 + ); + + ecs_components_add(ecs, ENTITY_SMOKE_DEPENDENCIES, ENTITY_SMOKE_DEPENDENCY_COUNT, id); + + component_animation_init + ( + ecs_component_get(ecs, COMPONENT_ANIMATION, id), + ecs, + &ENTITY_SMOKE_ANIMATION + ); + + component_delete_on_timer_init + ( + ecs_component_get(ecs, COMPONENT_DELETE_ON_TIMER, id), + ecs, + ENTITY_SMOKE_TIMER + ); + + return id; +} diff --git a/src/game/ecs/entity/game/entity_smoke_big.h b/src/game/ecs/entity/game/entity_smoke_big.h new file mode 100644 index 0000000..2d3074a --- /dev/null +++ b/src/game/ecs/entity/game/entity_smoke_big.h @@ -0,0 +1,7 @@ +#pragma once + +#include "entity_smoke.h" + +static const vec2 ENTITY_SMOKE_BIG_SIZE = {512.0f, 512.0f}; + +EntityID entity_smoke_big_add(ECS* ecs, vec3 position); diff --git a/src/game/ecs/entity/game/entity_target.c b/src/game/ecs/entity/game/entity_target.c new file mode 100644 index 0000000..5c43784 --- /dev/null +++ b/src/game/ecs/entity/game/entity_target.c @@ -0,0 +1,64 @@ +#include "entity_target.h" + +EntityID +entity_target_add(ECS* ecs, const vec3 position, u32 threshold, u32 stage, EntityID playerID) +{ + EntityID id; + + id = ecs_entity_add(ecs); + + ecs_components_add(ecs, ENTITY_TARGET_DEPENDENCIES, ENTITY_TARGET_DEPENDENCY_COUNT, id); + + component_world_object_init + ( + ecs_component_get(ecs, COMPONENT_WORLD_OBJECT, id), + ecs, + &ecs->resources->textures[TEXTURE_TARGET], + TARGET_SIZE, + position, + TARGET_HEIGHT_OFFSET, + TARGET_RADIUS + ); + + component_atlas_init + ( + ecs_component_get(ecs, COMPONENT_ATLAS, id), + ecs, + TARGET_ATLAS_FRAME_SIZE, + TARGET_ATLAS_SIZE, + 0 + ); + + component_threshold_init + ( + ecs_component_get(ecs, COMPONENT_THRESHOLD, id), + ecs, + threshold + ); + + component_stage_init + ( + ecs_component_get(ecs, COMPONENT_STAGE, id), + ecs, + stage + ); + + component_animation_target_init + ( + ecs_component_get(ecs, COMPONENT_ANIMATION_TARGET, id), + ecs, + ANIMATION_TARGET_IDLE_STAGE_ONE, + playerID + ); + + component_food_init + ( + ecs_component_get(ecs, COMPONENT_FOOD, id), + ecs, + 0, + TARGET_FOOD_MAX, + TARGET_FOOD_MULTIPLIER + ); + + return id; +} diff --git a/src/game/ecs/entity/game/entity_target.h b/src/game/ecs/entity/game/entity_target.h new file mode 100644 index 0000000..02930a6 --- /dev/null +++ b/src/game/ecs/entity/game/entity_target.h @@ -0,0 +1,35 @@ +#pragma once + +#include "../../component/game/component_food.h" +#include "../../component/game/component_solid.h" +#include "../../component/game/component_take_food.h" +#include "../../component/game/component_threshold.h" +#include "../../component/game/component_world_object.h" +#include "../../component/visual/component_atlas.h" +#include "../../component/animation/component_animation_target.h" + +static const TextureType TARGET_TEXTURE = TEXTURE_TARGET; +static const vec2 TARGET_SIZE = {1024.0f, 1024.0f}; +static const f32 TARGET_HEIGHT_OFFSET = 0.0f; +static const f32 TARGET_RADIUS = 192.0f; +static const s32 TARGET_FOOD_MAX = 9999; +static const s32 TARGET_FOOD_MULTIPLIER = 1; + +static const ivec2 TARGET_ATLAS_FRAME_SIZE = {256, 256}; +static const ivec2 TARGET_ATLAS_SIZE = {5, 5}; + +#define ENTITY_TARGET_DEPENDENCY_COUNT 9 +static const ComponentType ENTITY_TARGET_DEPENDENCIES[ENTITY_TARGET_DEPENDENCY_COUNT] = +{ + COMPONENT_WORLD_OBJECT, + COMPONENT_FOOD, + COMPONENT_THRESHOLD, + COMPONENT_TAKE_FOOD, + COMPONENT_STAGE, + COMPONENT_SOLID, + COMPONENT_ATLAS, + COMPONENT_ANIMATION, + COMPONENT_ANIMATION_TARGET +}; + +EntityID entity_target_add(ECS* ecs, const vec3 position, u32 threshold, u32 stage, EntityID playerID); diff --git a/src/game/ecs/entity/game/entity_trap.c b/src/game/ecs/entity/game/entity_trap.c new file mode 100644 index 0000000..6c30657 --- /dev/null +++ b/src/game/ecs/entity/game/entity_trap.c @@ -0,0 +1,23 @@ +#include "entity_trap.h" + +EntityID +entity_trap_add(ECS* ecs, const vec3 position) +{ + EntityID id; + + id = ecs_entity_add(ecs); + + ecs_components_add(ecs, ENTITY_TRAP_DEPENDENCIES, ENTITY_TRAP_DEPENDENCY_COUNT, id); + + component_plane_object_init + ( + ecs_component_get(ecs, COMPONENT_PLANE_OBJECT, id), + ecs, + &ecs->resources->textures[TEXTURE_TRAP], + ENTITY_TRAP_SIZE, + position, + ENTITY_TRAP_RADIUS + ); + + return id; +} diff --git a/src/game/ecs/entity/game/entity_trap.h b/src/game/ecs/entity/game/entity_trap.h new file mode 100644 index 0000000..59cb482 --- /dev/null +++ b/src/game/ecs/entity/game/entity_trap.h @@ -0,0 +1,16 @@ +#pragma once + +#include "../../component/game/component_plane_object.h" +#include "../../component/game/component_collide_slow.h" + +static vec2 ENTITY_TRAP_SIZE = {256.0f, 256.0f}; +static f32 ENTITY_TRAP_RADIUS = 128.0f; + +#define ENTITY_TRAP_DEPENDENCY_COUNT 2 +static const ComponentType ENTITY_TRAP_DEPENDENCIES[ENTITY_TRAP_DEPENDENCY_COUNT] = +{ + COMPONENT_PLANE_OBJECT, + COMPONENT_COLLIDE_SLOW +}; + +EntityID entity_trap_add(ECS* ecs, const vec3 position); diff --git a/src/game/ecs/entity/ui/entity_button.c b/src/game/ecs/entity/ui/entity_button.c new file mode 100644 index 0000000..eb062e2 --- /dev/null +++ b/src/game/ecs/entity/ui/entity_button.c @@ -0,0 +1,24 @@ +#include "entity_button.h" + +EntityID +entity_button_add(ECS* ecs, Texture* texture, vec2 size, vec3 position) +{ + EntityID id; + + id = ecs_entity_add(ecs); + + ecs_components_add(ecs, ENTITY_BUTTON_DEPENDENCIES, ENTITY_BUTTON_DEPENDENCY_COUNT, id); + + component_game_object_init + ( + ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, id), + ecs, + texture, + ENTITY_BUTTON_BUFFER, + ORIGIN_CENTER, + size, + position + ); + + return id; +} diff --git a/src/game/ecs/entity/ui/entity_button.h b/src/game/ecs/entity/ui/entity_button.h new file mode 100644 index 0000000..156b894 --- /dev/null +++ b/src/game/ecs/entity/ui/entity_button.h @@ -0,0 +1,22 @@ +#pragma once + +#include "../../component/game/component_game_object.h" +#include "../../component/ui/component_button.h" + +EntityID entity_button_add +( + ECS* ecs, + Texture* texture, + vec2 size, + vec3 position +); + +#define ENTITY_BUTTON_DEPENDENCY_COUNT 2 +static const ComponentType ENTITY_BUTTON_DEPENDENCIES[ENTITY_BUTTON_DEPENDENCY_COUNT] = +{ + COMPONENT_GAME_OBJECT, + COMPONENT_BUTTON +}; + +static const RendererBuffer ENTITY_BUTTON_BUFFER = RENDERER_BUFFER_UI; + diff --git a/src/game/ecs/entity/ui/entity_cursor.c b/src/game/ecs/entity/ui/entity_cursor.c new file mode 100644 index 0000000..0c15b1d --- /dev/null +++ b/src/game/ecs/entity/ui/entity_cursor.c @@ -0,0 +1,33 @@ +#include "entity_cursor.h" + +EntityID +entity_cursor_add(ECS* ecs) +{ + EntityID id; + + id = ecs_entity_add(ecs); + + ecs_components_add(ecs, ENTITY_CURSOR_DEPENDENCIES, ENTITY_CURSOR_DEPENDENCY_COUNT, id); + + component_game_object_init + ( + ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, id), + ecs, + &ecs->resources->textures[TEXTURE_CURSOR], + ENTITY_CURSOR_BUFFER, + ORIGIN_TOP_LEFT, + (f32*)ENTITY_CURSOR_SIZE, + (f32*)ENTITY_CURSOR_POSITION + ); + + component_pulsate_init + ( + ecs_component_get(ecs, COMPONENT_PULSATE, id), + ecs, + (f32*)ENTITY_CURSOR_PULSATE_MIN_SCALE, + (f32*)ENTITY_CURSOR_PULSATE_MAX_SCALE, + ENTITY_CURSOR_PULSATE_FREQUENCY + ); + + return id; +} diff --git a/src/game/ecs/entity/ui/entity_cursor.h b/src/game/ecs/entity/ui/entity_cursor.h new file mode 100644 index 0000000..620e4c5 --- /dev/null +++ b/src/game/ecs/entity/ui/entity_cursor.h @@ -0,0 +1,23 @@ +#pragma once + +#include "../../component/physics/component_copy_mouse_position.h" +#include "../../component/visual/component_pulsate.h" +#include "../../component/game/component_game_object.h" + +EntityID entity_cursor_add(ECS* ecs); + +#define ENTITY_CURSOR_DEPENDENCY_COUNT 3 +static const ComponentType ENTITY_CURSOR_DEPENDENCIES[ENTITY_CURSOR_DEPENDENCY_COUNT] = +{ + COMPONENT_GAME_OBJECT, + COMPONENT_COPY_MOUSE_POSITION, + COMPONENT_PULSATE, +}; + +static const RendererBuffer ENTITY_CURSOR_BUFFER = RENDERER_BUFFER_CURSOR; +static const vec2 ENTITY_CURSOR_SIZE = {32.0f, 32.0f}; +static const vec3 ENTITY_CURSOR_POSITION = {0.0f, 0.0f, 0.0f}; +static const vec2 ENTITY_CURSOR_PULSATE_MAX_SCALE = {1.1f, 1.1f}; +static const vec2 ENTITY_CURSOR_PULSATE_MIN_SCALE = {0.90f, 0.90f}; +static const f32 ENTITY_CURSOR_PULSATE_FREQUENCY = 5.0f; + diff --git a/src/game/ecs/entity/ui/entity_level_select_button.c b/src/game/ecs/entity/ui/entity_level_select_button.c new file mode 100644 index 0000000..d475fca --- /dev/null +++ b/src/game/ecs/entity/ui/entity_level_select_button.c @@ -0,0 +1,48 @@ +#include "entity_level_select_button.h" + +EntityID +entity_level_select_button_add(ECS* ecs, vec3 position, LevelStatusType status, u32 index) +{ + EntityID id; + + id = entity_button_add + ( + ecs, + &ecs->resources->textures[TEXTURE_LEVEL_SELECT_BUTTONS], + ENTITY_LEVEL_SELECT_BUTTON_SIZE, + position + ); + + ecs_components_add(ecs, ENTITY_LEVEL_SELECT_BUTTON_DEPENDENCIES, ENTITY_LEVEL_SELECT_BUTTON_DEPENDENCY_COUNT, id); + + component_atlas_init + ( + ecs_component_get(ecs, COMPONENT_ATLAS, id), + ecs, + ENTITY_LEVEL_SELECT_BUTTON_ATLAS_FRAME_SIZE, + ENTITY_LEVEL_SELECT_BUTTON_ATLAS_SIZE, + index + ); + + if (status == LEVEL_STATUS_LOCKED) + { + ComponentTextureQuad* textureQuad; + ComponentButton* button; + + textureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, id); + button = ecs_component_get(ecs, COMPONENT_BUTTON, id); + + glm_vec4_copy(ENTITY_LEVEL_SELECT_BUTTON_LOCKED_COLOR, textureQuad->color); + + button->component.isFunctionDisabled[ECS_FUNCTION_TICK] = true; + } + + entity_level_select_button_icon_add + ( + ecs, + status, + id + ); + + return id; +} diff --git a/src/game/ecs/entity/ui/entity_level_select_button.h b/src/game/ecs/entity/ui/entity_level_select_button.h new file mode 100644 index 0000000..20a8a7c --- /dev/null +++ b/src/game/ecs/entity/ui/entity_level_select_button.h @@ -0,0 +1,24 @@ +#pragma once + +#include "entity_button.h" +#include "entity_level_select_button_icon.h" + +#define ENTITY_LEVEL_SELECT_BUTTON_DEPENDENCY_COUNT 1 +static const ComponentType ENTITY_LEVEL_SELECT_BUTTON_DEPENDENCIES[ENTITY_LEVEL_SELECT_BUTTON_DEPENDENCY_COUNT] = +{ + COMPONENT_ATLAS +}; + +static const vec2 ENTITY_LEVEL_SELECT_BUTTON_SIZE = {128.0f, 128.0f}; + +static const ivec2 ENTITY_LEVEL_SELECT_BUTTON_ATLAS_FRAME_SIZE = {128, 128}; +static const ivec2 ENTITY_LEVEL_SELECT_BUTTON_ATLAS_SIZE = {1, 5}; +static const vec4 ENTITY_LEVEL_SELECT_BUTTON_LOCKED_COLOR = {0.5f, 0.5f, 0.5f, 1.0f}; + +EntityID entity_level_select_button_add +( + ECS* ecs, + vec3 position, + LevelStatusType status, + u32 index +); diff --git a/src/game/ecs/entity/ui/entity_level_select_button_icon.c b/src/game/ecs/entity/ui/entity_level_select_button_icon.c new file mode 100644 index 0000000..8dd8a1f --- /dev/null +++ b/src/game/ecs/entity/ui/entity_level_select_button_icon.c @@ -0,0 +1,45 @@ +#include "entity_level_select_button_icon.h" + +EntityID +entity_level_select_button_icon_add(ECS* ecs, LevelStatusType status, EntityID levelSelectButtonID) +{ + EntityID id; + ComponentTextureQuad* levelSelectButtonTextureQuad; + vec3 position; + + levelSelectButtonTextureQuad = ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, levelSelectButtonID); + + glm_vec3_copy(levelSelectButtonTextureQuad->position, position); + + glm_vec3_add(position, ENTITY_LEVEL_SELECT_BUTTON_ICON_OFFSET, position); + + id = entity_sprite_add + ( + ecs, + &ecs->resources->textures[TEXTURE_LEVEL_SELECT_ICONS], + RENDERER_BUFFER_UI, + ORIGIN_CENTER, + ENTITY_LEVEL_SELECT_BUTTON_ICON_SIZE, + position + ); + + ecs_components_add(ecs, ENTITY_LEVEL_SELECT_BUTTON_ICON_DEPENDENCIES, ENTITY_LEVEL_SELECT_BUTTON_ICON_DEPENDENCY_COUNT, id); + + component_atlas_init + ( + ecs_component_get(ecs, COMPONENT_ATLAS, id), + ecs, + ENTITY_LEVEL_SELECT_BUTTON_ICON_ATLAS_FRAME_SIZE, + ENTITY_LEVEL_SELECT_BUTTON_ICON_ATLAS_SIZE, + status + ); + + component_color_match_init + ( + ecs_component_get(ecs, COMPONENT_COLOR_MATCH, id), + ecs, + levelSelectButtonID + ); + + return id; +} diff --git a/src/game/ecs/entity/ui/entity_level_select_button_icon.h b/src/game/ecs/entity/ui/entity_level_select_button_icon.h new file mode 100644 index 0000000..ce76d77 --- /dev/null +++ b/src/game/ecs/entity/ui/entity_level_select_button_icon.h @@ -0,0 +1,33 @@ +#pragma once + +#include "../visual/entity_sprite.h" +#include "../../component/visual/component_atlas.h" +#include "../../component/visual/component_color_match.h" + +typedef enum LevelStatusType +{ + LEVEL_STATUS_UNLOCKED, + LEVEL_STATUS_LOCKED, + LEVEL_STATUS_BRONZE, + LEVEL_STATUS_SILVER, + LEVEL_STATUS_GOLD +} LevelStatusType; + +#define ENTITY_LEVEL_SELECT_BUTTON_ICON_DEPENDENCY_COUNT 2 +static const ComponentType ENTITY_LEVEL_SELECT_BUTTON_ICON_DEPENDENCIES[ENTITY_LEVEL_SELECT_BUTTON_ICON_DEPENDENCY_COUNT] = +{ + COMPONENT_ATLAS, + COMPONENT_COLOR_MATCH +}; + +static const vec2 ENTITY_LEVEL_SELECT_BUTTON_ICON_SIZE = {64.0f, 64.0f}; +static const vec3 ENTITY_LEVEL_SELECT_BUTTON_ICON_OFFSET = {48.0f, 48.0f, -0.01f}; +static const ivec2 ENTITY_LEVEL_SELECT_BUTTON_ICON_ATLAS_FRAME_SIZE = {32, 32}; +static const ivec2 ENTITY_LEVEL_SELECT_BUTTON_ICON_ATLAS_SIZE = {1, 5}; + +EntityID entity_level_select_button_icon_add +( + ECS* ecs, + LevelStatusType status, + EntityID levelSelectButtonID +); diff --git a/src/game/ecs/entity/ui/entity_logo.c b/src/game/ecs/entity/ui/entity_logo.c new file mode 100644 index 0000000..73cb73d --- /dev/null +++ b/src/game/ecs/entity/ui/entity_logo.c @@ -0,0 +1,30 @@ +#include "entity_logo.h" + +EntityID +entity_logo_add(ECS* ecs, vec3 position) +{ + EntityID id; + + id = entity_sprite_add + ( + ecs, + &ecs->resources->textures[TEXTURE_LOGO], + RENDERER_BUFFER_UI, + ORIGIN_CENTER, + ENTITY_LOGO_SIZE, + position + ); + + ecs_components_add(ecs, ENTITY_LOGO_DEPENDENCIES, ENTITY_LOGO_DEPENDENCY_COUNT, id); + + component_pulsate_init + ( + ecs_component_get(ecs, COMPONENT_PULSATE, id), + ecs, + ENTITY_LOGO_PULSATE_MIN_SCALE, + ENTITY_LOGO_PULSATE_MAX_SCALE, + ENTITY_LOGO_PULSATE_FREQUENCY + ); + + return id; +} diff --git a/src/game/ecs/entity/ui/entity_logo.h b/src/game/ecs/entity/ui/entity_logo.h new file mode 100644 index 0000000..eea07c1 --- /dev/null +++ b/src/game/ecs/entity/ui/entity_logo.h @@ -0,0 +1,18 @@ +#pragma once + +#include "../visual/entity_sprite.h" +#include "../../component/visual/component_pulsate.h" + +static const vec2 ENTITY_LOGO_SIZE = {500.0f, 250.0f}; +static const vec2 ENTITY_LOGO_PULSATE_MIN_SCALE = {0.95f, 0.95f}; +static const vec2 ENTITY_LOGO_PULSATE_MAX_SCALE = {1.05f, 1.05f}; +static const f32 ENTITY_LOGO_PULSATE_FREQUENCY = 20.0f; + +#define ENTITY_LOGO_DEPENDENCY_COUNT 1 +static const ComponentType ENTITY_LOGO_DEPENDENCIES[ENTITY_LOGO_DEPENDENCY_COUNT] = +{ + COMPONENT_PULSATE +}; + +EntityID entity_logo_add(ECS* ecs, vec3 position); + diff --git a/src/game/ecs/entity/ui/entity_medal.c b/src/game/ecs/entity/ui/entity_medal.c new file mode 100644 index 0000000..beda9e2 --- /dev/null +++ b/src/game/ecs/entity/ui/entity_medal.c @@ -0,0 +1,22 @@ +#include "entity_medal.h" + +EntityID +entity_medal_add(ECS* ecs, vec3 position, u32 index) +{ + EntityID id; + + id = entity_sprite_atlas_add + ( + ecs, + &ecs->resources->textures[TEXTURE_MEDALS], + RENDERER_BUFFER_UI, + ORIGIN_CENTER, + ENTITY_MEDAL_SIZE, + position, + ENTITY_MEDAL_ATLAS_FRAME_SIZE, + ENTITY_MEDAL_ATLAS_SIZE, + index + ); + + return id; +} diff --git a/src/game/ecs/entity/ui/entity_medal.h b/src/game/ecs/entity/ui/entity_medal.h new file mode 100644 index 0000000..ef33b60 --- /dev/null +++ b/src/game/ecs/entity/ui/entity_medal.h @@ -0,0 +1,10 @@ +#pragma once + +#include "../visual/entity_sprite_atlas.h" + +static const vec2 ENTITY_MEDAL_SIZE = {32.0f, 32.0f}; +static const ivec2 ENTITY_MEDAL_ATLAS_FRAME_SIZE = {32, 32}; +static const ivec2 ENTITY_MEDAL_ATLAS_SIZE = {1, 3}; + +EntityID entity_medal_add(ECS* ecs, vec3 position, u32 index); + diff --git a/src/game/ecs/entity/ui/entity_meter.c b/src/game/ecs/entity/ui/entity_meter.c new file mode 100644 index 0000000..b90d0a4 --- /dev/null +++ b/src/game/ecs/entity/ui/entity_meter.c @@ -0,0 +1,45 @@ +#include "entity_meter.h" + +EntityID +entity_meter_add(ECS* ecs, Texture* fillTexture, const vec3 position, ComponentType componentType, EntityID valueID) +{ + EntityID id; + vec3 fillPosition; + + glm_vec3_copy(position, fillPosition); + glm_vec3_add(fillPosition, ENTITY_METER_FILL_OFFSET, fillPosition); + + id = entity_sprite_add + ( + ecs, + fillTexture, + RENDERER_BUFFER_UI, + ORIGIN_TOP_LEFT, + ENTITY_METER_FILL_MIN_SIZE, + fillPosition + ); + + ecs_components_add(ecs, ENTITY_METER_DEPENDENCIES, ENTITY_METER_DEPENDENCY_COUNT, id); + + component_scale_value_init + ( + ecs_component_get(ecs, COMPONENT_SCALE_VALUE, id), + ecs, + ENTITY_METER_FILL_MIN_SIZE, + ENTITY_METER_FILL_MAX_SIZE, + componentType, + valueID + ); + + entity_sprite_add + ( + ecs, + &ecs->resources->textures[TEXTURE_METER], + RENDERER_BUFFER_UI, + ORIGIN_TOP_LEFT, + ENTITY_METER_SIZE, + position + ); + + return id; +} diff --git a/src/game/ecs/entity/ui/entity_meter.h b/src/game/ecs/entity/ui/entity_meter.h new file mode 100644 index 0000000..96381a8 --- /dev/null +++ b/src/game/ecs/entity/ui/entity_meter.h @@ -0,0 +1,17 @@ +#pragma once + +#include "../visual/entity_sprite.h" +#include "../../component/visual/component_scale_value.h" + +static const vec3 ENTITY_METER_FILL_OFFSET = {2.0f, 2.0f, 0.001f}; +static const vec2 ENTITY_METER_FILL_MIN_SIZE = {0.0f, 32.0f}; +static const vec2 ENTITY_METER_FILL_MAX_SIZE = {200.0f, 32.0f}; +static const vec2 ENTITY_METER_SIZE = {206.0f, 38.0f}; + +#define ENTITY_METER_DEPENDENCY_COUNT 1 +static const ComponentType ENTITY_METER_DEPENDENCIES[ENTITY_METER_DEPENDENCY_COUNT] = +{ + COMPONENT_SCALE_VALUE +}; + +EntityID entity_meter_add(ECS* ecs, Texture* fillTexture, const vec3 position, ComponentType componentType, EntityID valueID); diff --git a/src/game/ecs/entity/utility/entity_counter.c b/src/game/ecs/entity/utility/entity_counter.c new file mode 100644 index 0000000..392c70b --- /dev/null +++ b/src/game/ecs/entity/utility/entity_counter.c @@ -0,0 +1,13 @@ +#include "entity_counter.h" + +EntityID +entity_counter_add(ECS* ecs) +{ + EntityID id; + + id = ecs_entity_add(ecs); + + ecs_components_add(ecs, ENTITY_COUNTER_DEPENDENCIES, ENTITY_COUNTER_DEPENDENCY_COUNT, id); + + return id; +} diff --git a/src/game/ecs/entity/utility/entity_counter.h b/src/game/ecs/entity/utility/entity_counter.h new file mode 100644 index 0000000..572b423 --- /dev/null +++ b/src/game/ecs/entity/utility/entity_counter.h @@ -0,0 +1,11 @@ +#pragma once + +#include "../../component/utility/component_counter.h" + +#define ENTITY_COUNTER_DEPENDENCY_COUNT 1 +static const ComponentType ENTITY_COUNTER_DEPENDENCIES[ENTITY_COUNTER_DEPENDENCY_COUNT] = +{ + COMPONENT_COUNTER +}; + +EntityID entity_counter_add(ECS* ecs); diff --git a/src/game/ecs/entity/utility/entity_timer.c b/src/game/ecs/entity/utility/entity_timer.c new file mode 100644 index 0000000..19b2d13 --- /dev/null +++ b/src/game/ecs/entity/utility/entity_timer.c @@ -0,0 +1,15 @@ +#include "entity_timer.h" + +EntityID +entity_timer_add(ECS* ecs, u32 value) +{ + EntityID id; + + id = ecs_entity_add(ecs); + + ecs_components_add(ecs, ENTITY_TIMER_DEPENDENCIES, ENTITY_TIMER_DEPENDENCY_COUNT, id); + + component_timer_init(ecs_component_get(ecs, COMPONENT_TIMER, id), ecs, value); + + return id; +} diff --git a/src/game/ecs/entity/utility/entity_timer.h b/src/game/ecs/entity/utility/entity_timer.h new file mode 100644 index 0000000..c6b7f14 --- /dev/null +++ b/src/game/ecs/entity/utility/entity_timer.h @@ -0,0 +1,11 @@ +#pragma once + +#include "../../component/utility/component_timer.h" + +#define ENTITY_TIMER_DEPENDENCY_COUNT 1 +static const ComponentType ENTITY_TIMER_DEPENDENCIES[ENTITY_TIMER_DEPENDENCY_COUNT] = +{ + COMPONENT_TIMER +}; + +EntityID entity_timer_add(ECS* ecs, u32 value); diff --git a/src/game/ecs/entity/visual/entity_dialogue.c b/src/game/ecs/entity/visual/entity_dialogue.c new file mode 100644 index 0000000..7d26f13 --- /dev/null +++ b/src/game/ecs/entity/visual/entity_dialogue.c @@ -0,0 +1,42 @@ +#include "entity_dialogue.h" + +EntityID +entity_dialogue_add +( + ECS* ecs, + Font* font, + RendererBuffer buffer, + const char* string, + const vec3 position, + u32 wrap, + u32 speed +) +{ + EntityID id; + + id = ecs_entity_add(ecs); + + ecs_components_add(ecs, ENTITY_DIALOGUE_DEPENDENCIES, ENTITY_DIALOGUE_DEPENDENCY_COUNT, id); + + component_text_init + ( + ecs_component_get(ecs, COMPONENT_TEXT, id), + ecs, + font, + buffer, + string, + position, + strlen(string), + wrap + ); + + component_dialogue_init + ( + ecs_component_get(ecs, COMPONENT_DIALOGUE, id), + ecs, + string, + speed + ); + + return id; +} diff --git a/src/game/ecs/entity/visual/entity_dialogue.h b/src/game/ecs/entity/visual/entity_dialogue.h new file mode 100644 index 0000000..97b0391 --- /dev/null +++ b/src/game/ecs/entity/visual/entity_dialogue.h @@ -0,0 +1,23 @@ +#pragma once + +#include "../../component/visual/component_text.h" +#include "../../component/visual/component_dialogue.h" + +#define ENTITY_DIALOGUE_DEPENDENCY_COUNT 2 +static const ComponentType ENTITY_DIALOGUE_DEPENDENCIES[ENTITY_DIALOGUE_DEPENDENCY_COUNT] = +{ + COMPONENT_TEXT, + COMPONENT_DIALOGUE +}; + +EntityID +entity_dialogue_add +( + ECS* ecs, + Font* font, + RendererBuffer buffer, + const char* string, + const vec3 position, + u32 wrap, + u32 speed +); diff --git a/src/game/ecs/entity/visual/entity_glyph.c b/src/game/ecs/entity/visual/entity_glyph.c new file mode 100644 index 0000000..b4f6cf4 --- /dev/null +++ b/src/game/ecs/entity/visual/entity_glyph.c @@ -0,0 +1,49 @@ +#include "entity_glyph.h" + +EntityID +entity_glyph_add +( + ECS* ecs, + Texture* texture, + RendererBuffer buffer, + const vec2 size, + const vec3 position, + const vec4 color, + const vec4 dropShadowColor, + const vec2 dropShadowOffset +) +{ + EntityID id; + + id = ecs_entity_add(ecs); + + ecs_components_add(ecs, ENTITY_GLYPH_DEPENDENCIES, ENTITY_GLYPH_DEPENDENCY_COUNT, id); + + component_texture_quad_init + ( + ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, id), + ecs, + texture, + COMPONENT_TEXTURE_QUAD_FLIP_DEFAULT, + COMPONENT_TEXTURE_QUAD_ORIGIN_DEFAULT, + buffer, + COMPONENT_TEXTURE_QUAD_ROTATION_DEFAULT, + (f32*)size, + (f32*)COMPONENT_TEXTURE_QUAD_SCALE_DEFAULT, + (f32*)COMPONENT_TEXTURE_QUAD_UV_MIN_DEFAULT, + (f32*)COMPONENT_TEXTURE_QUAD_UV_MAX_DEFAULT, + (f32*)COMPONENT_TEXTURE_QUAD_OFFSET_DEFAULT, + (f32*)position, + (f32*)color + ); + + component_drop_shadow_init + ( + ecs_component_get(ecs, COMPONENT_DROP_SHADOW, id), + ecs, + (f32*)dropShadowColor, + (f32*)dropShadowOffset + ); + + return id; +} diff --git a/src/game/ecs/entity/visual/entity_glyph.h b/src/game/ecs/entity/visual/entity_glyph.h new file mode 100644 index 0000000..728798e --- /dev/null +++ b/src/game/ecs/entity/visual/entity_glyph.h @@ -0,0 +1,24 @@ +#pragma once + +#include "../../component/visual/component_texture_quad.h" +#include "../../component/visual/component_drop_shadow.h" + +#define ENTITY_GLYPH_DEPENDENCY_COUNT 2 +static const ComponentType ENTITY_GLYPH_DEPENDENCIES[ENTITY_GLYPH_DEPENDENCY_COUNT] = +{ + COMPONENT_TEXTURE_QUAD, + COMPONENT_DROP_SHADOW +}; + +EntityID +entity_glyph_add +( + ECS* ecs, + Texture* texture, + RendererBuffer buffer, + const vec2 size, + const vec3 position, + const vec4 color, + const vec4 dropShadowColor, + const vec2 dropShadowOffset +); diff --git a/src/game/ecs/entity/visual/entity_sprite.c b/src/game/ecs/entity/visual/entity_sprite.c new file mode 100644 index 0000000..a0adfcc --- /dev/null +++ b/src/game/ecs/entity/visual/entity_sprite.c @@ -0,0 +1,31 @@ +#include "entity_sprite.h" + +EntityID +entity_sprite_add(ECS* ecs, Texture* texture, RendererBuffer buffer, Origin origin, vec2 size, vec3 position) +{ + EntityID id; + + id = ecs_entity_add(ecs); + + ecs_components_add(ecs, ENTITY_SPRITE_DEPENDENCIES, ENTITY_SPRITE_DEPENDENCY_COUNT, id); + + component_texture_quad_init + ( + ecs_component_get(ecs, COMPONENT_TEXTURE_QUAD, id), + ecs, + texture, + COMPONENT_TEXTURE_QUAD_FLIP_DEFAULT, + origin, + buffer, + COMPONENT_TEXTURE_QUAD_ROTATION_DEFAULT, + (f32*)size, + (f32*)COMPONENT_TEXTURE_QUAD_SCALE_DEFAULT, + (f32*)COMPONENT_TEXTURE_QUAD_UV_MIN_DEFAULT, + (f32*)COMPONENT_TEXTURE_QUAD_UV_MAX_DEFAULT, + (f32*)COMPONENT_TEXTURE_QUAD_OFFSET_DEFAULT, + (f32*)position, + (f32*)OPAQUE + ); + + return id; +} diff --git a/src/game/ecs/entity/visual/entity_sprite.h b/src/game/ecs/entity/visual/entity_sprite.h new file mode 100644 index 0000000..14cd7ae --- /dev/null +++ b/src/game/ecs/entity/visual/entity_sprite.h @@ -0,0 +1,11 @@ +#pragma once + +#include "../../component/visual/component_texture_quad.h" + +#define ENTITY_SPRITE_DEPENDENCY_COUNT 1 +static const ComponentType ENTITY_SPRITE_DEPENDENCIES[ENTITY_SPRITE_DEPENDENCY_COUNT] = +{ + COMPONENT_TEXTURE_QUAD +}; + +EntityID entity_sprite_add(ECS* ecs, Texture* texture, RendererBuffer buffer, Origin origin, vec2 size, vec3 position); diff --git a/src/game/ecs/entity/visual/entity_sprite_atlas.c b/src/game/ecs/entity/visual/entity_sprite_atlas.c new file mode 100644 index 0000000..b36d21f --- /dev/null +++ b/src/game/ecs/entity/visual/entity_sprite_atlas.c @@ -0,0 +1,41 @@ +#include "entity_sprite_atlas.h" + +EntityID +entity_sprite_atlas_add +( + ECS* ecs, + Texture* texture, + RendererBuffer buffer, + Origin origin, + vec2 size, + vec3 position, + ivec2 frameSize, + ivec2 atlasSize, + u32 index +) +{ + EntityID id; + + id = entity_sprite_add + ( + ecs, + texture, + buffer, + origin, + size, + position + ); + + ecs_components_add(ecs, ENTITY_SPRITE_ATLAS_DEPENDENCIES, ENTITY_SPRITE_ATLAS_DEPENDENCY_COUNT, id); + + component_atlas_init + ( + ecs_component_get(ecs, COMPONENT_ATLAS, id), + ecs, + frameSize, + atlasSize, + index + ); + + return id; +} diff --git a/src/game/ecs/entity/visual/entity_sprite_atlas.h b/src/game/ecs/entity/visual/entity_sprite_atlas.h new file mode 100644 index 0000000..f48b35b --- /dev/null +++ b/src/game/ecs/entity/visual/entity_sprite_atlas.h @@ -0,0 +1,24 @@ +#pragma once + +#include "entity_sprite.h" +#include "../../component/visual/component_atlas.h" + +#define ENTITY_SPRITE_ATLAS_DEPENDENCY_COUNT 1 +static const ComponentType ENTITY_SPRITE_ATLAS_DEPENDENCIES[ENTITY_SPRITE_ATLAS_DEPENDENCY_COUNT] = +{ + COMPONENT_ATLAS +}; + +EntityID +entity_sprite_atlas_add +( + ECS* ecs, + Texture* texture, + RendererBuffer buffer, + Origin origin, + vec2 size, + vec3 position, + ivec2 frameSize, + ivec2 atlasSize, + u32 index +); diff --git a/src/game/ecs/entity/visual/entity_text.c b/src/game/ecs/entity/visual/entity_text.c new file mode 100644 index 0000000..781ac68 --- /dev/null +++ b/src/game/ecs/entity/visual/entity_text.c @@ -0,0 +1,33 @@ +#include "entity_text.h" + +EntityID +entity_text_add +( + ECS* ecs, + Font* font, + RendererBuffer buffer, + const char* string, + const vec3 position, + u32 wrap +) +{ + EntityID id; + + id = ecs_entity_add(ecs); + + ecs_components_add(ecs, ENTITY_TEXT_DEPENDENCIES, ENTITY_TEXT_DEPENDENCY_COUNT, id); + + component_text_init + ( + ecs_component_get(ecs, COMPONENT_TEXT, id), + ecs, + font, + buffer, + string, + position, + strlen(string), + wrap + ); + + return id; +} diff --git a/src/game/ecs/entity/visual/entity_text.h b/src/game/ecs/entity/visual/entity_text.h new file mode 100644 index 0000000..69457ec --- /dev/null +++ b/src/game/ecs/entity/visual/entity_text.h @@ -0,0 +1,24 @@ +#pragma once + +#include "../../component/visual/component_text.h" + +#define ENTITY_TEXT_SCALE_DEFAULT COMPONENT_TEXT_SCALE_DEFAULT +#define ENTITY_TEXT_OFFSET_DEFAULT COMPONENT_TEXT_OFFSET_DEFAULT + +#define ENTITY_TEXT_DEPENDENCY_COUNT 1 +static const ComponentType ENTITY_TEXT_DEPENDENCIES[ENTITY_TEXT_DEPENDENCY_COUNT] = +{ + COMPONENT_TEXT +}; + + +EntityID +entity_text_add +( + ECS* ecs, + Font* font, + RendererBuffer buffer, + const char* string, + const vec3 position, + u32 wrap +); diff --git a/src/game/ecs/entity/visual/entity_text_disappearing.c b/src/game/ecs/entity/visual/entity_text_disappearing.c new file mode 100644 index 0000000..25d09b2 --- /dev/null +++ b/src/game/ecs/entity/visual/entity_text_disappearing.c @@ -0,0 +1,48 @@ +#include "entity_text_disappearing.h" + +EntityID +entity_text_disappearing_add +( + ECS* ecs, + Font* font, + RendererBuffer buffer, + const char* string, + const vec3 position, + u32 wrap, + u32 timer +) +{ + EntityID id; + + id = entity_text_add + ( + ecs, + font, + buffer, + string, + position, + wrap + ); + + ecs_components_add(ecs, ENTITY_TEXT_DISAPPEARING_DEPENDENCIES, ENTITY_TEXT_DISAPPEARING_DEPENDENCY_COUNT, id); + + component_delete_on_timer_init + ( + ecs_component_get(ecs, COMPONENT_DELETE_ON_TIMER, id), + ecs, + timer + ); + + component_color_change_init + ( + ecs_component_get(ecs, COMPONENT_COLOR_CHANGE, id), + ecs, + OPAQUE, + TRANSPARENT, + timer, + false, + false + ); + + return id; +} diff --git a/src/game/ecs/entity/visual/entity_text_disappearing.h b/src/game/ecs/entity/visual/entity_text_disappearing.h new file mode 100644 index 0000000..e8d45c1 --- /dev/null +++ b/src/game/ecs/entity/visual/entity_text_disappearing.h @@ -0,0 +1,24 @@ +#pragma once + +#include "../../component/visual/component_color_change.h" +#include "../../component/utility/component_delete_on_timer.h" +#include "entity_text.h" + +EntityID +entity_text_disappearing_add +( + ECS* ecs, + Font* font, + RendererBuffer buffer, + const char* string, + const vec3 position, + u32 wrap, + u32 timer +); + +#define ENTITY_TEXT_DISAPPEARING_DEPENDENCY_COUNT 2 +static const ComponentType ENTITY_TEXT_DISAPPEARING_DEPENDENCIES[ENTITY_TEXT_DISAPPEARING_DEPENDENCY_COUNT] = +{ + COMPONENT_DELETE_ON_TIMER, + COMPONENT_COLOR_CHANGE +}; diff --git a/src/game/ecs/entity/visual/entity_value_text.c b/src/game/ecs/entity/visual/entity_value_text.c new file mode 100644 index 0000000..7b35bda --- /dev/null +++ b/src/game/ecs/entity/visual/entity_value_text.c @@ -0,0 +1,36 @@ +#include "entity_value_text.h" + +EntityID +entity_value_text_add +( + ECS* ecs, + Font* font, + RendererBuffer buffer, + const vec3 position, + ComponentType componentType, + ComponentValueTextType valueTextType, + const char* format, + EntityID valueTextID +) +{ + EntityID id; + + id = ecs_entity_add(ecs); + + ecs_components_add(ecs, ENTITY_VALUE_TEXT_DEPENDENCIES, ENTITY_VALUE_TEXT_DEPENDENCY_COUNT, id); + + component_value_text_init + ( + ecs_component_get(ecs, COMPONENT_VALUE_TEXT, id), + ecs, + font, + buffer, + position, + componentType, + valueTextType, + format, + valueTextID + ); + + return id; +} diff --git a/src/game/ecs/entity/visual/entity_value_text.h b/src/game/ecs/entity/visual/entity_value_text.h new file mode 100644 index 0000000..80ac8d4 --- /dev/null +++ b/src/game/ecs/entity/visual/entity_value_text.h @@ -0,0 +1,25 @@ +#pragma once + +#include "../../component/visual/component_value_text.h" + +EntityID +entity_value_text_add +( + ECS* ecs, + Font* font, + RendererBuffer buffer, + const vec3 position, + ComponentType componentType, + ComponentValueTextType valueTextType, + const char* format, + EntityID valueTextID +); + +static const vec4 ENTITY_VALUE_TEXT_COLOR = {1.0f, 1.0f, 1.0f, 1.0f}; +#define ENTITY_VALUE_TEXT_FONT FONT_DEFAULT + +#define ENTITY_VALUE_TEXT_DEPENDENCY_COUNT 1 +static const ComponentType ENTITY_VALUE_TEXT_DEPENDENCIES[ENTITY_VALUE_TEXT_DEPENDENCY_COUNT] = +{ + COMPONENT_VALUE_TEXT +}; diff --git a/src/game/game.c b/src/game/game.c new file mode 100644 index 0000000..836d626 --- /dev/null +++ b/src/game/game.c @@ -0,0 +1,125 @@ +#include "game.h" + +Game game; + +static void _game_tick(Game* self); +static void _game_update(Game* self); +static void _game_draw(Game* self); +static void _game_quit(Game* self); + +static void +_game_quit(Game* self) +{ + state_free(&self->state); + + ecs_free(&self->ecs); + + window_free(&self->window); + + resources_free(&self->resources); + + sdl_quit(); + + memset(self, '\0', sizeof(Game)); + + printf("%s\n", STRING_GAME_EXIT); + + exit(EXIT_SUCCESS); +} + +static void +_game_tick(Game* self) +{ + input_tick(&self->input); + + control_tick(&self->control, &self->input); + + state_tick(&self->state); + + ecs_tick(&self->ecs); + + if (event_press(&self->input.event, EVENT_QUIT)) + _game_quit(self); +} + +static void +_game_update(Game* self) +{ + renderer_update(&self->renderer); + ecs_update(&self->ecs); +} + +static void +_game_draw(Game* self) +{ + renderer_clear_color_set(&self->renderer, (f32*)RENDERER_CLEAR_COLOR); + + renderer_clear(&self->renderer); + + for (s32 i = 0; i < RENDERER_BUFFER_COUNT; i++) + renderer_buffer_init(&self->renderer, (RendererBuffer)i); + + ecs_draw(&self->ecs); + + for (s32 i = 0; i < RENDERER_BUFFER_COUNT; i++) + { + buffer_draw + ( + &self->renderer, + &self->resources.shaders[SHADER_TEXTURE_QUAD], + (RendererBuffer)i, + &self->postprocessing[i] + ); + renderer_buffer_free(&self->renderer, (RendererBuffer)i); + } + + renderer_present(&self->renderer); +} +void +game_init(Game* self) +{ + printf("%s\n", STRING_GAME_INIT); + + memset(self, '\0', sizeof(Game)); + + RANDOM_SEED_SET(time(NULL)); + + resource_shader_read(&self->resources); + + sdl_init(); + + window_init(&self->window, STRING_WINDOW_TITLE, (s32*)WINDOW_SIZE, WINDOW_FLAGS); + + renderer_init(&self->renderer, &self->window, CAMERA_ORTHOGRAPHIC, BUFFER_SIZES); + + renderer_clear_color_set(&self->renderer, (f32*)RENDERER_CLEAR_COLOR); + + for (s32 i = 0; i < RENDERER_BUFFER_COUNT; i++) + postprocessing_init(&self->postprocessing[i], OPAQUE, TRANSPARENT); + + if (!resources_init(&self->resources)) + { + printf("%s\n", STRING_RESOURCE_ERROR); + _game_quit(self); + } + + ecs_init(&self->ecs, &self->renderer, &self->control, &self->input, &self->resources, self->postprocessing); + + state_init(&self->state, &self->ecs, GAME_STATE_START); +} + +void +game_loop(Game* self) +{ + tick_update(&self->tick); + + while (self->tick.cumulative > TICK_DELAY) + { + _game_tick(self); + + self->tick.cumulative -= TICK_DELAY; + } + + _game_update(self); + _game_draw(self); +} diff --git a/src/game/game.h b/src/game/game.h new file mode 100644 index 0000000..44a350f --- /dev/null +++ b/src/game/game.h @@ -0,0 +1,28 @@ +#pragma once + +#include "GAME_COMMON.h" + +#define WINDOW_FLAGS SDL_WINDOW_OPENGL +#define TICK_DELAY 15 + +#define STRING_GAME_INIT "[INFO] Initializing game" +#define STRING_GAME_EXIT "[INFO] Game exited" +#define STRING_WINDOW_TITLE "Game Engine" +#define GAME_STATE_START STATE_TITLE + +static const ivec2 BUFFER_SIZES[RENDERER_BUFFER_COUNT] = +{ + {1280, 720}, + {6400, 3600}, + {1280, 720}, + {1280, 720}, + {1280, 720} +}; + +static const ivec2 WINDOW_SIZE = {1280, 720}; +static const vec4 RENDERER_CLEAR_COLOR = {0.0f, 0.0f, 0.0f, 1.0f}; + +void game_init(Game* game); +void game_loop(Game* game); + +extern Game game; diff --git a/src/game/input/control.c b/src/game/input/control.c new file mode 100644 index 0000000..1820f38 --- /dev/null +++ b/src/game/input/control.c @@ -0,0 +1,78 @@ +#include "control.h" + +void +control_tick(Control* self, Input* input) +{ + memcpy(&self->previous, &self->current, sizeof(bool) * CONTROL_COUNT); + memset(&self->current, '\0', sizeof(bool) * CONTROL_COUNT); + + if (input->keyboard.current[KEYBOARD_KEY_UP] || input->keyboard.current[KEYBOARD_KEY_W]) + self->current[CONTROL_UP] = true; + + if (input->keyboard.current[KEYBOARD_KEY_LEFT] || input->keyboard.current[KEYBOARD_KEY_A]) + self->current[CONTROL_LEFT] = true; + + if (input->keyboard.current[KEYBOARD_KEY_RIGHT] || input->keyboard.current[KEYBOARD_KEY_D]) + self->current[CONTROL_RIGHT] = true; + + if (input->keyboard.current[KEYBOARD_KEY_DOWN] || input->keyboard.current[KEYBOARD_KEY_S]) + self->current[CONTROL_DOWN] = true; + + if (input->mouse.current[MOUSE_BUTTON_LEFT]) + self->current[CONTROL_ACTION_PRIMARY] = true; + + if (input->mouse.current[MOUSE_BUTTON_RIGHT]) + self->current[CONTROL_ACTION_SECONDARY] = true; + + if (input->keyboard.current[KEYBOARD_KEY_SPACE] || input->mouse.current[MOUSE_BUTTON_MIDDLE]) + self->current[CONTROL_ACTION_TERTIARY] = true; + + if (input->keyboard.current[KEYBOARD_KEY_1]) + self->current[CONTROL_INVIGORATE] = true; + + if (input->keyboard.current[KEYBOARD_KEY_2]) + self->current[CONTROL_EXTEND] = true; + + if (input->keyboard.current[KEYBOARD_KEY_3]) + self->current[CONTROL_FORESIGHT] = true; + + if (input->keyboard.current[KEYBOARD_KEY_4]) + self->current[CONTROL_CANCEL] = true; + + if (input->keyboard.current[KEYBOARD_KEY_5]) + self->current[CONTROL_MAGNET] = true; + + if (input->keyboard.current[KEYBOARD_KEY_P]) + self->current[CONTROL_PAUSE] = true; + + if (input->keyboard.current[KEYBOARD_KEY_R]) + self->current[CONTROL_RETRY] = true; + + if (input->keyboard.current[KEYBOARD_KEY_ESCAPE]) + self->current[CONTROL_ESCAPE] = true; +} + +bool +control_held(Control* self, ControlType type) +{ + return self->current[type] && self->previous[type]; +} + +bool +control_pressed(Control* self, ControlType type) +{ + return self->current[type] && !self->previous[type]; +} + +bool +control_released(Control* self, ControlType type) +{ + return !self->current[type] && self->previous[type]; +} + +void +control_clear(Control* self) +{ + memset(&self->previous, '\0', sizeof(bool) * CONTROL_COUNT); + memset(&self->current, '\0', sizeof(bool) * CONTROL_COUNT); +} diff --git a/src/game/input/control.h b/src/game/input/control.h new file mode 100644 index 0000000..33913bd --- /dev/null +++ b/src/game/input/control.h @@ -0,0 +1,36 @@ +#pragma once + +#include "input.h" + +#define CONTROL_COUNT CONTROL_ESCAPE + 1 +typedef enum ControlType +{ + CONTROL_NONE, + CONTROL_UP, + CONTROL_DOWN, + CONTROL_LEFT, + CONTROL_RIGHT, + CONTROL_ACTION_PRIMARY, + CONTROL_ACTION_SECONDARY, + CONTROL_ACTION_TERTIARY, + CONTROL_INVIGORATE, + CONTROL_EXTEND, + CONTROL_FORESIGHT, + CONTROL_CANCEL, + CONTROL_MAGNET, + CONTROL_PAUSE, + CONTROL_RETRY, + CONTROL_ESCAPE +} ControlType; + +typedef struct Control +{ + bool current[CONTROL_COUNT]; + bool previous[CONTROL_COUNT]; +} Control; + +void control_tick(Control* control, Input* input); +bool control_pressed(Control* control, ControlType type); +bool control_held(Control* control, ControlType type); +bool control_released(Control* control, ControlType type); +void control_clear(Control* control); diff --git a/src/game/input/input.c b/src/game/input/input.c new file mode 100644 index 0000000..5b7737d --- /dev/null +++ b/src/game/input/input.c @@ -0,0 +1,9 @@ +#include "input.h" + +void +input_tick(Input* self) +{ + keyboard_update(&self->keyboard); + mouse_update(&self->mouse); + event_update(&self->event); +} diff --git a/src/game/input/input.h b/src/game/input/input.h new file mode 100644 index 0000000..c4a3476 --- /dev/null +++ b/src/game/input/input.h @@ -0,0 +1,14 @@ +#pragma once + +#include "../../engine/event.h" +#include "../../engine/keyboard.h" +#include "../../engine/mouse.h" + +typedef struct Input +{ + Keyboard keyboard; + Mouse mouse; + Event event; +} Input; + +void input_tick(Input* self); diff --git a/src/game/render/RENDER_COMMON.h b/src/game/render/RENDER_COMMON.h new file mode 100644 index 0000000..b489044 --- /dev/null +++ b/src/game/render/RENDER_COMMON.h @@ -0,0 +1,31 @@ +#pragma once + +#include "../../engine/renderer.h" +#include "../../engine/texture.h" + +typedef enum Flip +{ + FLIP_NONE, + FLIP_HORIZONTAL, + FLIP_VERTICAL, + FLIP_HORIZONTAL_VERTICAL +} Flip; + +typedef enum Origin +{ + ORIGIN_CENTER, + ORIGIN_TOP_LEFT, + ORIGIN_TOP, + ORIGIN_TOP_RIGHT, + ORIGIN_RIGHT, + ORIGIN_BOTTOM_RIGHT, + ORIGIN_BOTTOM, + ORIGIN_BOTTOM_LEFT, + ORIGIN_LEFT, +} Origin; + +typedef struct Postprocessing +{ + vec4 color; + vec4 colorCover; +} Postprocessing; diff --git a/src/game/render/buffer.c b/src/game/render/buffer.c new file mode 100644 index 0000000..b5ce529 --- /dev/null +++ b/src/game/render/buffer.c @@ -0,0 +1,44 @@ +#include "buffer.h" + +void +buffer_draw(Renderer* renderer, Shader* shader, RendererBuffer buffer, Postprocessing* postprocessing) +{ + mat4 model; + mat4 projection; + mat4 view; + vec2 size; + vec3 position; + Texture* texture; + + glm_vec2_zero(size); + glm_vec3_zero(position); + glm_mat4_identity(model); + + size[0] = renderer->bufferSizes[buffer][0]; + size[1] = renderer->bufferSizes[buffer][1]; + + position[2] *= BUFFER_Z_INCREMENT; + + glm_translate(model, position); + + camera_projection_get(&renderer->camera[buffer], projection); + camera_view_get(&renderer->camera[buffer], view); + + glDisable(GL_DEPTH_TEST); + + texture_quad_draw + ( + &renderer->fboTextures[buffer], + renderer, + shader, + (f32*)TEXTURE_QUAD_UV_MIN_DEFAULT, + (f32*)TEXTURE_QUAD_UV_MAX_DEFAULT, + model, + view, + projection, + size, + postprocessing->color, + postprocessing->colorCover, + FLIP_HORIZONTAL_VERTICAL + ); +} diff --git a/src/game/render/buffer.h b/src/game/render/buffer.h new file mode 100644 index 0000000..553423f --- /dev/null +++ b/src/game/render/buffer.h @@ -0,0 +1,8 @@ +#pragma once + +#include "postprocessing.h" +#include "texture_quad.h" + +#define BUFFER_Z_INCREMENT 0.0f + +void buffer_draw(Renderer* renderer, Shader* shader, RendererBuffer buffer, Postprocessing* postprocessing); diff --git a/src/game/render/postprocessing.c b/src/game/render/postprocessing.c new file mode 100644 index 0000000..b6d3c19 --- /dev/null +++ b/src/game/render/postprocessing.c @@ -0,0 +1,8 @@ +#include "postprocessing.h" + +void +postprocessing_init(Postprocessing* postprocessing, vec4 color, vec4 colorCover) +{ + glm_vec4_copy(color, postprocessing->color); + glm_vec4_copy(colorCover, postprocessing->colorCover); +} diff --git a/src/game/render/postprocessing.h b/src/game/render/postprocessing.h new file mode 100644 index 0000000..6f0a4fe --- /dev/null +++ b/src/game/render/postprocessing.h @@ -0,0 +1,5 @@ +#pragma once + +#include "RENDER_COMMON.h" + +void postprocessing_init(Postprocessing* postprocessing, vec4 color, vec4 colorCover); diff --git a/src/game/render/texture_quad.c b/src/game/render/texture_quad.c new file mode 100644 index 0000000..bee053d --- /dev/null +++ b/src/game/render/texture_quad.c @@ -0,0 +1,97 @@ +#include "texture_quad.h" + +void +texture_quad_draw +( + Texture* texture, + Renderer* renderer, + Shader* shader, + vec2 uvMin, + vec2 uvMax, + mat4 model, + mat4 view, + mat4 projection, + vec2 size, + vec4 color, + vec4 colorCover, + Flip flip +) +{ + f32 vertices[4][5]; + + u32 indices[2][3] = {{1, 2, 3}, {0, 1, 3}}; + f32 verticiesFlipNone[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]} + }; + + f32 verticiesFlipHorizontal[4][5] = + { + {size[0], 0.0f, 0.0f, uvMin[0], uvMin[1]}, + {size[0], size[1], 0.0f, uvMin[0], uvMax[1]}, + {0.0f, size[1], 0.0f, uvMax[0], uvMax[1]}, + {0.0f, 0.0f, 0.0f, uvMax[0], uvMin[1]} + }; + + f32 verticiesFlipVertical[4][5] = + { + {size[0], size[1], 0.0f, uvMin[0], uvMin[1]}, + {size[0], 0.0f, 0.0f, uvMin[0], uvMax[1]}, + {0.0f, 0.0f, 0.0f, uvMax[0], uvMax[1]}, + {0.0f, size[1], 0.0f, uvMax[0], uvMin[1]} + }; + + f32 verticiesFlipHorizontalVertical[4][5] = + { + {0.0f, size[1], 0.0f, uvMin[0], uvMin[1]}, + {0.0f, 0.0f, 0.0f, uvMin[0], uvMax[1]}, + {size[0], 0.0f, 0.0f, uvMax[0], uvMax[1]}, + {size[0], size[1], 0.0f, uvMax[0], uvMin[1]} + }; + + switch (flip) + { + case FLIP_HORIZONTAL: + memcpy(vertices, verticiesFlipHorizontal, sizeof(vertices)); + break; + case FLIP_VERTICAL: + memcpy(vertices, verticiesFlipVertical, sizeof(vertices)); + break; + case FLIP_HORIZONTAL_VERTICAL: + memcpy(vertices, verticiesFlipHorizontalVertical, sizeof(vertices)); + break; + case FLIP_NONE: + default: + memcpy(vertices, verticiesFlipNone, sizeof(vertices)); + break; + } + + vao_bind(&renderer->vao); + + vbo_bind(&renderer->vbo); + vbo_buffer(&renderer->vbo, sizeof(vertices), vertices); + + vbo_bind(&renderer->ebo); + vbo_buffer(&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)); + + renderer_shader_use(renderer, shader); + + shader_uniform_mat4_set(shader, TEXTURE_QUAD_UNIFORM_PROJECTION, projection); + shader_uniform_mat4_set(shader, TEXTURE_QUAD_UNIFORM_VIEW, view); + shader_uniform_mat4_set(shader, TEXTURE_QUAD_UNIFORM_MODEL, model); + shader_uniform_vec2_set(shader, TEXTURE_QUAD_UNIFORM_SIZE, size); + shader_uniform_vec4_set(shader, TEXTURE_QUAD_UNIFORM_COLOR, color); + shader_uniform_vec4_set(shader, TEXTURE_QUAD_UNIFORM_COLOR_COVER, colorCover); + shader_uniform_texture_set(shader, TEXTURE_QUAD_UNIFORM_TEXTURE, texture, 0); + + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + + vao_unbind(); + +} diff --git a/src/game/render/texture_quad.h b/src/game/render/texture_quad.h new file mode 100644 index 0000000..8a67670 --- /dev/null +++ b/src/game/render/texture_quad.h @@ -0,0 +1,35 @@ +#pragma once + +#include "RENDER_COMMON.h" + +#define TEXTURE_QUAD_UNIFORM_COLOR "u_color" +#define TEXTURE_QUAD_UNIFORM_COLOR_COVER "u_colorCover" +#define TEXTURE_QUAD_UNIFORM_TRANSFORM "u_transform" +#define TEXTURE_QUAD_UNIFORM_MODEL "u_model" +#define TEXTURE_QUAD_UNIFORM_VIEW "u_view" +#define TEXTURE_QUAD_UNIFORM_PROJECTION "u_projection" +#define TEXTURE_QUAD_UNIFORM_SIZE "u_size" +#define TEXTURE_QUAD_UNIFORM_TEXTURE "u_texture" + +void texture_quad_draw +( + Texture* texture, + Renderer* renderer, + Shader* shader, + vec2 uvMin, + vec2 uvMax, + mat4 model, + mat4 view, + mat4 projection, + vec2 size, + vec4 color, + vec4 colorCover, + Flip flip +); + +#define TEXTURE_QUAD_COLOR_DEFAULT (f32*)OPAQUE + +static const vec2 TEXTURE_QUAD_UV_MIN_DEFAULT = {0.0f, 0.0f}; +static const vec2 TEXTURE_QUAD_UV_MAX_DEFAULT = {1.0f, 1.0f}; +static const Flip TEXTURE_QUAD_FLIP_DEFAULT = FLIP_NONE; +static const Origin TEXTURE_QUAD_ORIGIN_DEFAULT = ORIGIN_TOP_LEFT; diff --git a/src/game/resource/RESOURCE_COMMON.h b/src/game/resource/RESOURCE_COMMON.h new file mode 100644 index 0000000..a128356 --- /dev/null +++ b/src/game/resource/RESOURCE_COMMON.h @@ -0,0 +1,286 @@ +#pragma once + +#include "../../engine/file.h" +#include "../../engine/shader.h" +#include "../../engine/font.h" +#include "../../engine/texture.h" +#include "../../engine/sound.h" +#include "../../engine/music.h" + +#define SHADER_COUNT SHADER_TEXTURE_QUAD + 1 +typedef enum ShaderType +{ + SHADER_TEXTURE_QUAD +} ShaderType; + +typedef struct ShaderPaths +{ + const char* vertex; + const char* fragment; +} ShaderPaths; + +static const ShaderPaths SHADER_PATHS[SHADER_COUNT] = +{ + { + .vertex = "res/shader/texture_quad.vs", + .fragment = "res/shader/texture_quad.fs" + } +}; + +#define TEXTURE_COUNT TEXTURE_ENDING + 1 +typedef enum TextureType +{ + TEXTURE_DEFAULT, + TEXTURE_CURSOR, + TEXTURE_LOGO, + TEXTURE_TITLE_BG, + TEXTURE_LEVEL_SELECT_BUTTONS, + TEXTURE_LEVEL_SELECT_ICONS, + TEXTURE_METER, + TEXTURE_METER_STAMINA, + TEXTURE_METER_POWER, + TEXTURE_MEDALS, + TEXTURE_GAME_BG, + TEXTURE_GAME_PLANE, + TEXTURE_SHADOW, + TEXTURE_PLAYER, + TEXTURE_TARGET, + TEXTURE_COLLECTIBLE, + TEXTURE_SMOKE, + TEXTURE_TRAP, + TEXTURE_CUTSCENE_ONE_SCENE_ONE, + TEXTURE_CUTSCENE_ONE_SCENE_TWO, + TEXTURE_CUTSCENE_ONE_SCENE_THREE, + TEXTURE_CUTSCENE_ONE_SCENE_FOUR, + TEXTURE_CUTSCENE_TWO_SCENE_ONE, + TEXTURE_CUTSCENE_TWO_SCENE_TWO, + TEXTURE_CUTSCENE_TWO_SCENE_THREE, + TEXTURE_CUTSCENE_TWO_SCENE_FOUR, + TEXTURE_CUTSCENE_TWO_SCENE_FIVE, + TEXTURE_CUTSCENE_THREE_SCENE_ONE, + TEXTURE_CUTSCENE_THREE_SCENE_TWO, + TEXTURE_CUTSCENE_THREE_SCENE_THREE, + TEXTURE_CUTSCENE_THREE_SCENE_FOUR, + TEXTURE_CUTSCENE_THREE_SCENE_FIVE, + TEXTURE_CUTSCENE_THREE_SCENE_SIX, + TEXTURE_CUTSCENE_FOUR_SCENE_ONE, + TEXTURE_CUTSCENE_FOUR_SCENE_TWO, + TEXTURE_CUTSCENE_FOUR_SCENE_THREE, + TEXTURE_CUTSCENE_FOUR_SCENE_FOUR, + TEXTURE_CUTSCENE_FOUR_SCENE_FIVE, + TEXTURE_CUTSCENE_FOUR_SCENE_SIX, + TEXTURE_CUTSCENE_FIVE_SCENE_ONE, + TEXTURE_CUTSCENE_FIVE_SCENE_TWO, + TEXTURE_CUTSCENE_FIVE_SCENE_THREE, + TEXTURE_CUTSCENE_FIVE_SCENE_FOUR, + TEXTURE_CUTSCENE_FIVE_SCENE_FIVE, + TEXTURE_CUTSCENE_FIVE_SCENE_SIX, + TEXTURE_CUTSCENE_FINAL_SCENE_ONE, + TEXTURE_CUTSCENE_FINAL_SCENE_TWO, + TEXTURE_CUTSCENE_FINAL_SCENE_THREE, + TEXTURE_CUTSCENE_FINAL_SCENE_FOUR, + TEXTURE_CUTSCENE_FINAL_SCENE_FIVE, + TEXTURE_CUTSCENE_FINAL_SCENE_SIX, + TEXTURE_CUTSCENE_FINAL_SCENE_SEVEN, + TEXTURE_CUTSCENE_FINAL_SCENE_EIGHT, + TEXTURE_CUTSCENE_FINAL_SCENE_NINE, + TEXTURE_CUTSCENE_FINAL_SCENE_TEN, + TEXTURE_CUTSCENE_FINAL_SCENE_ELEVEN, + TEXTURE_CUTSCENE_FINAL_SCENE_TWELVE, + TEXTURE_CUTSCENE_FINAL_SCENE_THIRTEEN, + TEXTURE_ENDING +} TextureType; + +static const char* TEXTURE_PATHS[TEXTURE_COUNT] = +{ + "res/gfx/default.png", + "res/gfx/cursor.png", + "res/gfx/logo.png", + "res/gfx/titleBG.png", + "res/gfx/levelSelectButtons.png", + "res/gfx/levelSelectIcons.png", + "res/gfx/meter.png", + "res/gfx/meterStamina.png", + "res/gfx/meterPower.png", + "res/gfx/medals.png", + "res/gfx/gameBG.png", + "res/gfx/gamePlane.png", + "res/gfx/shadow.png", + "res/gfx/player.png", + "res/gfx/target.png", + "res/gfx/collectible.png", + "res/gfx/smoke.png", + "res/gfx/trap.png", + "res/gfx/cutscene/c1s1.png", + "res/gfx/cutscene/c1s2.png", + "res/gfx/cutscene/c1s3.png", + "res/gfx/cutscene/c1s4.png", + "res/gfx/cutscene/c2s1.png", + "res/gfx/cutscene/c2s2.png", + "res/gfx/cutscene/c2s3.png", + "res/gfx/cutscene/c2s4.png", + "res/gfx/cutscene/c2s5.png", + "res/gfx/cutscene/c3s1.png", + "res/gfx/cutscene/c3s2.png", + "res/gfx/cutscene/c3s3.png", + "res/gfx/cutscene/c3s4.png", + "res/gfx/cutscene/c3s5.png", + "res/gfx/cutscene/c3s6.png", + "res/gfx/cutscene/c4s1.png", + "res/gfx/cutscene/c4s2.png", + "res/gfx/cutscene/c4s3.png", + "res/gfx/cutscene/c4s4.png", + "res/gfx/cutscene/c4s5.png", + "res/gfx/cutscene/c4s6.png", + "res/gfx/cutscene/c5s1.png", + "res/gfx/cutscene/c5s2.png", + "res/gfx/cutscene/c5s3.png", + "res/gfx/cutscene/c5s4.png", + "res/gfx/cutscene/c5s5.png", + "res/gfx/cutscene/c5s6.png", + "res/gfx/cutscene/c6s1.png", + "res/gfx/cutscene/c6s2.png", + "res/gfx/cutscene/c6s3.png", + "res/gfx/cutscene/c6s4.png", + "res/gfx/cutscene/c6s5.png", + "res/gfx/cutscene/c6s6.png", + "res/gfx/cutscene/c6s7.png", + "res/gfx/cutscene/c6s8.png", + "res/gfx/cutscene/c6s9.png", + "res/gfx/cutscene/c6s10.png", + "res/gfx/cutscene/c6s11.png", + "res/gfx/cutscene/c6s12.png", + "res/gfx/cutscene/c6s13.png", + "res/gfx/cutscene/ending.png" +}; + +#define FONT_COUNT FONT_BIG + 1 +typedef enum FontType +{ + FONT_DEFAULT, + FONT_SMALL, + FONT_BIG +} FontType; + +static const char* FONT_PATHS[FONT_COUNT] = +{ + "res/font/default.ttf", + "res/font/default.ttf", + "res/font/default.ttf" +}; + +static const u32 FONT_SIZES[FONT_COUNT] = +{ + 32, + 24, + 48 +}; + +#define SOUND_COUNT (SOUND_CANCEL + 1) +#define SOUND_BURP_COUNT 3 +#define SOUND_GURGLE_COUNT 3 +#define SOUND_LUNGE_COUNT 3 +#define SOUND_GULP_COUNT 3 +typedef enum SoundType +{ + SOUND_BLIP, + SOUND_SELECT, + SOUND_PAUSE, + SOUND_UNPAUSE, + SOUND_BRONZE, + SOUND_SILVER, + SOUND_GOLD, + SOUND_EVENT, + SOUND_LOW_TIMER_TICK, + SOUND_FINISH, + SOUND_LUNGE, + SOUND_LUNGE_2, + SOUND_LUNGE_3, + SOUND_GULP, + SOUND_GULP_2, + SOUND_GULP_3, + SOUND_BURP, + SOUND_BURP_2, + SOUND_BURP_3, + SOUND_GURGLE, + SOUND_GURGLE_2, + SOUND_GURGLE_3, + SOUND_APPEAR, + SOUND_STICKY, + SOUND_FOOD_COLLECT, + SOUND_CANT_CARRY, + SOUND_BLEH, + SOUND_POWER, + SOUND_STAMINA, + SOUND_MAGNET, + SOUND_EXTEND, + SOUND_FORESIGHT, + SOUND_INVIGORATE, + SOUND_CANCEL +} SoundType; + +static const char* SOUND_PATHS[SOUND_COUNT] = +{ + "res/sound/blip.ogg", + "res/sound/select.ogg", + "res/sound/pause.ogg", + "res/sound/unpause.ogg", + "res/sound/bronze.ogg", + "res/sound/silver.ogg", + "res/sound/gold.ogg", + "res/sound/event.ogg", + "res/sound/lowTimerTick.ogg", + "res/sound/finish.ogg", + "res/sound/lunge.ogg", + "res/sound/lunge2.ogg", + "res/sound/lunge3.ogg", + "res/sound/gulp.ogg", + "res/sound/gulp2.ogg", + "res/sound/gulp3.ogg", + "res/sound/burp.ogg", + "res/sound/burp2.ogg", + "res/sound/burp3.ogg", + "res/sound/gurgle.ogg", + "res/sound/gurgle2.ogg", + "res/sound/gurgle3.ogg", + "res/sound/appear.ogg", + "res/sound/sticky.ogg", + "res/sound/foodCollect.ogg", + "res/sound/cantCarry.ogg", + "res/sound/bleh.ogg", + "res/sound/power.ogg", + "res/sound/stamina.ogg", + "res/sound/magnet.ogg", + "res/sound/extend.ogg", + "res/sound/foresight.ogg", + "res/sound/invigorate.ogg", + "res/sound/cancel.ogg" +}; + +#define MUSIC_COUNT MUSIC_VICTORY + 1 +typedef enum MusicType +{ + MUSIC_TITLE, + MUSIC_CUTSCENE, + MUSIC_WIND, + MUSIC_GAME, + MUSIC_VICTORY +} MusicType; + +static const char* MUSIC_PATHS[MUSIC_COUNT] = +{ + "res/music/title.ogg", + "res/music/cutscene.ogg", + "res/music/wind.ogg", + "res/music/game.ogg", + "res/music/victory.ogg" +}; + +typedef struct Resources +{ + Shader shaders[SHADER_COUNT]; + Texture textures[TEXTURE_COUNT]; + Music music[MUSIC_COUNT]; + Sound sounds[SOUND_COUNT]; + Font fonts[FONT_COUNT]; +} Resources; diff --git a/src/game/resource/resource_font.c b/src/game/resource/resource_font.c new file mode 100644 index 0000000..48c40a9 --- /dev/null +++ b/src/game/resource/resource_font.c @@ -0,0 +1,25 @@ +#include "resource_font.h" + +bool +resource_font_init(Resources* self, FontType type) +{ + if (!font_init(&self->fonts[type], FONT_PATHS[type], FONT_SIZES[type])) + { + printf(STRING_RESOURCE_FONT_ERROR, FONT_PATHS[type]); + return false; + } + + printf(STRING_RESOURCE_FONT_INIT, FONT_PATHS[type]); + + return true; +} + +void +resource_font_free(Resources* self, FontType type) +{ + if (self->fonts[type].isInit) + { + font_free(&self->fonts[type]); + printf(STRING_RESOURCE_FONT_FREE, FONT_PATHS[type]); + } +} diff --git a/src/game/resource/resource_font.h b/src/game/resource/resource_font.h new file mode 100644 index 0000000..998409a --- /dev/null +++ b/src/game/resource/resource_font.h @@ -0,0 +1,10 @@ +#pragma once + +#include "RESOURCE_COMMON.h" + +#define STRING_RESOURCE_FONT_ERROR "[ERROR] Unable to initialize font resource: %s\n" +#define STRING_RESOURCE_FONT_FREE "[INFO] Freed font resource: %s\n" +#define STRING_RESOURCE_FONT_INIT "[INFO] Initialized font resource: %s\n" + +void resource_font_free(Resources* self, FontType type); +bool resource_font_init(Resources* self, FontType type); diff --git a/src/game/resource/resource_music.c b/src/game/resource/resource_music.c new file mode 100644 index 0000000..3d16ac4 --- /dev/null +++ b/src/game/resource/resource_music.c @@ -0,0 +1,26 @@ +#include "resource_music.h" + +bool +resource_music_init(Resources* self, MusicType type) +{ + if (!music_init(&self->music[type], MUSIC_PATHS[type])) + { + printf(STRING_RESOURCE_MUSIC_ERROR, MUSIC_PATHS[type]); + return false; + } + + printf(STRING_RESOURCE_MUSIC_INIT, MUSIC_PATHS[type]); + + return true; +} + +void +resource_music_free(Resources* self, MusicType type) +{ + if (self->music[type].isInit) + { + music_free(&self->music[type]); + + printf(STRING_RESOURCE_MUSIC_FREE, MUSIC_PATHS[type]); + } +} diff --git a/src/game/resource/resource_music.h b/src/game/resource/resource_music.h new file mode 100644 index 0000000..2d6f980 --- /dev/null +++ b/src/game/resource/resource_music.h @@ -0,0 +1,10 @@ +#pragma once + +#include "RESOURCE_COMMON.h" + +#define STRING_RESOURCE_MUSIC_ERROR "[ERROR] Unable to initialize music resource: %s\n" +#define STRING_RESOURCE_MUSIC_FREE "[INFO] Freed music resource: %s\n" +#define STRING_RESOURCE_MUSIC_INIT "[INFO] Initialized music resource: %s\n" + +void resource_music_free(Resources* self, MusicType type); +bool resource_music_init(Resources* self, MusicType type); diff --git a/src/game/resource/resource_shader.c b/src/game/resource/resource_shader.c new file mode 100644 index 0000000..f641330 --- /dev/null +++ b/src/game/resource/resource_shader.c @@ -0,0 +1,63 @@ +#include "resource_shader.h" + +typedef struct ShaderData +{ + char vertex[SHADER_BUFFER_SIZE]; + char fragment[SHADER_BUFFER_SIZE]; +} ShaderData; + +static ShaderData shaderData[SHADER_COUNT]; + +void +resource_shader_read(Resources* self) +{ + for (s32 i = 0; i < SHADER_COUNT; i++) + { + file_read + ( + SHADER_PATHS[i].vertex, + (void*)shaderData[i].vertex, + SHADER_BUFFER_SIZE, + "r" + ); + + file_read + ( + SHADER_PATHS[i].fragment, + (void*)shaderData[i].fragment, + SHADER_BUFFER_SIZE, + "r" + ); + } +} + +bool +resource_shader_init(Resources* self, ShaderType type) +{ + if + ( + !shader_init + ( + &self->shaders[type], + shaderData[type].vertex, + shaderData[type].fragment + ) + ) + { + printf(STRING_RESOURCE_SHADER_ERROR, SHADER_PATHS[type].vertex, SHADER_PATHS[type].fragment); + return false; + } + + printf(STRING_RESOURCE_SHADER_INIT, SHADER_PATHS[type].vertex, SHADER_PATHS[type].fragment); + return true; +} + +void +resource_shader_free(Resources* self, ShaderType type) +{ + if (self->shaders[type].isInit) + { + shader_free(&self->shaders[type]); + printf(STRING_RESOURCE_SHADER_FREE, SHADER_PATHS[type].vertex, SHADER_PATHS[type].fragment); + } +} diff --git a/src/game/resource/resource_shader.h b/src/game/resource/resource_shader.h new file mode 100644 index 0000000..07ffd8b --- /dev/null +++ b/src/game/resource/resource_shader.h @@ -0,0 +1,13 @@ +#pragma once + +#include "RESOURCE_COMMON.h" + +#define SHADER_BUFFER_SIZE 2048 + +#define STRING_RESOURCE_SHADER_ERROR "[ERROR] Unable to initialize shader resource: %s & %s\n" +#define STRING_RESOURCE_SHADER_FREE "[INFO] Freed shader resource: %s & %s\n" +#define STRING_RESOURCE_SHADER_INIT "[INFO] Initialized shader resource: %s & %s\n" + +void resource_shader_free(Resources* self, ShaderType type); +bool resource_shader_init(Resources* self, ShaderType type); +void resource_shader_read(Resources* self); diff --git a/src/game/resource/resource_sound.c b/src/game/resource/resource_sound.c new file mode 100644 index 0000000..4c7f90b --- /dev/null +++ b/src/game/resource/resource_sound.c @@ -0,0 +1,26 @@ +#include "resource_sound.h" + +bool +resource_sound_init(Resources* self, SoundType type) +{ + if (!sound_init(&self->sounds[type], SOUND_PATHS[type])) + { + printf(STRING_RESOURCE_SOUND_ERROR, SOUND_PATHS[type]); + return false; + } + + printf(STRING_RESOURCE_SOUND_INIT, SOUND_PATHS[type]); + + return true; +} + +void +resource_sound_free(Resources* self, SoundType type) +{ + if (self->sounds[type].isInit) + { + sound_free(&self->sounds[type]); + + printf(STRING_RESOURCE_SOUND_FREE, SOUND_PATHS[type]); + } +} diff --git a/src/game/resource/resource_sound.h b/src/game/resource/resource_sound.h new file mode 100644 index 0000000..d64e646 --- /dev/null +++ b/src/game/resource/resource_sound.h @@ -0,0 +1,10 @@ +#pragma once + +#include "RESOURCE_COMMON.h" + +#define STRING_RESOURCE_SOUND_ERROR "[ERROR] Unable to initialize sound resource: %s\n" +#define STRING_RESOURCE_SOUND_FREE "[INFO] Freed sound resource: %s\n" +#define STRING_RESOURCE_SOUND_INIT "[INFO] Initialized sound resource: %s\n" + +void resource_sound_free(Resources* self, SoundType type); +bool resource_sound_init(Resources* self, SoundType type); diff --git a/src/game/resource/resource_texture.c b/src/game/resource/resource_texture.c new file mode 100644 index 0000000..5803771 --- /dev/null +++ b/src/game/resource/resource_texture.c @@ -0,0 +1,26 @@ +#include "resource_texture.h" + +bool +resource_texture_init(Resources* self, TextureType type) +{ + if (!texture_from_path_init(&self->textures[type], TEXTURE_PATHS[type])) + { + printf(STRING_RESOURCE_TEXTURE_ERROR, TEXTURE_PATHS[type]); + return false; + } + + printf(STRING_RESOURCE_TEXTURE_INIT, TEXTURE_PATHS[type]); + + return true; +} + +void +resource_texture_free(Resources* self, TextureType type) +{ + if (self->textures[type].isInit) + { + texture_free(&self->textures[type]); + + printf(STRING_RESOURCE_TEXTURE_FREE, TEXTURE_PATHS[type]); + } +} diff --git a/src/game/resource/resource_texture.h b/src/game/resource/resource_texture.h new file mode 100644 index 0000000..c0309eb --- /dev/null +++ b/src/game/resource/resource_texture.h @@ -0,0 +1,10 @@ +#pragma once + +#include "RESOURCE_COMMON.h" + +#define STRING_RESOURCE_TEXTURE_ERROR "[ERROR] Unable to initialize texture resource: %s\n" +#define STRING_RESOURCE_TEXTURE_FREE "[INFO] Freed texture resource: %s\n" +#define STRING_RESOURCE_TEXTURE_INIT "[INFO] Initialized texture resource: %s\n" + +void resource_texture_free(Resources* self, TextureType type); +bool resource_texture_init(Resources* self, TextureType type); diff --git a/src/game/resource/resources.c b/src/game/resource/resources.c new file mode 100644 index 0000000..a00c239 --- /dev/null +++ b/src/game/resource/resources.c @@ -0,0 +1,46 @@ +#include "resources.h" + +bool +resources_init(Resources* self) +{ + for (s32 i = 0; i < SHADER_COUNT; i++) + if (!resource_shader_init(self, (ShaderType)i)) + return false; + + for (s32 i = 0; i < TEXTURE_COUNT; i++) + if (!resource_texture_init(self, (TextureType)i)) + return false; + + for (s32 i = 0; i < FONT_COUNT; i++) + if (!resource_font_init(self, (FontType)i)) + return false; + + for (s32 i = 0; i < SOUND_COUNT; i++) + if (!resource_sound_init(self, (SoundType)i)) + return false; + + for (s32 i = 0; i < MUSIC_COUNT; i++) + if (!resource_music_init(self, (MusicType)i)) + return false; + + return true; +} + +void +resources_free(Resources* self) +{ + for (s32 i = 0; i < SHADER_COUNT; i++) + resource_shader_free(self, (ShaderType)i); + + for (s32 i = 0; i < TEXTURE_COUNT; i++) + resource_texture_free(self, (TextureType)i); + + for (s32 i = 0; i < FONT_COUNT; i++) + resource_font_free(self, (FontType)i); + + for (s32 i = 0; i < SOUND_COUNT; i++) + resource_sound_free(self, (SoundType)i); + + for (s32 i = 0; i < MUSIC_COUNT; i++) + resource_music_free(self, (MusicType)i); +} diff --git a/src/game/resource/resources.h b/src/game/resource/resources.h new file mode 100644 index 0000000..8cba6be --- /dev/null +++ b/src/game/resource/resources.h @@ -0,0 +1,12 @@ +#pragma once + +#include "resource_font.h" +#include "resource_music.h" +#include "resource_shader.h" +#include "resource_sound.h" +#include "resource_texture.h" + +#define STRING_RESOURCE_ERROR "[ERROR] Unable to load resource! Exiting..." + +void resources_free(Resources* self); +bool resources_init(Resources* self); diff --git a/src/game/state/STATE_COMMON.h b/src/game/state/STATE_COMMON.h new file mode 100644 index 0000000..f71274b --- /dev/null +++ b/src/game/state/STATE_COMMON.h @@ -0,0 +1,52 @@ +#pragma once + +#include "level/level.h" +#include "cutscene/cutscene.h" +#include "title/title.h" +#include "ending/ending.h" + +#include "../resource/resource_texture.h" + +#define LEVEL_COUNT (LEVEL_FIVE + 1) +typedef enum LevelType +{ + LEVEL_ONE, + LEVEL_TWO, + LEVEL_THREE, + LEVEL_FOUR, + LEVEL_FIVE +} LevelType; + +#define STATE_COUNT (STATE_CUTSCENE_THREE + 1) +typedef enum StateType +{ + STATE_TITLE, + STATE_CUTSCENE_ONE, + STATE_CUTSCENE_TWO, + STATE_CUTSCENE_THREE, + STATE_CUTSCENE_FOUR, + STATE_CUTSCENE_FIVE, + STATE_CUTSCENE_FINAL, + STATE_ENDING, + STATE_LEVEL_ONE, + STATE_LEVEL_TWO, + STATE_LEVEL_THREE, + STATE_LEVEL_FOUR, + STATE_LEVEL_FIVE +} StateType; + +typedef struct State +{ + ECS* ecs; + StateType type; + StateType setType; + bool isChanging; + LevelData levelData[LEVEL_COUNT]; + union + { + Level level; + Title title; + Cutscene cutscene; + Ending ending; + } states; +} State; diff --git a/src/game/state/cutscene/CUTSCENE_COMMON.h b/src/game/state/cutscene/CUTSCENE_COMMON.h new file mode 100644 index 0000000..ac2923b --- /dev/null +++ b/src/game/state/cutscene/CUTSCENE_COMMON.h @@ -0,0 +1,30 @@ +#pragma once + +#include "../../ecs/entity/visual/entity_dialogue.h" +#include "../../ecs/entity/visual/entity_text_disappearing.h" +#include "../../ecs/entity/ui/entity_cursor.h" + +#define SCENE_STRING_MAX 256 + +typedef struct Scene +{ + TextureType texture; + const char* string; +} Scene; + +typedef struct SceneCollection +{ + const Scene* scenes; + u32 count; +} SceneCollection; + +typedef struct Cutscene +{ + ECS* ecs; + EntityID cursor; + EntityID dialogue; + EntityID sprite; + SceneCollection sceneCollection; + bool isFinished; + u32 sceneIndex; +} Cutscene; diff --git a/src/game/state/cutscene/cutscene.c b/src/game/state/cutscene/cutscene.c new file mode 100644 index 0000000..4060218 --- /dev/null +++ b/src/game/state/cutscene/cutscene.c @@ -0,0 +1,115 @@ +#include "cutscene.h" + +static void _cutscene_dialogue_set(Cutscene* self); +static void _cutscene_sprite_set(Cutscene* self); + +static void +_cutscene_dialogue_set(Cutscene* self) +{ + ComponentDialogue* dialogue; + + dialogue = ecs_component_get(self->ecs, COMPONENT_DIALOGUE, self->dialogue); + + component_dialogue_init + ( + dialogue, + self->ecs, + self->sceneCollection.scenes[self->sceneIndex].string, + CUTSCENE_DIALOGUE_SPEED + ); +} + +static void +_cutscene_sprite_set(Cutscene* self) +{ + ComponentTextureQuad* textureQuad; + + textureQuad = ecs_component_get(self->ecs, COMPONENT_TEXTURE_QUAD, self->sprite); + + textureQuad->texture = &self->ecs->resources->textures[self->sceneCollection.scenes[self->sceneIndex].texture]; +} + +void +cutscene_init(Cutscene* self, ECS* ecs, const SceneCollection sceneCollection) +{ + memset(self, '\0', sizeof(Cutscene)); + + self->ecs = ecs; + + self->sceneCollection = sceneCollection; + + self->cursor = entity_cursor_add(self->ecs); + + self->dialogue = entity_dialogue_add + ( + self->ecs, + &self->ecs->resources->fonts[FONT_DEFAULT], + CUTSCENE_BUFFER, + "", + (f32*)CUTSCENE_DIALOGUE_POSITION, + CUTSCENE_DIALOGUE_WRAP, + CUTSCENE_DIALOGUE_SPEED + ); + + self->sprite = entity_sprite_add + ( + self->ecs, + &self->ecs->resources->textures[TEXTURE_DEFAULT], + CUTSCENE_BUFFER, + ORIGIN_CENTER, + (f32*)CUTSCENE_SPRITE_SIZE, + (f32*)CUTSCENE_SPRITE_POSITION + ); + + _cutscene_dialogue_set(self); + _cutscene_sprite_set(self); + + entity_text_disappearing_add + ( + ecs, + &self->ecs->resources->fonts[FONT_SMALL], + CUTSCENE_BUFFER, + CUTSCENE_STRING_SKIP, + CUTSCENE_SKIP_TEXT_POSITION, + CUTSCENE_SKIP_TEXT_WRAP, + CUTSCENE_SKIP_TEXT_TIMER + ); + + music_play(&self->ecs->resources->music[MUSIC_CUTSCENE], true); +} + +void +cutscene_tick(Cutscene* self) +{ + ComponentDialogue* dialogue; + + if (self->isFinished) + return; + + dialogue = ecs_component_get(self->ecs, COMPONENT_DIALOGUE, self->dialogue); + + if (control_released(self->ecs->control, CONTROL_ACTION_PRIMARY) && dialogue->isFinished) + { + self->sceneIndex++; + + if (self->sceneIndex >= self->sceneCollection.count) + { + self->isFinished = true; + return; + } + + _cutscene_dialogue_set(self); + } + + if (control_released(self->ecs->control, CONTROL_ACTION_TERTIARY)) + self->isFinished = true; +} + +void +cutscene_free(Cutscene* self) +{ + + + +} + diff --git a/src/game/state/cutscene/cutscene.h b/src/game/state/cutscene/cutscene.h new file mode 100644 index 0000000..dfbfc95 --- /dev/null +++ b/src/game/state/cutscene/cutscene.h @@ -0,0 +1,20 @@ +#pragma once + +#include "CUTSCENE_COMMON.h" + +static const vec3 CUTSCENE_DIALOGUE_POSITION = {300.0f, 500.0f, 0.0f}; +static const vec3 CUTSCENE_SKIP_TEXT_POSITION = {25.0f, 675.0f, 0.0f}; +static const f32 CUTSCENE_DIALOGUE_WRAP = 600; +static const u32 CUTSCENE_SKIP_TEXT_TIMER = 300; +static const s32 CUTSCENE_SKIP_TEXT_WRAP = -1; +static const u32 CUTSCENE_DIALOGUE_SPEED = 2; +static const vec3 CUTSCENE_SPRITE_POSITION = {640.0f, 250.0f, 0.0f}; +static const vec2 CUTSCENE_SPRITE_SIZE = {720.0f, 360.0f}; + +#define CUTSCENE_BUFFER RENDERER_BUFFER_UI + +#define CUTSCENE_STRING_SKIP "Press SPACE to skip cutscene..." + +void cutscene_init(Cutscene* self, ECS* ecs, const SceneCollection sceneCollection); +void cutscene_tick(Cutscene* self); +void cutscene_free(Cutscene* self); diff --git a/src/game/state/ending/ENDING_COMMON.h b/src/game/state/ending/ENDING_COMMON.h new file mode 100644 index 0000000..f93b85f --- /dev/null +++ b/src/game/state/ending/ENDING_COMMON.h @@ -0,0 +1,14 @@ +#pragma once + +#include "../../ecs/entity/visual/entity_text.h" +#include "../../ecs/entity/visual/entity_sprite.h" +#include "../../ecs/entity/ui/entity_cursor.h" + +typedef struct Ending +{ + ECS* ecs; + EntityID cursor; + EntityID text; + EntityID bg; + bool isFinished; +} Ending; diff --git a/src/game/state/ending/ending.c b/src/game/state/ending/ending.c new file mode 100644 index 0000000..d0ebf62 --- /dev/null +++ b/src/game/state/ending/ending.c @@ -0,0 +1,50 @@ +#include "ending.h" + +void +ending_init(Ending* self, ECS* ecs) +{ + memset(self, '\0', sizeof(Ending)); + + self->ecs = ecs; + + self->cursor = entity_cursor_add(self->ecs); + + self->text = entity_text_add + ( + ecs, + &ecs->resources->fonts[FONT_BIG], + RENDERER_BUFFER_UI, + STRING_ENDING_TEXT, + ENDING_TEXT_POSITION, + -1 + ); + + self->bg = entity_sprite_add + ( + ecs, + &ecs->resources->textures[TEXTURE_ENDING], + RENDERER_BUFFER_BACKGROUND, + ORIGIN_TOP_LEFT, + ENDING_BG_SIZE, + ENDING_BG_POSITION + ); + + music_play(&self->ecs->resources->music[MUSIC_VICTORY], true); +} + +void +ending_tick(Ending* self) +{ + if (self->isFinished) + return; + + if (control_released(self->ecs->control, CONTROL_ACTION_PRIMARY)) + self->isFinished = true; +} + +void +ending_free(Ending* self) +{ + +} + diff --git a/src/game/state/ending/ending.h b/src/game/state/ending/ending.h new file mode 100644 index 0000000..f22a525 --- /dev/null +++ b/src/game/state/ending/ending.h @@ -0,0 +1,13 @@ +#pragma once + +#include "ENDING_COMMON.h" + +static vec3 ENDING_TEXT_POSITION = {25.0f, 650.0f, 0.0f}; +static vec2 ENDING_BG_SIZE = {1280.0f, 720.0f}; +static vec3 ENDING_BG_POSITION = {0.0f, 0.0f, 0.0f}; + +#define STRING_ENDING_TEXT "THE END" + +void ending_init(Ending* self, ECS* ecs); +void ending_tick(Ending* self); +void ending_free(Ending* self); diff --git a/src/game/state/level/LEVEL_COMMON.h b/src/game/state/level/LEVEL_COMMON.h new file mode 100644 index 0000000..4038f7c --- /dev/null +++ b/src/game/state/level/LEVEL_COMMON.h @@ -0,0 +1,124 @@ +#pragma once + +#include "../../ecs/entity/ui/entity_cursor.h" +#include "../../ecs/entity/ui/entity_meter.h" +#include "../../ecs/entity/ui/entity_medal.h" +#include "../../ecs/entity/visual/entity_value_text.h" +#include "../../ecs/entity/game/entity_player.h" +#include "../../ecs/entity/game/entity_target.h" +#include "../../ecs/entity/game/entity_collectible_amulet.h" +#include "../../ecs/entity/game/entity_collectible_stamina.h" +#include "../../ecs/entity/game/entity_collectible_power.h" +#include "../../ecs/entity/game/entity_smoke_big.h" +#include "../../ecs/entity/game/entity_collectible_food.h" +#include "../../ecs/entity/game/entity_collectible_rotten_food.h" +#include "../../ecs/entity/game/entity_trap.h" +#include "../../ecs/entity/utility/entity_timer.h" +#include "../../ecs/entity/visual/entity_dialogue.h" +#include "../../ecs/entity/visual/entity_text_disappearing.h" + +#define LEVEL_TUTORIAL_TEXT_COUNT 3 + +#define LEVEL_COUNTDOWN_COUNT (LEVEL_COUNTDOWN_GO + 1) +typedef enum LevelCountdownState +{ + LEVEL_COUNTDOWN_READY, + LEVEL_COUNTDOWN_SET, + LEVEL_COUNTDOWN_GO +} LevelCountdownState; + +#define LEVEL_MEDAL_COUNT (LEVEL_MEDAL_GOLD + 1) +typedef enum LevelMedal +{ + LEVEL_MEDAL_NONE, + LEVEL_MEDAL_BRONZE, + LEVEL_MEDAL_SILVER, + LEVEL_MEDAL_GOLD +} LevelMedal; + +#define LEVEL_EVENT_COUNT (LEVEL_EVENT_ANCHOR_ARMS + 1) +typedef enum LevelEvent +{ + LEVEL_EVENT_NONE, + LEVEL_EVENT_ROTTEN_FOOD, + LEVEL_EVENT_STICKY_TRAPS, + LEVEL_EVENT_BUTTERFINGERS, + LEVEL_EVENT_OUT_OF_BREATH, + LEVEL_EVENT_POWER_LEECH, + LEVEL_EVENT_VIM_AND_VIGOR, + LEVEL_EVENT_GLUTTONY, + LEVEL_EVENT_ANCHOR_ARMS +} LevelEvent; + +typedef struct LevelSettings +{ + u32 medalThresholds[LEVEL_MEDAL_COUNT - 1]; + u32 time; + u32 eventTime; + vec4 colorCover; + u32 collectibleMax; + bool isPower; + bool isEvent; + bool isAmulet; + bool isPowerForesight; + bool isPowerCancel; + bool isPowerMagnet; + bool isPowerExtend; + bool isPowerInvigorate; + bool isTutorialMove; + bool isTutorialStamina; + bool isTutorialFood; + bool isTutorialEvent; + bool isTutorialPower; + bool isTutorialPowerForesight; + bool isTutorialPowerCancel; + bool isTutorialPowerMagnet; + bool isTutorialPowerExtend; + bool isTutorialPowerInvigorate; + bool isTutorialFinal; +} LevelSettings; + +typedef struct Level +{ + ECS* ecs; + LevelSettings settings; + LevelCountdownState countdownState; + LevelMedal medal; + s32 score; + s32 timeToMedal; + s32 timerValue; + u32 levelValue; + LevelMedal nextMedal; + LevelEvent event; + LevelEvent nextEvent; + Vector textQueue; + EntityID plane; + EntityID bg; + EntityID countdownTimer; + EntityID cursor; + EntityID finishTimer; + EntityID medalUI; + EntityID meterPower; + EntityID meterStamina; + EntityID pauseText; + EntityID pauseTipText; + EntityID player; + EntityID playerFoodUI; + EntityID target; + EntityID targetFoodUI; + EntityID thresholdUI; + EntityID collectibleMercyTimer; + EntityID timer; + EntityID timerUI; + EntityID eventTimer; + EntityID eventTimerUI; + EntityID amulet; + bool isAmuletSpawn; + bool isRottenFood; + bool isMagnet; + bool isComplete; + bool isCountdownDone; + bool isPaused; + bool isTimerDone; + bool isFinished; +} Level; diff --git a/src/game/state/level/collectible_spawn.c b/src/game/state/level/collectible_spawn.c new file mode 100644 index 0000000..87a28d9 --- /dev/null +++ b/src/game/state/level/collectible_spawn.c @@ -0,0 +1,540 @@ +#include "collectible_spawn.h" + +#define LEVEL_COLLECTIBLE_COLLECTIBLE_SPAWN_LINE_OFFSET 50.0f + +#define COLLECTIBLE_SPAWN_NO_POWER_COUNT 5 +#define COLLECTIBLE_SPAWN_ROTTEN_FOOD_NO_POWER_COUNT 6 +#define COLLECTIBLE_SPAWN_COUNT 6 +#define COLLECTIBLE_SPAWN_ROTTEN_FOOD_COUNT 7 +typedef enum CollectibleSpawnType +{ + COLLECTIBLE_SPAWN_FOOD_INDIVIDUAL, + COLLECTIBLE_SPAWN_FOOD_HORIZONTAL_LINE, + COLLECTIBLE_SPAWN_FOOD_VERTICAL_LINE, + COLLECTIBLE_SPAWN_FOOD_CIRCLE, + COLLECTIBLE_SPAWN_STAMINA_INDIVIDUAL, + COLLECTIBLE_SPAWN_POWER_INDIVIDUAL, + COLLECTIBLE_SPAWN_ROTTEN_FOOD_INDIVIDUAL +} CollectibleSpawnType; + +typedef struct CollectibleSpawn CollectibleSpawn; + +typedef void (*CollectibleSpawnFunction)(CollectibleSpawn*, Level*, vec3); + +typedef struct CollectibleSpawn +{ + CollectibleSpawnType spawnType; + CollectibleType collectibleType; + CollectibleSpawnFunction function; + u32 count; + f32 probability; +} CollectibleSpawn; + +void _level_collectible_spawn_individual_add(CollectibleSpawn* self, Level* level, vec3 position); +void _level_collectible_spawn_horizontal_line_add(CollectibleSpawn* self, Level* level, vec3 position); +void _level_collectible_spawn_vertical_line_add(CollectibleSpawn* self, Level* level, vec3 position); +void _level_collectible_spawn_circle_add(CollectibleSpawn* self, Level* level, vec3 position); +void _level_collectible_spawn_refresh_tick(Level* self); +u32 _level_collectible_spawn_food_count_get(Level* self); +void _level_collectible_spawn(Level* self, CollectibleType type, vec3 position); +void _level_collectibles_spawn(Level* self); + +static const struct CollectibleSpawn COLLECTIBLE_NO_POWER_SPAWNS[COLLECTIBLE_SPAWN_NO_POWER_COUNT] = +{ + { + .spawnType = COLLECTIBLE_SPAWN_FOOD_CIRCLE, + .collectibleType = COLLECTIBLE_FOOD, + .function = _level_collectible_spawn_circle_add, + .count = 10, + .probability = 0.05f + }, + { + .spawnType = COLLECTIBLE_SPAWN_FOOD_VERTICAL_LINE, + .collectibleType = COLLECTIBLE_FOOD, + .function = _level_collectible_spawn_vertical_line_add, + .count = 5, + .probability = 0.10f + }, + { + .spawnType = COLLECTIBLE_SPAWN_FOOD_HORIZONTAL_LINE, + .collectibleType = COLLECTIBLE_FOOD, + .function = _level_collectible_spawn_horizontal_line_add, + .count = 5, + .probability = 0.15f + }, + { + .spawnType = COLLECTIBLE_SPAWN_STAMINA_INDIVIDUAL, + .collectibleType = COLLECTIBLE_STAMINA, + .function = _level_collectible_spawn_individual_add, + .count = 1, + .probability = 0.30f + }, + { + .spawnType = COLLECTIBLE_SPAWN_FOOD_INDIVIDUAL, + .collectibleType = COLLECTIBLE_FOOD, + .function = _level_collectible_spawn_individual_add, + .count = 1, + .probability = 1.0f + } +}; + +static const struct CollectibleSpawn COLLECTIBLE_SPAWNS[COLLECTIBLE_SPAWN_COUNT] = +{ + { + .spawnType = COLLECTIBLE_SPAWN_FOOD_CIRCLE, + .collectibleType = COLLECTIBLE_FOOD, + .function = _level_collectible_spawn_circle_add, + .count = 10, + .probability = 0.05f + }, + { + .spawnType = COLLECTIBLE_SPAWN_FOOD_VERTICAL_LINE, + .collectibleType = COLLECTIBLE_FOOD, + .function = _level_collectible_spawn_vertical_line_add, + .count = 5, + .probability = 0.10f + }, + { + .spawnType = COLLECTIBLE_SPAWN_FOOD_HORIZONTAL_LINE, + .collectibleType = COLLECTIBLE_FOOD, + .function = _level_collectible_spawn_horizontal_line_add, + .count = 5, + .probability = 0.15f + }, + { + .spawnType = COLLECTIBLE_SPAWN_STAMINA_INDIVIDUAL, + .collectibleType = COLLECTIBLE_STAMINA, + .function = _level_collectible_spawn_individual_add, + .count = 1, + .probability = 0.30f + }, + { + .spawnType = COLLECTIBLE_SPAWN_POWER_INDIVIDUAL, + .collectibleType = COLLECTIBLE_POWER, + .function = _level_collectible_spawn_individual_add, + .count = 1, + .probability = 0.45f + }, + { + .spawnType = COLLECTIBLE_SPAWN_FOOD_INDIVIDUAL, + .collectibleType = COLLECTIBLE_FOOD, + .function = _level_collectible_spawn_individual_add, + .count = 1, + .probability = 1.0f + } +}; + +static const struct CollectibleSpawn COLLECTIBLE_ROTTEN_FOOD_NO_POWER_SPAWNS[COLLECTIBLE_SPAWN_ROTTEN_FOOD_NO_POWER_COUNT] = +{ + { + .spawnType = COLLECTIBLE_SPAWN_FOOD_CIRCLE, + .collectibleType = COLLECTIBLE_FOOD, + .function = _level_collectible_spawn_circle_add, + .count = 10, + .probability = 0.05f + }, + { + .spawnType = COLLECTIBLE_SPAWN_FOOD_VERTICAL_LINE, + .collectibleType = COLLECTIBLE_FOOD, + .function = _level_collectible_spawn_vertical_line_add, + .count = 5, + .probability = 0.10f + }, + { + .spawnType = COLLECTIBLE_SPAWN_FOOD_HORIZONTAL_LINE, + .collectibleType = COLLECTIBLE_FOOD, + .function = _level_collectible_spawn_horizontal_line_add, + .count = 5, + .probability = 0.15f + }, + { + .spawnType = COLLECTIBLE_SPAWN_STAMINA_INDIVIDUAL, + .collectibleType = COLLECTIBLE_STAMINA, + .function = _level_collectible_spawn_individual_add, + .count = 1, + .probability = 0.30f + }, + { + .spawnType = COLLECTIBLE_SPAWN_ROTTEN_FOOD_INDIVIDUAL, + .collectibleType = COLLECTIBLE_ROTTEN_FOOD, + .function = _level_collectible_spawn_individual_add, + .count = 1, + .probability = 0.45f + }, + { + .spawnType = COLLECTIBLE_SPAWN_FOOD_INDIVIDUAL, + .collectibleType = COLLECTIBLE_FOOD, + .function = _level_collectible_spawn_individual_add, + .count = 1, + .probability = 1.0f + } +}; + +static const struct CollectibleSpawn COLLECTIBLE_ROTTEN_FOOD_SPAWNS[COLLECTIBLE_SPAWN_ROTTEN_FOOD_COUNT] = +{ + { + .spawnType = COLLECTIBLE_SPAWN_FOOD_CIRCLE, + .collectibleType = COLLECTIBLE_FOOD, + .function = _level_collectible_spawn_circle_add, + .count = 10, + .probability = 0.05f + }, + { + .spawnType = COLLECTIBLE_SPAWN_FOOD_VERTICAL_LINE, + .collectibleType = COLLECTIBLE_FOOD, + .function = _level_collectible_spawn_vertical_line_add, + .count = 5, + .probability = 0.10f + }, + { + .spawnType = COLLECTIBLE_SPAWN_FOOD_HORIZONTAL_LINE, + .collectibleType = COLLECTIBLE_FOOD, + .function = _level_collectible_spawn_horizontal_line_add, + .count = 5, + .probability = 0.15f + }, + { + .spawnType = COLLECTIBLE_SPAWN_STAMINA_INDIVIDUAL, + .collectibleType = COLLECTIBLE_STAMINA, + .function = _level_collectible_spawn_individual_add, + .count = 1, + .probability = 0.30f + }, + { + .spawnType = COLLECTIBLE_SPAWN_POWER_INDIVIDUAL, + .collectibleType = COLLECTIBLE_POWER, + .function = _level_collectible_spawn_individual_add, + .count = 1, + .probability = 0.45f + }, + { + .spawnType = COLLECTIBLE_SPAWN_ROTTEN_FOOD_INDIVIDUAL, + .collectibleType = COLLECTIBLE_ROTTEN_FOOD, + .function = _level_collectible_spawn_individual_add, + .count = 1, + .probability = 0.60f + }, + { + .spawnType = COLLECTIBLE_SPAWN_FOOD_INDIVIDUAL, + .collectibleType = COLLECTIBLE_FOOD, + .function = _level_collectible_spawn_individual_add, + .count = 1, + .probability = 1.0f + } +}; + +void +level_collectible_spawn_clear(Level* self) +{ + for (s32 i = 0; i < (s32)self->ecs->lists[COMPONENT_COLLECTIBLE].components.count; i++) + { + ComponentCollectible* collectible; + ComponentPhysics* physics; + vec3 smokePosition; + + collectible = (ComponentCollectible*)vector_get(&self->ecs->lists[COMPONENT_COLLECTIBLE].components, i); + + physics = ecs_component_get(self->ecs, COMPONENT_PHYSICS, collectible->component.id); + + glm_vec3_copy(physics->position, smokePosition); + + smokePosition[2] += ENTITY_COLLECTIBLE_SMOKE_Z_OFFSET; + + entity_smoke_add + ( + self->ecs, + smokePosition + ); + + ecs_entity_delete(self->ecs, collectible->component.id); + + i--; + } + + sound_play(&self->ecs->resources->sounds[SOUND_APPEAR]); +} + +void +_level_collectible_spawn(Level* self, CollectibleType type, vec3 position) +{ + switch (type) + { + case COLLECTIBLE_ROTTEN_FOOD: + entity_collectible_rotten_food_add + ( + self->ecs, + position + ); + break; + case COLLECTIBLE_FOOD: + entity_collectible_food_add + ( + self->ecs, + position + ); + break; + case COLLECTIBLE_STAMINA: + entity_collectible_stamina_add + ( + self->ecs, + position + ); + break; + case COLLECTIBLE_POWER: + entity_collectible_power_add + ( + self->ecs, + position + ); + default: + break; + } +} + +void +_level_collectible_spawn_individual_add(CollectibleSpawn* self, Level* level, vec3 position) +{ + _level_collectible_spawn(level, self->collectibleType, position); +} + +void +_level_collectible_spawn_horizontal_line_add(CollectibleSpawn* self, Level* level, vec3 position) +{ + vec3 collectiblePosition; + f32 size; + + glm_vec3_copy(position, collectiblePosition); + + size = (ENTITY_COLLECTIBLE_SIZE[0] * self->count); + + collectiblePosition[0] -= size; + + collectiblePosition[0] = CLAMP(collectiblePosition[0], LEVEL_COLLECTIBLE_SPAWN_BOUNDS[0] + size, LEVEL_COLLECTIBLE_SPAWN_BOUNDS[2] - (size * 2)); + + for (s32 i = 0; i < (s32)self->count; i++) + { + collectiblePosition[0] += ENTITY_COLLECTIBLE_SIZE[0]; + _level_collectible_spawn(level, self->collectibleType, collectiblePosition); + } +} + +void +_level_collectible_spawn_vertical_line_add(CollectibleSpawn* self, Level* level, vec3 position) +{ + vec3 collectiblePosition; + f32 size; + + glm_vec3_copy(position, collectiblePosition); + + size = (ENTITY_COLLECTIBLE_SIZE[1] * self->count); + + collectiblePosition[1] -= size; + + collectiblePosition[1] = CLAMP(collectiblePosition[1], LEVEL_COLLECTIBLE_SPAWN_BOUNDS[1] + size, LEVEL_COLLECTIBLE_SPAWN_BOUNDS[3] - (size * 2)); + + for (s32 i = 0; i < (s32)self->count; i++) + { + collectiblePosition[1] += ENTITY_COLLECTIBLE_SIZE[0]; + _level_collectible_spawn(level, self->collectibleType, collectiblePosition); + } +} + +void +_level_collectible_spawn_circle_add(CollectibleSpawn* self, Level* level, vec3 position) +{ + vec3 collectiblePosition; + f32 angle; + f32 size; + + angle = 0.0f; + + glm_vec3_copy(position, collectiblePosition); + + size = ENTITY_COLLECTIBLE_SIZE[0] * 2; + + collectiblePosition[0] = CLAMP(collectiblePosition[0], LEVEL_COLLECTIBLE_SPAWN_BOUNDS[0] + (size * 3), LEVEL_COLLECTIBLE_SPAWN_BOUNDS[2] - (size * 3)); + collectiblePosition[1] = CLAMP(collectiblePosition[1], LEVEL_COLLECTIBLE_SPAWN_BOUNDS[1] + (size * 3), LEVEL_COLLECTIBLE_SPAWN_BOUNDS[3] - (size * 3)); + + for (s32 i = 0; i < (s32)self->count; i++) + { + angle = ((f32)i / self->count) * TAU; + + collectiblePosition[0] += size * cos(angle); + collectiblePosition[1] += size * sin(angle); + + _level_collectible_spawn(level, self->collectibleType, collectiblePosition); + } +} + +u32 +_level_collectible_spawn_food_count_get(Level* self) +{ + u32 count; + + count = 0; + + for (s32 i = 0; i < (s32)self->ecs->lists[COMPONENT_COLLECTIBLE].components.count; i++) + { + ComponentCollectible* collectible; + + collectible = (ComponentCollectible*)vector_get(&self->ecs->lists[COMPONENT_COLLECTIBLE].components, i); + + if (collectible->type == COLLECTIBLE_FOOD) + count++; + } + + return count; +} + +void +_level_collectible_spawn_refresh_tick(Level* self) +{ + u32 foodCount; + + foodCount = _level_collectible_spawn_food_count_get(self); + + if (foodCount == 0) + _level_collectibles_spawn(self); +} + +void +_level_collectibles_spawn(Level* self) +{ + level_collectible_spawn_clear(self); + + Vector spawns; + u32 collectibleCount; + + vector_init(&spawns, sizeof(u32)); + + collectibleCount = 0; + + while (collectibleCount <= self->settings.collectibleMax) + { + f32 random; + u32 index; + + random = RANDOM; + + if (self->settings.isPower && self->isRottenFood) + { + for (s32 i = 0; i < COLLECTIBLE_SPAWN_ROTTEN_FOOD_COUNT; i++) + { + CollectibleSpawn spawn; + + spawn = COLLECTIBLE_ROTTEN_FOOD_SPAWNS[i]; + + if (random < spawn.probability) + { + index = i; + vector_push(&spawns, &index); + collectibleCount += COLLECTIBLE_ROTTEN_FOOD_SPAWNS[index].count; + break; + } + } + } + else if (self->settings.isPower) + { + for (s32 i = 0; i < COLLECTIBLE_SPAWN_COUNT; i++) + { + CollectibleSpawn spawn; + + spawn = COLLECTIBLE_SPAWNS[i]; + + if (random < spawn.probability) + { + index = i; + vector_push(&spawns, &index); + collectibleCount += COLLECTIBLE_SPAWNS[index].count; + break; + } + } + } + else if (self->isRottenFood) + { + for (s32 i = 0; i < COLLECTIBLE_SPAWN_ROTTEN_FOOD_NO_POWER_COUNT; i++) + { + CollectibleSpawn spawn; + + spawn = COLLECTIBLE_ROTTEN_FOOD_NO_POWER_SPAWNS[i]; + + if (random < spawn.probability) + { + index = i; + vector_push(&spawns, &index); + collectibleCount += COLLECTIBLE_ROTTEN_FOOD_NO_POWER_SPAWNS[index].count; + break; + } + } + } + else + { + for (s32 i = 0; i < COLLECTIBLE_SPAWN_NO_POWER_COUNT; i++) + { + CollectibleSpawn spawn; + + spawn = COLLECTIBLE_NO_POWER_SPAWNS[i]; + + if (random < spawn.probability) + { + index = i; + vector_push(&spawns, &index); + collectibleCount += COLLECTIBLE_NO_POWER_SPAWNS[index].count; + break; + } + } + } + }; + + for (s32 i = 0; i < (s32)spawns.count; i++) + { + u32* index; + vec3 position; + bool isInRectangle; + + glm_vec3_zero(position); + + index = (u32*)vector_get(&spawns, i); + + isInRectangle = true; + + while(isInRectangle) + { + vec2 testPosition; + + position[0] = RANDOM_F32(LEVEL_COLLECTIBLE_SPAWN_BOUNDS[0], LEVEL_COLLECTIBLE_SPAWN_BOUNDS[2]); + position[1] = RANDOM_F32(LEVEL_COLLECTIBLE_SPAWN_BOUNDS[1], LEVEL_COLLECTIBLE_SPAWN_BOUNDS[3]); + + testPosition[0] = position[0]; + testPosition[1] = position[1]; + + isInRectangle = rectangle_has_point(&LEVEL_COLLECTIBLE_SPAWN_NO_NO_RECTANGLE, testPosition); + } + + if (self->settings.isPower && self->isRottenFood) + COLLECTIBLE_ROTTEN_FOOD_SPAWNS[*index].function(&COLLECTIBLE_ROTTEN_FOOD_SPAWNS[*index], self, position); + else if (self->settings.isPower) + COLLECTIBLE_SPAWNS[*index].function(&COLLECTIBLE_SPAWNS[*index], self, position); + else if (self->isRottenFood) + COLLECTIBLE_ROTTEN_FOOD_NO_POWER_SPAWNS[*index].function(&COLLECTIBLE_ROTTEN_FOOD_NO_POWER_SPAWNS[*index], self, position); + else + COLLECTIBLE_NO_POWER_SPAWNS[*index].function(&COLLECTIBLE_NO_POWER_SPAWNS[*index], self, position); + } + + vector_free(&spawns); + + sound_play(&self->ecs->resources->sounds[SOUND_APPEAR]); +} + +void +level_collectible_spawn_init(Level* self) +{ + _level_collectibles_spawn(self); +} + +void +level_collectible_spawn_tick(Level* self) +{ + if (self->isCountdownDone && !self->isTimerDone) + _level_collectible_spawn_refresh_tick(self); +} diff --git a/src/game/state/level/collectible_spawn.h b/src/game/state/level/collectible_spawn.h new file mode 100644 index 0000000..4e9e6cb --- /dev/null +++ b/src/game/state/level/collectible_spawn.h @@ -0,0 +1,21 @@ +#pragma once + +#include "LEVEL_COMMON.h" + +#define LEVEL_COLLECTIBLE_SPAWN_MAX 50 + +static const vec4 LEVEL_COLLECTIBLE_SPAWN_BOUNDS = {350.0f, 350.0f, 6300.0f, 3000.0f}; +static const f32 LEVEL_COLLECTIBLE_SPAWN_MERCY_TIMER = 600; +static const u32 LEVEL_COLLECTIBLE_SPAWN_MERCY_COUNT = 5; + +static const Rectangle LEVEL_COLLECTIBLE_SPAWN_NO_NO_RECTANGLE = +{ + .x = 2500.0f, + .y = 1400.0f, + .w = 1800.0f, + .h = 1400.0f +}; + +void level_collectible_spawn_clear(Level* self); +void level_collectible_spawn_init(Level* self); +void level_collectible_spawn_tick(Level* self); diff --git a/src/game/state/level/countdown.c b/src/game/state/level/countdown.c new file mode 100644 index 0000000..497e18f --- /dev/null +++ b/src/game/state/level/countdown.c @@ -0,0 +1,111 @@ +#include "countdown.h" + +void +level_countdown_init(Level* self) +{ + ComponentPlayerControl* playerControl; + ComponentTimer* levelTimer; + + playerControl = ecs_component_get(self->ecs, COMPONENT_PLAYER_CONTROL, self->player); + levelTimer = ecs_component_get(self->ecs, COMPONENT_TIMER, self->timer); + + playerControl->component.isDisabled = true; + levelTimer->component.isDisabled = true; + + self->countdownState = LEVEL_COUNTDOWN_READY; + + self->countdownTimer = entity_timer_add(self->ecs, LEVEL_COUNTDOWN_TIMER_VALUE); + + level_text_queue_add(self, LEVEL_STRING_RESET_REMINDER); + level_text_queue_add(self, LEVEL_STRING_COUNTDOWN_SKIP); + + entity_text_disappearing_add + ( + self->ecs, + &self->ecs->resources->fonts[FONT_BIG], + RENDERER_BUFFER_UI, + STRING_LEVEL_COUNTDOWN_READY, + LEVEL_COUNTDOWN_TEXT_POSITION, + -1, + LEVEL_COUNTDOWN_TIMER_VALUE + ); +} + +void +level_countdown_finish(Level* self) +{ + ComponentPlayerControl* playerControl; + ComponentTimer* levelTimer; + ComponentTimer* countdownTimer; + + playerControl = ecs_component_get(self->ecs, COMPONENT_PLAYER_CONTROL, self->player); + levelTimer = ecs_component_get(self->ecs, COMPONENT_TIMER, self->timer); + countdownTimer = ecs_component_get(self->ecs, COMPONENT_TIMER, self->countdownTimer); + + playerControl->component.isDisabled = false; + levelTimer->component.isDisabled = false; + + countdownTimer->isFinished = true; + countdownTimer->value = 0; + self->countdownState = LEVEL_COUNTDOWN_GO; + self->isCountdownDone = true; + + level_text_queue_clear(self); + level_tutorial_init(self); + + if (self->settings.isEvent) + { + ComponentTimer* eventTimer; + + level_event_init(self); + + eventTimer = ecs_component_get(self->ecs, COMPONENT_TIMER, self->eventTimer); + + eventTimer->component.isDisabled = false; + } + + entity_text_disappearing_add + ( + self->ecs, + &self->ecs->resources->fonts[FONT_BIG], + RENDERER_BUFFER_UI, + STRING_LEVEL_COUNTDOWN_GO, + LEVEL_COUNTDOWN_TEXT_POSITION, + -1, + LEVEL_COUNTDOWN_TIMER_VALUE + ); + + + + music_play(&self->ecs->resources->music[MUSIC_GAME], true); +} + +void +level_countdown_tick(Level* self) +{ + ComponentTimer* countdownTimer; + + if (self->countdownState == LEVEL_COUNTDOWN_GO) + return; + + countdownTimer = ecs_component_get(self->ecs, COMPONENT_TIMER, self->countdownTimer); + + if (countdownTimer->isFinished) + { + self->countdownState++; + + if (self->countdownState == LEVEL_COUNTDOWN_GO) + { + level_countdown_finish(self); + return; + } + + component_timer_init(countdownTimer, self->ecs, LEVEL_COUNTDOWN_TIMER_VALUE); + } + + if (control_pressed(self->ecs->control, CONTROL_ACTION_TERTIARY)) + { + level_countdown_finish(self); + return; + } +} diff --git a/src/game/state/level/countdown.h b/src/game/state/level/countdown.h new file mode 100644 index 0000000..1626edd --- /dev/null +++ b/src/game/state/level/countdown.h @@ -0,0 +1,17 @@ +#pragma once + +#include "tutorial.h" +#include "event.h" + +static const f32 LEVEL_COUNTDOWN_TIMER_VALUE = 70; +static const vec3 LEVEL_COUNTDOWN_TEXT_POSITION = {600.0f, 300.0f, 0.0f}; + +#define STRING_LEVEL_COUNTDOWN_READY "Ready..." +#define STRING_LEVEL_COUNTDOWN_GO "Feed!" + +#define LEVEL_STRING_COUNTDOWN_SKIP "Press SPACE to skip countdown..." +#define LEVEL_STRING_RESET_REMINDER "Need a break? Press P to pause." + +void level_countdown_init(Level* self); +void level_countdown_tick(Level* self); +void level_countdown_finish(Level* self); diff --git a/src/game/state/level/event.c b/src/game/state/level/event.c new file mode 100644 index 0000000..62c89b9 --- /dev/null +++ b/src/game/state/level/event.c @@ -0,0 +1,439 @@ +#include "event.h" + +void _level_event_foresight(Level* self); +void _level_event_cancel(Level* self); +void _level_event_extend(Level* self); +void _level_event_magnet(Level* self); +void _level_event_invigorate(Level* self); +void _level_event_power_player_color_change_init(Level* self); +void _level_event_sticky_traps_set(Level* self); +void _level_event_sticky_traps_clear(Level* self); + +void +_level_event_power_player_color_change_init(Level* self) +{ + ComponentColorChange* colorChange; + + colorChange = ecs_component_get(self->ecs, COMPONENT_COLOR_CHANGE, self->player); + + component_color_change_init + ( + colorChange, + self->ecs, + LEVEL_EVENT_PLAYER_POWER_COLOR, + TRANSPARENT, + LEVEL_EVENT_PLAYER_POWER_COLOR_CHANGE_TIME, + true, + false + ); +} + +void +_level_event_foresight(Level* self) +{ + level_text_queue_add(self, STRING_LEVEL_EVENT_FORESIGHTS[self->nextEvent]); + + sound_play(&self->ecs->resources->sounds[SOUND_FORESIGHT]); + + _level_event_power_player_color_change_init(self); +} + +void +_level_event_cancel(Level* self) +{ + self->nextEvent = LEVEL_EVENT_NONE; + level_text_queue_add(self, STRING_LEVEL_EVENT_CANCEL); + + sound_play(&self->ecs->resources->sounds[SOUND_CANCEL]); + + _level_event_power_player_color_change_init(self); +} + +void +_level_event_extend(Level* self) +{ + ComponentTimer* eventTimer; + + eventTimer = ecs_component_get(self->ecs, COMPONENT_TIMER, self->eventTimer); + + eventTimer->value += LEVEL_EVENT_POWER_EXTEND_TIME; + + level_text_queue_add(self, STRING_LEVEL_EVENT_EXTEND); + + sound_play(&self->ecs->resources->sounds[SOUND_EXTEND]); + + _level_event_power_player_color_change_init(self); +} + +void +_level_event_magnet(Level* self) +{ + ComponentCollect* collect; + + collect = ecs_component_get(self->ecs, COMPONENT_COLLECT, self->player); + + collect->circle.radius = LEVEL_EVENT_POWER_MAGNET_RADIUS; + + sound_play(&self->ecs->resources->sounds[SOUND_MAGNET]); + + self->isMagnet = true; + + level_text_queue_add(self, STRING_LEVEL_EVENT_MAGNET); + + _level_event_power_player_color_change_init(self); +} + + +void +_level_event_invigorate(Level* self) +{ + ComponentStamina* stamina; + + stamina = ecs_component_get(self->ecs, COMPONENT_STAMINA, self->player); + + stamina->value = stamina->max; + + level_text_queue_add(self, STRING_LEVEL_EVENT_INVIGORATE); + + sound_play(&self->ecs->resources->sounds[SOUND_INVIGORATE]); + + _level_event_power_player_color_change_init(self); +} + +void +_level_event_sticky_traps_set(Level* self) +{ + s32 stickyTrapsCount; + + stickyTrapsCount = RANDOM_S32(LEVEL_EVENT_STICKY_TRAPS_MIN, LEVEL_EVENT_STICKY_TRAPS_MAX); + + for (s32 i = 0; i < stickyTrapsCount; i++) + { + vec3 position; + u32 id; + bool isInRectangle; + ComponentPhysics* physics; + vec3 smokePosition; + + glm_vec3_zero(position); + + isInRectangle = true; + + while(isInRectangle) + { + vec2 testPosition; + + position[0] = RANDOM_F32(LEVEL_EVENT_STICKY_TRAPS_BOUNDS[0], LEVEL_EVENT_STICKY_TRAPS_BOUNDS[2]); + position[1] = RANDOM_F32(LEVEL_EVENT_STICKY_TRAPS_BOUNDS[1], LEVEL_EVENT_STICKY_TRAPS_BOUNDS[3]); + + testPosition[0] = position[0]; + testPosition[1] = position[1]; + + isInRectangle = rectangle_has_point(&LEVEL_EVENT_STICKY_TRAPS_NO_NO_RECTANGLE, testPosition); + } + + + id = entity_trap_add + ( + self->ecs, + position + ); + + physics = ecs_component_get(self->ecs, COMPONENT_PHYSICS, id); + + glm_vec3_copy(physics->position, smokePosition); + + smokePosition[2] += ENTITY_TRAP_SMOKE_Z_OFFSET; + + entity_smoke_big_add + ( + self->ecs, + smokePosition + ); + } +} + +void +_level_event_sticky_traps_clear(Level* self) +{ + for (s32 i = 0; i < (s32)self->ecs->lists[COMPONENT_PLANE_OBJECT].components.count; i++) + { + ComponentPlaneObject* planeObject; + ComponentPhysics* physics; + vec3 smokePosition; + + planeObject = (ComponentPlaneObject*)vector_get(&self->ecs->lists[COMPONENT_PLANE_OBJECT].components, i); + + physics = ecs_component_get(self->ecs, COMPONENT_PHYSICS, planeObject->component.id); + + glm_vec3_copy(physics->position, smokePosition); + + smokePosition[2] += ENTITY_TRAP_SMOKE_Z_OFFSET; + + entity_smoke_big_add + ( + self->ecs, + smokePosition + ); + + ecs_entity_delete(self->ecs, planeObject->component.id); + + i--; + } + + sound_play(&self->ecs->resources->sounds[SOUND_APPEAR]); +} + +void +_level_event_power_tick(Level* self) +{ + if (self->isMagnet) + { + ComponentCollect* collect; + + collect = ecs_component_get(self->ecs, COMPONENT_COLLECT, self->player); + + collect->circle.radius = PLAYER_COLLECT_RADIUS; + + self->isMagnet = false; + + } + + + if (self->settings.isPowerForesight) + { + if (control_released(self->ecs->control, CONTROL_FORESIGHT)) + { + ComponentPower* power; + + power = ecs_component_get(self->ecs, COMPONENT_POWER, self->player); + + if (power->value >= LEVEL_EVENT_FORESIGHT_POWER) + { + _level_event_foresight(self); + power->value -= LEVEL_EVENT_FORESIGHT_POWER; + } + } + } + + if (self->settings.isPowerCancel) + { + if (control_released(self->ecs->control, CONTROL_CANCEL)) + { + ComponentPower* power; + + power = ecs_component_get(self->ecs, COMPONENT_POWER, self->player); + + if (power->value >= LEVEL_EVENT_CANCEL_POWER) + { + _level_event_cancel(self); + power->value -= LEVEL_EVENT_CANCEL_POWER; + } + } + } + + if (self->settings.isPowerExtend) + { + if (control_released(self->ecs->control, CONTROL_EXTEND)) + { + ComponentPower* power; + + power = ecs_component_get(self->ecs, COMPONENT_POWER, self->player); + + if (power->value >= LEVEL_EVENT_EXTEND_POWER) + { + _level_event_extend(self); + power->value -= LEVEL_EVENT_EXTEND_POWER; + } + } + } + + + if (self->settings.isPowerMagnet) + { + if (control_released(self->ecs->control, CONTROL_MAGNET)) + { + ComponentPower* power; + + power = ecs_component_get(self->ecs, COMPONENT_POWER, self->player); + + if (power->value >= LEVEL_EVENT_MAGNET_POWER) + { + _level_event_magnet(self); + power->value -= LEVEL_EVENT_MAGNET_POWER; + } + } + } + + if (self->settings.isPowerInvigorate) + { + if (control_released(self->ecs->control, CONTROL_INVIGORATE)) + { + ComponentPower* power; + + power = ecs_component_get(self->ecs, COMPONENT_POWER, self->player); + + if (power->value >= LEVEL_EVENT_INVIGORATE_POWER) + { + _level_event_invigorate(self); + power->value -= LEVEL_EVENT_INVIGORATE_POWER; + } + } + } +} + +void +level_event_handle(Level* self) +{ + ComponentStamina* playerStamina; + ComponentPower* playerPower; + ComponentFood* playerFood; + ComponentFood* targetFood; + + switch (self->event) + { + case LEVEL_EVENT_ROTTEN_FOOD: + self->isRottenFood = true; + break; + case LEVEL_EVENT_STICKY_TRAPS: + _level_event_sticky_traps_set(self); + break; + case LEVEL_EVENT_BUTTERFINGERS: + playerFood = ecs_component_get(self->ecs, COMPONENT_FOOD, self->player); + playerFood->max = LEVEL_EVENT_BUTTERFINGERS_FOOD_MAX; + playerFood->value = MAX(playerFood->value, LEVEL_EVENT_BUTTERFINGERS_FOOD_MAX); + break; + case LEVEL_EVENT_OUT_OF_BREATH: + playerStamina = ecs_component_get(self->ecs, COMPONENT_STAMINA, self->player); + playerStamina->max = PLAYER_STAMINA_MAX * LEVEL_EVENT_OUT_OF_BREATH_STAMINA_MULTIPLIER; + break; + case LEVEL_EVENT_POWER_LEECH: + playerPower = ecs_component_get(self->ecs, COMPONENT_POWER, self->player); + playerPower->value = 0.0f; + break; + case LEVEL_EVENT_VIM_AND_VIGOR: + playerStamina = ecs_component_get(self->ecs, COMPONENT_STAMINA, self->player); + playerStamina->value = LEVEL_EVENT_VIM_AND_VIGOR_STAMINA_MAX; + playerStamina->max = LEVEL_EVENT_VIM_AND_VIGOR_STAMINA_MAX; + break; + case LEVEL_EVENT_GLUTTONY: + targetFood = ecs_component_get(self->ecs, COMPONENT_FOOD, self->target); + targetFood->multiplier = LEVEL_EVENT_GLUTTONY_FOOD_MULTIPLIER; + break; + case LEVEL_EVENT_ANCHOR_ARMS: + playerFood = ecs_component_get(self->ecs, COMPONENT_FOOD, self->player); + playerFood->max = LEVEL_EVENT_ANCHOR_ARMS_FOOD_MAX; + break; + case LEVEL_EVENT_NONE: + default: + break; + } +} + +void +level_event_return(Level* self) +{ + ComponentStamina* playerStamina; + ComponentPower* playerPower; + ComponentFood* playerFood; + ComponentFood* targetFood; + + switch (self->event) + { + case LEVEL_EVENT_ROTTEN_FOOD: + self->isRottenFood = false; + break; + case LEVEL_EVENT_STICKY_TRAPS: + _level_event_sticky_traps_clear(self); + break; + case LEVEL_EVENT_ANCHOR_ARMS: + case LEVEL_EVENT_BUTTERFINGERS: + playerFood = ecs_component_get(self->ecs, COMPONENT_FOOD, self->player); + playerFood->max = PLAYER_FOOD_MAX; + break; + case LEVEL_EVENT_VIM_AND_VIGOR: + playerStamina = ecs_component_get(self->ecs, COMPONENT_STAMINA, self->player); + playerStamina->value = PLAYER_STAMINA_MAX; + playerStamina->max = PLAYER_STAMINA_MAX; + break; + case LEVEL_EVENT_OUT_OF_BREATH: + playerStamina = ecs_component_get(self->ecs, COMPONENT_STAMINA, self->player); + playerStamina->max = PLAYER_STAMINA_MAX; + break; + case LEVEL_EVENT_GLUTTONY: + targetFood = ecs_component_get(self->ecs, COMPONENT_FOOD, self->target); + targetFood->multiplier = TARGET_FOOD_MULTIPLIER; + break; + case LEVEL_EVENT_NONE: + case LEVEL_EVENT_POWER_LEECH: + default: + break; + } +} + +void +_level_event_timer_init(Level* self) +{ + ecs_entity_delete(self->ecs, self->eventTimer); + + self->eventTimer = entity_timer_add + ( + self->ecs, + self->settings.eventTime + ); + + level_ui_event_timer_init(self); +} + +void +_level_event_set(Level* self) +{ + char* string; + LevelEvent event; + + level_event_return(self); + + if (self->nextEvent == LEVEL_EVENT_POWER_LEECH && !self->settings.isPower) + self->nextEvent = LEVEL_EVENT_NONE; + + self->event = self->nextEvent; + + string = STRING_LEVEL_EVENTS[self->nextEvent]; + + sound_play(&self->ecs->resources->sounds[SOUND_EVENT]); + + level_text_queue_add(self, string); + + level_event_handle(self); + + _level_event_timer_init(self); + + self->nextEvent = RANDOM_S32(LEVEL_EVENT_NONE, LEVEL_EVENT_COUNT - 1); +} + +void +level_event_init(Level* self) +{ + ComponentTimer* eventTimer; + + _level_event_timer_init(self); + + eventTimer = ecs_component_get(self->ecs, COMPONENT_TIMER, self->eventTimer); + + eventTimer->component.isDisabled = true; + + self->nextEvent = RANDOM_S32(LEVEL_EVENT_NONE, LEVEL_EVENT_COUNT - 1); +} + +void +level_event_tick(Level* self) +{ + ComponentTimer* eventTimer; + + eventTimer = ecs_component_get(self->ecs, COMPONENT_TIMER, self->eventTimer); + + if (eventTimer->isFinished) + _level_event_set(self); + + _level_event_power_tick(self); +} diff --git a/src/game/state/level/event.h b/src/game/state/level/event.h new file mode 100644 index 0000000..06e9738 --- /dev/null +++ b/src/game/state/level/event.h @@ -0,0 +1,68 @@ +#pragma once + +#include "text_queue.h" +#include "ui.h" + +#define LEVEL_EVENT_OUT_OF_BREATH_STAMINA_MULTIPLIER 0.5f +#define LEVEL_EVENT_VIM_AND_VIGOR_STAMINA_MAX 10000.0f +#define LEVEL_EVENT_ANCHOR_ARMS_FOOD_MAX 50 +#define LEVEL_EVENT_BUTTERFINGERS_FOOD_MAX 10 +#define LEVEL_EVENT_GLUTTONY_FOOD_MULTIPLIER 2; +#define LEVEL_EVENT_FORESIGHT_POWER 25.0f +#define LEVEL_EVENT_CANCEL_POWER 25.0f +#define LEVEL_EVENT_EXTEND_POWER 25.0f +#define LEVEL_EVENT_INVIGORATE_POWER 25.0f +#define LEVEL_EVENT_MAGNET_POWER 25.0f +#define LEVEL_EVENT_PLAYER_POWER_COLOR_CHANGE_TIME 60 +#define LEVEL_EVENT_POWER_MAGNET_RADIUS 3000.0f +#define LEVEL_EVENT_POWER_EXTEND_TIME 300 +#define LEVEL_EVENT_STICKY_TRAPS_MIN 5 +#define LEVEL_EVENT_STICKY_TRAPS_MAX 10 +#define ENTITY_TRAP_SMOKE_Z_OFFSET -0.01f + +static const vec4 LEVEL_EVENT_PLAYER_POWER_COLOR = {0.60f, 1.0f, 0.80f, 0.0f}; +static const vec4 LEVEL_EVENT_STICKY_TRAPS_BOUNDS = {350.0f, 350.0f, 6300.0f, 3000.0f}; + +#define STRING_LEVEL_EVENT_CANCEL "Next event cancelled!" +#define STRING_LEVEL_EVENT_EXTEND "The current event has been extended!" +#define STRING_LEVEL_EVENT_INVIGORATE "Stamina replenished!" +#define STRING_LEVEL_EVENT_MAGNET "Magnet activated!" + +static const char* STRING_LEVEL_EVENTS[LEVEL_EVENT_COUNT] = +{ + "Event: None | Nothing happens...", + "Event: Rotten Food | Don't collect the yucky food!", + "Event: Sticky Traps | Watch out for the slowing traps!", + "Event: Butterfingers | You can't carry as much food!", + "Event: Out of Breath | Your stamina maximum is halved!", + "Event: Power Leech | The power has been sapped out of you!", + "Event: Vim and Vigor | You have infinite stamina!", + "Event: Gluttony | Giving food to your mistress will double its value!", + "Event: Anchor Arms | You can carry more food!" +}; + +static const char* STRING_LEVEL_EVENT_FORESIGHTS[LEVEL_EVENT_COUNT] = +{ + "You feel that you may have wasted your foresight...", + "You sniff the scent of rotting food...", + "You feel the need to watch your step...", + "You feel your grip will be loosened...", + "You feel an oncoming bout of tiredness...", + "You feel the power within you is fleeting...", + "You sense an oncoming sensation of great energy...", + "You hear the distant rumbles of your mistress' belly...", + "You feel your grip will be strengthened..." +}; + +static const Rectangle LEVEL_EVENT_STICKY_TRAPS_NO_NO_RECTANGLE = +{ + .x = 2500.0f, + .y = 1400.0f, + .w = 1800.0f, + .h = 1400.0f +}; + +void level_event_init(Level* self); +void level_event_tick(Level* self); +void level_event_handle(Level* self); +void level_event_return(Level* self); diff --git a/src/game/state/level/level.c b/src/game/state/level/level.c new file mode 100644 index 0000000..ac182f9 --- /dev/null +++ b/src/game/state/level/level.c @@ -0,0 +1,320 @@ +#include "level.h" + +static void _level_entity_init(Level* self); +static void _level_finish(Level* self); +static void _level_finish_text_add(Level* self); +static void _level_finish_amulet_spawn(Level* self); + +static void +_level_finish_text_add(Level* self) +{ + char string[LEVEL_FINISH_STRING_MAX]; + char* medalString; + char* completeString; + ComponentFood* targetFood; + bool isFail; + + isFail = false; + + switch (self->medal) + { + + case LEVEL_MEDAL_BRONZE: + medalString = STRING_LEVEL_MEDAL_BRONZE; + break; + case LEVEL_MEDAL_SILVER: + medalString = STRING_LEVEL_MEDAL_SILVER; + break; + case LEVEL_MEDAL_GOLD: + medalString = STRING_LEVEL_MEDAL_GOLD; + break; + case LEVEL_MEDAL_NONE: + default: + medalString = STRING_LEVEL_MEDAL_NONE; + isFail = true; + break; + } + + if (isFail) + { + snprintf + ( + string, + LEVEL_FINISH_STRING_MAX, + LEVEL_FINISH_TEXT_FAILED_FORMAT, + STRING_LEVEL_FAILED, + medalString, + self->score + ); + } + else + { + u32 milliseconds; + u32 minutes; + u32 seconds; + + time_formatted_get(self->timeToMedal, &minutes, &seconds, &milliseconds); + + snprintf + ( + string, + LEVEL_FINISH_STRING_MAX, + LEVEL_FINISH_TEXT_FORMAT, + STRING_LEVEL_COMPLETE, + medalString, + minutes, + seconds, + milliseconds, + self->score + ); + } + + level_text_queue_clear(self); + level_text_queue_add(self, string); + +} + +static void +_level_finish(Level* self) +{ + ComponentTimer* finishTimer; + ComponentFood* playerFood; + ComponentFood* targetFood; + ComponentStage* targetStage; + + finishTimer = ecs_component_get(self->ecs, COMPONENT_TIMER, self->finishTimer); + playerFood = ecs_component_get(self->ecs, COMPONENT_FOOD, self->player); + targetFood = ecs_component_get(self->ecs, COMPONENT_FOOD, self->target); + targetStage = ecs_component_get(self->ecs, COMPONENT_STAGE, self->target); + + playerFood->value = 0; + + finishTimer->component.isDisabled = false; + + if (self->settings.isEvent) + { + ComponentTimer* eventTimer; + + eventTimer = ecs_component_get(self->ecs, COMPONENT_TIMER, self->eventTimer); + + eventTimer->component.isDisabled = true; + } + + self->isTimerDone = true; + self->score = targetFood->value; + + if (self->medal >= LEVEL_MEDAL_BRONZE) + self->isComplete = true; + + if (self->isComplete) + { + if ((s32)targetStage->value < TARGET_ATLAS_SIZE[0] - 1) + { + targetStage->value++; + sound_play(&self->ecs->resources->sounds[SOUND_GURGLE + RANDOM_S32(0, SOUND_GURGLE_COUNT - 1)]); + } + } + + sound_play(&self->ecs->resources->sounds[SOUND_FINISH]); + music_play(&self->ecs->resources->music[MUSIC_WIND], true); + + entity_text_disappearing_add + ( + self->ecs, + &self->ecs->resources->fonts[FONT_BIG], + RENDERER_BUFFER_UI, + STRING_LEVEL_FINISH, + LEVEL_FINISH_TEXT_POSITION, + -1, + LEVEL_FINISH_TEXT_VALUE + ); + + level_event_return(self); + + level_collectible_spawn_clear(self); + + _level_finish_text_add(self); +} + +static void +_level_finish_amulet_spawn(Level* self) +{ + ComponentPhysics* physics; + vec3 smokePosition; + + self->amulet = entity_collectible_amulet_add + ( + self->ecs, + LEVEL_AMULET_POSITION + ); + + physics = ecs_component_get(self->ecs, COMPONENT_PHYSICS, self->amulet); + + glm_vec3_copy(physics->position, smokePosition); + + smokePosition[2] += 0.001f; + + entity_smoke_big_add + ( + self->ecs, + smokePosition + ); + +} + +static void +_level_entity_init(Level* self) +{ + ComponentTimer* finishTimer; + + self->bg = entity_sprite_add + ( + self->ecs, + &self->ecs->resources->textures[TEXTURE_GAME_BG], + RENDERER_BUFFER_BACKGROUND, + ORIGIN_TOP_LEFT, + (f32*)LEVEL_BG_SIZE, + (f32*)LEVEL_BG_POSITION + ); + + self->plane = entity_sprite_add + ( + self->ecs, + &self->ecs->resources->textures[TEXTURE_GAME_PLANE], + RENDERER_BUFFER_WORLD, + ORIGIN_TOP_LEFT, + (f32*)LEVEL_PLANE_SIZE, + (f32*)LEVEL_PLANE_POSITION + ); + + self->timer = entity_timer_add + ( + self->ecs, + self->settings.time + ); + + self->finishTimer = entity_timer_add + ( + self->ecs, + LEVEL_FINISH_TIMER_VALUE + ); + + finishTimer = ecs_component_get(self->ecs, COMPONENT_TIMER, self->finishTimer); + finishTimer->component.isDisabled = true; + + self->player = entity_player_add + ( + self->ecs, + LEVEL_PLAYER_POSITION + ); + + self->target = entity_target_add + ( + self->ecs, + LEVEL_TARGET_POSITION, + self->settings.medalThresholds[0], + self->levelValue, + self->player + ); +} + +void +level_init(Level* self, ECS* ecs, LevelSettings settings, u32 levelValue) +{ + memset(self, '\0', sizeof(Level)); + + self->ecs = ecs; + + level_pause_init(self); + level_unpause(self); + + self->settings = settings; + self->medal = LEVEL_MEDAL_NONE; + self->nextMedal = LEVEL_MEDAL_BRONZE; + self->timerValue = 0; + self->levelValue = levelValue; + self->isCountdownDone = false; + + _level_entity_init(self); + + if (self->settings.isEvent) + level_event_init(self); + + level_ui_init(self); + + level_text_queue_init(self); + level_countdown_init(self); + + level_collectible_spawn_init(self); + + glm_vec4_copy(settings.colorCover, self->ecs->postprocessing[RENDERER_BUFFER_WORLD].colorCover); + glm_vec4_copy(settings.colorCover, self->ecs->postprocessing[RENDERER_BUFFER_BACKGROUND].colorCover); + + music_play(&self->ecs->resources->music[MUSIC_WIND], true); +} + +void +level_tick(Level* self) +{ + ComponentTimer* timer; + ComponentTimer* finishTimer; + + level_collectible_spawn_tick(self); + level_countdown_tick(self); + level_text_queue_tick(self); + level_pause_tick(self); + + if (self->settings.isEvent && !self->isTimerDone && self->isCountdownDone) + level_event_tick(self); + + timer = ecs_component_get(self->ecs, COMPONENT_TIMER, self->timer); + + self->timerValue = timer->value; + + level_ui_tick(self); + + if + ( + (!timer->isFinished && timer->value <= LEVEL_TIMER_LOW_TICK_THRESHOLD) && + self->isCountdownDone + ) + { + if (timer->value % SECOND_TICK == 0) + sound_play(&self->ecs->resources->sounds[SOUND_LOW_TIMER_TICK]); + } + + if (!timer->isFinished) + return; + + if (timer->isFinished && !self->isTimerDone) + _level_finish(self); + + if (self->settings.isAmulet) + { + if (!self->isAmuletSpawn) + { + _level_finish_amulet_spawn(self); + self->isAmuletSpawn = true; + } + else + { + if (self->ecs->lists[COMPONENT_COLLECTIBLE].components.count == 0) + self->isFinished = true; + } + } + else + { + + finishTimer = ecs_component_get(self->ecs, COMPONENT_TIMER, self->finishTimer); + + if (finishTimer->isFinished) + self->isFinished = true; + } +} + +void +level_free(Level* self) +{ + level_text_queue_free(self); +} + diff --git a/src/game/state/level/level.h b/src/game/state/level/level.h new file mode 100644 index 0000000..7bbf7f7 --- /dev/null +++ b/src/game/state/level/level.h @@ -0,0 +1,38 @@ +#pragma once + +#include "event.h" +#include "countdown.h" +#include "collectible_spawn.h" +#include "tutorial.h" +#include "pause.h" + +static const vec3 LEVEL_TRAP_POSITION = {2500.0f, 1000.0f, 0.0f}; +static const vec3 LEVEL_PLAYER_POSITION = {3275.0f, 2400.0f, 0.0f}; +static const vec3 LEVEL_TARGET_POSITION = {3275.0f, 1625.0f, 0.0f}; +static const vec3 LEVEL_PLANE_POSITION = {250.0f, 250.0f, 1.0f}; +static const vec3 LEVEL_PLANE_SIZE = {6300.0f, 3100.0f, 0.0f}; +static const vec3 LEVEL_BG_POSITION = {0.0f, 00.0f, 1.0f}; +static const vec3 LEVEL_BG_SIZE = {1280.0f, 720.0f, 0.0f}; + +static const f32 LEVEL_FINISH_TEXT_VALUE = 60; +static const vec3 LEVEL_FINISH_TEXT_POSITION = {600.0f, 300.0f, 0.0f}; +static const vec3 LEVEL_AMULET_POSITION = {6000.0f, 3200.0f, 0.0f}; + +#define LEVEL_FINISH_TIMER_VALUE 600 +#define LEVEL_TIMER_LOW_TICK_THRESHOLD 600 +#define LEVEL_FINISH_STRING_MAX 255 + +#define LEVEL_FINISH_TEXT_FORMAT "%s | Medal: %s | Medal time: %i'%02i\"%02i | Score: %i" +#define LEVEL_FINISH_TEXT_FAILED_FORMAT "%s | Medal: %s | Medal time: -\'--\"-- | Score: %i" + +#define STRING_LEVEL_FAILED "Level failed..." +#define STRING_LEVEL_COMPLETE "Level complete!" +#define STRING_LEVEL_MEDAL_GOLD "Gold" +#define STRING_LEVEL_MEDAL_SILVER "Silver" +#define STRING_LEVEL_MEDAL_BRONZE "Bronze" +#define STRING_LEVEL_MEDAL_NONE "None" +#define STRING_LEVEL_FINISH "FINISH!" + +void level_init(Level* self, ECS* ecs, LevelSettings settings, u32 levelValue); +void level_tick(Level* self); +void level_free(Level* self); diff --git a/src/game/state/level/pause.c b/src/game/state/level/pause.c new file mode 100644 index 0000000..1a03745 --- /dev/null +++ b/src/game/state/level/pause.c @@ -0,0 +1,88 @@ +#include "pause.h" + +void +level_pause_init(Level* self) +{ + self->isPaused = false; +} + +void +level_pause(Level* self) +{ + ComponentText* pauseText; + ComponentText* pauseTipText; + + self->pauseText = entity_text_add + ( + self->ecs, + &self->ecs->resources->fonts[FONT_BIG], + RENDERER_BUFFER_UI, + STRING_LEVEL_PAUSE, + LEVEL_PAUSE_TEXT_POSITION, + -1 + ); + + self->pauseTipText = entity_text_add + ( + self->ecs, + &self->ecs->resources->fonts[FONT_SMALL], + RENDERER_BUFFER_UI, + STRING_LEVEL_PAUSE_TIP, + LEVEL_PAUSE_TIP_TEXT_POSITION, + -1 + ); + + pauseText = ecs_component_get(self->ecs, COMPONENT_TEXT, self->pauseText); + pauseTipText = ecs_component_get(self->ecs, COMPONENT_TEXT, self->pauseTipText); + + glm_vec4_copy(OPAQUE, pauseText->color); + glm_vec4_copy(OPAQUE, pauseTipText->color); + + component_text_tick(pauseText, self->ecs); + component_text_tick(pauseTipText, self->ecs); + + self->ecs->isFunctionDisabled[ECS_FUNCTION_TICK] = true; + self->ecs->isFunctionDisabled[ECS_FUNCTION_UPDATE] = true; + + glm_vec3_copy(LEVEL_PAUSE_COLOR, self->ecs->postprocessing[RENDERER_BUFFER_WORLD].color); + glm_vec3_copy(LEVEL_PAUSE_COLOR, self->ecs->postprocessing[RENDERER_BUFFER_BACKGROUND].color); +} + +void +level_unpause(Level* self) +{ + ComponentText* pauseText; + ComponentText* pauseTipText; + + if (self->isPaused) + { + ecs_entity_delete(self->ecs, self->pauseText); + ecs_entity_delete(self->ecs, self->pauseTipText); + } + + self->ecs->isFunctionDisabled[ECS_FUNCTION_TICK] = false; + self->ecs->isFunctionDisabled[ECS_FUNCTION_UPDATE] = false; + + glm_vec3_copy(OPAQUE, self->ecs->postprocessing[RENDERER_BUFFER_WORLD].color); + glm_vec3_copy(OPAQUE, self->ecs->postprocessing[RENDERER_BUFFER_BACKGROUND].color); +} + +void +level_pause_tick(Level* self) +{ + if (control_pressed(self->ecs->control, CONTROL_PAUSE)) + { + if (!self->isPaused) + { + level_pause(self); + sound_play(&self->ecs->resources->sounds[SOUND_PAUSE]); + } + else + { + level_unpause(self); + sound_play(&self->ecs->resources->sounds[SOUND_UNPAUSE]); + } + + self->isPaused = !self->isPaused; + } +} diff --git a/src/game/state/level/pause.h b/src/game/state/level/pause.h new file mode 100644 index 0000000..cd15ed2 --- /dev/null +++ b/src/game/state/level/pause.h @@ -0,0 +1,23 @@ +#pragma once + +#include "LEVEL_COMMON.h" + +static const vec4 LEVEL_PAUSE_COLOR = {0.5f, 0.5f, 0.5f, 1.0f}; +static const vec3 LEVEL_PAUSE_TEXT_POSITION = {575.0f, 300.0f, 0.0f}; +static const vec3 LEVEL_PAUSE_TIP_TEXT_POSITION = {500.0f, 350.0f, 0.0f}; + +#define STRING_LEVEL_PAUSE "PAUSED" +#define STRING_LEVEL_PAUSE_TIP "R - Retry | ESC - Title Screen" + +#define LEVEL_PAUSE_COMPONENTS_COUNT 3 +static const ComponentType LEVEL_PAUSE_COMPONENTS[LEVEL_PAUSE_COMPONENTS_COUNT] = +{ + COMPONENT_WORLD_OBJECT, + COMPONENT_PHYSICS, + COMPONENT_TIMER +}; + +void level_pause_tick(Level* self); +void level_pause(Level* self); +void level_pause_init(Level* self); +void level_unpause(Level* self); diff --git a/src/game/state/level/text_queue.c b/src/game/state/level/text_queue.c new file mode 100644 index 0000000..7924390 --- /dev/null +++ b/src/game/state/level/text_queue.c @@ -0,0 +1,102 @@ +#include "text_queue.h" + +void level_text_queue_set(Level* self); +void level_text_queue_add(Level* self, const char* string); +void level_text_queue_clear(Level* self); + +void +level_text_queue_set(Level* self) +{ + self->ecs->isLog = false; + + for (s32 i = 0; i < (s32)self->textQueue.count; i++) + { + EntityID* id; + ComponentDeleteOnTimer* deleteOnTimer; + + id = vector_get(&self->textQueue, i); + + deleteOnTimer = ecs_component_get(self->ecs, COMPONENT_DELETE_ON_TIMER, *id); + + if (!deleteOnTimer) + { + vector_remove(&self->textQueue, i); + i--; + } + } + + self->ecs->isLog = true; + + for (s32 i = 0; i < (s32)self->textQueue.count; i++) + { + EntityID* id; + ComponentText* text; + + id = vector_get(&self->textQueue, i); + + text = ecs_component_get(self->ecs, COMPONENT_TEXT, *id); + + glm_vec3_copy(LEVEL_TEXT_QUEUE_POSITION, text->position); + + text->position[1] -= self->ecs->resources->fonts[FONT_SMALL].size * i; + } +} + +void +level_text_queue_clear(Level* self) +{ + self->ecs->isLog = false; + + for (s32 i = 0; i < (s32)self->textQueue.count; i++) + { + EntityID* id; + + id = vector_get(&self->textQueue, i); + + if (id) + ecs_entity_delete(self->ecs, *id); + } + + vector_clear(&self->textQueue); + + self->ecs->isLog = true; +} + +void +level_text_queue_add(Level* self, const char* string) +{ + EntityID id; + + id = entity_text_disappearing_add + ( + self->ecs, + &self->ecs->resources->fonts[FONT_SMALL], + RENDERER_BUFFER_UI, + string, + LEVEL_TEXT_QUEUE_POSITION, + -1, + LEVEL_TEXT_QUEUE_TIMER + ); + + vector_push(&self->textQueue, &id); + + level_text_queue_set(self); +} + +void +level_text_queue_init(Level* self) +{ + vector_init(&self->textQueue, sizeof(EntityID)); +} + +void +level_text_queue_tick(Level* self) +{ + level_text_queue_set(self); +} + +void +level_text_queue_free(Level* self) +{ + vector_free(&self->textQueue); +} diff --git a/src/game/state/level/text_queue.h b/src/game/state/level/text_queue.h new file mode 100644 index 0000000..c8afe73 --- /dev/null +++ b/src/game/state/level/text_queue.h @@ -0,0 +1,13 @@ +#pragma once + +#include "LEVEL_COMMON.h" + +static const f32 LEVEL_TEXT_QUEUE_TIMER = 1500; +static const vec3 LEVEL_TEXT_QUEUE_POSITION = {25.0f, 675.0f, 0.0f}; + +void level_text_queue_set(Level* self); +void level_text_queue_add(Level* self, const char* string); +void level_text_queue_clear(Level* self); +void level_text_queue_init(Level* self); +void level_text_queue_tick(Level* self); +void level_text_queue_free(Level* self); diff --git a/src/game/state/level/tutorial.c b/src/game/state/level/tutorial.c new file mode 100644 index 0000000..10c02df --- /dev/null +++ b/src/game/state/level/tutorial.c @@ -0,0 +1,39 @@ +#include "tutorial.h" + +void +level_tutorial_init(Level* self) +{ + if (self->settings.isTutorialFinal) + level_text_queue_add(self, LEVEL_STRING_TUTORIAL_FINAL); + + if (self->settings.isTutorialEvent) + level_text_queue_add(self, LEVEL_STRING_TUTORIAL_EVENT); + + if (self->settings.isTutorialPowerInvigorate) + level_text_queue_add(self, LEVEL_STRING_TUTORIAL_POWER_INVIGORATE); + + if (self->settings.isTutorialPowerCancel) + level_text_queue_add(self, LEVEL_STRING_TUTORIAL_POWER_CANCEL); + + if (self->settings.isTutorialPowerForesight) + level_text_queue_add(self, LEVEL_STRING_TUTORIAL_POWER_FORESIGHT); + + if (self->settings.isTutorialPowerExtend) + level_text_queue_add(self, LEVEL_STRING_TUTORIAL_POWER_EXTEND); + + if (self->settings.isTutorialPowerMagnet) + level_text_queue_add(self, LEVEL_STRING_TUTORIAL_POWER_MAGNET); + + if (self->settings.isTutorialPower) + level_text_queue_add(self, LEVEL_STRING_TUTORIAL_POWER); + + if (self->settings.isTutorialFood) + level_text_queue_add(self, LEVEL_STRING_TUTORIAL_FOOD); + + if (self->settings.isTutorialStamina) + level_text_queue_add(self, LEVEL_STRING_TUTORIAL_STAMINA); + + if (self->settings.isTutorialMove) + level_text_queue_add(self, LEVEL_STRING_TUTORIAL_MOVE); + +} diff --git a/src/game/state/level/tutorial.h b/src/game/state/level/tutorial.h new file mode 100644 index 0000000..ee7091c --- /dev/null +++ b/src/game/state/level/tutorial.h @@ -0,0 +1,18 @@ +#pragma once + +#include "text_queue.h" + +#define LEVEL_STRING_TUTORIAL_MOVE "Move around with the mouse." +#define LEVEL_STRING_TUTORIAL_STAMINA "Right click to use stamina to lunge in a direction for a quick boost. Replenish it with the red pickups." +#define LEVEL_STRING_TUTORIAL_FOOD "Get all the food you can hold and return to your mistress to feed her. Collect all food to spawn more!" +#define LEVEL_STRING_TUTORIAL_EVENT "Unexpected events may now occur. Be aware!" +#define LEVEL_STRING_TUTORIAL_POWER "The amulet unlocks new powers within. Replenish it with the green pickups." +#define LEVEL_STRING_TUTORIAL_POWER_INVIGORATE "The amulet grants you a new power! Press 1 to use some power to regain stamina." +#define LEVEL_STRING_TUTORIAL_POWER_EXTEND "The amulet grants you a new power! Press 2 to use some power to extend the current event." +#define LEVEL_STRING_TUTORIAL_POWER_FORESIGHT "The amulet grants you a new power! Press 3 to use some power to foresee the forthcoming event." +#define LEVEL_STRING_TUTORIAL_POWER_CANCEL "The amulet grants you a new power! Press 4 to use some power to cancel the forthcoming event." +#define LEVEL_STRING_TUTORIAL_POWER_MAGNET "The amulet grants you a new power! Press 5 to use some power to attract a lot of food close to you." +#define LEVEL_STRING_TUTORIAL_FINAL "This is the final level! Good luck!" +#define LEVEL_STRING_COUNTDOWN_SKIP "Press SPACE to skip countdown..." + +void level_tutorial_init(Level* self); diff --git a/src/game/state/level/ui.c b/src/game/state/level/ui.c new file mode 100644 index 0000000..aacb5f1 --- /dev/null +++ b/src/game/state/level/ui.c @@ -0,0 +1,179 @@ +#include "ui.h" + +void _level_ui_threshold_tick(Level* self); + +void +level_ui_event_timer_init(Level* self) +{ + if (self->eventTimerUI != 0) + ecs_entity_delete(self->ecs, self->eventTimerUI); + + self->eventTimerUI = entity_value_text_add + ( + self->ecs, + &self->ecs->resources->fonts[FONT_SMALL], + LEVEL_EVENT_TIMER_BUFFER, + LEVEL_EVENT_TIMER_POSITION, + LEVEL_EVENT_TIMER_COMPONENT_TYPE, + LEVEL_EVENT_TIMER_VALUE_TEXT_TYPE, + LEVEL_EVENT_TIMER_FORMAT, + self->eventTimer + ); +} + +void +_level_ui_threshold_tick(Level* self) +{ + ComponentFood* food; + + if (self->medal == LEVEL_MEDAL_GOLD) + return; + + food = ecs_component_get(self->ecs, COMPONENT_FOOD, self->target); + + for (s32 i = 0; i < (LEVEL_MEDAL_COUNT - 1); i++) + { + u32 thresholdValue; + u32 medal; + + medal = (LEVEL_MEDAL_COUNT - 1) - i; + + thresholdValue = self->settings.medalThresholds[medal - 1]; + + if (food->value >= (s32)thresholdValue) + { + ComponentAtlas* medalAtlas; + ComponentThreshold* threshold; + + self->medal = medal; + + if (self->nextMedal <= self->medal) + { + switch(self->medal) + { + case (LEVEL_MEDAL_GOLD): + level_text_queue_add(self, STRING_LEVEL_GOLD); + sound_play(&self->ecs->resources->sounds[SOUND_GOLD]); + break; + case (LEVEL_MEDAL_SILVER): + level_text_queue_add(self, STRING_LEVEL_SILVER); + sound_play(&self->ecs->resources->sounds[SOUND_SILVER]); + break; + case (LEVEL_MEDAL_BRONZE): + level_text_queue_add(self, STRING_LEVEL_BRONZE); + sound_play(&self->ecs->resources->sounds[SOUND_BRONZE]); + break; + default: + break; + } + + self->timeToMedal = self->settings.time - self->timerValue; + } + else + return; + + self->nextMedal = self->medal + 1; + + self->nextMedal = MAX(self->nextMedal, LEVEL_MEDAL_GOLD); + + medalAtlas = ecs_component_get(self->ecs, COMPONENT_ATLAS, self->medalUI); + threshold = ecs_component_get(self->ecs, COMPONENT_THRESHOLD, self->target); + + threshold->value = self->settings.medalThresholds[self->nextMedal - 1]; + medalAtlas->index = self->nextMedal - 1; + + break; + } + } +} + +void +level_ui_init(Level* self) +{ + self->cursor = entity_cursor_add(self->ecs); + + self->playerFoodUI = entity_value_text_add + ( + self->ecs, + &self->ecs->resources->fonts[FONT_DEFAULT], + LEVEL_PLAYER_FOOD_UI_BUFFER, + LEVEL_PLAYER_FOOD_UI_POSITION, + LEVEL_PLAYER_FOOD_UI_COMPONENT_TYPE, + LEVEL_PLAYER_FOOD_UI_VALUE_TEXT_TYPE, + LEVEL_PLAYER_FOOD_UI_FORMAT, + self->player + ); + + self->targetFoodUI = entity_value_text_add + ( + self->ecs, + &self->ecs->resources->fonts[FONT_DEFAULT], + LEVEL_TARGET_FOOD_UI_BUFFER, + LEVEL_TARGET_FOOD_UI_POSITION, + LEVEL_TARGET_FOOD_UI_COMPONENT_TYPE, + LEVEL_TARGET_FOOD_UI_VALUE_TEXT_TYPE, + LEVEL_TARGET_FOOD_UI_FORMAT, + self->target + ); + + self->timerUI = entity_value_text_add + ( + self->ecs, + &self->ecs->resources->fonts[FONT_DEFAULT], + LEVEL_TIMER_BUFFER, + LEVEL_TIMER_POSITION, + LEVEL_TIMER_COMPONENT_TYPE, + LEVEL_TIMER_VALUE_TEXT_TYPE, + LEVEL_TIMER_FORMAT, + self->timer + ); + + self->thresholdUI = entity_value_text_add + ( + self->ecs, + &self->ecs->resources->fonts[FONT_SMALL], + LEVEL_THRESHOLD_UI_BUFFER, + LEVEL_THRESHOLD_UI_POSITION, + LEVEL_THRESHOLD_UI_COMPONENT_TYPE, + LEVEL_THRESHOLD_UI_VALUE_TEXT_TYPE, + LEVEL_THRESHOLD_UI_FORMAT, + self->target + ); + + self->medalUI = entity_medal_add + ( + self->ecs, + LEVEL_MEDAL_POSITION, + 0 + ); + + self->meterStamina = entity_meter_add + ( + self->ecs, + &self->ecs->resources->textures[TEXTURE_METER_STAMINA], + LEVEL_PLAYER_METER_STAMINA_POSITION, + COMPONENT_STAMINA, + self->player + ); + + if (self->settings.isPower) + { + self->meterPower = entity_meter_add + ( + self->ecs, + &self->ecs->resources->textures[TEXTURE_METER_POWER], + LEVEL_PLAYER_METER_POWER_POSITION, + COMPONENT_POWER, + self->player + ); + } + + if (self->settings.isEvent) + level_ui_event_timer_init(self); +} + +void +level_ui_tick(Level* self) +{ + _level_ui_threshold_tick(self); +} diff --git a/src/game/state/level/ui.h b/src/game/state/level/ui.h new file mode 100644 index 0000000..5f3c988 --- /dev/null +++ b/src/game/state/level/ui.h @@ -0,0 +1,41 @@ +#pragma once + +#include "text_queue.h" + +static const vec3 LEVEL_PLAYER_FOOD_UI_POSITION = {32.0f, 32.0f, 0.0f}; +static const vec3 LEVEL_PLAYER_METER_STAMINA_POSITION = {1050.0f, 675.0f, 0.0f}; +static const vec3 LEVEL_PLAYER_METER_POWER_POSITION = {1050.0f, 630.0f, 0.0f}; +static const vec3 LEVEL_TARGET_FOOD_UI_POSITION = {1200.0f, 32.0f, 0.0f}; +static const vec3 LEVEL_THRESHOLD_UI_POSITION = {1200.0f, 64.0f, 0.0f}; +static const vec3 LEVEL_MEDAL_POSITION = {1175.0f, 75.0f, 0.0f}; +static const vec3 LEVEL_TIMER_POSITION = {600.0f, 32.0f, 0.0f}; +static const vec3 LEVEL_EVENT_TIMER_POSITION = {575.0f, 64.0f, 0.0f}; + +#define LEVEL_TIMER_FORMAT "%i'%02i\"%02i" +#define LEVEL_EVENT_TIMER_FORMAT "Event: %i'%02i\"%02i" +#define LEVEL_PLAYER_FOOD_UI_FORMAT "%i/%i" +#define LEVEL_TARGET_FOOD_UI_FORMAT "%i" +#define LEVEL_THRESHOLD_UI_FORMAT "%i" +#define LEVEL_TIMER_BUFFER RENDERER_BUFFER_UI +#define LEVEL_EVENT_TIMER_BUFFER RENDERER_BUFFER_UI +#define LEVEL_PLAYER_FOOD_UI_BUFFER RENDERER_BUFFER_UI +#define LEVEL_TARGET_FOOD_UI_BUFFER RENDERER_BUFFER_UI +#define LEVEL_THRESHOLD_UI_BUFFER RENDERER_BUFFER_UI +#define LEVEL_TIMER_VALUE_TEXT_TYPE COMPONENT_VALUE_TEXT_TYPE_TIMER +#define LEVEL_EVENT_TIMER_VALUE_TEXT_TYPE COMPONENT_VALUE_TEXT_TYPE_TIMER +#define LEVEL_PLAYER_FOOD_UI_VALUE_TEXT_TYPE COMPONENT_VALUE_TEXT_TYPE_INTEGER_MAX +#define LEVEL_TARGET_FOOD_UI_VALUE_TEXT_TYPE COMPONENT_VALUE_TEXT_TYPE_INTEGER +#define LEVEL_THRESHOLD_UI_VALUE_TEXT_TYPE COMPONENT_VALUE_TEXT_TYPE_INTEGER +#define LEVEL_TIMER_COMPONENT_TYPE COMPONENT_TIMER +#define LEVEL_EVENT_TIMER_COMPONENT_TYPE COMPONENT_TIMER +#define LEVEL_THRESHOLD_UI_COMPONENT_TYPE COMPONENT_THRESHOLD +#define LEVEL_PLAYER_FOOD_UI_COMPONENT_TYPE COMPONENT_FOOD +#define LEVEL_TARGET_FOOD_UI_COMPONENT_TYPE COMPONENT_FOOD + +#define STRING_LEVEL_GOLD "You got the gold medal! Keep going for a high score!" +#define STRING_LEVEL_SILVER "You got the silver medal!" +#define STRING_LEVEL_BRONZE "You got the bronze medal! Level completed!" + +void level_ui_init(Level* self); +void level_ui_tick(Level* self); +void level_ui_event_timer_init(Level* self); diff --git a/src/game/state/state.c b/src/game/state/state.c new file mode 100644 index 0000000..cfb83c9 --- /dev/null +++ b/src/game/state/state.c @@ -0,0 +1,237 @@ +#include "state.h" + +static void _state_set(State* self, StateType type); +static void _state_level_tick(State* self, LevelType type); + +static void +_state_level_tick(State* self, LevelType type) +{ + level_tick(&self->states.level); + + if (self->states.level.isPaused) + { + if (control_released(self->ecs->control, CONTROL_RETRY)) + _state_set(self, self->type); + + if (control_released(self->ecs->control, CONTROL_ESCAPE)) + { + level_unpause(&self->states.level); + _state_set(self, STATE_TITLE); + } + } + + if (self->states.level.isFinished) + { + if (self->states.level.medal > LEVEL_MEDAL_NONE) + self->levelData[type].status = LEVEL_STATUS_LOCKED + self->states.level.medal; + + self->levelData[type].time = self->states.level.timeToMedal; + self->levelData[type].score = self->states.level.score; + + if (self->states.level.isComplete && type < LEVEL_FIVE) + { + if (self->levelData[type + 1].status == LEVEL_STATUS_LOCKED) + self->levelData[type + 1].status = LEVEL_STATUS_UNLOCKED; + } + + if (type < LEVEL_FIVE) + _state_set(self, STATE_TITLE); + else + _state_set(self, STATE_CUTSCENE_FINAL); + } +} + +static void +_state_set(State* self, StateType type) +{ + state_free(self); + + self->type = type; + + for (s32 i = 0; i < RENDERER_BUFFER_COUNT; i++) + postprocessing_init(&self->ecs->postprocessing[i], OPAQUE, TRANSPARENT); + + switch (self->type) + { + case STATE_TITLE: + title_init(&self->states.title, self->ecs, (LevelData*)self->levelData, LEVEL_COUNT); + break; + case STATE_CUTSCENE_ONE: + cutscene_init(&self->states.cutscene, self->ecs, CUTSCENE_ONE); + break; + case STATE_CUTSCENE_TWO: + cutscene_init(&self->states.cutscene, self->ecs, CUTSCENE_TWO); + break; + case STATE_CUTSCENE_THREE: + cutscene_init(&self->states.cutscene, self->ecs, CUTSCENE_THREE); + break; + case STATE_CUTSCENE_FOUR: + cutscene_init(&self->states.cutscene, self->ecs, CUTSCENE_FOUR); + break; + case STATE_CUTSCENE_FIVE: + cutscene_init(&self->states.cutscene, self->ecs, CUTSCENE_FIVE); + break; + case STATE_CUTSCENE_FINAL: + cutscene_init(&self->states.cutscene, self->ecs, CUTSCENE_FINAL); + break; + case STATE_ENDING: + ending_init(&self->states.ending, self->ecs); + break; + case STATE_LEVEL_ONE: + level_init(&self->states.level, self->ecs, LEVEL_SETTINGS[LEVEL_ONE], LEVEL_ONE); + break; + case STATE_LEVEL_TWO: + level_init(&self->states.level, self->ecs, LEVEL_SETTINGS[LEVEL_TWO], LEVEL_TWO); + break; + case STATE_LEVEL_THREE: + level_init(&self->states.level, self->ecs, LEVEL_SETTINGS[LEVEL_THREE], LEVEL_THREE); + break; + case STATE_LEVEL_FOUR: + level_init(&self->states.level, self->ecs, LEVEL_SETTINGS[LEVEL_FOUR], LEVEL_FOUR); + break; + case STATE_LEVEL_FIVE: + level_init(&self->states.level, self->ecs, LEVEL_SETTINGS[LEVEL_FIVE], LEVEL_FIVE); + break; + default: + break; + } +} + +void +state_init(State* self, ECS* ecs, StateType type) +{ + memset(self, '\0', sizeof(State)); + + self->ecs = ecs; + + memcpy(self->levelData, LEVEL_DATA_DEFAULT, sizeof(LEVEL_DATA_DEFAULT)); + + _state_set(self, type); +} + +void +state_free(State* self) +{ + switch (self->type) + { + case STATE_TITLE: + title_free(&self->states.title); + break; + case STATE_LEVEL_ONE: + case STATE_LEVEL_TWO: + case STATE_LEVEL_THREE: + case STATE_LEVEL_FOUR: + case STATE_LEVEL_FIVE: + level_free(&self->states.level); + break; + case STATE_CUTSCENE_ONE: + case STATE_CUTSCENE_TWO: + case STATE_CUTSCENE_THREE: + case STATE_CUTSCENE_FOUR: + case STATE_CUTSCENE_FIVE: + case STATE_CUTSCENE_FINAL: + cutscene_free(&self->states.cutscene); + break; + case STATE_ENDING: + ending_free(&self->states.ending); + default: + break; + } + ecs_clear(self->ecs); +} + +void +state_change(State* self, StateType type) +{ + self->setType = type; +} + +void +state_tick(State* self) +{ + if (self->isChanging) + { + self->isChanging = false; + state_free(self); + + memset(&self->states, '\0', sizeof(self->states)); + + _state_set(self, self->setType); + return; + } + + switch (self->type) + { + case STATE_LEVEL_ONE: + _state_level_tick(self, LEVEL_ONE); + break; + case STATE_LEVEL_TWO: + _state_level_tick(self, LEVEL_TWO); + break; + case STATE_LEVEL_THREE: + _state_level_tick(self, LEVEL_THREE); + break; + case STATE_LEVEL_FOUR: + _state_level_tick(self, LEVEL_FOUR); + break; + case STATE_LEVEL_FIVE: + _state_level_tick(self, LEVEL_FIVE); + break; + case STATE_TITLE: + title_tick(&self->states.title); + + if (self->states.title.isLevelSelected) + _state_set(self, STATE_CUTSCENE_ONE + self->states.title.levelSelected); + + break; + case STATE_CUTSCENE_ONE: + cutscene_tick(&self->states.cutscene); + + if (self->states.cutscene.isFinished) + _state_set(self, STATE_LEVEL_ONE); + + break; + case STATE_CUTSCENE_TWO: + cutscene_tick(&self->states.cutscene); + + if (self->states.cutscene.isFinished) + _state_set(self, STATE_LEVEL_TWO); + + break; + case STATE_CUTSCENE_THREE: + cutscene_tick(&self->states.cutscene); + + if (self->states.cutscene.isFinished) + _state_set(self, STATE_LEVEL_THREE); + + break; + case STATE_CUTSCENE_FOUR: + cutscene_tick(&self->states.cutscene); + + if (self->states.cutscene.isFinished) + _state_set(self, STATE_LEVEL_FOUR); + + break; + case STATE_CUTSCENE_FIVE: + cutscene_tick(&self->states.cutscene); + + if (self->states.cutscene.isFinished) + _state_set(self, STATE_LEVEL_FIVE); + + break; + case STATE_CUTSCENE_FINAL: + cutscene_tick(&self->states.cutscene); + + if (self->states.cutscene.isFinished) + _state_set(self, STATE_ENDING); + break; + case STATE_ENDING: + ending_tick(&self->states.ending); + + if (self->states.ending.isFinished) + _state_set(self, STATE_TITLE); + break; + default: + break; + } +} diff --git a/src/game/state/state.h b/src/game/state/state.h new file mode 100644 index 0000000..578c3be --- /dev/null +++ b/src/game/state/state.h @@ -0,0 +1,398 @@ +#pragma once + +#include "STATE_COMMON.h" + +#define CUTSCENE_ONE_COUNT 4 +static const Scene CUTSCENE_ONE_SCENES[CUTSCENE_ONE_COUNT] = +{ + { + .texture = TEXTURE_CUTSCENE_ONE_SCENE_ONE, + .string = "In an far off patch of unknown wilderness, there has been an unexpected period of abundance. It is as if full meals grow from the ground like weeds in a garden." + }, + { + .texture = TEXTURE_CUTSCENE_ONE_SCENE_TWO, + .string = "The assertive frilled matriarch sees opportunity. Scrounging for scraps for much of her life, Fortune has presented her with a chance for boundless hedonism." + }, + { + .texture = TEXTURE_CUTSCENE_ONE_SCENE_THREE, + .string = "Turning to her ever faithful underling, she speaks: \"My little runt. Feed me, and feed me lots; that is your meager life's greatest ambition. Not a single morsel must go elsewhere.\"" + }, + { + .texture = TEXTURE_CUTSCENE_ONE_SCENE_FOUR, + .string = "Without hesitation, her dutiful servant rushes out into the wilds, to fetch as much food as its claws can hold, its heart beating fast with adoration for its mistress..." + } +}; + +#define CUTSCENE_TWO_COUNT 5 +static const Scene CUTSCENE_TWO_SCENES[CUTSCENE_TWO_COUNT] = +{ + { + .texture = TEXTURE_CUTSCENE_TWO_SCENE_ONE, + .string = "The first expeditions had been a resounding success. The frilled matriarch has spent her time lounging and indulging in the delights her slave had brought her. It even began to reflect on her physique." + }, + { + .texture = TEXTURE_CUTSCENE_TWO_SCENE_TWO, + .string = "The runt looks out into the wilderness. It had become... quite cloudy, where the two are. Things felt...strange, chaotic. It triggered the creature's most primal of instincts..." + }, + { + .texture = TEXTURE_CUTSCENE_TWO_SCENE_THREE, + .string = "...but, its objective was more important than anything else." + }, + { + .texture = TEXTURE_CUTSCENE_TWO_SCENE_FOUR, + .string = "Although...one instinct did claw at the creature...hunger. Though the creature's body pleaded to consume the fruits of its labor..every morsel must be delivered to the matriarch at all costs, as she insisted!" + }, + { + .texture = TEXTURE_CUTSCENE_TWO_SCENE_FIVE, + .string = "As the creature journeyed onwards, into the discordant wilds, within the clouds, a gleam of turquoise emitted from their depths, and a small object decends from the sky above..." + } +}; + +#define CUTSCENE_THREE_COUNT 6 +static const Scene CUTSCENE_THREE_SCENES[CUTSCENE_THREE_COUNT] = +{ + { + .texture = TEXTURE_CUTSCENE_THREE_SCENE_ONE, + .string = "While scrounging for more foodstuffs, in the dense thicket, the frilled runt uncovers a golden trinket that illuminates the creature's face in an unearthly turquoise." + }, + { + .texture = TEXTURE_CUTSCENE_THREE_SCENE_TWO, + .string = "Grasping onto it, the tiny being suddenly feels...different." + }, + { + .texture = TEXTURE_CUTSCENE_THREE_SCENE_THREE, + .string = "The runt thinks nothing of it; its mind too occupied with its directive. But... a strange power seems to ruminate through the amulet..." + }, + { + .texture = TEXTURE_CUTSCENE_THREE_SCENE_FOUR, + .string = "As the creature scampers off with its newfound prize, the frilled matriarch eyes glide over to her underling and its plunder in between one of her many gorging sessions." + }, + { + .texture = TEXTURE_CUTSCENE_THREE_SCENE_FIVE, + .string = "The frilled runt returned to its duty. Unfortunately, the amulet did not solve its hunger problem..." + }, + { + .texture = TEXTURE_CUTSCENE_THREE_SCENE_SIX, + .string = "However, it did make the creature feel...livelier. Perhaps that boost could stave off the hunger..." + }, +}; + +#define CUTSCENE_FOUR_COUNT 6 +static const Scene CUTSCENE_FOUR_SCENES[CUTSCENE_FOUR_COUNT] = +{ + { + .texture = TEXTURE_CUTSCENE_FOUR_SCENE_ONE, + .string = "It seemed that the amulet's power was strengthening. Suddenly, the creature could feel things before they were set to happen. It predicted that its growing mistress would ask fo-" + }, + { + .texture = TEXTURE_CUTSCENE_FOUR_SCENE_TWO, + .string = "\"Servant! Fetch more food for your famished mistress!\"" + }, + { + .texture = TEXTURE_CUTSCENE_FOUR_SCENE_THREE, + .string = "...its prediction was accurate! But, that was likely to happen, anyways. As the creature left to plunder from the abundance, it also predicted the clouds would recede..." + }, + { + .texture = TEXTURE_CUTSCENE_FOUR_SCENE_FOUR, + .string = "...and so it did. The amulet glowed that brilliant turquoise as it did...could the amulet also use its power to dispel or change the events happening around the creature?" + }, + { + .texture = TEXTURE_CUTSCENE_FOUR_SCENE_FIVE, + .string = "It seemed that the amulet's power was only growing, and so too was the frilled runt's...what other secrets might it hold?" + }, + { + .texture = TEXTURE_CUTSCENE_FOUR_SCENE_SIX, + .string = "The frilled matriarch looked onward to her steadfast worker. \"Ah...if only my mouth was not full when my servant comes...how I wish...to give my thanks.\"" + }, +}; + + +#define CUTSCENE_FIVE_COUNT 6 +static const Scene CUTSCENE_FIVE_SCENES[CUTSCENE_FIVE_COUNT] = +{ + { + .texture = TEXTURE_CUTSCENE_FIVE_SCENE_ONE, + .string = "The frilled runt, having wieleded the amulet's magick, had begun to master it. That magick seeped through the creature, indispensible like blood." + }, + { + .texture = TEXTURE_CUTSCENE_FIVE_SCENE_TWO, + .string = "Not only did it grant new powers, it seemed to give the creature...visions. The creature had begun to experience something else besides the endless beat of instinct." + }, + { + .texture = TEXTURE_CUTSCENE_FIVE_SCENE_THREE, + .string = "It dawned to the creature the reality of its situation. Endless servitude. Tiresome labor. Painful starvation. All to appease some insiginificant lifeform's appetites." + }, + { + .texture = TEXTURE_CUTSCENE_FIVE_SCENE_FOUR, + .string = "As the frilled monarch finished gorging upon a morsel, it catches her single prized laborer deep in thought." + }, + { + .texture = TEXTURE_CUTSCENE_FIVE_SCENE_FIVE, + .string = "\"My dear servant! Fetch me more food to feed my growing belly!\" she beams excitedly, her thick digits sunk into her now-voluminous yellow flesh." + }, + { + .texture = TEXTURE_CUTSCENE_FIVE_SCENE_SIX, + .string = "With the help of the amulet, a new feeling twinged through the creature's body. With its increasing strength, it seemed anything was possible. Perhaps it would best to just...play along with this charade! Until...until..." + } +}; + +#define CUTSCENE_FINAL_COUNT 13 +static const Scene CUTSCENE_FINAL_SCENES[CUTSCENE_FINAL_COUNT] = +{ + { + .texture = TEXTURE_CUTSCENE_FINAL_SCENE_ONE, + .string = "As the frilled matriarch erupted out a thunderous belch after eating her next meal, she figured it'd be the best time to have a stretch." + }, + { + .texture = TEXTURE_CUTSCENE_FINAL_SCENE_TWO, + .string = "Unfortunately for the gluttonous reptile, her body had acquired so much flesh, that her encumbered muscles could not heave her rotund rear end off the ground." + }, + { + .texture = TEXTURE_CUTSCENE_FINAL_SCENE_THREE, + .string = "She'd thought about it before, but now it had truly dawned upon the stubborn matriarch that perhaps she had taken in...a bit too much. Constantly taking, never giving. Her bloated body was evidence of that." + }, + { + .texture = TEXTURE_CUTSCENE_FINAL_SCENE_FOUR, + .string = "The frilled matriarch looks to her underling, no longer distracted by her vice of gluttony. There's a...vulnerability, to her face." + }, + { + .texture = TEXTURE_CUTSCENE_FINAL_SCENE_FIVE, + .string = "\"...I...think I might've had enough. Thank...thank you. Well...you're...hungry too, right, my...m-my little...friend?\"" + }, + { + .texture = TEXTURE_CUTSCENE_FINAL_SCENE_SIX, + .string = "Her little friend was, indeed, starving, and had been for a while. As a pang of hunger struck, so did a pang of that strange, alien sense of negativity.. " + }, + { + .texture = TEXTURE_CUTSCENE_FINAL_SCENE_SEVEN, + .string = "\"Surely, you could've eaten some of the food yourself! And... I saw you with that golden trinket. It's got quite the power, does it?\"" + }, + { + .texture = TEXTURE_CUTSCENE_FINAL_SCENE_EIGHT, + .string = "That golden trinket had stirred those feelings. It had also stirred untold, growing power. A lesser creature would fell the useless, blubbery monarch and usurp her throne using its mighty magicks then and there." + }, + { + .texture = TEXTURE_CUTSCENE_FINAL_SCENE_NINE, + .string = "But...the runt was not a lesser creature. That amulet also granted...wisdom; a sense of reality. The mistress was flawed, but as she was served, she began to appreciate the tireless efforts of her companion. She belived the runt should not suffer." + }, + { + .texture = TEXTURE_CUTSCENE_FINAL_SCENE_TEN, + .string = "Perhaps things were better when that trinket did not grant the creature these pointed feelings. The past was in the past. The frilled runt only had one gift left to relinquish...the amulet, dedicating its power to the greatest leader it knew." + }, + { + .texture = TEXTURE_CUTSCENE_FINAL_SCENE_ELEVEN, + .string = "The power present in the creature's body soon transferred to that of the frilled monarch. \"Now, my little friend...perhaps I should use this amulet's power to feed you as much as you did me!" + }, + { + .texture = TEXTURE_CUTSCENE_FINAL_SCENE_TWELVE, + .string = "..!" + }, + { + .texture = TEXTURE_CUTSCENE_FINAL_SCENE_THIRTEEN, + .string = "The clouds recede as the two enjoy the abundance...together! Perhaps...a little too much!" + }, +}; + +static const SceneCollection CUTSCENE_ONE = +{ + .scenes = CUTSCENE_ONE_SCENES, + .count = CUTSCENE_ONE_COUNT +}; + +static const SceneCollection CUTSCENE_TWO = +{ + .scenes = CUTSCENE_TWO_SCENES, + .count = CUTSCENE_TWO_COUNT +}; + +static const SceneCollection CUTSCENE_THREE = +{ + .scenes = CUTSCENE_THREE_SCENES, + .count = CUTSCENE_THREE_COUNT +}; + +static const SceneCollection CUTSCENE_FOUR = +{ + .scenes = CUTSCENE_FOUR_SCENES, + .count = CUTSCENE_FOUR_COUNT +}; + +static const SceneCollection CUTSCENE_FIVE = +{ + .scenes = CUTSCENE_FIVE_SCENES, + .count = CUTSCENE_FIVE_COUNT +}; + +static const SceneCollection CUTSCENE_FINAL = +{ + .scenes = CUTSCENE_FINAL_SCENES, + .count = CUTSCENE_FINAL_COUNT +}; + +static const LevelSettings LEVEL_SETTINGS[LEVEL_COUNT] = +{ + { + .medalThresholds = {100, 200, 300}, + .time = 7200, + .colorCover = {-0.05f, -0.05f, -0.05f, 0.0f}, + .collectibleMax = 30, + .eventTime = 0, + .isPower = false, + .isEvent = false, + .isAmulet = false, + .isPowerForesight = false, + .isPowerCancel = false, + .isPowerMagnet = false, + .isPowerExtend = false, + .isPowerInvigorate = false, + .isTutorialMove = true, + .isTutorialStamina = true, + .isTutorialFood = true, + .isTutorialEvent = false, + .isTutorialPower = false, + .isTutorialPowerForesight = false, + .isTutorialPowerCancel = false, + .isTutorialPowerMagnet = false, + .isTutorialPowerExtend = false, + .isTutorialPowerInvigorate = false, + .isTutorialFinal = false + }, + { + .medalThresholds = {150, 300, 450}, + .time = 10800, + .colorCover = {0.0f, 0.0f, 0.0f, 0.0f}, + .collectibleMax = 35, + .eventTime = 1800, + .isPower = false, + .isEvent = true, + .isAmulet = true, + .isPowerForesight = false, + .isPowerCancel = false, + .isPowerMagnet = false, + .isPowerExtend = false, + .isPowerInvigorate = false, + .isTutorialMove = false, + .isTutorialStamina = false, + .isTutorialFood = false, + .isTutorialEvent = true, + .isTutorialPower = false, + .isTutorialPowerForesight = false, + .isTutorialPowerCancel = false, + .isTutorialPowerMagnet = false, + .isTutorialPowerExtend = false, + .isTutorialPowerInvigorate = false, + .isTutorialFinal = false + }, + { + .medalThresholds = {300, 400, 500}, + .time = 10800, + .colorCover = {0.05f, 0.05f, 0.05f, 0.0f}, + .collectibleMax = 40, + .eventTime = 1500, + .isPower = true, + .isEvent = true, + .isAmulet = false, + .isPowerForesight = false, + .isPowerCancel = false, + .isPowerMagnet = false, + .isPowerExtend = false, + .isPowerInvigorate = true, + .isTutorialMove = false, + .isTutorialStamina = false, + .isTutorialFood = false, + .isTutorialEvent = false, + .isTutorialPower = true, + .isTutorialPowerForesight = false, + .isTutorialPowerCancel = false, + .isTutorialPowerMagnet = false, + .isTutorialPowerExtend = false, + .isTutorialPowerInvigorate = true, + .isTutorialFinal = false + }, + { + .medalThresholds = {400, 500, 600}, + .time = 10800, + .colorCover = {0.1f, 0.05f, 0.0f, 0.0f}, + .collectibleMax = 45, + .eventTime = 1200, + .isPower = true, + .isEvent = true, + .isAmulet = false, + .isPowerForesight = true, + .isPowerCancel = true, + .isPowerMagnet = false, + .isPowerExtend = true, + .isPowerInvigorate = true, + .isTutorialMove = false, + .isTutorialStamina = false, + .isTutorialFood = false, + .isTutorialEvent = false, + .isTutorialPower = false, + .isTutorialPowerForesight = true, + .isTutorialPowerCancel = true, + .isTutorialPowerMagnet = false, + .isTutorialPowerExtend = true, + .isTutorialPowerInvigorate = false, + .isTutorialFinal = false + }, + { + .medalThresholds = {500, 750, 1000}, + .time = 18000, + .colorCover = {-0.025f, -0.00f, -0.025f, 0.0f}, + .collectibleMax = 50, + .eventTime = 900, + .isPower = true, + .isEvent = true, + .isAmulet = false, + .isPowerForesight = true, + .isPowerCancel = true, + .isPowerMagnet = false, + .isPowerExtend = true, + .isPowerInvigorate = true, + .isTutorialMove = false, + .isTutorialStamina = false, + .isTutorialFood = false, + .isTutorialEvent = false, + .isTutorialPower = false, + .isTutorialPowerForesight = false, + .isTutorialPowerCancel = false, + .isTutorialPowerMagnet = false, + .isTutorialPowerExtend = false, + .isTutorialPowerInvigorate = false, + .isTutorialFinal = true + } +}; + +static const LevelData LEVEL_DATA_DEFAULT[LEVEL_COUNT] = +{ + { + .status = LEVEL_STATUS_UNLOCKED, + .score = -1, + .time = -1 + }, + { + .status = LEVEL_STATUS_LOCKED, + .score = -1, + .time = -1 + }, + { + .status = LEVEL_STATUS_LOCKED, + .score = -1, + .time = -1 + }, + { + .status = LEVEL_STATUS_LOCKED, + .score = -1, + .time = -1 + }, + { + .status = LEVEL_STATUS_LOCKED, + .score = -1, + .time = -1 + }, +}; + +void state_change(State* self, StateType type); +void state_init(State* self, ECS* ecs, StateType type); +void state_free(State* self); +void state_tick(State* self); diff --git a/src/game/state/title/TITLE_COMMON.h b/src/game/state/title/TITLE_COMMON.h new file mode 100644 index 0000000..9a58b09 --- /dev/null +++ b/src/game/state/title/TITLE_COMMON.h @@ -0,0 +1,29 @@ +#pragma once + +#include "../../ecs/ecs.h" +#include "../../ecs/entity/ui/entity_cursor.h" +#include "../../ecs/entity/ui/entity_logo.h" +#include "../../ecs/entity/visual/entity_text.h" +#include "../../ecs/entity/ui/entity_level_select_button.h" + +typedef struct LevelData +{ + LevelStatusType status; + s32 time; + s32 score; +} LevelData; + +typedef struct Title +{ + ECS* ecs; + LevelData* levelData; + bool isLevelSelected; + u32 levelSelected; + u32 levelCount; + EntityID cursor; + EntityID credits; + EntityID levelSelectText; + EntityID bg; + EntityID logo; + Vector levelSelectButtons; /* EntityID */ +} Title; diff --git a/src/game/state/title/title.c b/src/game/state/title/title.c new file mode 100644 index 0000000..65beca9 --- /dev/null +++ b/src/game/state/title/title.c @@ -0,0 +1,175 @@ +#include "title.h" + +void _title_entity_init(Title* self, ECS* ecs); +void _title_level_data_text_init(Title* self, ECS* ecs, u32 level); +void _title_level_select_button_init(Title* self, ECS* ecs, u32 level); + +void +_title_level_data_text_init(Title* self, ECS* ecs, u32 level) +{ + const char string[TITLE_LEVEL_DATA_TEXT_MAX]; + LevelData* levelData; + vec3 position; + + levelData = &self->levelData[level]; + + glm_vec3_copy(TITLE_LEVEL_DATA_TEXT_POSITION, position); + + position[0] += TITLE_LEVEL_DATA_TEXT_X_OFFSET * level; + + if (levelData->time <= 0) + { + snprintf + ( + string, + TITLE_LEVEL_DATA_TEXT_MAX, + "%s", + STRING_TITLE_LEVEL_DATA_UNINITIALIZED + ); + } + else + { + u32 minutes; + u32 seconds; + u32 milliseconds; + + time_formatted_get(levelData->time, &minutes, &seconds, &milliseconds); + + snprintf + ( + string, + TITLE_LEVEL_DATA_TEXT_MAX, + TITLE_LEVEL_DATA_TIME_FORMAT, + minutes, + seconds, + milliseconds, + levelData->score + ); + } + + entity_text_add + ( + ecs, + &ecs->resources->fonts[FONT_SMALL], + RENDERER_BUFFER_UI, + string, + position, + -1 + ); +} + + +void +_title_level_select_button_init(Title* self, ECS* ecs, u32 level) +{ + EntityID id; + vec3 position; + + glm_vec3_copy(TITLE_LEVEL_SELECT_BUTTON_POSITION, position); + + position[0] += TITLE_LEVEL_SELECT_BUTTON_X_OFFSET * level; + + id = entity_level_select_button_add + ( + ecs, + position, + self->levelData[level].status, + level + ); + + vector_push(&self->levelSelectButtons, &id); +} + +void +_title_entity_init(Title* self, ECS* ecs) +{ + self->cursor = entity_cursor_add(ecs); + + for (s32 i = 0; i < (s32)self->levelCount; i++) + { + _title_level_select_button_init(self, ecs, i); + _title_level_data_text_init(self, ecs, i); + } + + self->credits = entity_text_add + ( + ecs, + &ecs->resources->fonts[FONT_DEFAULT], + RENDERER_BUFFER_UI, + STRING_TITLE_LEVEL_SELECT, + TITLE_LEVEL_SELECT_POSITION, + -1 + ); + + self->levelSelectText = entity_text_add + ( + ecs, + &ecs->resources->fonts[FONT_SMALL], + RENDERER_BUFFER_UI, + STRING_TITLE_CREDITS, + TITLE_CREDITS_POSITION, + -1 + ); + + self->bg = entity_sprite_add + ( + ecs, + &ecs->resources->textures[TEXTURE_TITLE_BG], + RENDERER_BUFFER_BACKGROUND, + ORIGIN_TOP_LEFT, + TITLE_BG_SIZE, + TITLE_BG_POSITION + ); + + self->logo = entity_logo_add + ( + ecs, + TITLE_LOGO_POSITION + ); +} + +void +title_init(Title* self, ECS* ecs, LevelData* levelData, u32 levelCount) +{ + memset(self, '\0', sizeof(Title)); + + self->ecs = ecs; + self->levelCount = levelCount; + + self->levelData = malloc(sizeof(LevelData) * levelCount); + memcpy(self->levelData, levelData, sizeof(LevelData) * levelCount); + + vector_init(&self->levelSelectButtons, sizeof(EntityID)); + + _title_entity_init(self, ecs); + + music_play(&self->ecs->resources->music[MUSIC_TITLE], false); +} + +void +title_free(Title* self) +{ + free(self->levelData); + vector_clear(&self->levelSelectButtons); +} + +void +title_tick(Title* self) +{ + for (s32 i = 0; i < (s32)self->levelSelectButtons.count; i++) + { + ComponentButton* button; + EntityID* id; + + id = vector_get(&self->levelSelectButtons, i); + + button = ecs_component_get(self->ecs, COMPONENT_BUTTON, *id); + + if (button->isJustPressed) + { + self->levelSelected = i; + self->isLevelSelected = true; + } + } + +} diff --git a/src/game/state/title/title.h b/src/game/state/title/title.h new file mode 100644 index 0000000..b7f4bfb --- /dev/null +++ b/src/game/state/title/title.h @@ -0,0 +1,25 @@ +#pragma once + +#include "TITLE_COMMON.h" + +#define TITLE_LEVEL_SELECT_BUTTON_X_OFFSET (ENTITY_LEVEL_SELECT_BUTTON_SIZE[0] + (ENTITY_LEVEL_SELECT_BUTTON_SIZE[0] / 2)) +#define TITLE_LEVEL_DATA_TEXT_X_OFFSET (TITLE_LEVEL_SELECT_BUTTON_X_OFFSET) + +#define STRING_TITLE_CREDITS "WeightGaming Gain Jam 2024 (Theme: \"Unexpected Outcomes\") | Design, Programming Sound, Art by Shweet | Music by FraynVGM\nCharacters, graphics, music, sound, script licensed under CC0 | Source code licensed under GPLv3" +#define STRING_TITLE_LEVEL_SELECT "Select level..." +#define STRING_TITLE_LEVEL_DATA_UNINITIALIZED "Time: -\'--\"--\nScore: ---" + +#define TITLE_LEVEL_DATA_TEXT_MAX 64 +#define TITLE_LEVEL_DATA_TIME_FORMAT "Time: %i\'%02i\"%02i\nScore: %i" + +static vec3 TITLE_LEVEL_SELECT_BUTTON_POSITION = {256.0f, 500.0f, 0.0f}; +static vec3 TITLE_BG_POSITION = {0.0f, 0.0f, 0.0f}; +static vec3 TITLE_LOGO_POSITION = {640.0f, 200.0f, 0.0f}; +static vec3 TITLE_LEVEL_DATA_TEXT_POSITION = {190.0f, 590.0f, 0.0f}; +static vec3 TITLE_CREDITS_POSITION = {25.0f, 650.0f, 0.0f}; +static vec3 TITLE_LEVEL_SELECT_POSITION = {570.0f, 400.0f, 0.0f}; +static vec2 TITLE_BG_SIZE = {1280.0f, 720.0f}; + +void title_init(Title* self, ECS* ecs, LevelData* levelData, u32 levelCount); +void title_tick(Title* self); +void title_free(Title* self); diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..fc726b8 --- /dev/null +++ b/src/main.c @@ -0,0 +1,22 @@ +#include "main.h" + +void +loop(void) +{ + game_loop(&game); +} + +s32 +main(s32 argc, char** argv) +{ + game_init(&game); + +#ifdef EMSCRIPTEN + emscripten_set_main_loop(loop, 60, true); +#else + while (true) + loop(); +#endif + + return EXIT_SUCCESS; +} diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..4c430e3 --- /dev/null +++ b/src/main.h @@ -0,0 +1,7 @@ +#pragma once + +#include "game/game.h" + +#ifdef EMSCRIPTEN +#include +#endif