commit a1f998f581d75e29917e8df33f0b2c9870fd48db Author: Medusa Slockbower Date: Tue Jun 3 14:29:27 2025 -0400 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..97db7bc --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/build/ +/docs/ +/Doxyfile diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..1805ed4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,87 @@ +cmake_minimum_required(VERSION 3.5) + +set(VERSION_MAJOR 0) +set(VERSION_MINOR 0) +set(VERSION_PATCH 1) +set(PROJECT_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") + +project(glw VERSION ${PROJECT_VERSION}) + +set(GLW_HEADERS + buffer.h + common.h + shader.h + vertex_descriptor.h + texture.h + framebuffer.h + texture_array.h + debug.h + timer.h +) + +# Set CPP Standard +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_C_STANDARD 23) + +# Find Dependencies +find_package(glm REQUIRED) +find_package(GLEW REQUIRED) +find_package(OpenGL REQUIRED COMPONENTS OpenGL) + +add_library(glw INTERFACE + ${GLW_HEADERS} +) + +target_link_libraries(glw INTERFACE + Freetype::Freetype + GLEW::GLEW + OpenGL::GL + open-cpp-utils +) + +# Testing Framework ---------------------------------------------------------------------------------------------------- + +if (GTest_FOUND) + +find_package(GTest) + +add_executable(glw-test) + +target_link_libraries(glw-test PRIVATE + GTest::gtest + glw +) + +endif () + +# DOXYGEN ============================================================================================================== +# https://vicrucann.github.io/tutorials/quick-cmake-doxygen/ + +find_package(Doxygen) + +if(DOXYGEN_FOUND) + get_filename_component(DOXYGEN_PROJECT_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) + set(DOXYGEN_CONFIG_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in) + set(DOXYGEN_CONFIG_OUT ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile) + + configure_file(${DOXYGEN_CONFIG_IN} ${DOXYGEN_CONFIG_OUT} @ONLY) + message("Doxygen Build Started.") + + if(WIN32) + add_custom_target(glw-documentation ALL + COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_CONFIG_OUT} + COMMAND start firefox "${CMAKE_CURRENT_SOURCE_DIR}/Documentation/html/index.html" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Generating Doxygen Documentation" + VERBATIM) + else() + add_custom_target(glw-documentation ALL + COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_CONFIG_OUT} + COMMAND firefox "${CMAKE_CURRENT_SOURCE_DIR}/Documentation/html/index.html" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Generating Doxygen Documentation" + VERBATIM) + endif() +else() + message("Doxygen not found.") +endif() \ No newline at end of file diff --git a/Doxyfile.in b/Doxyfile.in new file mode 100755 index 0000000..0316f23 --- /dev/null +++ b/Doxyfile.in @@ -0,0 +1,5 @@ +OUTPUT_DIRECTORY = "@CMAKE_CURRENT_SOURCE_DIR@/docs/" +INPUT = "@CMAKE_CURRENT_SOURCE_DIR@/README.md" "@CMAKE_CURRENT_SOURCE_DIR@/" +RECURSIVE = YES +PROJECT_NAME = "@DOXYGEN_PROJECT_NAME@" +PROJECT_NUMBER = "@CMAKE_PROJECT_VERSION@" \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..d6e9855 --- /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. + + glw, an open-source library that wraps OpenGL structures into classes. + Copyright (C) 2024 Medusa Slockbower + + 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: + + glw Copyright (C) 2024 Medusa Slockbower + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100755 index 0000000..53c6a69 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# glw +Open Source C++ Wrapper for OpenGL diff --git a/buffer.h b/buffer.h new file mode 100755 index 0000000..772d5d5 --- /dev/null +++ b/buffer.h @@ -0,0 +1,412 @@ +// ===================================================================================================================== +// glw, an open-source library that wraps OpenGL structures into classes. +// Copyright (C) 2024 Medusa Slockbower +// +// 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 . +// ===================================================================================================================== + +#ifndef GLW_BUFFER_H +#define GLW_BUFFER_H + +#include "common.h" + +#include +#include + +namespace ocu = open_cpp_utils; + +namespace glw +{ + +// ===================================================================================================================== +// Definitions +// ===================================================================================================================== + + +// Typedefs ------------------------------------------------------------------------------------------------------------ + +using buffer_t = GLenum; + +template +class buffer; + + +// Enums --------------------------------------------------------------------------------------------------------------- + +enum buffer_type +{ + buf_vertex = GL_ARRAY_BUFFER +, buf_element = GL_ELEMENT_ARRAY_BUFFER +, buf_copy_read = GL_COPY_READ_BUFFER +, buf_copy_write = GL_COPY_WRITE_BUFFER +, buf_pixel_pack = GL_PIXEL_PACK_BUFFER +, buf_pixel_unpack = GL_PIXEL_UNPACK_BUFFER +, buf_query = GL_QUERY_BUFFER +, buf_texture = GL_TEXTURE_BUFFER +, buf_transform_feedback = GL_TRANSFORM_FEEDBACK_BUFFER +, buf_uniform = GL_UNIFORM_BUFFER +, buf_indirect_draw = GL_DRAW_INDIRECT_BUFFER +, buf_atomic_counter = GL_ATOMIC_COUNTER_BUFFER +, buf_indirect_dispatch = GL_DISPATCH_INDIRECT_BUFFER +, buf_shader_storage = GL_SHADER_STORAGE_BUFFER +, buf_parameter = GL_PARAMETER_BUFFER +}; + +enum buffer_flags +{ + buf_flags_read = GL_MAP_READ_BIT +, buf_flags_write = GL_MAP_WRITE_BIT +, buf_flags_read_write = buf_flags_read | buf_flags_write +, buf_flags_dynamic = GL_DYNAMIC_STORAGE_BIT +, buf_flags_persistent = GL_MAP_PERSISTENT_BIT +, buf_flags_coherent = GL_MAP_COHERENT_BIT | bf_persistent +, buf_flags_client = GL_CLIENT_STORAGE_BIT +}; + +enum mapping_flags +{ + buf_map_read = GL_MAP_READ_BIT +, buf_map_write = GL_MAP_WRITE_BIT +, buf_map_read_write = buf_map_read | buf_map_write +, buf_map_persistent = GL_MAP_PERSISTENT_BIT +, buf_map_coherent = GL_MAP_COHERENT_BIT | buf_map_persistent +, buf_map_invalidate_range = GL_MAP_INVALIDATE_RANGE_BIT +, buf_map_invalidate_buffer = GL_MAP_INVALIDATE_BUFFER_BIT +, buf_map_flush_explicity = GL_MAP_FLUSH_EXPLICIT_BIT | buf_map_write +, buf_map_unsynchronized = GL_MAP_UNSYNCHRONIZED_BIT + +, buf_map_optional = buf_map_invalidate_range + | buf_map_invalidate_buffer + | buf_map_flush_explicity + | buf_map_unsynchronized +}; + + +// Buffer Aliases + +template using vertex_buffer = buffer; +template using element_buffer = buffer; +template using copy_read_buffer = buffer; +template using copy_write_buffer = buffer; +template using pixel_pack_buffer = buffer; +template using pixel_unpack_buffer = buffer; +template using query_buffer = buffer; +template using texture_buffer = buffer; +template using transform_feedback_buffer = buffer; +template using uniform_buffer = buffer; +template using indirect_draw_buffer = buffer; +template using atomic_counter_buffer = buffer; +template using indirect_dispatch_buffer = buffer; +template using shader_storage_buffer = buffer; +template using parameter_buffer = buffer; + + +// Buffer Definition --------------------------------------------------------------------------------------------------- + +template +class buffer +{ +// Constants =========================================================================================================== + +public: + static constexpr buffer_t type = T_; + static constexpr flags_t flags = Fs_; + + +// Functions =========================================================================================================== + +public: + +// Constructors -------------------------------------------------------------------------------------------------------- + + /** + * \brief Construct a buffer filled with the provided data + * \param size Size of the buffer in bytes + * \param data Pointer to the data to initialize the buffer with, if null, initialized with 0 + */ + buffer(size_t size, const void* data = nullptr); + + buffer(const buffer&); + buffer(buffer&&) = default; + ~buffer(); + + +// Access -------------------------------------------------------------------------------------------------------------- + + /** + * \brief Map the buffer to the CPU + * \param size Size of the region to map + * \param offset Offset into the buffer to map + * \param map_flags Flags to map the buffer with + * \return Whether the buffer was successfully mapped + */ + bool map(size_t size = -1, offset_t offset = 0, flags_t map_flags = mapping_flags::read); + + void unmap(); + + template + T* data() { static_assert(flags | buffer_flags::write); return map_; } + + /** + * \brief + * \tparam T + * \return + */ + template + const T* data() const { static_assert(flags | buffer_flags::read); return map_; } + + /** + * \brief Bind the buffer for usage with gl functions + */ + void bind(); + + /** + * \brief Attach the buffer to a specific base location for usage in a shader program + * \param location Location to bind the buffer to + */ + void attach(location_t location); + + +// Status -------------------------------------------------------------------------------------------------------------- + + [[nodiscard]] bool mapped() const { return map_ != nullptr; } + + [[nodiscard]] bool valid() const { return handle_ != NULL; } + + +// Capacity ------------------------------------------------------------------------------------------------------------ + + [[nodiscard]] size_t size() const { return size_; } + + template + [[nodiscard]] size_t capacity() const { return size_ / sizeof(T); } + + +// Modifiers ----------------------------------------------------------------------------------------------------------- + + /** + * \brief Read a section of the buffer from the gpu into a location on the cpu + * \param buffer Pointer to the buffer to read into + * \param size Size of the buffer + * \param offset Offset into the gpu memory + */ + void read(void* buffer, size_t size, offset_t offset = 0); + + /** + * \brief Write a section to the buffer on the gpu from the cpu + * \param buffer Pointer to the buffer to write from + * \param size Size of the buffer + * \param offset Offset into the gpu memory + */ + void write(const void* buffer, size_t size, offset_t offset = 0); + + /** + * \brief Clear a portion of the buffer + * \param size Size of the section to clear, if negative, size will be automatically calculated using the offset. + * \param offset Offset into the buffer + * \param data Value to clear the buffer with + * \param layout Layout of the provided data + * \param type Type of the provided data + * \param format Format of the provided data + */ + void clear(size_t size = -1, offset_t offset = 0, const void* data = nullptr, + enum_t layout = r_i, enum_t type = uint8, enum_t format = r8_ui); + + /** + * \brief Copy data from another buffer + * \tparam oType Type of the other buffer + * \tparam oFlags Flags of the other buffer + * \param src Source buffer to copy from + * \param size Size of the section of data to copy + * \param src_offset Offset into the source buffer + * \param dst_offset Offset into the destination buffer + */ + template + void copy(const buffer& src, size_t size = -1, offset_t src_offset = 0, offset_t dst_offset = 0); + + /** + * \brief Resize the buffer + * \param size New size of the data in bytes + */ + void resize(size_t size); + + +// Variables =========================================================================================================== + +private: + handle_t handle_; + size_t size_; + + void* map_; + offset_t map_start_, map_end_; + flags_t map_flags_; +}; + + +// ===================================================================================================================== +// Implementations +// ===================================================================================================================== + + +// Constructors -------------------------------------------------------------------------------------------------------- + +template +buffer::buffer(size_t size, const void *data) + : handle_(NULL) + , size_(size) + , map_(nullptr) + , map_start_(0), map_end_(0) + , map_flags_(0) +{ + glCreateBuffers(1, &handle_); + glNamedBufferStorage(handle_, size_, data, flags); +} + +template +buffer::buffer(const buffer& other) + : handle_(NULL) + , size_(other.size_) + , map_(nullptr) + , map_start_(0), map_end_(0) + , map_flags_(0) +{ + glCreateBuffers(1, &handle_); + glNamedBufferData(handle_, size_, nullptr, flags); + copy(other, size_, 0, 0); +} + + +// Access -------------------------------------------------------------------------------------------------------------- + +template +buffer::~buffer() +{ + glDeleteBuffers(1, &handle_); +} + +template +bool buffer::map(size_t size, offset_t offset, flags_t map_flags) +{ + static_assert(flags & read_write); + + if(map_) return false; + + map_flags &= flags | optional; + if(size < 0) size = size_ - offset; + + map_flags_ = map_flags; + map_start_ = offset; map_end_ = map_start_ + size; + return map_ = glMapNamedBufferRange(handle_, offset, size, map_flags_); +} + +template +void buffer::unmap() +{ + glUnmapNamedBuffer(handle_); + map_ = nullptr; +} + +template +void buffer::bind() +{ + glBindBuffer(type, handle_); +} + +template +void buffer::attach(location_t location) +{ + glBindBufferBase(type, location, handle_); +} + +template +void buffer::read(void* buffer, size_t size, offset_t offset) +{ + // If not mapped, use glGetBufferSubData to avoid mapping the buffer + if(map_ == nullptr) + { + glGetNamedBufferSubData(handle_, offset, size, buffer); + return; + } + + // Check if we need to remap the buffer + offset_t start = offset, end = offset + size; + if(start < map_start_ || end > map_end_ || !(map_flags_ & mapping_flags::read)) + { + flags_t map_flags = map_flags_ | mapping_flags::read; + start = glm::min(start, map_start_); end = glm::max(end, map_end_); + unmap(); + map(end - start, start, map_flags); + } + + // Copy from the mapping + offset = offset - map_start_; + memcpy(buffer, map_ + offset, size); +} + +template +void buffer::write(const void *buffer, size_t size, offset_t offset) +{ + // if the buffer isn't mapped and is dynamic, use glBufferSubData to avoid mapping the buffer + if(map_ == nullptr && flags | dynamic) + { + glNamedBufferSubData(handle_, offset, size, buffer); + } + + // Check if we need to remap the buffer + offset_t start = offset, end = offset + size; + if(start < map_start_ || end > map_end_ || !(map_flags_ & mapping_flags::write)) + { + flags_t map_flags = map_flags_ | mapping_flags::write; + start = glm::min(start, map_start_); end = glm::max(end, map_end_); + unmap(); + map(end - start, start, map_flags); + } + + // Copy to the mapping + offset = offset - map_start_; + memcpy(map_ + offset, buffer, size); +} + +template +void buffer::clear(size_t size, offset_t offset, const void* data, + layout_t layout, type_t type, format_t format) +{ + glClearNamedBufferSubData(handle_, format, offset, size, format, type, data); +} + +template +template +void buffer::copy(const buffer& src, size_t size, + offset_t src_offset, offset_t dst_offset) +{ + glCopyNamedBufferSubData(src.handle_, handle_, src_offset, dst_offset, size); +} + +template +void buffer::resize(size_t size) +{ + if(map_) unmap(); + + handle_t handle; + glCreateBuffers(1, &handle); + glNamedBufferStorage(handle, size, nullptr, flags); + glCopyNamedBufferSubData(handle_, handle, 0, 0, glm::min(size_, size)); + glDeleteBuffers(1, &handle_); + handle_ = handle; + size_ = size; +} + +} + +#endif //BUFFER_H diff --git a/common.h b/common.h new file mode 100755 index 0000000..2edd6ec --- /dev/null +++ b/common.h @@ -0,0 +1,421 @@ +// ===================================================================================================================== +// glw, an open-source library that wraps OpenGL structures into classes. +// Copyright (C) 2024 Medusa Slockbower +// +// 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 . +// ===================================================================================================================== + +#ifndef GLW_COMMON_H +#define GLW_COMMON_H + +#define GLW_STRINGIFY_(X) #X +#define GLW_STRINGIFY(X) GLW_STRINGIFY_(X) + +#include + +#include + +namespace glw +{ + +// Typedefs ============================================================================================================ + +using handle_t = GLuint; +using size_t = GLsizei; +using offset_t = GLintptr; +using flags_t = GLbitfield; +using index_t = GLint; +using location_t = GLuint; +using enum_t = GLenum; +using int_t = GLint; +using int64_t = GLint64; +using float_t = GLfloat; +using uint_t = GLuint; +using char_t = GLchar; + + +// Template Pack Contains Value + +template struct contains; +template struct contains_enum; + +template struct contains { static constexpr bool value = std::false_type{}; }; +template struct contains_enum { static constexpr bool value = std::false_type{}; }; + +template +struct contains +{ + static constexpr bool value = std::is_same::value || (sizeof...(Ts) > 0 && contains::value); + constexpr operator bool() const { return value; } +}; + +template +struct contains_enum +{ + static constexpr bool value = T == T0 || (sizeof...(Ts) > 0 && contains_enum::value); + constexpr operator bool() const { return value; } +}; + + +// Math Functions +template +inline genType min(genType&& v) { return std::forward(v); } + +template +inline genType min(genType&& a, genType&& b) { return std::forward(a < b ? a : b); } + +template +inline genType min(genType&& a, genType&& b, genType&& rest...) +{ + return max(std::forward(a < b ? a : b), std::forward(rest)...); +} + + +template +inline genType&& max(genType&& v) { return std::forward(v); } + +template +inline genType&& max(genType&& a, genType&& b) { return std::forward(a > b ? a : b); } + +template +inline genType&& max(genType&& a, genType&& b, genType&& rest...) +{ + return max(std::forward(a > b ? a : b), std::forward(rest)...); +} + +template +inline genType ceil_div(const genType& a, const genType& b) +{ + return 1 + ((a - 1) / b); +} + + +// Enums =============================================================================================================== + +enum access : enum_t +{ + access_read = GL_READ_ONLY +, access_write = GL_WRITE_ONLY +, access_read_write = GL_READ_WRITE +}; + +enum layout : enum_t +{ + +// Floating Point Layouts ============================================================================================== + + r = GL_RED +, rg = GL_RG +, rgb = GL_RGB +, bgr = GL_BGR +, rgba = GL_RGBA +, bgra = GL_BGRA + + +// Integer Layouts ===================================================================================================== + +, r_i = GL_RED_INTEGER +, rg_i = GL_RG_INTEGER +, rgb_i = GL_RGB_INTEGER +, bgr_i = GL_BGR_INTEGER +, rgba_i = GL_RGBA_INTEGER +, bgra_i = GL_BGRA_INTEGER + + +// Special Layouts ===================================================================================================== + +, depth = GL_DEPTH_COMPONENT +, stencil = GL_STENCIL_INDEX +, depth_stencil = GL_DEPTH_STENCIL + +}; + + +enum format : enum_t +{ + +// Fixed & Floating Points Formats ===================================================================================== + + r8 = GL_R8 +, r8_snorm = GL_R8_SNORM +, r16 = GL_R16 +, r16f = GL_R16F +, r16_snorm = GL_R16_SNORM +, r32 = GL_R32F + +, rg8 = GL_RG8 +, rg8_snorm = GL_RG8_SNORM +, rg16 = GL_RG16 +, rg16f = GL_RG16F +, rg16_snorm = GL_RG16_SNORM +, rg32 = GL_RG32F + +, rgb332 = GL_R3_G3_B2 +, rgb4 = GL_RGB4 +, rgb5 = GL_RGB5 +, rbg8 = GL_RGB8 +, srgb8 = GL_SRGB8 +, rbg8_snorm = GL_RGB8_SNORM +, rgb9e5 = GL_RGB9_E5 +, rgb10 = GL_RGB10 +, rgb11_11_10f = GL_R11F_G11F_B10F +, rgb12 = GL_RGB12 +, rgb16 = GL_RGB16 +, rgb16f = GL_RGB16F +, rgb16_snorm = GL_RGB16_SNORM +, rgb32f = GL_RGB32F + +, rgba2 = GL_RGBA2 +, rgba4 = GL_RGBA4 +, rgb5_a1 = GL_RGB5_A1 +, rgba8 = GL_RGBA8 +, srgba8 = GL_SRGB8_ALPHA8 +, rbga8_snorm = GL_RGBA8_SNORM +, rgb10_a2 = GL_RGB10_A2 +, rgba12 = GL_RGBA12 +, rgba16 = GL_RGBA16 +, rgba16f = GL_RGBA16F +, rgba16_snorm = GL_RGBA16_SNORM +, rgba32f = GL_RGBA32F + + +// Integer Formats ===================================================================================================== + +, r8_i = GL_R8I +, r8_ui = GL_R8UI +, r16_i = GL_R16I +, r16_ui = GL_R16UI +, r32_i = GL_R32I +, r32_ui = GL_R32UI + +, rg8_i = GL_RG8I +, rg8_ui = GL_RG8UI +, rg16_i = GL_RG16I +, rg16_ui = GL_RG16UI +, rg32_i = GL_RG32I +, rg32_ui = GL_RG32UI + +, rgb8_i = GL_RGB8I +, rgb8_ui = GL_RGB8UI +, rgb16_i = GL_RGB16I +, rgb16_ui = GL_RGB16UI +, rgb32_i = GL_RGB32I +, rgb32_ui = GL_RGB32UI + +, rgba8_i = GL_RGBA8I +, rgba8_ui = GL_RGBA8UI +, rgb10_a2_ui = GL_RGB10_A2UI +, rgba16_i = GL_RGBA16I +, rgba16_ui = GL_RGBA16UI +, rgba32_i = GL_RGBA32I +, rgba32_ui = GL_RGBA32UI + + +// Depth / Stencil Formats ============================================================================================= + +, depth16 = GL_DEPTH_COMPONENT16 +, depth24 = GL_DEPTH_COMPONENT24 +, depth32 = GL_DEPTH_COMPONENT32 +, depth32_f = GL_DEPTH_COMPONENT32F + +, stencil1 = GL_STENCIL_INDEX1 +, stencil4 = GL_STENCIL_INDEX4 +, stencil8 = GL_STENCIL_INDEX8 +, stencil16 = GL_STENCIL_INDEX16 + +, depth24_stencil = GL_DEPTH24_STENCIL8 +, depth32_f_stencil = GL_DEPTH32F_STENCIL8 + + +// Compressed Formats ================================================================================================== + + +// Generic Formats +, r_compressed = GL_COMPRESSED_RED +, rg_compressed = GL_COMPRESSED_RG +, rgb_compressed = GL_COMPRESSED_RGB +, srgb_compressed = GL_COMPRESSED_SRGB +, rgba_compressed = GL_COMPRESSED_RGBA +, srgba_compressed = GL_COMPRESSED_SRGB_ALPHA + +// BPTC +, rgb_bptc = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT +, rgb_bptc_signed = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT +, rgba_bptc_unorm = GL_COMPRESSED_RGBA_BPTC_UNORM +, srgba_bptc = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM + +// RGTC +, r_rgtc = GL_COMPRESSED_RED_RGTC1 +, r_rgtc_signed = GL_COMPRESSED_SIGNED_RED_RGTC1 +, rg_rgtc = GL_COMPRESSED_RG_RGTC2 +, rg_rgtc_signed = GL_COMPRESSED_SIGNED_RG_RGTC2 + +// EAC +, r_eac = GL_COMPRESSED_R11_EAC +, rg_eac = GL_COMPRESSED_RG11_EAC +, r_eac_signed = GL_COMPRESSED_SIGNED_R11_EAC +, rg_eac_signed = GL_COMPRESSED_SIGNED_RG11_EAC +, rgba_eac = GL_COMPRESSED_RGBA8_ETC2_EAC +, srgba_eac = GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC + +// ASTC +, rgba_astc4x4 = GL_COMPRESSED_RGBA_ASTC_4x4_KHR +, rgba_astc5x4 = GL_COMPRESSED_RGBA_ASTC_5x4_KHR +, rgba_astc5x5 = GL_COMPRESSED_RGBA_ASTC_5x5_KHR +, rgba_astc6x5 = GL_COMPRESSED_RGBA_ASTC_6x5_KHR +, rgba_astc6x6 = GL_COMPRESSED_RGBA_ASTC_6x6_KHR +, rgba_astc8x5 = GL_COMPRESSED_RGBA_ASTC_8x5_KHR +, rgba_astc8x6 = GL_COMPRESSED_RGBA_ASTC_8x6_KHR +, rgba_astc8x8 = GL_COMPRESSED_RGBA_ASTC_8x8_KHR +, rgba_astc10x5 = GL_COMPRESSED_RGBA_ASTC_10x5_KHR +, rgba_astc10x6 = GL_COMPRESSED_RGBA_ASTC_10x6_KHR +, rgba_astc10x8 = GL_COMPRESSED_RGBA_ASTC_10x8_KHR +, rgba_astc10x10 = GL_COMPRESSED_RGBA_ASTC_10x10_KHR +, rgba_astc12x10 = GL_COMPRESSED_RGBA_ASTC_12x10_KHR +, rgba_astc12x12 = GL_COMPRESSED_RGBA_ASTC_12x12_KHR + +, srgba_astc4x4 = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR +, srgba_astc5x4 = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR +, srgba_astc5x5 = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR +, srgba_astc6x5 = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR +, srgba_astc6x6 = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR +, srgba_astc8x5 = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR +, srgba_astc8x6 = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR +, srgba_astc8x8 = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR +, srgba_astc10x5 = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR +, srgba_astc10x6 = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR +, srgba_astc10x8 = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR +, srgba_astc10x10 = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR +, srgba_astc12x10 = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR +, srgba_astc12x12 = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR + +}; + +inline constexpr bool is_depth(enum_t fmt) +{ + switch(fmt) + { + case(depth16): case(depth24): + case(depth32): case(depth32_f): + case(depth24_stencil): case(depth32_f_stencil): + return true; + + default: return false; + } +} + +inline constexpr bool is_stencil(enum_t fmt) +{ + switch(fmt) + { + case(stencil1): case(stencil4): + case(stencil8): case(stencil16): + case(depth24_stencil): case(depth32_f_stencil): + return true; + + default: return false; + } +} + +template +struct format_traits +{ +static constexpr enum_t format = F_; +static constexpr bool is_depth = glw::is_depth(format); +static constexpr bool is_stencil = glw::is_stencil(format); +static constexpr bool is_depth_stencil = std::is_same, std::bool_constant>{}; +}; + + + + +enum type : enum_t +{ + int8 = GL_BYTE +, uint8 = GL_UNSIGNED_BYTE +, int16 = GL_SHORT +, uint16 = GL_UNSIGNED_SHORT +, int32 = GL_INT +, uint32 = GL_UNSIGNED_INT + +, float16 = GL_HALF_FLOAT +, float32 = GL_FLOAT +, float64 = GL_DOUBLE + +, uint8_332 = GL_UNSIGNED_BYTE_3_3_2 +, uint8_233r = GL_UNSIGNED_BYTE_2_3_3_REV +, uint16_565 = GL_UNSIGNED_SHORT_5_6_5 +, uint16_565r = GL_UNSIGNED_SHORT_5_6_5_REV +, uint32_10_11_11 = GL_UNSIGNED_INT_10F_11F_11F_REV + +, uint16_4444 = GL_UNSIGNED_SHORT_4_4_4_4 +, uint16_4444r = GL_UNSIGNED_SHORT_4_4_4_4_REV +, uint16_5551 = GL_UNSIGNED_SHORT_5_5_5_1 +, uint16_1555r = GL_UNSIGNED_SHORT_1_5_5_5_REV +, uint32_8888 = GL_UNSIGNED_INT_8_8_8_8 +, uint32_8888r = GL_UNSIGNED_INT_8_8_8_8_REV +, uint32_rgb10_a2 = GL_UNSIGNED_INT_10_10_10_2 +, uint32_a2_bgr10 = GL_UNSIGNED_INT_2_10_10_10_REV +, uint32_9995r = GL_UNSIGNED_INT_5_9_9_9_REV + +}; + +inline constexpr enum_t size_of(enum_t type) +{ + switch(type) + { + // 1 byte + case(int8): case(uint8): + case(uint8_332): case(uint8_233r): + return 1; + + // 2 byte + case(int16): case(uint16): + case(uint16_565): case(uint16_565r): + case(uint16_4444): case(uint16_4444r): + case(uint16_5551): case(uint16_1555r): + case(float16): + return 2; + + // 4 byte + case(int32): case(uint32): + case(uint32_10_11_11): + case(uint32_8888): case(uint32_8888r): + case(uint32_rgb10_a2): case(uint32_a2_bgr10): + case(uint32_9995r): + case(float32): + return 4; + + // 8 byte + case(float64): + return 8; + } + return 0; +} + +enum compare : enum_t +{ + never = GL_NEVER +, always = GL_ALWAYS +, less = GL_LESS +, greater = GL_GREATER +, equal = GL_EQUAL +, lequal = GL_LEQUAL +, gequal = GL_GEQUAL +, nequal = GL_NOTEQUAL +}; + +} + +#endif //COMMON_H diff --git a/debug.h b/debug.h new file mode 100755 index 0000000..134a6f9 --- /dev/null +++ b/debug.h @@ -0,0 +1,183 @@ +// ===================================================================================================================== +// glw, an open-source library that wraps OpenGL structures into classes. +// Copyright (C) 2024 Medusa Slockbower +// +// 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 . +// ===================================================================================================================== + +#ifndef GLW_DEBUG_H +#define GLW_DEBUG_H + +#include "common.h" + +namespace glw::debug +{ + +/** + * \brief OpenGL error codes + */ +enum error +{ + error_invalid_enum = GL_INVALID_ENUM +, error_invalid_value = GL_INVALID_VALUE +, error_invalid_operation = GL_INVALID_OPERATION +, error_stack_overflow = GL_STACK_OVERFLOW +, error_stack_underflow = GL_STACK_UNDERFLOW +, error_out_of_memory = GL_OUT_OF_MEMORY +, error_invalid_framebuffer_operation = GL_INVALID_FRAMEBUFFER_OPERATION +, error_context_lost = GL_CONTEXT_LOST +, error_table_too_large = GL_TABLE_TOO_LARGE +}; + +/** + * \brief Converts an error code into a string representation + * \param error The error code to translate + * \return C string containing the string representation + */ +inline const char_t* translate_error(enum_t error) +{ + switch(error) + { + case error_invalid_enum: return GLW_STRINGIFY(error_invalid_enum); + case error_invalid_value: return GLW_STRINGIFY(error_invalid_value); + case error_invalid_operation: return GLW_STRINGIFY(error_invalid_operation); + case error_stack_overflow: return GLW_STRINGIFY(error_stack_overflow); + case error_stack_underflow: return GLW_STRINGIFY(error_stack_underflow); + case error_out_of_memory: return GLW_STRINGIFY(error_out_of_memory); + case error_invalid_framebuffer_operation: return GLW_STRINGIFY(error_invalid_framebuffer_operation); + case error_context_lost: return GLW_STRINGIFY(error_context_lost); + case error_table_too_large: return GLW_STRINGIFY(error_table_too_large); + default: return GLW_STRINGIFY(error_unknown); + } +} + +/** + * \brief Get the last error thrown by OpenGL, it is preferable to use the callback handler for performance + * \return Error code of the last error + */ +inline enum_t get_error() { return glGetError(); } + +/** + * \brief Source ids of a debug message + */ +enum debug_source +{ + source_api = GL_DEBUG_SOURCE_API +, source_window_system = GL_DEBUG_SOURCE_WINDOW_SYSTEM +, source_shader_compiler = GL_DEBUG_SOURCE_SHADER_COMPILER +, source_third_party = GL_DEBUG_SOURCE_THIRD_PARTY +, source_application = GL_DEBUG_SOURCE_APPLICATION +, source_other = GL_DEBUG_SOURCE_OTHER +}; + +/** + * \brief Translate a debug message source into a string representation + * \param source ID of the debug message source + * \return C string containing the string representation + */ +inline const char_t* translate_source(enum_t source) +{ + switch(source) + { + case source_api: return GLW_STRINGIFY(source_api); + case source_window_system: return GLW_STRINGIFY(source_window_system); + case source_shader_compiler: return GLW_STRINGIFY(source_shader_compiler); + case source_third_party: return GLW_STRINGIFY(source_third_party); + case source_application: return GLW_STRINGIFY(source_application); + case source_other: return GLW_STRINGIFY(source_other); + default: return GLW_STRINGIFY(source_unknown); + } +} + +/** + * \brief Types of debug messages + */ +enum debug_type +{ + type_error = GL_DEBUG_TYPE_ERROR +, type_deprecated_behavior = GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR +, type_undefined_behavior = GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR +, type_portability = GL_DEBUG_TYPE_PORTABILITY +, type_performance = GL_DEBUG_TYPE_PERFORMANCE +, type_marker = GL_DEBUG_TYPE_MARKER +, type_push_group = GL_DEBUG_TYPE_PUSH_GROUP +, type_pop_group = GL_DEBUG_TYPE_POP_GROUP +, type_other = GL_DEBUG_TYPE_OTHER +}; + +inline void push_group(enum_t src, uint_t id, size_t len, const char_t* msg) { glPushDebugGroup(src, id, len, msg); } +inline void pop_group() { glPopDebugGroup(); } + +inline void set_label(enum_t id, handle_t name, size_t len, const char_t* label) { glObjectLabel(id, name, len, label); } +inline void set_label(void* ptr, size_t len, const char_t* label) { glObjectPtrLabel(ptr, len, label); } + +inline void get_label(enum_t id, handle_t name, size_t buf_size, size_t& length, char_t* buf) +{ glGetObjectLabel(id, name, buf_size, &length, buf); } + +inline void get_label(void* ptr, size_t buf_size, size_t& length, char_t* buf) +{ glGetObjectPtrLabel(ptr, buf_size, &length, buf); } + +inline const char_t* translate_type(enum_t source) +{ + switch(source) + { + case type_error: return GLW_STRINGIFY(type_error); + case type_deprecated_behavior: return GLW_STRINGIFY(type_deprecated_behavior); + case type_undefined_behavior: return GLW_STRINGIFY(type_undefined_behavior); + case type_portability: return GLW_STRINGIFY(type_portability); + case type_performance: return GLW_STRINGIFY(type_performance); + case type_marker: return GLW_STRINGIFY(type_marker); + case type_push_group: return GLW_STRINGIFY(type_push_group); + case type_pop_group: return GLW_STRINGIFY(type_pop_group); + case type_other: return GLW_STRINGIFY(type_other); + default: return GLW_STRINGIFY(type_unknown); + } +} + +enum debug_severity +{ + severity_low = GL_DEBUG_SEVERITY_LOW +, severity_medium = GL_DEBUG_SEVERITY_MEDIUM +, severity_high = GL_DEBUG_SEVERITY_HIGH +, severity_notification = GL_DEBUG_SEVERITY_NOTIFICATION +}; + +inline const char_t* translate_severity(enum_t severity) +{ + switch(severity) + { + case severity_low: return GLW_STRINGIFY(severity_low); + case severity_medium: return GLW_STRINGIFY(severity_medium); + case severity_high: return GLW_STRINGIFY(severity_high); + case severity_notification: return GLW_STRINGIFY(severity_notification); + default: return GLW_STRINGIFY(severity_unknown); + } +} + +inline void insert_message(enum_t source, enum_t type, uint_t id, enum_t severity, size_t length, const char_t* message) +{ + glDebugMessageInsert(source, type, id, severity, length, message); +} + +using debug_callback = GLDEBUGPROC; + +inline void set_debug_callback(debug_callback callback, void* user_data) +{ + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback(callback, user_data); +} + +} + +#endif //DEBUG_H diff --git a/framebuffer.h b/framebuffer.h new file mode 100755 index 0000000..918acc6 --- /dev/null +++ b/framebuffer.h @@ -0,0 +1,375 @@ +// ===================================================================================================================== +// glw, an open-source library that wraps OpenGL structures into classes. +// Copyright (C) 2024 Medusa Slockbower +// +// 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 . +// ===================================================================================================================== + +#ifndef GLW_FRAMEBUFFER_H +#define GLW_FRAMEBUFFER_H + +#include "texture.h" +#include "texture_array.h" + +#include + +namespace glw +{ + enum framebuffer_usage : enum_t + { + fb_usage_read = GL_READ_FRAMEBUFFER + , fb_usage_draw = GL_DRAW_FRAMEBUFFER + , fb_usage_any = GL_FRAMEBUFFER + }; + + enum framebuffer_status : enum_t + { + fb_status_complete = GL_FRAMEBUFFER_COMPLETE + , fb_status_undefined = GL_FRAMEBUFFER_UNDEFINED + , fb_status_incomplete_attachment = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT + , fb_status_missing_attachment = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT + , fb_status_incomplete_draw = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER + , fb_status_incomplete_read = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER + , fb_status_incomplete_multisample = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE + , fb_status_incomplete_layers = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS + , fb_status_unsupported = GL_FRAMEBUFFER_UNSUPPORTED + , fb_status_unknown = 0 + }; + + static const char* translate_framebuffer_status(enum_t status) + { + switch(status) + { + case(fb_status_complete): return "Complete"; + case(fb_status_undefined): return "Undefined"; + case(fb_status_incomplete_attachment): return "Incomplete Attachment"; + case(fb_status_missing_attachment): return "Missing Attachment"; + case(fb_status_incomplete_draw): return "Incomplete Draw"; + case(fb_status_incomplete_read): return "Incomplete Read"; + case(fb_status_incomplete_multisample): return "Incomplete Multisample"; + case(fb_status_incomplete_layers): return "Incomplete Layers"; + case(fb_status_unsupported): return "Unsupported"; + + case(fb_status_unknown): + default: + return "Unknown"; + } + } + + enum attachment_bit + { + fb_depth_bit = GL_DEPTH_BUFFER_BIT + , fb_stencil_bit = GL_STENCIL_BUFFER_BIT + , fb_color_bit = GL_COLOR_BUFFER_BIT + }; + + enum attachment + { + no_attachment = GL_NONE + + , depth_attachment = GL_DEPTH_ATTACHMENT + , stencil_attachment = GL_STENCIL_ATTACHMENT + , depth_stencil_attachment = GL_DEPTH_STENCIL_ATTACHMENT + + , color_attachment0 = GL_COLOR_ATTACHMENT0 + , color_attachment1 = GL_COLOR_ATTACHMENT1 + , color_attachment2 = GL_COLOR_ATTACHMENT2 + , color_attachment3 = GL_COLOR_ATTACHMENT3 + , color_attachment4 = GL_COLOR_ATTACHMENT4 + , color_attachment5 = GL_COLOR_ATTACHMENT5 + , color_attachment6 = GL_COLOR_ATTACHMENT6 + , color_attachment7 = GL_COLOR_ATTACHMENT7 + , color_attachment8 = GL_COLOR_ATTACHMENT8 + , color_attachment9 = GL_COLOR_ATTACHMENT9 + , color_attachment10 = GL_COLOR_ATTACHMENT10 + , color_attachment11 = GL_COLOR_ATTACHMENT11 + , color_attachment12 = GL_COLOR_ATTACHMENT12 + , color_attachment13 = GL_COLOR_ATTACHMENT13 + , color_attachment14 = GL_COLOR_ATTACHMENT14 + , color_attachment15 = GL_COLOR_ATTACHMENT15 + + , front_buffer = GL_FRONT + , back_buffer = GL_BACK + , front_and_back_buffer = GL_FRONT_AND_BACK + , left_buffer = GL_LEFT + , right_buffer = GL_RIGHT + , front_left_buffer = GL_FRONT_LEFT + , front_right_buffer = GL_FRONT_RIGHT + , back_left_buffer = GL_BACK_LEFT + , back_right_buffer = GL_BACK_RIGHT + }; + + inline constexpr handle_t default_framebuffer = 0; + +template +class framebuffer +{ +// Constants =========================================================================================================== + + static_assert(!contains_enum::value); + static_assert(!contains_enum::value); + static_assert(!contains_enum::value); + static_assert(!contains_enum::value); + + static_assert(!contains_enum::value); + static_assert(!contains_enum::value); + static_assert(!contains_enum::value); + static_assert(!contains_enum::value); + + static_assert(!contains_enum::value); + static_assert(!contains_enum::value); + + using array_type = texarray; + +public: + + inline static constexpr enum_t type = T_; + +private: + + +// Functions =========================================================================================================== + +// Helpers ------------------------------------------------------------------------------------------------------------- + +private: + template + void bind_textures_() + { + auto& tex = textures_.template get(); + bool color = false; + + switch(tex.get_format()) + {; + case depth16: + case depth24: + case depth32_f: + glNamedFramebufferTexture(handle_, depth_attachment, tex.handle(), 0); + break; + + case stencil1: + case stencil4: + case stencil8: + case stencil16: + glNamedFramebufferTexture(handle_, stencil_attachment, tex.handle(), 0); + break; + + case depth24_stencil: + case depth32_f_stencil: + glNamedFramebufferTexture(handle_, depth_stencil_attachment, tex.handle(), 0); + break; + + default: + glNamedFramebufferTexture(handle_, color_attachment0 + C, tex.handle(), 0); + colors_.push_back(color_attachment0 + C); + color = true; + break; + } + + if constexpr(I + 1 < array_type::length) + { + if(color) bind_textures_(); + else bind_textures_(); + } + } + + +// Constructors -------------------------------------------------------------------------------------------------------- + +public: + framebuffer(size_t size) + : handle_(NULL), size_(size, 1, 1), samples_(1), textures_(size) + { static_assert(contains_enum::value); glCreateFramebuffers(1, &handle_); } + + framebuffer(glm::ivec2 size) + : handle_(NULL), size_(size, 1), samples_(1), textures_(size) + { static_assert(contains_enum::value); glCreateFramebuffers(1, &handle_); } + + framebuffer(glm::ivec2 size, size_t samples = 1) requires(type == texture2DMS) + : handle_(NULL), size_(size, 1), samples_(samples), textures_(size, samples) + { glCreateFramebuffers(1, &handle_); } + + framebuffer(glm::ivec3 size) + : handle_(NULL), size_(size), samples_(1), textures_(size) + { static_assert(contains_enum::value); glCreateFramebuffers(1, &handle_); } + + framebuffer(glm::ivec3 size, size_t samples = 1) requires(type == texture2DMSArray) + : handle_(NULL), size_(size), samples_(samples), textures_(size, samples) + { glCreateFramebuffers(1, &handle_); } + + ~framebuffer() { glDeleteFramebuffers(1, &handle_); } + + +// Attachments --------------------------------------------------------------------------------------------------------- + + void rebuild(); + void build() { rebuild(); }; + + template + void blit( + enum_t src_att + , FB& dst, enum_t dst_att + , glm::ivec2 src_off, glm::ivec2 src_size + , glm::ivec2 dst_off, glm::ivec2 dst_size + , enum_t filter + ) { blit(src_att, dst.handle_, dst_att, src_off, src_size, dst_off, dst_size, filter); } + + void blit( + enum_t src_att + , handle_t dst, enum_t dst_att + , glm::ivec2 src_off, glm::ivec2 src_size + , glm::ivec2 dst_off, glm::ivec2 dst_size + , enum_t filter + ); + + template + auto& get() { return textures_.template get(); } + + template + const auto& get() const { return textures_.template get(); } + + +// Status -------------------------------------------------------------------------------------------------------------- + + enum_t get_status() const { return glCheckNamedFramebufferStatus(handle_, GL_FRAMEBUFFER); } + bool is_complete() const { return get_status() == fb_status_complete; } + + void bind(enum_t usage = fb_usage_any) { glBindFramebuffer(usage, handle_); } + + +// Capacity ------------------------------------------------------------------------------------------------------------ + + const glm::ivec3& size() const { return size_; } + + void resize(size_t size); + void resize(const glm::ivec2& size); + void resize(const glm::ivec2& size, size_t samples); + void resize(const glm::ivec3& size); + void resize(const glm::ivec3& size, size_t samples); + + size_t sample_count() const { return samples_; } + +// Variables =========================================================================================================== + +private: + handle_t handle_; + glm::ivec3 size_; + size_t samples_; + array_type textures_; + std::vector colors_; +}; + +template +void framebuffer::rebuild() +{ + colors_.clear(); colors_.reserve(textures_.length); + bind_textures_(); + + glNamedFramebufferDrawBuffers(handle_, colors_.size(), colors_.data()); +} + +template +void framebuffer::blit(uint32_t src_att, handle_t dst, uint32_t dst_att, glm::ivec2 src_off, + glm::ivec2 src_size, glm::ivec2 dst_off, glm::ivec2 dst_size, enum_t filter) +{ + flags_t mask; + bool src_color = (src_att >= color_attachment0 && src_att <= color_attachment15) + || (src_att >= front_left_buffer && src_att <= front_and_back_buffer); + bool dst_color = (dst_att >= color_attachment0 && dst_att <= color_attachment15) + || (dst_att >= front_left_buffer && dst_att <= front_and_back_buffer); + + if(src_att != dst_att && src_color != dst_color) return; + + switch(src_att) + { + case depth_attachment: mask = fb_depth_bit; break; + case stencil_attachment: mask = fb_stencil_bit; break; + case depth_stencil_attachment: mask = fb_depth_bit | fb_stencil_bit; break; + default: + mask = fb_color_bit; + glNamedFramebufferReadBuffer(handle_, src_att); + glNamedFramebufferDrawBuffer(dst, dst_att); + break; + } + + glBlitNamedFramebuffer( + handle_, dst + , src_off.x, src_off.y, src_off.x + src_size.x, src_off.y + src_size.y + , dst_off.x, dst_off.y, dst_off.x + dst_size.x, dst_off.y + dst_size.y + , mask, filter + ); +} + +template +void framebuffer::resize(size_t size) +{ + const auto& sample = textures_.template get<0>(); + if(sample.size() == size) return; + + glDeleteFramebuffers(1, &handle_); + glCreateFramebuffers(1, &handle_); + textures_.resize(size); + rebuild(); +} + +template +void framebuffer::resize(const glm::ivec2 &size) +{ + const auto& sample = textures_.template get<0>(); + if(sample.size() == size) return; + + glDeleteFramebuffers(1, &handle_); + glCreateFramebuffers(1, &handle_); + textures_.resize(size); + rebuild(); +} + +template +void framebuffer::resize(const glm::ivec2 &size, size_t samples) +{ + const auto& sample = textures_.template get<0>(); + if(sample.size() == size && sample.samples() == samples) return; + + glDeleteFramebuffers(1, &handle_); + glCreateFramebuffers(1, &handle_); + textures_.resize(size, samples); + rebuild(); +} + +template +void framebuffer::resize(const glm::ivec3 &size) +{ + const auto& sample = textures_.template get<0>(); + if(sample.size() == size) return; + + glDeleteFramebuffers(1, &handle_); + glCreateFramebuffers(1, &handle_); + textures_.resize(size); + rebuild(); +} + +template +void framebuffer::resize(const glm::ivec3 &size, size_t samples) +{ + const auto& sample = textures_.template get<0>(); + if(sample.size() == size && sample.samples() == samples) return; + + glDeleteFramebuffers(1, &handle_); + glCreateFramebuffers(1, &handle_); + textures_.resize(size, samples); + rebuild(); +} +} + +#endif // GLW_FRAMEBUFFER_H diff --git a/shader.h b/shader.h new file mode 100755 index 0000000..9647301 --- /dev/null +++ b/shader.h @@ -0,0 +1,502 @@ +// ===================================================================================================================== +// glw, an open-source library that wraps OpenGL structures into classes. +// Copyright (C) 2024 Medusa Slockbower +// +// 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 . +// ===================================================================================================================== + +#ifndef GLW_SHADER_H +#define GLW_SHADER_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +namespace ocu = open_cpp_utils; + +namespace glw +{ + +// ===================================================================================================================== +// Definitions +// ===================================================================================================================== + + +// Typedefs ------------------------------------------------------------------------------------------------------------ + + +// Enums --------------------------------------------------------------------------------------------------------------- + +enum source_type +{ + vertex = GL_VERTEX_SHADER +, tess_ctrl = GL_TESS_CONTROL_SHADER +, tess_eval = GL_TESS_EVALUATION_SHADER +, geometry = GL_GEOMETRY_SHADER +, fragment = GL_FRAGMENT_SHADER +, compute = GL_COMPUTE_SHADER +}; + +enum uniform_type +{ +// bool ---------------------------------------------------------------------------------------------------------------- + + b = GL_BOOL +, bvec2 = GL_BOOL_VEC2 +, bvec3 = GL_BOOL_VEC3 +, bvec4 = GL_BOOL_VEC4 + + +// int ----------------------------------------------------------------------------------------------------------------- + +, i = GL_INT +, ivec2 = GL_INT_VEC2 +, ivec3 = GL_INT_VEC3 +, ivec4 = GL_INT_VEC4 + + +// unsigned int -------------------------------------------------------------------------------------------------------- + +, u = GL_UNSIGNED_INT +, uvec2 = GL_UNSIGNED_INT_VEC2 +, uvec3 = GL_UNSIGNED_INT_VEC3 +, uvec4 = GL_UNSIGNED_INT_VEC4 + + +// float --------------------------------------------------------------------------------------------------------------- + +, f = GL_FLOAT +, vec2 = GL_FLOAT_VEC2 +, vec3 = GL_FLOAT_VEC3 +, vec4 = GL_FLOAT_VEC4 +, mat2 = GL_FLOAT_MAT2 +, mat3 = GL_FLOAT_MAT3 +, mat4 = GL_FLOAT_MAT4 +, mat2x3 = GL_FLOAT_MAT2x3 +, mat2x4 = GL_FLOAT_MAT2x4 +, mat3x2 = GL_FLOAT_MAT3x2 +, mat3x4 = GL_FLOAT_MAT3x4 +, mat4x2 = GL_FLOAT_MAT4x2 +, mat4x3 = GL_FLOAT_MAT4x3 + + +// double -------------------------------------------------------------------------------------------------------------- + +, d = GL_DOUBLE +, dvec2 = GL_DOUBLE_VEC2 +, dvec3 = GL_DOUBLE_VEC3 +, dvec4 = GL_DOUBLE_VEC4 +, dmat2 = GL_DOUBLE_MAT2 +, dmat3 = GL_DOUBLE_MAT3 +, dmat4 = GL_DOUBLE_MAT4 +, dmat2x3 = GL_DOUBLE_MAT2x3 +, dmat2x4 = GL_DOUBLE_MAT2x4 +, dmat3x2 = GL_DOUBLE_MAT3x2 +, dmat3x4 = GL_DOUBLE_MAT3x4 +, dmat4x2 = GL_DOUBLE_MAT4x2 +, dmat4x3 = GL_DOUBLE_MAT4x3 + + +// sampler ------------------------------------------------------------------------------------------------------------- + +, sampler1D = GL_SAMPLER_1D +, sampler1DShadow = GL_SAMPLER_1D_SHADOW +, sampler1DArray = GL_SAMPLER_1D_ARRAY +, sampler1DArrayShadow = GL_SAMPLER_1D_ARRAY_SHADOW + +, sampler2D = GL_SAMPLER_2D +, sampler2DShadow = GL_SAMPLER_2D_SHADOW +, sampler2DRect = GL_SAMPLER_2D_RECT +, sampler2DRectShadow = GL_SAMPLER_2D_RECT_SHADOW +, sampler2DArray = GL_SAMPLER_2D_ARRAY +, sampler2DArrayShadow = GL_SAMPLER_2D_ARRAY_SHADOW +, sampler2DMS = GL_SAMPLER_2D_MULTISAMPLE +, sampler2DMSArray = GL_SAMPLER_2D_MULTISAMPLE_ARRAY + +, samplerCube = GL_SAMPLER_CUBE +, samplerCubeShadow = GL_SAMPLER_CUBE_SHADOW +, samplerCubeArray = GL_SAMPLER_CUBE_MAP_ARRAY + +, sampler3D = GL_SAMPLER_3D + + +// isampler ------------------------------------------------------------------------------------------------------------ + +, isampler1D = GL_INT_SAMPLER_1D +, isampler1DArray = GL_INT_SAMPLER_1D_ARRAY + +, isampler2D = GL_INT_SAMPLER_2D +, isampler2DRect = GL_INT_SAMPLER_2D_RECT +, isampler2DArray = GL_INT_SAMPLER_2D_ARRAY +, isampler2DMS = GL_INT_SAMPLER_2D_MULTISAMPLE +, isampler2DMSArray = GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY + +, isamplerCube = GL_INT_SAMPLER_CUBE +, isamplerCubeArray = GL_INT_SAMPLER_CUBE_MAP_ARRAY + +, isampler3D = GL_INT_SAMPLER_3D + + +// usampler ------------------------------------------------------------------------------------------------------------ + +, usampler1D = GL_UNSIGNED_INT_SAMPLER_1D +, usampler1DArray = GL_UNSIGNED_INT_SAMPLER_1D_ARRAY + +, usampler2D = GL_UNSIGNED_INT_SAMPLER_2D +, usampler2DRect = GL_UNSIGNED_INT_SAMPLER_2D_RECT +, usampler2DArray = GL_UNSIGNED_INT_SAMPLER_2D_ARRAY +, usampler2DMS = GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE +, usampler2DMSArray = GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY + +, usamplerCube = GL_UNSIGNED_INT_SAMPLER_CUBE +, usamplerCubeArray = GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY + +, usampler3D = GL_UNSIGNED_INT_SAMPLER_3D + + +// image --------------------------------------------------------------------------------------------------------------- + +, image1D = GL_IMAGE_1D +, image1DArray = GL_IMAGE_1D_ARRAY + +, image2D = GL_IMAGE_2D +, image2DRect = GL_IMAGE_2D_RECT +, image2DArray = GL_IMAGE_2D_ARRAY +, image2DMS = GL_IMAGE_2D_MULTISAMPLE +, image2DMSArray = GL_IMAGE_2D_MULTISAMPLE_ARRAY + +, imageCube = GL_IMAGE_CUBE +, imageCubeArray = GL_IMAGE_CUBE_MAP_ARRAY + +, image3D = GL_IMAGE_3D + + +// iimage -------------------------------------------------------------------------------------------------------------- + +, iimage1D = GL_INT_IMAGE_1D +, iimage1DArray = GL_INT_IMAGE_1D_ARRAY + +, iimage2D = GL_INT_IMAGE_2D +, iimage2DRect = GL_INT_IMAGE_2D_RECT +, iimage2DArray = GL_INT_IMAGE_2D_ARRAY +, iimage2DMS = GL_INT_IMAGE_2D_MULTISAMPLE +, iimage2DMSArray = GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY + +, iimageCube = GL_INT_IMAGE_CUBE +, iimageCubeArray = GL_INT_IMAGE_CUBE_MAP_ARRAY + +, iimage3D = GL_INT_IMAGE_3D + + +// uimage -------------------------------------------------------------------------------------------------------------- + +, uimage1D = GL_UNSIGNED_INT_IMAGE_1D +, uimage1DArray = GL_UNSIGNED_INT_IMAGE_1D_ARRAY + +, uimage2D = GL_UNSIGNED_INT_IMAGE_2D +, uimage2DRect = GL_UNSIGNED_INT_IMAGE_2D_RECT +, uimage2DArray = GL_UNSIGNED_INT_IMAGE_2D_ARRAY +, uimage2DMS = GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE +, uimage2DMSArray = GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY + +, uimageCube = GL_UNSIGNED_INT_IMAGE_CUBE +, uimageCubeArray = GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY + +, uimage3D = GL_UNSIGNED_INT_IMAGE_3D + + +// atomic -------------------------------------------------------------------------------------------------------------- + +, atomic_uint = GL_UNSIGNED_INT_ATOMIC_COUNTER +}; + + +// Buffer Definition --------------------------------------------------------------------------------------------------- + +class shader +{ +// Typedefs ============================================================================================================ + +public: + struct uniform + { + public: + uniform() : shader_(0), name_(""), type_(int8), location_(-1) { } + uniform(const std::string& str) : shader_(0), name_(str), type_(int8), location_(-1) { } + uniform(shader& shader, const std::string& name, enum_t type); + uniform(const uniform& u) : shader_(u.shader_), name_(u.name_), type_(u.type_), location_(u.location_) { } + ~uniform() = default; + + template + inline uniform& operator=(T v) { assert(false); return *this; } + + const std::string& name() const { return name_; } + enum_t type() const { return type_; } + index_t location() const { return location_; } + + private: + handle_t shader_; + std::string name_; + enum_t type_; + index_t location_; + }; + + // OpenGL Built Ins + static constexpr char gl_NumWorkGroups[] = "gl_NumWorkGroups"; + static constexpr char gl_WorkGroupID[] = "gl_WorkGroupID"; + static constexpr char gl_LocalInvocationID[] = "gl_LocalInvocationID"; + static constexpr char gl_GlobalInvocationID[] = "gl_GlobalInvocationID"; + static constexpr char gl_LocalInvocationIndex[] = "gl_LocalInvocationIndex"; + + // GLW Built Ins + static constexpr char glw_RequestedInvocations[] = "glw_RequestedInvocations"; + static inline const std::string built_ins_compute = std::format("uniform ivec3 {};", glw_RequestedInvocations); + +private: + using uniform_map = std::unordered_map; + + +// Functions =========================================================================================================== + +public: + + shader(); + ~shader(); + + bool attach_source(enum_t type, size_t count, const char** source, const size_t* lengths); + bool attach_source(enum_t type, const std::vector& source); + bool link(); + + void bind() const; + + void dispatch(int x = 1, int y = 1, int z = 1); + + uniform operator[](const std::string& str); + + const std::string& get_error_string() const { return error_; } + + inline static std::string group_size(int x, int y, int z) + { return std::format("layout (local_size_x = {}, local_size_y = {}, local_size_z = {}) in;", x, y, z); } + +private: + handle_t handle_; + std::string error_; + int work_group_size_[3]; + bool pass_requested_invocations_; + uniform_map uniforms_; +}; + + + + + +// ===================================================================================================================== +// Implementation +// ===================================================================================================================== + + +// uniform ------------------------------------------------------------------------------------------------------------- + +inline shader::uniform::uniform(shader& shader, const std::string& name, enum_t type) + : shader_(shader.handle_) + , name_(name) + , type_(type) + , location_(0) +{ + location_ = glGetUniformLocation(shader_, name_.c_str()); +} + +#define validate(handle, type) if(handle == 0) return *this; assert(type_ == type); + +template<> inline shader::uniform& shader::uniform::operator=(bool v) { validate(shader_, uniform_type::b); glProgramUniform1i(shader_, location_, v); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::bvec2 v) { validate(shader_, uniform_type::bvec2); glProgramUniform2i(shader_, location_, v.x, v.y); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::bvec3 v) { validate(shader_, uniform_type::bvec3); glProgramUniform3i(shader_, location_, v.x, v.y, v.z); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::bvec4 v) { validate(shader_, uniform_type::bvec4); glProgramUniform4i(shader_, location_, v.x, v.y, v.z, v.w); return *this; } + +template<> inline shader::uniform& shader::uniform::operator=(int v) { validate(shader_, uniform_type::i); glProgramUniform1i(shader_, location_, v); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::ivec2 v) { validate(shader_, uniform_type::ivec2); glProgramUniform2i(shader_, location_, v.x, v.y); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::ivec3 v) { validate(shader_, uniform_type::ivec3); glProgramUniform3i(shader_, location_, v.x, v.y, v.z); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::ivec4 v) { validate(shader_, uniform_type::ivec4); glProgramUniform4i(shader_, location_, v.x, v.y, v.z, v.w); return *this; } + +template<> inline shader::uniform& shader::uniform::operator=(glm::uint v) { validate(shader_, uniform_type::u); glProgramUniform1ui(shader_, location_, v); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::uvec2 v) { validate(shader_, uniform_type::uvec2); glProgramUniform2ui(shader_, location_, v.x, v.y); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::uvec3 v) { validate(shader_, uniform_type::uvec3); glProgramUniform3ui(shader_, location_, v.x, v.y, v.z); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::uvec4 v) { validate(shader_, uniform_type::uvec4); glProgramUniform4ui(shader_, location_, v.x, v.y, v.z, v.w); return *this; } + +template<> inline shader::uniform& shader::uniform::operator=(float v) { validate(shader_, uniform_type::f); glProgramUniform1f(shader_, location_, v); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::vec2 v) { validate(shader_, uniform_type::vec2); glProgramUniform2f(shader_, location_, v.x, v.y); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::vec3 v) { validate(shader_, uniform_type::vec3); glProgramUniform3f(shader_, location_, v.x, v.y, v.z); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::vec4 v) { validate(shader_, uniform_type::vec4); glProgramUniform4f(shader_, location_, v.x, v.y, v.z, v.w); return *this; } + +template<> inline shader::uniform& shader::uniform::operator=(double v) { validate(shader_, uniform_type::d); glProgramUniform1d(shader_, location_, v); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::dvec2 v) { validate(shader_, uniform_type::dvec2); glProgramUniform2d(shader_, location_, v.x, v.y); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::dvec3 v) { validate(shader_, uniform_type::dvec3); glProgramUniform3d(shader_, location_, v.x, v.y, v.z); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::dvec4 v) { validate(shader_, uniform_type::dvec4); glProgramUniform4d(shader_, location_, v.x, v.y, v.z, v.w); return *this; } + +template<> inline shader::uniform& shader::uniform::operator= (glm::mat2 v) { validate(shader_, uniform_type::mat2); glProgramUniformMatrix2fv (shader_, location_, 1, GL_FALSE, &v[0][0]); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::mat2x3 v) { validate(shader_, uniform_type::mat2x3); glProgramUniformMatrix2x3fv(shader_, location_, 1, GL_FALSE, &v[0][0]); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::mat2x4 v) { validate(shader_, uniform_type::mat2x4); glProgramUniformMatrix2x4fv(shader_, location_, 1, GL_FALSE, &v[0][0]); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::mat3x2 v) { validate(shader_, uniform_type::mat3x2); glProgramUniformMatrix3x2fv(shader_, location_, 1, GL_FALSE, &v[0][0]); return *this; } +template<> inline shader::uniform& shader::uniform::operator= (glm::mat3 v) { validate(shader_, uniform_type::mat3); glProgramUniformMatrix3fv (shader_, location_, 1, GL_FALSE, &v[0][0]); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::mat3x4 v) { validate(shader_, uniform_type::mat3x4); glProgramUniformMatrix3x4fv(shader_, location_, 1, GL_FALSE, &v[0][0]); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::mat4x2 v) { validate(shader_, uniform_type::mat4x2); glProgramUniformMatrix4x2fv(shader_, location_, 1, GL_FALSE, &v[0][0]); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::mat4x3 v) { validate(shader_, uniform_type::mat4x3); glProgramUniformMatrix4x3fv(shader_, location_, 1, GL_FALSE, &v[0][0]); return *this; } +template<> inline shader::uniform& shader::uniform::operator= (glm::mat4 v) { validate(shader_, uniform_type::mat4); glProgramUniformMatrix4fv (shader_, location_, 1, GL_FALSE, &v[0][0]); return *this; } + +template<> inline shader::uniform& shader::uniform::operator= (glm::dmat2 v) { validate(shader_, uniform_type::dmat2); glProgramUniformMatrix2dv (shader_, location_, 1, GL_FALSE, &v[0][0]); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::dmat2x3 v) { validate(shader_, uniform_type::dmat2x3); glProgramUniformMatrix2x3dv(shader_, location_, 1, GL_FALSE, &v[0][0]); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::dmat2x4 v) { validate(shader_, uniform_type::dmat2x4); glProgramUniformMatrix2x4dv(shader_, location_, 1, GL_FALSE, &v[0][0]); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::dmat3x2 v) { validate(shader_, uniform_type::dmat3x2); glProgramUniformMatrix3x2dv(shader_, location_, 1, GL_FALSE, &v[0][0]); return *this; } +template<> inline shader::uniform& shader::uniform::operator= (glm::dmat3 v) { validate(shader_, uniform_type::dmat3); glProgramUniformMatrix3dv (shader_, location_, 1, GL_FALSE, &v[0][0]); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::dmat3x4 v) { validate(shader_, uniform_type::dmat3x4); glProgramUniformMatrix3x4dv(shader_, location_, 1, GL_FALSE, &v[0][0]); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::dmat4x2 v) { validate(shader_, uniform_type::dmat4x2); glProgramUniformMatrix4x2dv(shader_, location_, 1, GL_FALSE, &v[0][0]); return *this; } +template<> inline shader::uniform& shader::uniform::operator=(glm::dmat4x3 v) { validate(shader_, uniform_type::dmat4x3); glProgramUniformMatrix4x3dv(shader_, location_, 1, GL_FALSE, &v[0][0]); return *this; } +template<> inline shader::uniform& shader::uniform::operator= (glm::dmat4 v) { validate(shader_, uniform_type::dmat4); glProgramUniformMatrix4dv (shader_, location_, 1, GL_FALSE, &v[0][0]); return *this; } + + +// shader -------------------------------------------------------------------------------------------------------------- + +inline shader::shader() + : handle_(glCreateProgram()) + , work_group_size_{ 1 } + , pass_requested_invocations_(false) +{ + +} + +inline shader::~shader() +{ + glDeleteProgram(handle_); +} + +inline bool shader::attach_source(enum_t type, size_t count, const char** source, const size_t* lengths) +{ + handle_t shader = glCreateShader(type); + glShaderSource(shader, count, source, lengths); + glCompileShader(shader); + + int result; glGetShaderiv(shader, GL_COMPILE_STATUS, &result); + + if(result) glAttachShader(handle_, shader); + else + { + int res; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &res); + error_.resize(res); + glGetShaderInfoLog(shader, res, &res, error_.data()); + } + + glDeleteShader(shader); + + return result; +} + +inline bool shader::attach_source(enum_t type, const std::vector& source) +{ + std::vector src; src.reserve(source.size()); + std::vector len; len.reserve(source.size()); + + for(const std::string& str : source) + { + src.push_back(str.c_str()); + len.push_back(static_cast(str.length())); + } + + return attach_source(type, static_cast(source.size()), src.data(), len.data()); +} + +inline bool shader::link() +{ + glLinkProgram(handle_); + + int result; glGetProgramiv(handle_, GL_LINK_STATUS, &result); + + if(!result) + { + int res; glGetProgramiv(handle_, GL_INFO_LOG_LENGTH, &res); + error_.resize(res); + glGetProgramInfoLog(handle_, res, &res, error_.data()); + + return false; + } + + glGetProgramiv(handle_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &result); + std::string buffer(result + 1, '\0'); + size_t max_length = static_cast(buffer.capacity()); + char* str = buffer.data(); + glGetProgramiv(handle_, GL_ACTIVE_UNIFORMS, &result); + + for(int i = 0; i < result; ++i) + { + enum_t type; size_t length, size; + glGetActiveUniform(handle_, i, max_length, &length, &size, &type, str); + std::string res = buffer.substr(0, length).c_str(); + uniforms_[res] = uniform(*this, res, type); + + const bool len = length == sizeof(glw_RequestedInvocations) - 1; + const bool cmp = (strncmp(buffer.c_str(), glw_RequestedInvocations, length) == 0); + pass_requested_invocations_ |= (len && cmp); + } + + glGetProgramiv(handle_, GL_COMPUTE_WORK_GROUP_SIZE, work_group_size_); + + return true; +} + +inline void shader::bind() const +{ + glUseProgram(handle_); +} + +inline void shader::dispatch(int x, int y, int z) +{ + int num_groups_x = ceil_div(x, work_group_size_[0]); + int num_groups_y = ceil_div(y, work_group_size_[1]); + int num_groups_z = ceil_div(z, work_group_size_[2]); + + bind(); + + if(pass_requested_invocations_) + this->operator[](glw_RequestedInvocations) = glm::ivec3(x, y, z); + + glDispatchCompute(num_groups_x, num_groups_y, num_groups_z); +} + +inline shader::uniform shader::operator[](const std::string &str) +{ + auto it = uniforms_.find(str); + + if(it != uniforms_.end()) + return it->second; + + return uniform(); +} + +} + + +#endif //SHADER_H diff --git a/texture.h b/texture.h new file mode 100755 index 0000000..5d6a936 --- /dev/null +++ b/texture.h @@ -0,0 +1,654 @@ +// ===================================================================================================================== +// glw, an open-source library that wraps OpenGL structures into classes. +// Copyright (C) 2024 Medusa Slockbower +// +// 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 . +// ===================================================================================================================== + +#ifndef GLW_TEXTURE_H +#define GLW_TEXTURE_H + +#include +#include + +#include "common.h" + +#include +#include +#include + +#include + +namespace ocu = open_cpp_utils; + +namespace glw +{ + +// ===================================================================================================================== +// Definitions +// ===================================================================================================================== + + +using swizzle_t = glm::vec<4, enum_t>; +using wrapping_t = glm::vec<3, enum_t>; + +// Enums --------------------------------------------------------------------------------------------------------------- + +enum texture_type : enum_t +{ + texture1D = GL_TEXTURE_1D +, texture1DArray = GL_TEXTURE_1D_ARRAY + +, texture2D = GL_TEXTURE_2D +, textureRect = GL_TEXTURE_RECTANGLE +, texture2DArray = GL_TEXTURE_2D_ARRAY +, texture2DMS = GL_TEXTURE_2D_MULTISAMPLE +, texture2DMSArray = GL_TEXTURE_2D_MULTISAMPLE_ARRAY + +, textureCubemap = GL_TEXTURE_CUBE_MAP +, textureCubemapArray = GL_TEXTURE_CUBE_MAP_ARRAY + +, texture3D = GL_TEXTURE_3D +}; + +enum texture_param : enum_t +{ + depth_stencil_mode = GL_DEPTH_STENCIL_TEXTURE_MODE + +, base_mip_level = GL_TEXTURE_BASE_LEVEL +, max_mip_level = GL_TEXTURE_MAX_LEVEL + +, compare_mode = GL_TEXTURE_COMPARE_MODE +, compare_func = GL_TEXTURE_COMPARE_FUNC + +, lod_min = GL_TEXTURE_MIN_LOD +, lod_max = GL_TEXTURE_MAX_LOD +, lod_bias = GL_TEXTURE_LOD_BIAS + +, min_filter = GL_TEXTURE_MIN_FILTER +, mag_filter = GL_TEXTURE_MAG_FILTER + +, swizzle = GL_TEXTURE_SWIZZLE_RGBA +, swizzle_r = GL_TEXTURE_SWIZZLE_R +, swizzle_g = GL_TEXTURE_SWIZZLE_G +, swizzle_b = GL_TEXTURE_SWIZZLE_B +, swizzle_a = GL_TEXTURE_SWIZZLE_A + +, wrap_s = GL_TEXTURE_WRAP_S +, wrap_t = GL_TEXTURE_WRAP_T +, wrap_r = GL_TEXTURE_WRAP_R +, border = GL_TEXTURE_BORDER_COLOR +}; + +enum filtering : enum_t +{ + nearest = GL_NEAREST +, linear = GL_LINEAR +, point = GL_NEAREST_MIPMAP_NEAREST +, bilinear = GL_LINEAR_MIPMAP_NEAREST +, trilinear = GL_LINEAR_MIPMAP_LINEAR +}; + +enum wrapping : enum_t +{ + clamp = GL_CLAMP_TO_EDGE +, clamp_to_border = GL_CLAMP_TO_BORDER +, mirrored = GL_MIRRORED_REPEAT +, repeate = GL_REPEAT +, mirrored_clamp = GL_MIRROR_CLAMP_TO_EDGE +}; + +enum swizzle : enum_t +{ + red = GL_TEXTURE_SWIZZLE_R +, green = GL_TEXTURE_SWIZZLE_G +, blue = GL_TEXTURE_SWIZZLE_B +, alpha = GL_TEXTURE_SWIZZLE_A +}; + + +template +class texture +{ +// Constants =========================================================================================================== + +public: + inline static constexpr enum_t type = T_; + inline static constexpr enum_t format = PF_; + + inline static constexpr struct type_traits + { + static constexpr enum_t type = T_; + static constexpr enum_t format = PF_; + static constexpr bool layered = contains_enum{}; + } traits {}; + + +// Functions =========================================================================================================== + +private: + void get_current_params_(); + +// Constructors -------------------------------------------------------------------------------------------------------- + +public: + texture(size_t size); + texture(glm::ivec2 size); + texture(glm::ivec2 size, size_t samples); + texture(glm::ivec3 size); + texture(glm::ivec3 size, size_t samples); + + texture(texture&& move); + + ~texture(); + + inline constexpr enum_t get_type() const { return type; } + inline constexpr enum_t get_format() const { return format; } + +// Handle -------------------------------------------------------------------------------------------------------------- + + /** + * \brief ONLY USE THIS IF YOU KNOW WHAT YOU ARE DOING + * \return The OpenGL name for the texture + */ + handle_t handle() { return handle_; } + + +// Capacity ------------------------------------------------------------------------------------------------------------ + + size_t size() const requires(contains_enum::value) { return size_.x; } + glm::ivec2 size() const requires(contains_enum::value) { return size_; } + glm::ivec3 size() const requires(contains_enum::value) { return size_; } + + void resize(size_t size); + void resize(glm::ivec2 size); + void resize(glm::ivec2 size, size_t samples); + void resize(glm::ivec3 size); + void resize(glm::ivec3 size, size_t samples); + + size_t num_samples() const { return samples_; } + +// Modifiers ----------------------------------------------------------------------------------------------------------- + + void upload(const void* pixels, size_t size, index_t offset = 0, index_t level = 0, enum_t layout = r_i, enum_t type = uint8) + requires(contains_enum::value) + { + glTextureSubImage1D(handle_, level, offset, size, layout, type, pixels); + glGenerateTextureMipmap(handle_); + } + + void upload(const void* pixels, glm::ivec2 size, glm::ivec2 offset = glm::ivec2(0), index_t level = 0, enum_t layout = r_i, enum_t type = uint8) + requires(contains_enum::value) + { + glTextureSubImage2D(handle_, level, offset.x, offset.y, size.x, size.y, layout, type, pixels); + } + + void upload(const void* pixels, glm::ivec3 size, glm::ivec3 offset = glm::ivec3(0), index_t level = 0, enum_t layout = r_i, enum_t type = uint8) + requires(contains_enum::value) + { + glTextureSubImage3D(handle_, level, offset.x, offset.y, offset.x, size.x, size.y, size.z, layout, type, pixels); + } + + void clear(size_t size = -1, index_t offset = 0, index_t level = 0, const void* data = nullptr, enum_t layout = r_i, enum_t type = uint8) + { + static_assert(contains_enum::value); + + size = size < 0 ? size_.x - offset : size; + glClearTexSubImage(handle_, level, offset, 0, 0, size, 1, 1, layout, type, data); + } + + void clear(glm::ivec2 size = glm::ivec2(-1), glm::ivec2 offset = glm::ivec2(0), index_t level = 0, const void* data = nullptr, enum_t layout = r_i, enum_t type = uint8) + { + static_assert(contains_enum::value); + + size.x = size.x < 0 ? size_.x - offset.x : size.x; + size.y = size.y < 0 ? size_.y - offset.y : size.y; + glClearTexSubImage(handle_, level, offset.x, offset.y, 0, size.x, size.y, 1, layout, type, data); + } + + void clear(glm::ivec3 size = glm::ivec3(-1), glm::ivec3 offset = glm::ivec3(0), index_t level = 0, const void* data = nullptr, enum_t layout = r_i, enum_t type = uint8) + { + static_assert(contains_enum::value); + size.x = size.x < 0 ? size_.x - offset.x : size.x; + size.y = size.y < 0 ? size_.y - offset.y : size.y; + size.z = size.z < 0 ? size_.z - offset.z : size.z; + glClearTexSubImage(handle_, level, offset.x, offset.y, offset.z, size.x, size.y, size.z, layout, type, data); + } + + template + void copy(const texture& src, size_t size = -1, + offset_t src_offset = 0, index_t src_level = 0, + offset_t dst_offset = 0, index_t dst_level = 0) + { + using otexture = texture; + static_assert(contains_enum::value && type == otexture::type); + size = size < 0 ? src.size_.x - src_offset : size; + + glCopyImageSubData( + src.handle_, otexture::type, src_level, src_offset, 0, 0, + handle_, type, dst_level, dst_offset, 0, 0, + size, 0, 0 + ); + } + + template + void copy(const texture& src, glm::ivec2 size = glm::ivec2(-1), + glm::ivec2 src_offset = glm::ivec2(0), index_t src_level = 0, + glm::ivec2 dst_offset = glm::ivec2(0), index_t dst_level = 0) + { + using otexture = texture; + static_assert(contains_enum::value && type == otexture::type); + size.x = size.x < 0 ? src.size_.x - src_offset.x : size.x; + size.y = size.y < 0 ? src.size_.y - src_offset.y : size.y; + + glCopyImageSubData( + src.handle_, otexture::type, src_level, src_offset.x, src_offset.y, 0, + handle_, type, dst_level, dst_offset.x, dst_offset.y, 0, + size.x, size.y, 0 + ); + } + + template + void copy(const texture& src, glm::ivec3 size = glm::ivec3(-1), + glm::ivec3 src_offset = glm::ivec3(0), index_t src_level = 0, + glm::ivec3 dst_offset = glm::ivec3(0), index_t dst_level = 0) + { + using otexture = texture; + static_assert(contains_enum::value && type == otexture::type); + size.x = size.x < 0 ? src.size_.x - src_offset.x : size.x; + size.y = size.y < 0 ? src.size_.y - src_offset.y : size.y; + size.z = size.z < 0 ? src.size_.z - src_offset.z : size.z; + + glCopyImageSubData( + src.handle_, otexture::type, src_level, src_offset.x, src_offset.y, src_offset.z, + handle_, type, dst_level, dst_offset.x, dst_offset.y, dst_offset.z, + size.x, size.y, size.z + ); + } + + +// Binding ------------------------------------------------------------------------------------------------------------- + + void bind(location_t loc) + { + glActiveTexture(GL_TEXTURE0 + loc); + glBindTexture(type, handle_); + } + + void bind_image(location_t loc, enum_t access) + { + glBindImageTexture(loc, handle_, 0, traits.layered, 0, access, format); + } + + void bind_image(location_t loc, index_t level, bool layered, index_t layer, enum_t access, enum_t format) + { + glBindImageTexture(loc, handle_, level, layered, layer, access, format); + } + + +// Depth / Stencil ----------------------------------------------------------------------------------------------------- + + void set_ds_mode(enum_t mode) { glTextureParameteri(handle_, GL_DEPTH_STENCIL_TEXTURE_MODE, depth_stencil_mode_ = mode); } + enum_t get_ds_mode() const { return depth_stencil_mode_; } + + void set_compare_mode(enum_t mode) { glTextureParameteri(handle_, GL_TEXTURE_COMPARE_MODE, compare_mode_ = mode); } + enum_t get_compare_mode() const { return compare_mode_; } + + void set_compare_func(enum_t func) { glTextureParameteri(handle_, GL_TEXTURE_COMPARE_FUNC, compare_func_ = func); } + enum_t get_compare_func() const { return compare_func_; } + + void set_comparison(enum_t mode, enum_t func) { set_compare_mode(mode); set_compare_func(func); } + + +// Mip Mapping --------------------------------------------------------------------------------------------------------- + + // TODO: Fix bug from optimization in resize, might be better to make a "rebuild" function + void set_num_mip_levels(size_t value) + requires(contains_enum::value) + { mip_levels_ = value; resize(size_.x); } + + void set_num_mip_levels(size_t value) + requires(contains_enum::value) + { mip_levels_ = value; resize(size_.x, size_.y); } + + void set_num_mip_levels(size_t value) + requires(contains_enum::value) + { mip_levels_ = value; resize(size_.x, size_.y, size_.z); } + + size_t get_num_mip_levels() const { return mip_levels_; } + + void set_base_mip_level(size_t value) { glTextureParameteri(handle_, GL_TEXTURE_BASE_LEVEL, base_mip_level_ = value); } + size_t get_base_mip_level() const { return base_mip_level_; } + + void set_max_mip_level(size_t value) { glTextureParameteri(handle_, GL_TEXTURE_MAX_LEVEL, max_mip_level_ = value); } + size_t get_max_mip_level() const { return max_mip_level_; } + + void set_lod_min(float value) { glTextureParameterf(handle_, GL_TEXTURE_MIN_LOD, lod_min_ = value); } + float get_lod_min() const { return lod_min_; } + + void set_lod_max(float value) { glTextureParameterf(handle_, GL_TEXTURE_MAX_LOD, lod_max_ = value); } + float get_lod_max() const { return lod_max_; } + + void set_lod_range(float min, float max) { set_lod_min(min); set_lod_max(max); } + + void set_lod_bias(float value) { glTextureParameterf(handle_, GL_TEXTURE_LOD_BIAS, lod_bias_ = value); } + float get_lod_bias() const { return lod_bias_; } + + void generate_mipmaps() { glGenerateTextureMipmap(handle_); } + + +// Filtering ----------------------------------------------------------------------------------------------------------- + + void set_min_filter(enum_t value) { glTextureParameteri(handle_, GL_TEXTURE_MIN_FILTER, min_filter_ = value); } + enum_t get_min_filter() const { return min_filter_; } + + void set_mag_filter(enum_t value) { glTextureParameteri(handle_, GL_TEXTURE_MAG_FILTER, mag_filter_ = value); } + enum_t get_mag_filter() const { return mag_filter_; } + + +// Swizzling ----------------------------------------------------------------------------------------------------------- + + void set_swizzle_r(enum_t swizzle) { glTextureParameteri(handle_, GL_TEXTURE_SWIZZLE_R, swizzle_.r = swizzle); } + enum_t get_swizzle_r() const { return swizzle_.r; } + + void set_swizzle_g(enum_t swizzle) { glTextureParameteri(handle_, GL_TEXTURE_SWIZZLE_G, swizzle_.g = swizzle); } + enum_t get_swizzle_g() const { return swizzle_.g; } + + void set_swizzle_b(enum_t swizzle) { glTextureParameteri(handle_, GL_TEXTURE_SWIZZLE_B, swizzle_.b = swizzle); } + enum_t get_swizzle_b() const { return swizzle_.b; } + + void set_swizzle_a(enum_t swizzle) { glTextureParameteri(handle_, GL_TEXTURE_SWIZZLE_A, swizzle_.a = swizzle); } + enum_t get_swizzle_a() const { return swizzle_.a; } + + void set_swizzle(const swizzle_t& swizzle) { glTextureParameterIuiv(handle_, GL_TEXTURE_SWIZZLE_RGBA, &(swizzle_ = swizzle).x); } + const swizzle_t& get_swizzle() const { return swizzle_; } + + +// Wrapping ------------------------------------------------------------------------------------------------------------ + + void set_wrapping_s(enum_t value) { glTextureParameteri(handle_, GL_TEXTURE_WRAP_S, wrapping_.x = value); } + enum_t get_wrapping_s() const { return wrapping_.x; } + + void set_wrapping_t(enum_t value) { glTextureParameteri(handle_, GL_TEXTURE_WRAP_T, wrapping_.y = value); } + enum_t get_wrapping_t() const { return wrapping_.y; } + + void set_wrapping_r(enum_t value) { glTextureParameteri(handle_, GL_TEXTURE_WRAP_R, wrapping_.z = value); } + enum_t get_wrapping_r() const { return wrapping_.z; } + + void set_wrapping(const wrapping_t& value) + { + glTextureParameteri(handle_, GL_TEXTURE_WRAP_S, wrapping_.x = value.x); + glTextureParameteri(handle_, GL_TEXTURE_WRAP_T, wrapping_.y = value.y); + glTextureParameteri(handle_, GL_TEXTURE_WRAP_R, wrapping_.z = value.z); + } + + const wrapping_t& get_wrapping() const { return wrapping_; } + + void set_border_color(const glm::vec4& value) { glTextureParameterfv(handle_, GL_TEXTURE_BORDER_COLOR, &(border_color_ = value).x); } + const glm::vec4& get_border_color() const { return border_color_; } + +// Variables =========================================================================================================== + +private: + handle_t handle_; + glm::ivec3 size_; + size_t samples_, mip_levels_; + + enum_t depth_stencil_mode_; + size_t base_mip_level_, max_mip_level_; + glm::vec4 border_color_; + enum_t compare_mode_, compare_func_; + float lod_min_, lod_max_, lod_bias_; + enum_t min_filter_, mag_filter_; + swizzle_t swizzle_; + wrapping_t wrapping_; +}; + +template +void texture::get_current_params_() +{ + glGetTextureParameterIuiv(handle_, GL_DEPTH_STENCIL_TEXTURE_MODE, &depth_stencil_mode_); + glGetTextureParameteriv(handle_, GL_TEXTURE_BASE_LEVEL, &base_mip_level_); + glGetTextureParameteriv(handle_, GL_TEXTURE_MAX_LEVEL, &max_mip_level_); + + glGetTextureParameterfv(handle_, GL_TEXTURE_BORDER_COLOR, &border_color_.x); + + glGetTextureParameterIuiv(handle_, GL_TEXTURE_COMPARE_MODE, &compare_mode_); + glGetTextureParameterIuiv(handle_, GL_TEXTURE_COMPARE_FUNC, &compare_func_); + + glGetTextureParameterfv(handle_, GL_TEXTURE_MIN_LOD, &lod_min_); + glGetTextureParameterfv(handle_, GL_TEXTURE_MAX_LOD, &lod_max_); + glGetTextureParameterfv(handle_, GL_TEXTURE_LOD_BIAS, &lod_bias_); + + glGetTextureParameterIuiv(handle_, GL_TEXTURE_MIN_FILTER, &min_filter_); + glGetTextureParameterIuiv(handle_, GL_TEXTURE_MAG_FILTER, &mag_filter_); + + glGetTextureParameterIuiv(handle_, GL_TEXTURE_SWIZZLE_RGBA, &swizzle_.x); + glGetTextureParameterIuiv(handle_, GL_TEXTURE_WRAP_S, &wrapping_.x); + glGetTextureParameterIuiv(handle_, GL_TEXTURE_WRAP_T, &wrapping_.y); + glGetTextureParameterIuiv(handle_, GL_TEXTURE_WRAP_R, &wrapping_.z); +} + +template +texture::texture(size_t size) + : handle_(NULL) + , size_(size, size, size) + , samples_(1), mip_levels_(0) + , depth_stencil_mode_() + , base_mip_level_(), max_mip_level_() + , border_color_() + , compare_mode_(), compare_func_() + , lod_min_(), lod_max_(), lod_bias_() + , min_filter_(), mag_filter_() + , swizzle_(), wrapping_() +{ + static_assert(contains_enum::value); + + mip_levels_ = static_cast(glm::log2(static_cast(size))); + mip_levels_ = std::max(mip_levels_ - 6, 1); + + glCreateTextures(type, 1, &handle_); + glTextureStorage1D(handle_, mip_levels_, format, size); + + get_current_params_(); +} + +template +texture::texture(glm::ivec2 size) + : handle_(NULL) + , size_(size, 1) + , samples_(1), mip_levels_(0) + , depth_stencil_mode_() + , base_mip_level_(), max_mip_level_() + , border_color_() + , compare_mode_(), compare_func_() + , lod_min_(), lod_max_(), lod_bias_() + , min_filter_(), mag_filter_() + , swizzle_(), wrapping_() +{ + static_assert(contains_enum::value); + + mip_levels_ = static_cast(glm::log2(static_cast(min(size.x, size.y)))); + mip_levels_ = std::max(mip_levels_ - 6, 1); + + glCreateTextures(type, 1, &handle_); + glTextureStorage2D(handle_, mip_levels_, format, size.x, size.y); + + get_current_params_(); +} + +template +texture::texture(glm::ivec2 size, size_t samples) + : handle_(NULL) + , size_(size, 1) + , samples_(samples), mip_levels_(0) + , depth_stencil_mode_() + , base_mip_level_(), max_mip_level_() + , border_color_() + , compare_mode_(), compare_func_() + , lod_min_(), lod_max_(), lod_bias_() + , min_filter_(), mag_filter_() + , swizzle_(), wrapping_() +{ + static_assert(contains_enum::value); + + glCreateTextures(type, 1, &handle_); + glTextureStorage2DMultisample(handle_, samples, format, size.x, size.y, true); + + get_current_params_(); +} + +template +texture::texture(glm::ivec3 size) + : handle_(NULL) + , size_(size) + , samples_(1), mip_levels_(0) + , depth_stencil_mode_() + , base_mip_level_(), max_mip_level_() + , border_color_() + , compare_mode_(), compare_func_() + , lod_min_(), lod_max_(), lod_bias_() + , min_filter_(), mag_filter_() + , swizzle_(), wrapping_() +{ + static_assert(contains_enum::value); + + mip_levels_ = static_cast(glm::log2(static_cast(min(size.x, size.y, size.z)))); + mip_levels_ = std::max(mip_levels_ - 6, 1); + + glCreateTextures(type, 1, &handle_); + glTextureStorage3D(handle_, mip_levels_, format, size.x, size.y, size.z); + + get_current_params_(); +} + +template +texture::texture(glm::ivec3 size, size_t samples) + : handle_(NULL) + , size_(size) + , samples_(samples), mip_levels_(0) + , depth_stencil_mode_() + , base_mip_level_(), max_mip_level_() + , border_color_() + , compare_mode_(), compare_func_() + , lod_min_(), lod_max_(), lod_bias_() + , min_filter_(), mag_filter_() + , swizzle_(), wrapping_() +{ + static_assert(contains_enum::value); + + glCreateTextures(type, 1, &handle_); + glTextureStorage3DMultisample(handle_, samples, format, size.x, size.y, size.z, true); + + get_current_params_(); +} + +template +texture::texture(texture&& move) + : handle_(move.handle_) + , size_(move.size_) + , samples_(move.samples_) + , mip_levels_(move.mip_levels_) + , depth_stencil_mode_(move.depth_stencil_mode_) + , base_mip_level_(move.base_mip_level_) + , max_mip_level_(move.max_mip_level_) + , border_color_(move.border_color_) + , compare_mode_(move.compare_mode_) + , compare_func_(move.compare_func_) + , lod_min_(move.lod_min_) + , lod_max_(move.lod_max_) + , lod_bias_(move.lod_bias_) + , min_filter_(move.min_filter_) + , mag_filter_(move.mag_filter_) + , swizzle_(move.swizzle_) + , wrapping_(move.wrapping_) + +{ + move.handle_ = 0; +} + +template +texture::~texture() +{ + if(handle_) glDeleteTextures(1, &handle_); +} + +template +void texture::resize(size_t size) +{ + static_assert(contains_enum::value); + + if(size == size_.x) return; + + glDeleteTextures(1, &handle_); + glCreateTextures(type, 1, &handle_); + glTextureStorage1D(handle_, mip_levels_, format, size); + size_ = glm::ivec3(size, 1, 1); +} + +template +void texture::resize(glm::ivec2 size) +{ + static_assert(contains_enum::value); + + if(size.x == size_.x && size.y == size_.y) return; + + glDeleteTextures(1, &handle_); + glCreateTextures(type, 1, &handle_); + glTextureStorage2D(handle_, mip_levels_, format, size.x, size.y); + size_ = glm::ivec3(size, 1); +} + +template +void texture::resize(glm::ivec2 size, size_t samples) +{ + static_assert(contains_enum::value); + + if(size.x == size_.x && size.y == size_.y && samples == samples_) return; + + glDeleteTextures(1, &handle_); + glCreateTextures(type, 1, &handle_); + glTextureStorage2DMultisample(handle_, samples_ = samples, format, size.x, size.y, true); + size_ = glm::ivec3(size, 1); +} + +template +void texture::resize(glm::ivec3 size) +{ + static_assert(contains_enum::value); + + if(size.x == size_.x && size.y == size_.y && size.z == size_.z) return; + + glDeleteTextures(1, &handle_); + glCreateTextures(type, 1, &handle_); + glTextureStorage3D(handle_, mip_levels_, format, size.x, size.y, size.z); + size_ = glm::ivec3(size); +} + +template +void texture::resize(glm::ivec3 size, size_t samples) +{ + static_assert(contains_enum::value); + + if(size.x == size_.x && size.y == size_.y && size.z == size_.z && samples == samples_) return; + + glDeleteTextures(1, &handle_); + glCreateTextures(type, 1, &handle_); + glTextureStorage3DMultisample(handle_, samples_ = samples, format, size.x, size.y, size.z, true); + size_ = glm::ivec3(size); +} + +} + +#endif // GLW_TEXTURE_H diff --git a/texture_array.h b/texture_array.h new file mode 100755 index 0000000..69d491c --- /dev/null +++ b/texture_array.h @@ -0,0 +1,83 @@ +// ===================================================================================================================== +// glw, an open-source library that wraps OpenGL structures into classes. +// Copyright (C) 2024 Medusa Slockbower +// +// 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 . +// ===================================================================================================================== + +#ifndef GLW_TEXTURE_ARRAY_H +#define GLW_TEXTURE_ARRAY_H + +#include "common.h" +#include "texture.h" + +namespace glw +{ + +template +class texarray +{ +// Constants =========================================================================================================== + +public: + inline static constexpr enum_t type = T_; + inline static constexpr size_t length = sizeof...(Fs_); + +private: + using array_type = std::tuple...>; + + +// Functions =========================================================================================================== + + // Helpers + template void resize_(size_t size) { get().resize(size); if constexpr (I < length - 1) resize_(size); } + template void resize_(glm::ivec2 size) { get().resize(size); if constexpr (I < length - 1) resize_(size); } + template void resize_(glm::ivec2 size, size_t samples) { get().resize(size); if constexpr (I < length - 1) resize_(size, samples); } + template void resize_(glm::ivec3 size) { get().resize(size); if constexpr (I < length - 1) resize_(size); } + template void resize_(glm::ivec3 size, size_t samples) { get().resize(size); if constexpr (I < length - 1) resize_(size, samples); } + +public: + texarray(size_t size) : array_(texture{ size }...) { } + texarray(glm::ivec2 size) : array_(texture{ size }...) { } + texarray(glm::ivec2 size, size_t samples) : array_(texture{ size, samples }...) { } + texarray(glm::ivec3 size) : array_(texture{ size }...) { } + texarray(glm::ivec3 size, size_t samples) : array_(texture{ size, samples }...) { } + + void resize(size_t size) { resize_(size); } + void resize(glm::ivec2 size) { resize_(size); } + void resize(glm::ivec2 size, size_t samples) { resize_(size, samples); } + void resize(glm::ivec3 size) { resize_(size); } + void resize(glm::ivec3 size, size_t samples) { resize_(size, samples); } + + // Variables =========================================================================================================== + + template + constexpr std::tuple_element_t<_Index, array_type>& get() noexcept + { + return std::get<_Index>(array_); + } + + template + constexpr const std::tuple_element_t<_Index, array_type>& get() const noexcept + { + return std::get<_Index>(array_); + } + +private: + array_type array_; +}; + +} + +#endif //TEXTURE_ARRAY_H diff --git a/timer.h b/timer.h new file mode 100755 index 0000000..44a3631 --- /dev/null +++ b/timer.h @@ -0,0 +1,62 @@ +// ===================================================================================================================== +// glw, an open-source library that wraps OpenGL structures into classes. +// Copyright (C) 2024 Medusa Slockbower +// +// 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 . +// ===================================================================================================================== + +#ifndef GLW_TIMER_H +#define GLW_TIMER_H + +#include +#include "common.h" + +namespace glw +{ + +class timer +{ +private: + enum + { + begin = 0 + , end = 1 + }; + +public: + timer() : handles_{ 0 }, running_(false) { glCreateQueries(GL_TIMESTAMP, 2, handles_); } + timer(const timer&) = delete; + timer(timer&&) = default; + ~timer() { glDeleteQueries(2, handles_); } + + void start() { assert(not running_); glQueryCounter(handles_[begin], GL_TIMESTAMP); running_ = true; } + void stop() { assert(running_); glQueryCounter(handles_[end], GL_TIMESTAMP); running_ = false; } + int64_t poll() + { + assert(not running_); + int32_t available = false; + while(not available) glGetQueryObjectiv(handles_[end], GL_QUERY_RESULT_AVAILABLE, &available); + int64_t start; glGetQueryObjecti64v(handles_[begin], GL_QUERY_RESULT, &start); + int64_t stop; glGetQueryObjecti64v(handles_[end], GL_QUERY_RESULT, &stop); + return stop - start; + } + +private: + handle_t handles_[2]; + bool running_; +}; + +} + +#endif //TIMER_H diff --git a/vertex_descriptor.h b/vertex_descriptor.h new file mode 100755 index 0000000..7a93b07 --- /dev/null +++ b/vertex_descriptor.h @@ -0,0 +1,114 @@ +// ===================================================================================================================== +// glw, an open-source library that wraps OpenGL structures into classes. +// Copyright (C) 2024 Medusa Slockbower +// +// 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 . +// ===================================================================================================================== + +#ifndef GLW_VERTEX_DESCRIPTOR_H +#define GLW_VERTEX_DESCRIPTOR_H + +#include "common.h" + +#include + +namespace ocu = open_cpp_utils; + +namespace glw +{ + +// ===================================================================================================================== +// Definitions +// ===================================================================================================================== + +class vertex_descriptor +{ +// Functions =========================================================================================================== + +private: + struct attribute + { + size_t size; + enum_t type; + bool normalized; + index_t offset; + }; + + +// Functions =========================================================================================================== + +public: + vertex_descriptor(); + vertex_descriptor(const vertex_descriptor&); + vertex_descriptor(vertex_descriptor&&) = default; + ~vertex_descriptor(); + + void add_attribute(enum_t type, size_t size, bool normalized); + + void bind(); + +// Variables =========================================================================================================== + +private: + handle_t handle_; + ocu::dynarray attributes_; +}; + +inline vertex_descriptor::vertex_descriptor() + : handle_(NULL) +{ + glCreateVertexArrays(1, &handle_); +} + +inline vertex_descriptor::vertex_descriptor(const vertex_descriptor& other) + : handle_(NULL) +{ + glCreateVertexArrays(1, &handle_); + attributes_.reserve(other.attributes_.size()); + + for(const attribute& attrib : other.attributes_) + { + add_attribute(attrib.type, attrib.size, attrib.normalized); + } +} + +inline vertex_descriptor::~vertex_descriptor() +{ + glDeleteVertexArrays(1, &handle_); +} + +inline void vertex_descriptor::add_attribute(enum_t type, size_t size, bool normalized) +{ + index_t offset = 0; + + if(attributes_.empty() == false) + { + const attribute& prev = attributes_.back(); + offset = prev.offset + prev.size * size_of(prev.type); + } + + glEnableVertexArrayAttrib(handle_, attributes_.size()); + glVertexArrayAttribFormat(handle_, attributes_.size(), size, type, normalized, offset); + + attributes_.push_back(attribute(size, type, normalized, offset)); +} + +inline void vertex_descriptor::bind() +{ + glBindVertexArray(handle_); +} + +} + +#endif //VERTEX_DESCRIPTOR_H