diff --git a/.gitignore b/.gitignore index cd2946a..6182da7 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,5 @@ $RECYCLE.BIN/ Network Trash Folder Temporary Items .apdisk + +/build \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..5b6b6a9 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/dynamic_libs"] + path = src/dynamic_libs + url = https://github.com/Maschell/dynamic_libs diff --git a/GX2_template.cbp b/GX2_template.cbp new file mode 100644 index 0000000..e28a604 --- /dev/null +++ b/GX2_template.cbp @@ -0,0 +1,281 @@ + + + + + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9cecc1d --- /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. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + 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: + + {project} Copyright (C) {year} {fullname} + 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/Makefile b/Makefile new file mode 100644 index 0000000..149acec --- /dev/null +++ b/Makefile @@ -0,0 +1,227 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITPPC)),) +$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") +endif +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=devkitPRO") +endif +export PATH := $(DEVKITPPC)/bin:$(PORTLIBS)/bin:$(PATH) +export LIBOGC_INC := $(DEVKITPRO)/libogc/include +export LIBOGC_LIB := $(DEVKITPRO)/libogc/lib/wii +export PORTLIBS := $(DEVKITPRO)/portlibs/ppc + +PREFIX := powerpc-eabi- + +export AS := $(PREFIX)as +export CC := $(PREFIX)gcc +export CXX := $(PREFIX)g++ +export AR := $(PREFIX)ar +export OBJCOPY := $(PREFIX)objcopy + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := gx2_template +BUILD := build +BUILD_DBG := $(TARGET)_dbg +SOURCES := src \ + src/common \ + src/dynamic_libs \ + src/fs \ + src/game \ + src/gui \ + src/menu \ + src/resources \ + src/sounds \ + src/system \ + src/utils \ + src/video \ + src/video/shaders +DATA := data \ + data/images \ + data/fonts \ + data/sounds + +INCLUDES := src + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +CFLAGS := -std=gnu11 -mrvl -mcpu=750 -meabi -mhard-float -ffast-math \ + -O3 -Wall -Wextra -Wno-unused-parameter -Wno-strict-aliasing $(INCLUDE) +CXXFLAGS := -std=gnu++11 -mrvl -mcpu=750 -meabi -mhard-float -ffast-math \ + -O3 -Wall -Wextra -Wno-unused-parameter -Wno-strict-aliasing $(INCLUDE) +ASFLAGS := -mregnames +LDFLAGS := -nostartfiles -Wl,-Map,$(notdir $@).map,-wrap,malloc,-wrap,free,-wrap,memalign,-wrap,calloc,-wrap,realloc,-wrap,malloc_usable_size,-wrap,_malloc_r,-wrap,_free_r,-wrap,_realloc_r,-wrap,_calloc_r,-wrap,_memalign_r,-wrap,_malloc_usable_size_r,-wrap,valloc,-wrap,_valloc_r,-wrap,_pvalloc_r,--gc-sections + +#--------------------------------------------------------------------------------- +Q := @ +MAKEFLAGS += --no-print-directory +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -lgcc -lgd -lpng -ljpeg -lz -lfreetype -lmad -lvorbisidec + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(CURDIR) \ + $(DEVKITPPC)/lib \ + $(DEVKITPPC)/lib/gcc/powerpc-eabi/4.8.2 + + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- +export PROJECTDIR := $(CURDIR) +export OUTPUT := $(CURDIR)/$(TARGETDIR)/$(TARGET) +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +export DEPSDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +FILELIST := $(shell bash ./filelist.sh) +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +TTFFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.ttf))) +PNGFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.png))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) \ + $(PNGFILES:.png=.png.o) $(addsuffix .o,$(BINFILES)) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) -I$(LIBOGC_INC) \ + -I$(PORTLIBS)/include -I$(PORTLIBS)/include/freetype2 + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + -L$(LIBOGC_LIB) -L$(PORTLIBS)/lib + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean install + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).bin $(BUILD_DBG).elf + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).elf: $(OFILES) + +#--------------------------------------------------------------------------------- +# This rule links in binary data with the .jpg extension +#--------------------------------------------------------------------------------- +%.elf: link.ld $(OFILES) + @echo "linking ... $(TARGET).elf" + $(Q)$(LD) -n -T $^ $(LDFLAGS) -o ../$(BUILD_DBG).elf $(LIBPATHS) $(LIBS) + $(Q)$(OBJCOPY) -S -R .comment -R .gnu.attributes ../$(BUILD_DBG).elf $@ + +../data/loader.bin: + $(MAKE) -C ../loader clean + $(MAKE) -C ../loader +#--------------------------------------------------------------------------------- +%.a: +#--------------------------------------------------------------------------------- + @echo $(notdir $@) + @rm -f $@ + @$(AR) -rc $@ $^ + +#--------------------------------------------------------------------------------- +%.o: %.cpp + @echo $(notdir $<) + @$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) -c $< -o $@ $(ERROR_FILTER) + +#--------------------------------------------------------------------------------- +%.o: %.c + @echo $(notdir $<) + @$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) -c $< -o $@ $(ERROR_FILTER) + +#--------------------------------------------------------------------------------- +%.o: %.S + @echo $(notdir $<) + @$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER) + +#--------------------------------------------------------------------------------- +%.png.o : %.png + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +#--------------------------------------------------------------------------------- +%.jpg.o : %.jpg + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +#--------------------------------------------------------------------------------- +%.ttf.o : %.ttf + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +#--------------------------------------------------------------------------------- +%.bin.o : %.bin + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +#--------------------------------------------------------------------------------- +%.wav.o : %.wav + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +#--------------------------------------------------------------------------------- +%.mp3.o : %.mp3 + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +#--------------------------------------------------------------------------------- +%.ogg.o : %.ogg + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/README.md b/README.md new file mode 100644 index 0000000..8b0048e --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +#GX2_GUI_Template# +This a (hopefully clean) template for GX2 (gui) project. [...] + +#Usage# +This example with render a white screen and return to the Homewbrew Launcher by pressing the Home button.
+At menu/MainWindowTV.cpp the magic of drawing the white screen is happening. + +#Building# +In order to build this application, you need the custom liboGC and portlibs modified/created by dimok. You can find them on the loadiine_gx2 repo (https://github.com/dimok789/loadiine_gx2/releases/tag/v0.2). Simply put the files in your devkit folder and run the Makefile. + +#Credits# +A big thanks goes out to dimok for creating the HBL, the dynamic libs and every stuff he made. The "environment" of this app is copied from HBL. In fact is just a cropped version of the HBL with a few extra GUI Element. So big shoutouts to dimok! + diff --git a/data/fonts/font.ttf b/data/fonts/font.ttf new file mode 100644 index 0000000..04be6f5 Binary files /dev/null and b/data/fonts/font.ttf differ diff --git a/data/sounds/bgMusic.ogg b/data/sounds/bgMusic.ogg new file mode 100644 index 0000000..d341468 Binary files /dev/null and b/data/sounds/bgMusic.ogg differ diff --git a/data/sounds/button_click.mp3 b/data/sounds/button_click.mp3 new file mode 100644 index 0000000..ec4aad7 Binary files /dev/null and b/data/sounds/button_click.mp3 differ diff --git a/filelist.sh b/filelist.sh new file mode 100644 index 0000000..87cbee1 --- /dev/null +++ b/filelist.sh @@ -0,0 +1,83 @@ +#! /bin/bash +# +# Automatic resource file list generation +# Created by Dimok + +outFile="./src/resources/filelist.h" +count_old=$(cat $outFile 2>/dev/null | tr -d '\n\n' | sed 's/[^0-9]*\([0-9]*\).*/\1/') + +count=0 +if [[ $OSTYPE == darwin* ]]; +then + +for i in $(gfind ./data/images/ ./data/sounds/ ./data/fonts/ -maxdepth 1 -type f \( ! -printf "%f\n" \) | sort -f) +do + files[count]=$i + count=$((count+1)) +done + +else + +for i in $(find ./data/images/ ./data/sounds/ ./data/fonts/ -maxdepth 1 -type f \( ! -printf "%f\n" \) | sort -f) +do + files[count]=$i + count=$((count+1)) +done + +fi + +if [ "$count_old" != "$count" ] || [ ! -f $outFile ] +then + +echo "Generating filelist.h for $count files." >&2 +cat < $outFile +/**************************************************************************** + * Loadiine resource files. + * This file is generated automatically. + * Includes $count files. + * + * NOTE: + * Any manual modification of this file will be overwriten by the generation. + ****************************************************************************/ +#ifndef _FILELIST_H_ +#define _FILELIST_H_ + +#include + +typedef struct _RecourceFile +{ + const char *filename; + const u8 *DefaultFile; + const u32 &DefaultFileSize; + u8 *CustomFile; + u32 CustomFileSize; +} RecourceFile; + +EOF + +for i in ${files[@]} +do + filename=${i%.*} + extension=${i##*.} + echo 'extern const u8 '$filename'_'$extension'[];' >> $outFile + echo 'extern const u32 '$filename'_'$extension'_size;' >> $outFile + echo '' >> $outFile +done + +echo 'static RecourceFile RecourceList[] =' >> $outFile +echo '{' >> $outFile + +for i in ${files[@]} +do + filename=${i%.*} + extension=${i##*.} + echo -e '\t{"'$i'", '$filename'_'$extension', '$filename'_'$extension'_size, NULL, 0},' >> $outFile +done + +echo -e '\t{NULL, NULL, 0, NULL, 0}' >> $outFile +echo '};' >> $outFile + +echo '' >> $outFile +echo '#endif' >> $outFile + +fi diff --git a/gx2_template.elf b/gx2_template.elf new file mode 100644 index 0000000..6fe538e Binary files /dev/null and b/gx2_template.elf differ diff --git a/gx2_template_dbg.elf b/gx2_template_dbg.elf new file mode 100644 index 0000000..cb1641a Binary files /dev/null and b/gx2_template_dbg.elf differ diff --git a/src/Application.cpp b/src/Application.cpp new file mode 100644 index 0000000..51c01d4 --- /dev/null +++ b/src/Application.cpp @@ -0,0 +1,198 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include "Application.h" +#include "common/common.h" +#include "dynamic_libs/os_functions.h" +#include "gui/FreeTypeGX.h" +#include "gui/VPadController.h" +#include "gui/WPadController.h" +#include "resources/Resources.h" +#include "sounds/SoundHandler.hpp" +#include "utils/logger.h" + +Application *Application::applicationInstance = NULL; +bool Application::exitApplication = false; + +Application::Application() + : CThread(CThread::eAttributeAffCore1 | CThread::eAttributePinnedAff, 0, 0x20000) + , bgMusic(NULL) + , video(NULL) + , mainWindow(NULL) + , exitCode(EXIT_RELAUNCH_ON_LOAD) +{ + controller[0] = new VPadController(GuiTrigger::CHANNEL_1); + controller[1] = new WPadController(GuiTrigger::CHANNEL_2); + controller[2] = new WPadController(GuiTrigger::CHANNEL_3); + controller[3] = new WPadController(GuiTrigger::CHANNEL_4); + controller[4] = new WPadController(GuiTrigger::CHANNEL_5); + + //! create bgMusic + /* + bgMusic = new GuiSound(Resources::GetFile("bgMusic.ogg"), Resources::GetFileSize("bgMusic.ogg")); + bgMusic->SetLoop(true); + bgMusic->Play(); + bgMusic->SetVolume(50);*/ + + exitApplication = false; +} + +Application::~Application(){ + log_printf("Destroy music\n"); + + delete bgMusic; + + log_printf("Destroy controller\n"); + + for(int i = 0; i < 5; i++) + delete controller[i]; + + log_printf("Destroy async deleter\n"); + AsyncDeleter::triggerDeleteProcess(); + AsyncDeleter::destroyInstance(); + + log_printf("Clear resources\n"); + Resources::Clear(); + + log_printf("Stop sound handler\n"); + SoundHandler::DestroyInstance(); +} + +int Application::exec(){ + //! start main GX2 thread + resumeThread(); + //! now wait for thread to finish + shutdownThread(); + + return exitCode; +} + +void Application::fadeOut(){ + GuiImage fadeOut(video->getTvWidth(), video->getTvHeight(), (GX2Color){ 0, 0, 0, 255 }); + + for(int i = 0; i < 255; i += 10) + { + if(i > 255) + i = 255; + + fadeOut.setAlpha(i / 255.0f); + + //! start rendering DRC + video->prepareDrcRendering(); + mainWindow->drawDrc(video); + + GX2SetDepthOnlyControl(GX2_DISABLE, GX2_DISABLE, GX2_COMPARE_ALWAYS); + fadeOut.draw(video); + GX2SetDepthOnlyControl(GX2_ENABLE, GX2_ENABLE, GX2_COMPARE_LEQUAL); + + video->drcDrawDone(); + + //! start rendering TV + video->prepareTvRendering(); + + mainWindow->drawTv(video); + + GX2SetDepthOnlyControl(GX2_DISABLE, GX2_DISABLE, GX2_COMPARE_ALWAYS); + fadeOut.draw(video); + GX2SetDepthOnlyControl(GX2_ENABLE, GX2_ENABLE, GX2_COMPARE_LEQUAL); + + video->tvDrawDone(); + + //! as last point update the effects as it can drop elements + mainWindow->updateEffects(); + + video->waitForVSync(); + } + + //! one last cleared black screen + video->prepareDrcRendering(); + video->drcDrawDone(); + video->prepareTvRendering(); + video->tvDrawDone(); + video->waitForVSync(); + video->tvEnable(false); + video->drcEnable(false); +} + +void Application::executeThread(void){ + log_printf("Initialize video\n"); + video = new CVideo(GX2_TV_SCAN_MODE_720P, GX2_DRC_SINGLE); + + log_printf("Video size %i x %i\n", video->getTvWidth(), video->getTvHeight()); + + //! setup default Font + log_printf("Initialize main font system\n"); + FreeTypeGX *fontSystem = new FreeTypeGX(Resources::GetFile("font.ttf"), Resources::GetFileSize("font.ttf"), true); + GuiText::setPresetFont(fontSystem); + + log_printf("Initialize main window\n"); + + mainWindow = new MainWindow(video->getTvWidth(), video->getTvHeight()); + + log_printf("Entering main loop\n"); + + //! main GX2 loop (60 Hz cycle with max priority on core 1) + while(!exitApplication) + { + //! Read out inputs + for(int i = 0; i < 5; i++) + { + if(controller[i]->update(video->getTvWidth(), video->getTvHeight()) == false) + continue; + + if(controller[i]->data.buttons_d & VPAD_BUTTON_HOME){ + exitApplication = true; + } + + //! update controller states + mainWindow->update(controller[i]); + } + + mainWindow->process(); + + //! start rendering DRC + video->prepareDrcRendering(); + mainWindow->drawDrc(video); + video->drcDrawDone(); + + //! start rendering TV + video->prepareTvRendering(); + mainWindow->drawTv(video); + video->tvDrawDone(); + + //! enable screen after first frame render + if(video->getFrameCount() == 0) { + video->tvEnable(true); + video->drcEnable(true); + } + + //! as last point update the effects as it can drop elements + mainWindow->updateEffects(); + + video->waitForVSync(); + + //! transfer elements to real delete list here after all processes are finished + //! the elements are transfered to another list to delete the elements in a separate thread + //! and avoid blocking the GUI thread + AsyncDeleter::triggerDeleteProcess(); + } + + fadeOut(); + + delete mainWindow; + delete fontSystem; + delete video; +} diff --git a/src/Application.h b/src/Application.h new file mode 100644 index 0000000..9abbafd --- /dev/null +++ b/src/Application.h @@ -0,0 +1,73 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 _APPLICATION_H +#define _APPLICATION_H + +#include "menu/MainWindow.h" +#include "video/CVideo.h" +#include "system/CThread.h" + +class Application : public CThread +{ +public: + static Application * instance() { + if(!applicationInstance) + applicationInstance = new Application(); + return applicationInstance; + } + static void destroyInstance() { + if(applicationInstance) { + delete applicationInstance; + applicationInstance = NULL; + } + } + + CVideo *getVideo(void) const { + return video; + } + MainWindow *getMainWindow(void) const { + return mainWindow; + } + + GuiSound *getBgMusic(void) const { + return bgMusic; + } + + int exec(void); + void fadeOut(void); + + void quit(int code) { + exitCode = code; + exitApplication = true; + } +private: + Application(); + virtual ~Application(); + + static Application *applicationInstance; + static bool exitApplication; + + void executeThread(void); + + GuiSound *bgMusic; + CVideo *video; + MainWindow *mainWindow; + GuiController *controller[5]; + int exitCode; +}; + +#endif //_APPLICATION_H diff --git a/src/common/common.h b/src/common/common.h new file mode 100644 index 0000000..7d224c8 --- /dev/null +++ b/src/common/common.h @@ -0,0 +1,59 @@ +#ifndef COMMON_H +#define COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "os_defs.h" + +#define CAFE_OS_SD_PATH "/vol/external01" +#define SD_PATH "sd:" +#define WIIU_PATH "/wiiu" + +/* Macros for libs */ +#define LIB_CORE_INIT 0 +#define LIB_NSYSNET 1 +#define LIB_GX2 2 +#define LIB_AOC 3 +#define LIB_AX 4 +#define LIB_FS 5 +#define LIB_OS 6 +#define LIB_PADSCORE 7 +#define LIB_SOCKET 8 +#define LIB_SYS 9 +#define LIB_VPAD 10 +#define LIB_NN_ACP 11 +#define LIB_SYSHID 12 +#define LIB_VPADBASE 13 + +// functions types +#define STATIC_FUNCTION 0 +#define DYNAMIC_FUNCTION 1 + +// none dynamic libs +#define LIB_LOADER 0x1001 + +#ifndef MEM_BASE +#define MEM_BASE (0x00800000) +#endif + +#define ELF_DATA_ADDR (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x00)) +#define ELF_DATA_SIZE (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x04)) +#define MAIN_ENTRY_ADDR (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x00)) +#define OS_FIRMWARE (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x04)) + +#define OS_SPECIFICS ((OsSpecifics*)(MEM_BASE + 0x1500)) + +#ifndef EXIT_SUCCESS +#define EXIT_SUCCESS 0 +#endif +#define EXIT_HBL_EXIT 0xFFFFFFFE +#define EXIT_RELAUNCH_ON_LOAD 0xFFFFFFFD + +#ifdef __cplusplus +} +#endif + +#endif /* COMMON_H */ + diff --git a/src/common/os_defs.h b/src/common/os_defs.h new file mode 100644 index 0000000..48a4c8f --- /dev/null +++ b/src/common/os_defs.h @@ -0,0 +1,25 @@ +#ifndef __OS_DEFS_H_ +#define __OS_DEFS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _OsSpecifics +{ + unsigned int addr_OSDynLoad_Acquire; + unsigned int addr_OSDynLoad_FindExport; + unsigned int addr_OSTitle_main_entry; + + unsigned int addr_KernSyscallTbl1; + unsigned int addr_KernSyscallTbl2; + unsigned int addr_KernSyscallTbl3; + unsigned int addr_KernSyscallTbl4; + unsigned int addr_KernSyscallTbl5; +} OsSpecifics; + +#ifdef __cplusplus +} +#endif + +#endif // __OS_DEFS_H_ diff --git a/src/common/types.h b/src/common/types.h new file mode 100644 index 0000000..3435e56 --- /dev/null +++ b/src/common/types.h @@ -0,0 +1,7 @@ +#ifndef TYPES_H +#define TYPES_H + +#include + +#endif /* TYPES_H */ + diff --git a/src/dynamic_libs b/src/dynamic_libs new file mode 160000 index 0000000..befce10 --- /dev/null +++ b/src/dynamic_libs @@ -0,0 +1 @@ +Subproject commit befce1016a6ca1ea5be68b038b396170aa618cad diff --git a/src/entry.c b/src/entry.c new file mode 100644 index 0000000..759cee0 --- /dev/null +++ b/src/entry.c @@ -0,0 +1,14 @@ +#include +#include "dynamic_libs/os_functions.h" +#include "dynamic_libs/sys_functions.h" +#include "common/common.h" +#include "utils/utils.h" +#include "main.h" + +int __entry_menu(int argc, char **argv) +{ + //! ******************************************************************* + //! * Jump to our application * + //! ******************************************************************* + return Menu_Main(); +} diff --git a/src/fs/CFile.cpp b/src/fs/CFile.cpp new file mode 100644 index 0000000..b26cbf5 --- /dev/null +++ b/src/fs/CFile.cpp @@ -0,0 +1,198 @@ +#include +#include +#include "CFile.hpp" + + +CFile::CFile() +{ + iFd = -1; + mem_file = NULL; + filesize = 0; + pos = 0; +} + +CFile::CFile(const std::string & filepath, eOpenTypes mode) +{ + iFd = -1; + this->open(filepath, mode); +} + +CFile::CFile(const u8 * mem, int size) +{ + iFd = -1; + this->open(mem, size); +} + +CFile::~CFile() +{ + this->close(); +} + +int CFile::open(const std::string & filepath, eOpenTypes mode) +{ + this->close(); + + s32 openMode = 0; + + switch(mode) + { + default: + case ReadOnly: + openMode = O_RDONLY; + break; + case WriteOnly: + openMode = O_WRONLY; + break; + case ReadWrite: + openMode = O_RDWR; + break; + case Append: + openMode = O_APPEND | O_WRONLY; + break; + } + + //! Using fopen works only on the first launch as expected + //! on the second launch it causes issues because we don't overwrite + //! the .data sections which is needed for a normal application to re-init + //! this will be added with launching as RPX + iFd = ::open(filepath.c_str(), openMode); + if(iFd < 0) + return iFd; + + + filesize = ::lseek(iFd, 0, SEEK_END); + ::lseek(iFd, 0, SEEK_SET); + + return 0; +} + +int CFile::open(const u8 * mem, int size) +{ + this->close(); + + mem_file = mem; + filesize = size; + + return 0; +} + +void CFile::close() +{ + if(iFd >= 0) + ::close(iFd); + + iFd = -1; + mem_file = NULL; + filesize = 0; + pos = 0; +} + +int CFile::read(u8 * ptr, size_t size) +{ + if(iFd >= 0) + { + int ret = ::read(iFd, ptr,size); + if(ret > 0) + pos += ret; + return ret; + } + + int readsize = size; + + if(readsize > (s64) (filesize-pos)) + readsize = filesize-pos; + + if(readsize <= 0) + return readsize; + + if(mem_file != NULL) + { + memcpy(ptr, mem_file+pos, readsize); + pos += readsize; + return readsize; + } + + return -1; +} + +int CFile::write(const u8 * ptr, size_t size) +{ + if(iFd >= 0) + { + size_t done = 0; + while(done < size) + { + int ret = ::write(iFd, ptr, size - done); + if(ret <= 0) + return ret; + + ptr += ret; + done += ret; + pos += ret; + } + return done; + } + + return -1; +} + +int CFile::seek(long int offset, int origin) +{ + int ret = 0; + s64 newPos = pos; + + if(origin == SEEK_SET) + { + newPos = offset; + } + else if(origin == SEEK_CUR) + { + newPos += offset; + } + else if(origin == SEEK_END) + { + newPos = filesize+offset; + } + + if(newPos < 0) + { + pos = 0; + } + else { + pos = newPos; + } + + if(iFd >= 0) + ret = ::lseek(iFd, pos, SEEK_SET); + + if(mem_file != NULL) + { + if(pos > filesize) + { + pos = filesize; + } + } + + return ret; +} + +int CFile::fwrite(const char *format, ...) +{ + int result = -1; + char * tmp = NULL; + + va_list va; + va_start(va, format); + if((vasprintf(&tmp, format, va) >= 0) && tmp) + { + result = this->write((u8 *)tmp, strlen(tmp)); + } + va_end(va); + + if(tmp) + free(tmp); + + return result; +} + + diff --git a/src/fs/CFile.hpp b/src/fs/CFile.hpp new file mode 100644 index 0000000..a95d3cd --- /dev/null +++ b/src/fs/CFile.hpp @@ -0,0 +1,57 @@ +#ifndef CFILE_HPP_ +#define CFILE_HPP_ + +#include +#include +#include +#include +#include +#include + +class CFile +{ + public: + enum eOpenTypes + { + ReadOnly, + WriteOnly, + ReadWrite, + Append + }; + + CFile(); + CFile(const std::string & filepath, eOpenTypes mode); + CFile(const u8 * memory, int memsize); + virtual ~CFile(); + + int open(const std::string & filepath, eOpenTypes mode); + int open(const u8 * memory, int memsize); + + bool isOpen() const { + if(iFd >= 0) + return true; + + if(mem_file) + return true; + + return false; + } + + void close(); + + int read(u8 * ptr, size_t size); + int write(const u8 * ptr, size_t size); + int fwrite(const char *format, ...); + int seek(long int offset, int origin); + u64 tell() { return pos; }; + u64 size() { return filesize; }; + void rewind() { this->seek(0, SEEK_SET); }; + + protected: + int iFd; + const u8 * mem_file; + u64 filesize; + u64 pos; +}; + +#endif diff --git a/src/fs/DirList.cpp b/src/fs/DirList.cpp new file mode 100644 index 0000000..147deaf --- /dev/null +++ b/src/fs/DirList.cpp @@ -0,0 +1,223 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * DirList Class + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include + +#include "DirList.h" +#include "utils/StringTools.h" + +DirList::DirList() +{ + Flags = 0; + Filter = 0; +} + +DirList::DirList(const std::string & path, const char *filter, u32 flags) +{ + this->LoadPath(path, filter, flags); + this->SortList(); +} + +DirList::~DirList() +{ + ClearList(); +} + +bool DirList::LoadPath(const std::string & folder, const char *filter, u32 flags) +{ + if(folder.empty()) return false; + + Flags = flags; + Filter = filter; + + std::string folderpath(folder); + u32 length = folderpath.size(); + + //! clear path of double slashes + RemoveDoubleSlashs(folderpath); + + //! remove last slash if exists + if(length > 0 && folderpath[length-1] == '/') + folderpath.erase(length-1); + + return InternalLoadPath(folderpath); +} + +bool DirList::InternalLoadPath(std::string &folderpath) +{ + if(folderpath.size() < 3) + return false; + + struct dirent *dirent = NULL; + DIR *dir = NULL; + + dir = opendir(folderpath.c_str()); + if (dir == NULL) + return false; + + while ((dirent = readdir(dir)) != 0) + { + bool isDir = dirent->d_type & DT_DIR; + const char *filename = dirent->d_name; + + if(isDir) + { + if(strcmp(filename,".") == 0 || strcmp(filename,"..") == 0) + continue; + + if(Flags & CheckSubfolders) + { + int length = folderpath.size(); + if(length > 2 && folderpath[length-1] != '/') + folderpath += '/'; + folderpath += filename; + InternalLoadPath(folderpath); + folderpath.erase(length); + } + + if(!(Flags & Dirs)) + continue; + } + else if(!(Flags & Files)) + { + continue; + } + + if(Filter) + { + char * fileext = strrchr(filename, '.'); + if(!fileext) + continue; + + if(strtokcmp(fileext, Filter, ",") == 0) + AddEntrie(folderpath, filename, isDir); + } + else + { + AddEntrie(folderpath, filename, isDir); + } + } + closedir(dir); + + return true; +} + +void DirList::AddEntrie(const std::string &filepath, const char * filename, bool isDir) +{ + if(!filename) + return; + + int pos = FileInfo.size(); + + FileInfo.resize(pos+1); + + FileInfo[pos].FilePath = (char *) malloc(filepath.size()+strlen(filename)+2); + if(!FileInfo[pos].FilePath) + { + FileInfo.resize(pos); + return; + } + + sprintf(FileInfo[pos].FilePath, "%s/%s", filepath.c_str(), filename); + FileInfo[pos].isDir = isDir; +} + +void DirList::ClearList() +{ + for(u32 i = 0; i < FileInfo.size(); ++i) + { + if(FileInfo[i].FilePath) + free(FileInfo[i].FilePath); + } + + FileInfo.clear(); + std::vector().swap(FileInfo); +} + +const char * DirList::GetFilename(int ind) const +{ + if (!valid(ind)) + return ""; + + return FullpathToFilename(FileInfo[ind].FilePath); +} + +static bool SortCallback(const DirEntry & f1, const DirEntry & f2) +{ + if(f1.isDir && !(f2.isDir)) return true; + if(!(f1.isDir) && f2.isDir) return false; + + if(f1.FilePath && !f2.FilePath) return true; + if(!f1.FilePath) return false; + + if(strcasecmp(f1.FilePath, f2.FilePath) > 0) + return false; + + return true; +} + +void DirList::SortList() +{ + if(FileInfo.size() > 1) + std::sort(FileInfo.begin(), FileInfo.end(), SortCallback); +} + +void DirList::SortList(bool (*SortFunc)(const DirEntry &a, const DirEntry &b)) +{ + if(FileInfo.size() > 1) + std::sort(FileInfo.begin(), FileInfo.end(), SortFunc); +} + +u64 DirList::GetFilesize(int index) const +{ + struct stat st; + const char *path = GetFilepath(index); + + if(!path || stat(path, &st) != 0) + return 0; + + return st.st_size; +} + +int DirList::GetFileIndex(const char *filename) const +{ + if(!filename) + return -1; + + for (u32 i = 0; i < FileInfo.size(); ++i) + { + if (strcasecmp(GetFilename(i), filename) == 0) + return i; + } + + return -1; +} diff --git a/src/fs/DirList.h b/src/fs/DirList.h new file mode 100644 index 0000000..2a34208 --- /dev/null +++ b/src/fs/DirList.h @@ -0,0 +1,95 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * DirList Class + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef ___DIRLIST_H_ +#define ___DIRLIST_H_ + +#include +#include +#include + +typedef struct +{ + char * FilePath; + bool isDir; +} DirEntry; + +class DirList +{ +public: + //!Constructor + DirList(void); + //!\param path Path from where to load the filelist of all files + //!\param filter A fileext that needs to be filtered + //!\param flags search/filter flags from the enum + DirList(const std::string & path, const char *filter = NULL, u32 flags = Files | Dirs); + //!Destructor + virtual ~DirList(); + //! Load all the files from a directory + bool LoadPath(const std::string & path, const char *filter = NULL, u32 flags = Files | Dirs); + //! Get a filename of the list + //!\param list index + const char * GetFilename(int index) const; + //! Get the a filepath of the list + //!\param list index + const char *GetFilepath(int index) const { if (!valid(index)) return ""; else return FileInfo[index].FilePath; } + //! Get the a filesize of the list + //!\param list index + u64 GetFilesize(int index) const; + //! Is index a dir or a file + //!\param list index + bool IsDir(int index) const { if(!valid(index)) return false; return FileInfo[index].isDir; }; + //! Get the filecount of the whole list + int GetFilecount() const { return FileInfo.size(); }; + //! Sort list by filepath + void SortList(); + //! Custom sort command for custom sort functions definitions + void SortList(bool (*SortFunc)(const DirEntry &a, const DirEntry &b)); + //! Get the index of the specified filename + int GetFileIndex(const char *filename) const; + //! Enum for search/filter flags + enum + { + Files = 0x01, + Dirs = 0x02, + CheckSubfolders = 0x08, + }; +protected: + // Internal parser + bool InternalLoadPath(std::string &path); + //!Add a list entrie + void AddEntrie(const std::string &filepath, const char * filename, bool isDir); + //! Clear the list + void ClearList(); + //! Check if valid pos is requested + inline bool valid(u32 pos) const { return (pos < FileInfo.size()); }; + + u32 Flags; + const char *Filter; + std::vector FileInfo; +}; + +#endif diff --git a/src/fs/fs_utils.c b/src/fs/fs_utils.c new file mode 100644 index 0000000..8c4d5c8 --- /dev/null +++ b/src/fs/fs_utils.c @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include +#include "dynamic_libs/fs_defs.h" +#include "dynamic_libs/fs_functions.h" + +int MountFS(void *pClient, void *pCmd, char **mount_path) +{ + int result = -1; + + void *mountSrc = malloc(FS_MOUNT_SOURCE_SIZE); + if(!mountSrc) + return -3; + + char* mountPath = (char*) malloc(FS_MAX_MOUNTPATH_SIZE); + if(!mountPath) { + free(mountSrc); + return -4; + } + + memset(mountSrc, 0, FS_MOUNT_SOURCE_SIZE); + memset(mountPath, 0, FS_MAX_MOUNTPATH_SIZE); + + // Mount sdcard + if (FSGetMountSource(pClient, pCmd, FS_SOURCETYPE_EXTERNAL, mountSrc, -1) == 0) + { + result = FSMount(pClient, pCmd, mountSrc, mountPath, FS_MAX_MOUNTPATH_SIZE, -1); + if((result == 0) && mount_path) { + *mount_path = (char*)malloc(strlen(mountPath) + 1); + if(*mount_path) + strcpy(*mount_path, mountPath); + } + } + + free(mountPath); + free(mountSrc); + return result; +} + +int UmountFS(void *pClient, void *pCmd, const char *mountPath) +{ + int result = -1; + result = FSUnmount(pClient, pCmd, mountPath, -1); + + return result; +} + +int LoadFileToMem(const char *filepath, u8 **inbuffer, u32 *size) +{ + //! always initialze input + *inbuffer = NULL; + if(size) + *size = 0; + + int iFd = open(filepath, O_RDONLY); + if (iFd < 0) + return -1; + + u32 filesize = lseek(iFd, 0, SEEK_END); + lseek(iFd, 0, SEEK_SET); + + u8 *buffer = (u8 *) malloc(filesize); + if (buffer == NULL) + { + close(iFd); + return -2; + } + + u32 blocksize = 0x4000; + u32 done = 0; + int readBytes = 0; + + while(done < filesize) + { + if(done + blocksize > filesize) { + blocksize = filesize - done; + } + readBytes = read(iFd, buffer + done, blocksize); + if(readBytes <= 0) + break; + done += readBytes; + } + + close(iFd); + + if (done != filesize) + { + free(buffer); + return -3; + } + + *inbuffer = buffer; + + //! sign is optional input + if(size) + *size = filesize; + + return filesize; +} + +int CheckFile(const char * filepath) +{ + if(!filepath) + return 0; + + struct stat filestat; + + char dirnoslash[strlen(filepath)+2]; + snprintf(dirnoslash, sizeof(dirnoslash), "%s", filepath); + + while(dirnoslash[strlen(dirnoslash)-1] == '/') + dirnoslash[strlen(dirnoslash)-1] = '\0'; + + char * notRoot = strrchr(dirnoslash, '/'); + if(!notRoot) + { + strcat(dirnoslash, "/"); + } + + if (stat(dirnoslash, &filestat) == 0) + return 1; + + return 0; +} + +int CreateSubfolder(const char * fullpath) +{ + if(!fullpath) + return 0; + + int result = 0; + + char dirnoslash[strlen(fullpath)+1]; + strcpy(dirnoslash, fullpath); + + int pos = strlen(dirnoslash)-1; + while(dirnoslash[pos] == '/') + { + dirnoslash[pos] = '\0'; + pos--; + } + + if(CheckFile(dirnoslash)) + { + return 1; + } + else + { + char parentpath[strlen(dirnoslash)+2]; + strcpy(parentpath, dirnoslash); + char * ptr = strrchr(parentpath, '/'); + + if(!ptr) + { + //!Device root directory (must be with '/') + strcat(parentpath, "/"); + struct stat filestat; + if (stat(parentpath, &filestat) == 0) + return 1; + + return 0; + } + + ptr++; + ptr[0] = '\0'; + + result = CreateSubfolder(parentpath); + } + + if(!result) + return 0; + + if (mkdir(dirnoslash, 0777) == -1) + { + return 0; + } + + return 1; +} diff --git a/src/fs/fs_utils.h b/src/fs/fs_utils.h new file mode 100644 index 0000000..7022695 --- /dev/null +++ b/src/fs/fs_utils.h @@ -0,0 +1,23 @@ +#ifndef __FS_UTILS_H_ +#define __FS_UTILS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +int MountFS(void *pClient, void *pCmd, char **mount_path); +int UmountFS(void *pClient, void *pCmd, const char *mountPath); + +int LoadFileToMem(const char *filepath, u8 **inbuffer, u32 *size); + +//! todo: C++ class +int CreateSubfolder(const char * fullpath); +int CheckFile(const char * filepath); + +#ifdef __cplusplus +} +#endif + +#endif // __FS_UTILS_H_ diff --git a/src/fs/sd_fat_devoptab.c b/src/fs/sd_fat_devoptab.c new file mode 100644 index 0000000..f5b278b --- /dev/null +++ b/src/fs/sd_fat_devoptab.c @@ -0,0 +1,1019 @@ +/*************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include "dynamic_libs/fs_functions.h" +#include "dynamic_libs/os_functions.h" +#include "fs_utils.h" + +#define FS_ALIGNMENT 0x40 +#define FS_ALIGN(x) (((x) + FS_ALIGNMENT - 1) & ~(FS_ALIGNMENT - 1)) + +typedef struct _sd_fat_private_t { + char *mount_path; + void *pClient; + void *pCmd; + void *pMutex; +} sd_fat_private_t; + +typedef struct _sd_fat_file_state_t { + sd_fat_private_t *dev; + int fd; /* File descriptor */ + int flags; /* Opening flags */ + bool read; /* True if allowed to read from file */ + bool write; /* True if allowed to write to file */ + bool append; /* True if allowed to append to file */ + u64 pos; /* Current position within the file (in bytes) */ + u64 len; /* Total length of the file (in bytes) */ + struct _sd_fat_file_state_t *prevOpenFile; /* The previous entry in a double-linked FILO list of open files */ + struct _sd_fat_file_state_t *nextOpenFile; /* The next entry in a double-linked FILO list of open files */ +} sd_fat_file_state_t; + +typedef struct _sd_fat_dir_entry_t { + sd_fat_private_t *dev; + int dirHandle; +} sd_fat_dir_entry_t; + +static sd_fat_private_t *sd_fat_get_device_data(const char *path) +{ + const devoptab_t *devoptab = NULL; + char name[128] = {0}; + int i; + + // Get the device name from the path + strncpy(name, path, 127); + strtok(name, ":/"); + + // Search the devoptab table for the specified device name + // NOTE: We do this manually due to a 'bug' in GetDeviceOpTab + // which ignores names with suffixes and causes names + // like "ntfs" and "ntfs1" to be seen as equals + for (i = 3; i < STD_MAX; i++) { + devoptab = devoptab_list[i]; + if (devoptab && devoptab->name) { + if (strcmp(name, devoptab->name) == 0) { + return (sd_fat_private_t *)devoptab->deviceData; + } + } + } + + return NULL; +} + +static char *sd_fat_real_path (const char *path, sd_fat_private_t *dev) +{ + // Sanity check + if (!path) + return NULL; + + // Move the path pointer to the start of the actual path + if (strchr(path, ':') != NULL) { + path = strchr(path, ':') + 1; + } + + int mount_len = strlen(dev->mount_path); + + char *new_name = (char*)malloc(mount_len + strlen(path) + 1); + if(new_name) { + strcpy(new_name, dev->mount_path); + strcpy(new_name + mount_len, path); + return new_name; + } + return new_name; +} + +static int sd_fat_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fileStruct; + + file->dev = dev; + // Determine which mode the file is opened for + file->flags = flags; + + const char *mode_str; + + if ((flags & 0x03) == O_RDONLY) { + file->read = true; + file->write = false; + file->append = false; + mode_str = "r"; + } else if ((flags & 0x03) == O_WRONLY) { + file->read = false; + file->write = true; + file->append = (flags & O_APPEND); + mode_str = file->append ? "a" : "w"; + } else if ((flags & 0x03) == O_RDWR) { + file->read = true; + file->write = true; + file->append = (flags & O_APPEND); + mode_str = file->append ? "a+" : "r+"; + } else { + r->_errno = EACCES; + return -1; + } + + int fd = -1; + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(path, dev); + if(!path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = FSOpenFile(dev->pClient, dev->pCmd, real_path, mode_str, &fd, -1); + + free(real_path); + + if(result == 0) + { + FSStat stats; + result = FSGetStatFile(dev->pClient, dev->pCmd, fd, &stats, -1); + if(result != 0) { + FSCloseFile(dev->pClient, dev->pCmd, fd, -1); + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; + } + file->fd = fd; + file->pos = 0; + file->len = stats.size; + OSUnlockMutex(dev->pMutex); + return (int)file; + } + + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; +} + + +static int sd_fat_close_r (struct _reent *r, int fd) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + + int result = FSCloseFile(file->dev->pClient, file->dev->pCmd, file->fd, -1); + + OSUnlockMutex(file->dev->pMutex); + + if(result < 0) + { + r->_errno = result; + return -1; + } + return 0; +} + +static off_t sd_fat_seek_r (struct _reent *r, int fd, off_t pos, int dir) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return 0; + } + + OSLockMutex(file->dev->pMutex); + + switch(dir) + { + case SEEK_SET: + file->pos = pos; + break; + case SEEK_CUR: + file->pos += pos; + break; + case SEEK_END: + file->pos = file->len + pos; + break; + default: + r->_errno = EINVAL; + return -1; + } + + int result = FSSetPosFile(file->dev->pClient, file->dev->pCmd, file->fd, file->pos, -1); + + OSUnlockMutex(file->dev->pMutex); + + if(result == 0) + { + return file->pos; + } + + return result; +} + +static ssize_t sd_fat_write_r (struct _reent *r, int fd, const char *ptr, size_t len) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return 0; + } + + if(!file->write) + { + r->_errno = EACCES; + return 0; + } + + OSLockMutex(file->dev->pMutex); + + size_t len_aligned = FS_ALIGN(len); + if(len_aligned > 0x4000) + len_aligned = 0x4000; + + unsigned char *tmpBuf = (unsigned char *)memalign(FS_ALIGNMENT, len_aligned); + if(!tmpBuf) { + r->_errno = ENOMEM; + OSUnlockMutex(file->dev->pMutex); + return 0; + } + + size_t done = 0; + + while(done < len) + { + size_t write_size = (len_aligned < (len - done)) ? len_aligned : (len - done); + memcpy(tmpBuf, ptr + done, write_size); + + int result = FSWriteFile(file->dev->pClient, file->dev->pCmd, tmpBuf, 0x01, write_size, file->fd, 0, -1); + if(result < 0) + { + r->_errno = result; + break; + } + else if(result == 0) + { + if(write_size > 0) + done = 0; + break; + } + else + { + done += result; + file->pos += result; + } + } + + free(tmpBuf); + OSUnlockMutex(file->dev->pMutex); + return done; +} + +static ssize_t sd_fat_read_r (struct _reent *r, int fd, char *ptr, size_t len) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return 0; + } + + if(!file->read) + { + r->_errno = EACCES; + return 0; + } + + OSLockMutex(file->dev->pMutex); + + size_t len_aligned = FS_ALIGN(len); + if(len_aligned > 0x4000) + len_aligned = 0x4000; + + unsigned char *tmpBuf = (unsigned char *)memalign(FS_ALIGNMENT, len_aligned); + if(!tmpBuf) { + r->_errno = ENOMEM; + OSUnlockMutex(file->dev->pMutex); + return 0; + } + + size_t done = 0; + + while(done < len) + { + size_t read_size = (len_aligned < (len - done)) ? len_aligned : (len - done); + + int result = FSReadFile(file->dev->pClient, file->dev->pCmd, tmpBuf, 0x01, read_size, file->fd, 0, -1); + if(result < 0) + { + r->_errno = result; + done = 0; + break; + } + else if(result == 0) + { + //! TODO: error on read_size > 0 + break; + } + else + { + memcpy(ptr + done, tmpBuf, read_size); + done += result; + file->pos += result; + } + } + + free(tmpBuf); + OSUnlockMutex(file->dev->pMutex); + return done; +} + + +static int sd_fat_fstat_r (struct _reent *r, int fd, struct stat *st) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + + // Zero out the stat buffer + memset(st, 0, sizeof(struct stat)); + + FSStat stats; + int result = FSGetStatFile(file->dev->pClient, file->dev->pCmd, file->fd, &stats, -1); + if(result != 0) { + r->_errno = result; + OSUnlockMutex(file->dev->pMutex); + return -1; + } + + st->st_mode = S_IFREG; + st->st_size = stats.size; + st->st_blocks = (stats.size + 511) >> 9; + st->st_nlink = 1; + + // Fill in the generic entry stats + st->st_dev = stats.ent_id; + st->st_uid = stats.owner_id; + st->st_gid = stats.group_id; + st->st_ino = stats.ent_id; + st->st_atime = stats.mtime; + st->st_ctime = stats.ctime; + st->st_mtime = stats.mtime; + OSUnlockMutex(file->dev->pMutex); + return 0; +} + +static int sd_fat_ftruncate_r (struct _reent *r, int fd, off_t len) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + + int result = FSTruncateFile(file->dev->pClient, file->dev->pCmd, file->fd, -1); + + OSUnlockMutex(file->dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_fsync_r (struct _reent *r, int fd) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + + int result = FSFlushFile(file->dev->pClient, file->dev->pCmd, file->fd, -1); + + OSUnlockMutex(file->dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_stat_r (struct _reent *r, const char *path, struct stat *st) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + // Zero out the stat buffer + memset(st, 0, sizeof(struct stat)); + + char *real_path = sd_fat_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + FSStat stats; + + int result = FSGetStat(dev->pClient, dev->pCmd, real_path, &stats, -1); + + free(real_path); + + if(result < 0) { + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; + } + + // mark root also as directory + st->st_mode = ((stats.flag & 0x80000000) || (strlen(dev->mount_path) + 1 == strlen(real_path)))? S_IFDIR : S_IFREG; + st->st_nlink = 1; + st->st_size = stats.size; + st->st_blocks = (stats.size + 511) >> 9; + // Fill in the generic entry stats + st->st_dev = stats.ent_id; + st->st_uid = stats.owner_id; + st->st_gid = stats.group_id; + st->st_ino = stats.ent_id; + st->st_atime = stats.mtime; + st->st_ctime = stats.ctime; + st->st_mtime = stats.mtime; + + OSUnlockMutex(dev->pMutex); + + return 0; +} + +static int sd_fat_link_r (struct _reent *r, const char *existing, const char *newLink) +{ + r->_errno = ENOTSUP; + return -1; +} + +static int sd_fat_unlink_r (struct _reent *r, const char *name) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(name); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(name, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + + int result = FSRemove(dev->pClient, dev->pCmd, real_path, -1); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_chdir_r (struct _reent *r, const char *name) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(name); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(name, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = FSChangeDir(dev->pClient, dev->pCmd, real_path, -1); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_rename_r (struct _reent *r, const char *oldName, const char *newName) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(oldName); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_oldpath = sd_fat_real_path(oldName, dev); + if(!real_oldpath) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + char *real_newpath = sd_fat_real_path(newName, dev); + if(!real_newpath) { + r->_errno = ENOMEM; + free(real_oldpath); + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = FSRename(dev->pClient, dev->pCmd, real_oldpath, real_newpath, -1); + + free(real_oldpath); + free(real_newpath); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; + +} + +static int sd_fat_mkdir_r (struct _reent *r, const char *path, int mode) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = FSMakeDir(dev->pClient, dev->pCmd, real_path, -1); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + // Zero out the stat buffer + memset(buf, 0, sizeof(struct statvfs)); + + char *real_path = sd_fat_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + u64 size; + + int result = FSGetFreeSpaceSize(dev->pClient, dev->pCmd, real_path, &size, -1); + + free(real_path); + + if(result < 0) { + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; + } + + // File system block size + buf->f_bsize = 512; + + // Fundamental file system block size + buf->f_frsize = 512; + + // Total number of blocks on file system in units of f_frsize + buf->f_blocks = size >> 9; // this is unknown + + // Free blocks available for all and for non-privileged processes + buf->f_bfree = buf->f_bavail = size >> 9; + + // Number of inodes at this point in time + buf->f_files = 0xffffffff; + + // Free inodes available for all and for non-privileged processes + buf->f_ffree = 0xffffffff; + + // File system id + buf->f_fsid = (int)dev; + + // Bit mask of f_flag values. + buf->f_flag = 0; + + // Maximum length of filenames + buf->f_namemax = 255; + + OSUnlockMutex(dev->pMutex); + + return 0; +} + +static DIR_ITER *sd_fat_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return NULL; + } + + sd_fat_dir_entry_t *dirIter = (sd_fat_dir_entry_t *)dirState->dirStruct; + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return NULL; + } + + int dirHandle; + + int result = FSOpenDir(dev->pClient, dev->pCmd, real_path, &dirHandle, -1); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) + { + r->_errno = result; + return NULL; + } + + dirIter->dev = dev; + dirIter->dirHandle = dirHandle; + + return dirState; +} + +static int sd_fat_dirclose_r (struct _reent *r, DIR_ITER *dirState) +{ + sd_fat_dir_entry_t *dirIter = (sd_fat_dir_entry_t *)dirState->dirStruct; + if(!dirIter->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dirIter->dev->pMutex); + + int result = FSCloseDir(dirIter->dev->pClient, dirIter->dev->pCmd, dirIter->dirHandle, -1); + + OSUnlockMutex(dirIter->dev->pMutex); + + if(result < 0) + { + r->_errno = result; + return -1; + } + return 0; +} + +static int sd_fat_dirreset_r (struct _reent *r, DIR_ITER *dirState) +{ + sd_fat_dir_entry_t *dirIter = (sd_fat_dir_entry_t *)dirState->dirStruct; + if(!dirIter->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dirIter->dev->pMutex); + + int result = FSRewindDir(dirIter->dev->pClient, dirIter->dev->pCmd, dirIter->dirHandle, -1); + + OSUnlockMutex(dirIter->dev->pMutex); + + if(result < 0) + { + r->_errno = result; + return -1; + } + return 0; +} + +static int sd_fat_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *st) +{ + sd_fat_dir_entry_t *dirIter = (sd_fat_dir_entry_t *)dirState->dirStruct; + if(!dirIter->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dirIter->dev->pMutex); + + FSDirEntry * dir_entry = malloc(sizeof(FSDirEntry)); + + int result = FSReadDir(dirIter->dev->pClient, dirIter->dev->pCmd, dirIter->dirHandle, dir_entry, -1); + if(result < 0) + { + free(dir_entry); + r->_errno = result; + OSUnlockMutex(dirIter->dev->pMutex); + return -1; + } + + // Fetch the current entry + strcpy(filename, dir_entry->name); + + if(st) + { + memset(st, 0, sizeof(struct stat)); + st->st_mode = (dir_entry->stat.flag & 0x80000000) ? S_IFDIR : S_IFREG; + st->st_nlink = 1; + st->st_size = dir_entry->stat.size; + st->st_blocks = (dir_entry->stat.size + 511) >> 9; + st->st_dev = dir_entry->stat.ent_id; + st->st_uid = dir_entry->stat.owner_id; + st->st_gid = dir_entry->stat.group_id; + st->st_ino = dir_entry->stat.ent_id; + st->st_atime = dir_entry->stat.mtime; + st->st_ctime = dir_entry->stat.ctime; + st->st_mtime = dir_entry->stat.mtime; + } + + free(dir_entry); + OSUnlockMutex(dirIter->dev->pMutex); + return 0; +} + +// NTFS device driver devoptab +static const devoptab_t devops_sd_fat = { + NULL, /* Device name */ + sizeof (sd_fat_file_state_t), + sd_fat_open_r, + sd_fat_close_r, + sd_fat_write_r, + sd_fat_read_r, + sd_fat_seek_r, + sd_fat_fstat_r, + sd_fat_stat_r, + sd_fat_link_r, + sd_fat_unlink_r, + sd_fat_chdir_r, + sd_fat_rename_r, + sd_fat_mkdir_r, + sizeof (sd_fat_dir_entry_t), + sd_fat_diropen_r, + sd_fat_dirreset_r, + sd_fat_dirnext_r, + sd_fat_dirclose_r, + sd_fat_statvfs_r, + sd_fat_ftruncate_r, + sd_fat_fsync_r, + NULL, /* sd_fat_chmod_r */ + NULL, /* sd_fat_fchmod_r */ + NULL /* Device data */ +}; + +static int sd_fat_add_device (const char *name, const char *mount_path, void *pClient, void *pCmd) +{ + devoptab_t *dev = NULL; + char *devname = NULL; + char *devpath = NULL; + int i; + + // Sanity check + if (!name) { + errno = EINVAL; + return -1; + } + + // Allocate a devoptab for this device + dev = (devoptab_t *) malloc(sizeof(devoptab_t) + strlen(name) + 1); + if (!dev) { + errno = ENOMEM; + return -1; + } + + // Use the space allocated at the end of the devoptab for storing the device name + devname = (char*)(dev + 1); + strcpy(devname, name); + + // create private data + sd_fat_private_t *priv = (sd_fat_private_t *)malloc(sizeof(sd_fat_private_t) + strlen(mount_path) + 1); + if(!priv) { + free(dev); + errno = ENOMEM; + return -1; + } + + devpath = (char*)(priv+1); + strcpy(devpath, mount_path); + + // setup private data + priv->mount_path = devpath; + priv->pClient = pClient; + priv->pCmd = pCmd; + priv->pMutex = malloc(OS_MUTEX_SIZE); + + if(!priv->pMutex) { + free(dev); + free(priv); + errno = ENOMEM; + return -1; + } + + OSInitMutex(priv->pMutex); + + // Setup the devoptab + memcpy(dev, &devops_sd_fat, sizeof(devoptab_t)); + dev->name = devname; + dev->deviceData = priv; + + // Add the device to the devoptab table (if there is a free slot) + for (i = 3; i < STD_MAX; i++) { + if (devoptab_list[i] == devoptab_list[0]) { + devoptab_list[i] = dev; + return 0; + } + } + + // failure, free all memory + free(priv); + free(dev); + + // If we reach here then there are no free slots in the devoptab table for this device + errno = EADDRNOTAVAIL; + return -1; +} + +static int sd_fat_remove_device (const char *path, void **pClient, void **pCmd, char **mountPath) +{ + const devoptab_t *devoptab = NULL; + char name[128] = {0}; + int i; + + // Get the device name from the path + strncpy(name, path, 127); + strtok(name, ":/"); + + // Find and remove the specified device from the devoptab table + // NOTE: We do this manually due to a 'bug' in RemoveDevice + // which ignores names with suffixes and causes names + // like "ntfs" and "ntfs1" to be seen as equals + for (i = 3; i < STD_MAX; i++) { + devoptab = devoptab_list[i]; + if (devoptab && devoptab->name) { + if (strcmp(name, devoptab->name) == 0) { + devoptab_list[i] = devoptab_list[0]; + + if(devoptab->deviceData) + { + sd_fat_private_t *priv = (sd_fat_private_t *)devoptab->deviceData; + *pClient = priv->pClient; + *pCmd = priv->pCmd; + *mountPath = (char*) malloc(strlen(priv->mount_path)+1); + if(*mountPath) + strcpy(*mountPath, priv->mount_path); + if(priv->pMutex) + free(priv->pMutex); + free(devoptab->deviceData); + } + + free((devoptab_t*)devoptab); + return 0; + } + } + } + + return -1; +} + +int mount_sd_fat(const char *path) +{ + int result = -1; + + // get command and client + void* pClient = malloc(FS_CLIENT_SIZE); + void* pCmd = malloc(FS_CMD_BLOCK_SIZE); + + if(!pClient || !pCmd) { + // just in case free if not 0 + if(pClient) + free(pClient); + if(pCmd) + free(pCmd); + return -2; + } + + FSInit(); + FSInitCmdBlock(pCmd); + FSAddClientEx(pClient, 0, -1); + + char *mountPath = NULL; + + if(MountFS(pClient, pCmd, &mountPath) == 0) { + result = sd_fat_add_device(path, mountPath, pClient, pCmd); + free(mountPath); + } + + return result; +} + +int unmount_sd_fat(const char *path) +{ + void *pClient = 0; + void *pCmd = 0; + char *mountPath = 0; + + int result = sd_fat_remove_device(path, &pClient, &pCmd, &mountPath); + if(result == 0) + { + UmountFS(pClient, pCmd, mountPath); + FSDelClient(pClient); + free(pClient); + free(pCmd); + free(mountPath); + //FSShutdown(); + } + return result; +} diff --git a/src/fs/sd_fat_devoptab.h b/src/fs/sd_fat_devoptab.h new file mode 100644 index 0000000..8df487a --- /dev/null +++ b/src/fs/sd_fat_devoptab.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef __SD_FAT_DEVOPTAB_H_ +#define __SD_FAT_DEVOPTAB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +int mount_sd_fat(const char *path); +int unmount_sd_fat(const char *path); + +#ifdef __cplusplus +} +#endif + +#endif // __SD_FAT_DEVOPTAB_H_ diff --git a/src/gui/FreeTypeGX.cpp b/src/gui/FreeTypeGX.cpp new file mode 100644 index 0000000..6111153 --- /dev/null +++ b/src/gui/FreeTypeGX.cpp @@ -0,0 +1,608 @@ +/* + * FreeTypeGX is a wrapper class for libFreeType which renders a compiled + * FreeType parsable font into a GX texture for Wii homebrew development. + * Copyright (C) 2008 Armin Tamzarian + * Modified by Dimok, 2015 for WiiU GX2 + * + * This file is part of FreeTypeGX. + * + * FreeTypeGX is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * FreeTypeGX 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FreeTypeGX. If not, see . + */ + +#include "FreeTypeGX.h" +#include "video/CVideo.h" +#include "video/shaders/Texture2DShader.h" +#include "utils/logger.h" + +using namespace std; + +#define ALIGN4(x) (((x) + 3) & ~3) + +/** + * Default constructor for the FreeTypeGX class for WiiXplorer. + */ +FreeTypeGX::FreeTypeGX(const uint8_t* fontBuffer, FT_Long bufferSize, bool lastFace) +{ + int faceIndex = 0; + ftPointSize = 0; + GX2InitSampler(&ftSampler, GX2_TEX_CLAMP_CLAMP_BORDER, GX2_TEX_XY_FILTER_BILINEAR); + + FT_Init_FreeType(&ftLibrary); + if(lastFace) + { + FT_New_Memory_Face(ftLibrary, (FT_Byte *)fontBuffer, bufferSize, -1, &ftFace); + faceIndex = ftFace->num_faces - 1; // Use the last face + FT_Done_Face(ftFace); + ftFace = NULL; + } + FT_New_Memory_Face(ftLibrary, (FT_Byte *) fontBuffer, bufferSize, faceIndex, &ftFace); + + ftKerningEnabled = FT_HAS_KERNING(ftFace); +} + +/** + * Default destructor for the FreeTypeGX class. + */ +FreeTypeGX::~FreeTypeGX() +{ + unloadFont(); + FT_Done_Face(ftFace); + FT_Done_FreeType(ftLibrary); +} + +/** + * Convert a short char string to a wide char string. + * + * This routine converts a supplied short character string into a wide character string. + * Note that it is the user's responsibility to clear the returned buffer once it is no longer needed. + * + * @param strChar Character string to be converted. + * @return Wide character representation of supplied character string. + */ + +wchar_t* FreeTypeGX::charToWideChar(const char* strChar) +{ + if (!strChar) return NULL; + + wchar_t *strWChar = new (std::nothrow) wchar_t[strlen(strChar) + 1]; + if (!strWChar) return NULL; + + int bt = mbstowcs(strWChar, strChar, strlen(strChar)); + if (bt > 0) + { + strWChar[bt] = 0; + return strWChar; + } + + wchar_t *tempDest = strWChar; + while ((*tempDest++ = *strChar++)) + ; + + return strWChar; +} + +char *FreeTypeGX::wideCharToUTF8(const wchar_t* strChar) +{ + if(!strChar) { + return NULL; + } + + size_t len = 0; + wchar_t wc; + + for (size_t i = 0; strChar[i]; ++i) + { + wc = strChar[i]; + if (wc < 0x80) + ++len; + else if (wc < 0x800) + len += 2; + else if (wc < 0x10000) + len += 3; + else + len += 4; + } + + char *pOut = new (std::nothrow) char[len]; + if(!pOut) + return NULL; + + size_t n = 0; + + for (size_t i = 0; strChar[i]; ++i) + { + wc = strChar[i]; + if (wc < 0x80) + pOut[n++] = (char)wc; + else if (wc < 0x800) + { + pOut[n++] = (char)((wc >> 6) | 0xC0); + pOut[n++] = (char)((wc & 0x3F) | 0x80); + } + else if (wc < 0x10000) + { + pOut[n++] = (char)((wc >> 12) | 0xE0); + pOut[n++] = (char)(((wc >> 6) & 0x3F) | 0x80); + pOut[n++] = (char)((wc & 0x3F) | 0x80); + } + else + { + pOut[n++] = (char)(((wc >> 18) & 0x07) | 0xF0); + pOut[n++] = (char)(((wc >> 12) & 0x3F) | 0x80); + pOut[n++] = (char)(((wc >> 6) & 0x3F) | 0x80); + pOut[n++] = (char)((wc & 0x3F) | 0x80); + } + } + return pOut; +} + +/** + * Clears all loaded font glyph data. + * + * This routine clears all members of the font map structure and frees all allocated memory back to the system. + */ +void FreeTypeGX::unloadFont() +{ + map::iterator itr; + map::iterator itr2; + + for (itr = fontData.begin(); itr != fontData.end(); itr++) + { + for (itr2 = itr->second.ftgxCharMap.begin(); itr2 != itr->second.ftgxCharMap.end(); itr2++) + { + if(itr2->second.texture) + { + if(itr2->second.texture->surface.image_data) + free(itr2->second.texture->surface.image_data); + + delete itr2->second.texture; + itr2->second.texture = NULL; + } + } + } + + fontData.clear(); +} + +/** + * Caches the given font glyph in the instance font texture buffer. + * + * This routine renders and stores the requested glyph's bitmap and relevant information into its own quickly addressible + * structure within an instance-specific map. + * + * @param charCode The requested glyph's character code. + * @return A pointer to the allocated font structure. + */ +ftgxCharData * FreeTypeGX::cacheGlyphData(wchar_t charCode, int16_t pixelSize) +{ + map::iterator itr = fontData.find(pixelSize); + if (itr != fontData.end()) + { + map::iterator itr2 = itr->second.ftgxCharMap.find(charCode); + if (itr2 != itr->second.ftgxCharMap.end()) + { + return &itr2->second; + } + } + //!Cache ascender and decender as well + ftGX2Data *ftData = &fontData[pixelSize]; + + FT_UInt gIndex; + uint16_t textureWidth = 0, textureHeight = 0; + if (ftPointSize != pixelSize) + { + ftPointSize = pixelSize; + FT_Set_Pixel_Sizes(ftFace, 0, ftPointSize); + ftData->ftgxAlign.ascender = (int16_t) ftFace->size->metrics.ascender >> 6; + ftData->ftgxAlign.descender = (int16_t) ftFace->size->metrics.descender >> 6; + ftData->ftgxAlign.max = 0; + ftData->ftgxAlign.min = 0; + } + + gIndex = FT_Get_Char_Index(ftFace, (FT_ULong) charCode); + if (gIndex != 0 && FT_Load_Glyph(ftFace, gIndex, FT_LOAD_DEFAULT | FT_LOAD_RENDER) == 0) + { + if (ftFace->glyph->format == FT_GLYPH_FORMAT_BITMAP) + { + FT_Bitmap *glyphBitmap = &ftFace->glyph->bitmap; + + textureWidth = ALIGN4(glyphBitmap->width); + textureHeight = ALIGN4(glyphBitmap->rows); + if(textureWidth == 0) + textureWidth = 4; + if(textureHeight == 0) + textureHeight = 4; + + ftgxCharData *charData = &ftData->ftgxCharMap[charCode]; + charData->renderOffsetX = (int16_t) ftFace->glyph->bitmap_left; + charData->glyphAdvanceX = (uint16_t) (ftFace->glyph->advance.x >> 6); + charData->glyphAdvanceY = (uint16_t) (ftFace->glyph->advance.y >> 6); + charData->glyphIndex = (uint32_t) gIndex; + charData->renderOffsetY = (int16_t) ftFace->glyph->bitmap_top; + charData->renderOffsetMax = (int16_t) ftFace->glyph->bitmap_top; + charData->renderOffsetMin = (int16_t) glyphBitmap->rows - ftFace->glyph->bitmap_top; + + //! Initialize texture + charData->texture = new GX2Texture; + GX2InitTexture(charData->texture, textureWidth, textureHeight, 1, 0, GX2_SURFACE_FORMAT_TC_R5_G5_B5_A1_UNORM, GX2_SURFACE_DIM_2D, GX2_TILE_MODE_LINEAR_ALIGNED); + + loadGlyphData(glyphBitmap, charData); + + return charData; + } + } + return NULL; +} + +/** + * Locates each character in this wrapper's configured font face and proccess them. + * + * This routine locates each character in the configured font face and renders the glyph's bitmap. + * Each bitmap and relevant information is loaded into its own quickly addressible structure within an instance-specific map. + */ +uint16_t FreeTypeGX::cacheGlyphDataComplete(int16_t pixelSize) +{ + uint32_t i = 0; + FT_UInt gIndex; + + FT_ULong charCode = FT_Get_First_Char(ftFace, &gIndex); + while (gIndex != 0) + { + if (cacheGlyphData(charCode, pixelSize) != NULL) ++i; + charCode = FT_Get_Next_Char(ftFace, charCode, &gIndex); + } + return (uint16_t) (i); +} + +/** + * Loads the rendered bitmap into the relevant structure's data buffer. + * + * This routine does a simple byte-wise copy of the glyph's rendered 8-bit grayscale bitmap into the structure's buffer. + * Each byte is converted from the bitmap's intensity value into the a uint32_t RGBA value. + * + * @param bmp A pointer to the most recently rendered glyph's bitmap. + * @param charData A pointer to an allocated ftgxCharData structure whose data represent that of the last rendered glyph. + */ + +void FreeTypeGX::loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData) +{ + charData->texture->surface.image_data = (uint8_t *) memalign(charData->texture->surface.align, charData->texture->surface.image_size); + if(!charData->texture->surface.image_data) + return; + + memset(charData->texture->surface.image_data, 0x00, charData->texture->surface.image_size); + + uint8_t *src = (uint8_t *)bmp->buffer; + uint16_t *dst = (uint16_t *)charData->texture->surface.image_data; + int32_t x, y; + + for(y = 0; y < bmp->rows; y++) + { + for(x = 0; x < bmp->width; x++) + { + uint8_t intensity = src[y * bmp->width + x] >> 3; + dst[y * charData->texture->surface.pitch + x] = intensity ? ((intensity << 11) | (intensity << 6) | (intensity << 1) | 1) : 0; + } + } + GX2Invalidate(GX2_INVALIDATE_CPU_TEXTURE, charData->texture->surface.image_data, charData->texture->surface.image_size); +} + +/** + * Determines the x offset of the rendered string. + * + * This routine calculates the x offset of the rendered string based off of a supplied positional format parameter. + * + * @param width Current pixel width of the string. + * @param format Positional format of the string. + */ +int16_t FreeTypeGX::getStyleOffsetWidth(uint16_t width, uint16_t format) +{ + if (format & FTGX_JUSTIFY_LEFT) + return 0; + else if (format & FTGX_JUSTIFY_CENTER) + return -(width >> 1); + else if (format & FTGX_JUSTIFY_RIGHT) return -width; + return 0; +} + +/** + * Determines the y offset of the rendered string. + * + * This routine calculates the y offset of the rendered string based off of a supplied positional format parameter. + * + * @param offset Current pixel offset data of the string. + * @param format Positional format of the string. + */ +int16_t FreeTypeGX::getStyleOffsetHeight(int16_t format, uint16_t pixelSize) +{ + std::map::iterator itr = fontData.find(pixelSize); + if (itr == fontData.end()) return 0; + + switch (format & FTGX_ALIGN_MASK) + { + case FTGX_ALIGN_TOP: + return itr->second.ftgxAlign.descender; + + case FTGX_ALIGN_MIDDLE: + default: + return (itr->second.ftgxAlign.ascender + itr->second.ftgxAlign.descender + 1) >> 1; + + case FTGX_ALIGN_BOTTOM: + return itr->second.ftgxAlign.ascender; + + case FTGX_ALIGN_BASELINE: + return 0; + + case FTGX_ALIGN_GLYPH_TOP: + return itr->second.ftgxAlign.max; + + case FTGX_ALIGN_GLYPH_MIDDLE: + return (itr->second.ftgxAlign.max + itr->second.ftgxAlign.min + 1) >> 1; + + case FTGX_ALIGN_GLYPH_BOTTOM: + return itr->second.ftgxAlign.min; + } + return 0; +} + +/** + * Processes the supplied text string and prints the results at the specified coordinates. + * + * This routine processes each character of the supplied text string, loads the relevant preprocessed bitmap buffer, + * a texture from said buffer, and loads the resultant texture into the EFB. + * + * @param x Screen X coordinate at which to output the text. + * @param y Screen Y coordinate at which to output the text. Note that this value corresponds to the text string origin and not the top or bottom of the glyphs. + * @param text NULL terminated string to output. + * @param color Optional color to apply to the text characters. If not specified default value is ftgxWhite: (GXColor){0xff, 0xff, 0xff, 0xff} + * @param textStyle Flags which specify any styling which should be applied to the rendered string. + * @return The number of characters printed. + */ + +uint16_t FreeTypeGX::drawText(CVideo *video, int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, const glm::vec4 & color, uint16_t textStyle, uint16_t textWidth, const float &textBlur, const float & colorBlurIntensity, const glm::vec4 & blurColor, const float & internalRenderingScale) +{ + if (!text) + return 0; + + uint16_t fullTextWidth = (textWidth > 0) ? textWidth : getWidth(text, pixelSize); + uint16_t x_pos = x, printed = 0; + uint16_t x_offset = 0, y_offset = 0; + FT_Vector pairDelta; + + if (textStyle & FTGX_JUSTIFY_MASK) + { + x_offset = getStyleOffsetWidth(fullTextWidth, textStyle); + } + if (textStyle & FTGX_ALIGN_MASK) + { + y_offset = getStyleOffsetHeight(textStyle, pixelSize); + } + + int i = 0; + while (text[i]) + { + ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize); + + if (glyphData != NULL) + { + if (ftKerningEnabled && i > 0) + { + FT_Get_Kerning(ftFace, fontData[pixelSize].ftgxCharMap[text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta); + x_pos += (pairDelta.x >> 6); + + } + copyTextureToFramebuffer(video, glyphData->texture,x_pos + glyphData->renderOffsetX + x_offset, y + glyphData->renderOffsetY - y_offset, z, color, textBlur, colorBlurIntensity, blurColor,internalRenderingScale); + + x_pos += glyphData->glyphAdvanceX; + ++printed; + } + ++i; + } + + return printed; +} + + +/** + * Processes the supplied string and return the width of the string in pixels. + * + * This routine processes each character of the supplied text string and calculates the width of the entire string. + * Note that if precaching of the entire font set is not enabled any uncached glyph will be cached after the call to this function. + * + * @param text NULL terminated string to calculate. + * @return The width of the text string in pixels. + */ +uint16_t FreeTypeGX::getWidth(const wchar_t *text, int16_t pixelSize) +{ + if (!text) return 0; + + uint16_t strWidth = 0; + FT_Vector pairDelta; + + int i = 0; + while (text[i]) + { + ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize); + + if (glyphData != NULL) + { + if (ftKerningEnabled && (i > 0)) + { + FT_Get_Kerning(ftFace, fontData[pixelSize].ftgxCharMap[text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta); + strWidth += pairDelta.x >> 6; + } + + strWidth += glyphData->glyphAdvanceX; + } + ++i; + } + return strWidth; +} + +/** + * Single char width + */ +uint16_t FreeTypeGX::getCharWidth(const wchar_t wChar, int16_t pixelSize, const wchar_t prevChar) +{ + uint16_t strWidth = 0; + ftgxCharData * glyphData = cacheGlyphData(wChar, pixelSize); + + if (glyphData != NULL) + { + if (ftKerningEnabled && prevChar != 0x0000) + { + FT_Vector pairDelta; + FT_Get_Kerning(ftFace, fontData[pixelSize].ftgxCharMap[prevChar].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta); + strWidth += pairDelta.x >> 6; + } + strWidth += glyphData->glyphAdvanceX; + } + + return strWidth; +} + +/** + * Processes the supplied string and return the height of the string in pixels. + * + * This routine processes each character of the supplied text string and calculates the height of the entire string. + * Note that if precaching of the entire font set is not enabled any uncached glyph will be cached after the call to this function. + * + * @param text NULL terminated string to calculate. + * @return The height of the text string in pixels. + */ +uint16_t FreeTypeGX::getHeight(const wchar_t *text, int16_t pixelSize) +{ + getOffset(text, pixelSize); + return fontData[pixelSize].ftgxAlign.max - fontData[pixelSize].ftgxAlign.min; +} + +/** + * Get the maximum offset above and minimum offset below the font origin line. + * + * This function calculates the maximum pixel height above the font origin line and the minimum + * pixel height below the font origin line and returns the values in an addressible structure. + * + * @param text NULL terminated string to calculate. + * @param offset returns the max and min values above and below the font origin line + * + */ +void FreeTypeGX::getOffset(const wchar_t *text, int16_t pixelSize, uint16_t widthLimit) +{ + if (fontData.find(pixelSize) != fontData.end()) + return; + + int16_t strMax = 0, strMin = 9999; + uint16_t currWidth = 0; + + int i = 0; + + while (text[i]) + { + if (widthLimit > 0 && currWidth >= widthLimit) break; + + ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize); + + if (glyphData != NULL) + { + strMax = glyphData->renderOffsetMax > strMax ? glyphData->renderOffsetMax : strMax; + strMin = glyphData->renderOffsetMin < strMin ? glyphData->renderOffsetMin : strMin; + currWidth += glyphData->glyphAdvanceX; + } + + ++i; + } + + if (ftPointSize != pixelSize) + { + ftPointSize = pixelSize; + FT_Set_Pixel_Sizes(ftFace, 0, ftPointSize); + } + + fontData[pixelSize].ftgxAlign.ascender = ftFace->size->metrics.ascender >> 6; + fontData[pixelSize].ftgxAlign.descender = ftFace->size->metrics.descender >> 6; + fontData[pixelSize].ftgxAlign.max = strMax; + fontData[pixelSize].ftgxAlign.min = strMin; +} + +/** + * Copies the supplied texture quad to the EFB. + * + * This routine uses the in-built GX quad builder functions to define the texture bounds and location on the EFB target. + * + * @param texObj A pointer to the glyph's initialized texture object. + * @param texWidth The pixel width of the texture object. + * @param texHeight The pixel height of the texture object. + * @param screenX The screen X coordinate at which to output the rendered texture. + * @param screenY The screen Y coordinate at which to output the rendered texture. + * @param color Color to apply to the texture. + */ +void FreeTypeGX::copyTextureToFramebuffer(CVideo *pVideo, GX2Texture *texture, int16_t x, int16_t y, int16_t z, const glm::vec4 & color, const float & defaultBlur, const float & blurIntensity, const glm::vec4 & blurColor, const float & internalRenderingScale) +{ + static const f32 imageAngle = 0.0f; + static const f32 blurScale = (2.0f/ (internalRenderingScale)); + + f32 offsetLeft = blurScale * ((f32)x + 0.5f * (f32)texture->surface.width) * (f32)pVideo->getWidthScaleFactor(); + f32 offsetTop = blurScale * ((f32)y - 0.5f * (f32)texture->surface.height) * (f32)pVideo->getHeightScaleFactor(); + + f32 widthScale = blurScale * (f32)texture->surface.width * pVideo->getWidthScaleFactor(); + f32 heightScale = blurScale * (f32)texture->surface.height * pVideo->getHeightScaleFactor(); + + glm::vec3 positionOffsets( offsetLeft, offsetTop, (f32)z ); + + //! blur doubles due to blur we have to scale the texture + glm::vec3 scaleFactor( widthScale, heightScale, 1.0f ); + + glm::vec3 blurDirection; + blurDirection[2] = 1.0f; + + Texture2DShader::instance()->setShaders(); + Texture2DShader::instance()->setAttributeBuffer(); + Texture2DShader::instance()->setAngle(imageAngle); + Texture2DShader::instance()->setOffset(positionOffsets); + Texture2DShader::instance()->setScale(scaleFactor); + Texture2DShader::instance()->setTextureAndSampler(texture, &ftSampler); + + if(blurIntensity > 0.0f) + { + //! glow blur color + Texture2DShader::instance()->setColorIntensity(blurColor); + + //! glow blur horizontal + blurDirection[0] = blurIntensity; + blurDirection[1] = 0.0f; + Texture2DShader::instance()->setBlurring(blurDirection); + Texture2DShader::instance()->draw(); + + //! glow blur vertical + blurDirection[0] = 0.0f; + blurDirection[1] = blurIntensity; + Texture2DShader::instance()->setBlurring(blurDirection); + Texture2DShader::instance()->draw(); + } + + //! set text color + Texture2DShader::instance()->setColorIntensity(color); + + //! blur horizontal + blurDirection[0] = defaultBlur; + blurDirection[1] = 0.0f; + Texture2DShader::instance()->setBlurring(blurDirection); + Texture2DShader::instance()->draw(); + + //! blur vertical + blurDirection[0] = 0.0f; + blurDirection[1] = defaultBlur; + Texture2DShader::instance()->setBlurring(blurDirection); + Texture2DShader::instance()->draw(); +} diff --git a/src/gui/FreeTypeGX.h b/src/gui/FreeTypeGX.h new file mode 100644 index 0000000..cd430b4 --- /dev/null +++ b/src/gui/FreeTypeGX.h @@ -0,0 +1,155 @@ +/* + * FreeTypeGX is a wrapper class for libFreeType which renders a compiled + * FreeType parsable font into a GX texture for Wii homebrew development. + * Copyright (C) 2008 Armin Tamzarian + * Modified by Dimok, 2015 for WiiU GX2 + * + * This file is part of FreeTypeGX. + * + * FreeTypeGX is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * FreeTypeGX 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FreeTypeGX. If not, see . + */ + +#ifndef FREETYPEGX_H_ +#define FREETYPEGX_H_ + +#include +#include +#include +#include FT_FREETYPE_H +#include FT_BITMAP_H + +#include +#include +#include +#include + +#include +#include + +#include "dynamic_libs/gx2_functions.h" + +/*! \struct ftgxCharData_ + * + * Font face character glyph relevant data structure. + */ +typedef struct ftgxCharData_ +{ + int16_t renderOffsetX; /**< Texture X axis bearing offset. */ + uint16_t glyphAdvanceX; /**< Character glyph X coordinate advance in pixels. */ + uint16_t glyphAdvanceY; /**< Character glyph Y coordinate advance in pixels. */ + uint32_t glyphIndex; /**< Charachter glyph index in the font face. */ + + int16_t renderOffsetY; /**< Texture Y axis bearing offset. */ + int16_t renderOffsetMax; /**< Texture Y axis bearing maximum value. */ + int16_t renderOffsetMin; /**< Texture Y axis bearing minimum value. */ + + GX2Texture * texture; +} ftgxCharData; + +/*! \struct ftgxDataOffset_ + * + * Offset structure which hold both a maximum and minimum value. + */ +typedef struct ftgxDataOffset_ +{ + int16_t ascender; /**< Maximum data offset. */ + int16_t descender; /**< Minimum data offset. */ + int16_t max; /**< Maximum data offset. */ + int16_t min; /**< Minimum data offset. */ +} ftgxDataOffset; + +typedef struct ftgxCharData_ ftgxCharData; +typedef struct ftgxDataOffset_ ftgxDataOffset; +#define _TEXT(t) L ## t /**< Unicode helper macro. */ + +#define FTGX_NULL 0x0000 +#define FTGX_JUSTIFY_LEFT 0x0001 +#define FTGX_JUSTIFY_CENTER 0x0002 +#define FTGX_JUSTIFY_RIGHT 0x0004 +#define FTGX_JUSTIFY_MASK 0x000f + +#define FTGX_ALIGN_TOP 0x0010 +#define FTGX_ALIGN_MIDDLE 0x0020 +#define FTGX_ALIGN_BOTTOM 0x0040 +#define FTGX_ALIGN_BASELINE 0x0080 +#define FTGX_ALIGN_GLYPH_TOP 0x0100 +#define FTGX_ALIGN_GLYPH_MIDDLE 0x0200 +#define FTGX_ALIGN_GLYPH_BOTTOM 0x0400 +#define FTGX_ALIGN_MASK 0x0ff0 + +#define FTGX_STYLE_UNDERLINE 0x1000 +#define FTGX_STYLE_STRIKE 0x2000 +#define FTGX_STYLE_MASK 0xf000 + +/**< Constant color value used only to sanitize Doxygen documentation. */ +static const GX2ColorF32 ftgxWhite = (GX2ColorF32){ 1.0f, 1.0f, 1.0f, 1.0f }; + + +//! forward declaration +class CVideo; + +/*! \class FreeTypeGX + * \brief Wrapper class for the libFreeType library with GX rendering. + * \author Armin Tamzarian + * \version 0.2.4 + * + * FreeTypeGX acts as a wrapper class for the libFreeType library. It supports precaching of transformed glyph data into + * a specified texture format. Rendering of the data to the EFB is accomplished through the application of high performance + * GX texture functions resulting in high throughput of string rendering. + */ +class FreeTypeGX +{ + private: + FT_Library ftLibrary; /**< FreeType FT_Library instance. */ + FT_Face ftFace; /**< FreeType reusable FT_Face typographic object. */ + int16_t ftPointSize; /**< Current set size of the rendered font. */ + bool ftKerningEnabled; /**< Flag indicating the availability of font kerning data. */ + uint8_t vertexIndex; /**< Vertex format descriptor index. */ + GX2Sampler ftSampler; + + typedef struct _ftGX2Data + { + ftgxDataOffset ftgxAlign; + std::map ftgxCharMap; + } ftGX2Data; + + std::map fontData; /**< Map which holds the glyph data structures for the corresponding characters in one size. */ + + int16_t getStyleOffsetWidth(uint16_t width, uint16_t format); + int16_t getStyleOffsetHeight(int16_t format, uint16_t pixelSize); + + void unloadFont(); + ftgxCharData *cacheGlyphData(wchar_t charCode, int16_t pixelSize); + uint16_t cacheGlyphDataComplete(int16_t pixelSize); + void loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData); + + void copyTextureToFramebuffer(CVideo * pVideo, GX2Texture *tex, int16_t screenX, int16_t screenY, int16_t screenZ, const glm::vec4 & color, const float &textBlur, const float &colorBlurIntensity, const glm::vec4 & blurColor, const float & internalRenderingScale); + + public: + FreeTypeGX(const uint8_t* fontBuffer, FT_Long bufferSize, bool lastFace = false); + ~FreeTypeGX(); + + uint16_t drawText(CVideo * pVideo, int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, const glm::vec4 & color, + uint16_t textStyling, uint16_t textWidth, const float &textBlur, const float &colorBlurIntensity, const glm::vec4 & blurColor, const float & internalRenderingScale); + + uint16_t getWidth(const wchar_t *text, int16_t pixelSize); + uint16_t getCharWidth(const wchar_t wChar, int16_t pixelSize, const wchar_t prevChar = 0x0000); + uint16_t getHeight(const wchar_t *text, int16_t pixelSize); + void getOffset(const wchar_t *text, int16_t pixelSize, uint16_t widthLimit = 0); + + static wchar_t* charToWideChar(const char* p); + static char* wideCharToUTF8(const wchar_t* strChar); +}; + +#endif /* FREETYPEGX_H_ */ diff --git a/src/gui/GameBgImage.cpp b/src/gui/GameBgImage.cpp new file mode 100644 index 0000000..6497f4f --- /dev/null +++ b/src/gui/GameBgImage.cpp @@ -0,0 +1,42 @@ +#include "GameBgImage.h" +#include "video/CVideo.h" +#include "video/shaders/Shader3D.h" + +GameBgImage::GameBgImage(const std::string & filename, GuiImageData *preloadImage) + : GuiImageAsync(filename, preloadImage) +{ + identity = glm::mat4(1.0f); + alphaFadeOut = glm::vec4(1.0f, 0.075f, 5.305f, 2.0f); +} + +GameBgImage::~GameBgImage() +{ +} + +void GameBgImage::draw(CVideo *pVideo) +{ + if(!getImageData() || !getImageData()->getTexture()) + return; + + //! first setup 2D GUI positions + f32 currPosX = getCenterX(); + f32 currPosY = getCenterY(); + f32 currPosZ = getDepth(); + f32 currScaleX = getScaleX() * (f32)getWidth() * pVideo->getWidthScaleFactor(); + f32 currScaleY = getScaleY() * (f32)getHeight() * pVideo->getHeightScaleFactor(); + f32 currScaleZ = getScaleZ() * (f32)getWidth() * pVideo->getDepthScaleFactor(); + + glm::mat4 m_modelView = glm::translate(identity, glm::vec3(currPosX,currPosY, currPosZ)); + m_modelView = glm::scale(m_modelView, glm::vec3(currScaleX, currScaleY, currScaleZ)); + + Shader3D::instance()->setShaders(); + Shader3D::instance()->setProjectionMtx(identity); + Shader3D::instance()->setViewMtx(identity); + Shader3D::instance()->setModelViewMtx(m_modelView); + Shader3D::instance()->setTextureAndSampler(getImageData()->getTexture(), getImageData()->getSampler()); + Shader3D::instance()->setAlphaFadeOut(alphaFadeOut); + Shader3D::instance()->setDistanceFadeOut(0.0f); + Shader3D::instance()->setColorIntensity(glm::vec4(1.0f, 1.0f, 1.0f, getAlpha())); + Shader3D::instance()->setAttributeBuffer(); + Shader3D::instance()->draw(); +} diff --git a/src/gui/GameBgImage.h b/src/gui/GameBgImage.h new file mode 100644 index 0000000..a78b715 --- /dev/null +++ b/src/gui/GameBgImage.h @@ -0,0 +1,23 @@ +#ifndef _GAME_BG_IMAGE_H_ +#define _GAME_BG_IMAGE_H_ + +#include "GuiImageAsync.h" +#include "video/shaders/Shader3D.h" + +class GameBgImage : public GuiImageAsync +{ +public: + GameBgImage(const std::string & filename, GuiImageData *preloadImage); + virtual ~GameBgImage(); + + void setAlphaFadeOut(const glm::vec4 & a) { + alphaFadeOut = a; + } + + void draw(CVideo *pVideo); +private: + glm::mat4 identity; + glm::vec4 alphaFadeOut; +}; + +#endif // _GAME_BG_IMAGE_H_ diff --git a/src/gui/GameIcon.cpp b/src/gui/GameIcon.cpp new file mode 100644 index 0000000..2e1aa73 --- /dev/null +++ b/src/gui/GameIcon.cpp @@ -0,0 +1,321 @@ +#include "GameIcon.h" +#include "GameIconModel.h" +#include "Application.h" +#include "video/CVideo.h" +#include "video/shaders/Shader3D.h" +#include "video/shaders/ShaderFractalColor.h" + +static const f32 cfIconMirrorScale = 1.15f; +static const f32 cfIconMirrorAlpha = 0.45f; + +GameIcon::GameIcon(const std::string & filename, GuiImageData *preloadImage) + : GuiImageAsync(filename, preloadImage) +{ + bSelected = false; + bRenderStroke = true; + bRenderReflection = false; + bIconLast = false; + strokeFractalEnable = 1; + strokeBlurBorder = 0.0f; + distanceFadeout = 0.0f; + rotationX = 0.0f; + reflectionAlpha = 0.4f; + strokeWidth = 2.35f; + colorIntensity = glm::vec4(1.0f); + colorIntensityMirror = colorIntensity; + alphaFadeOutNorm = glm::vec4(0.0f); + alphaFadeOutRefl = glm::vec4(-1.0f, 0.0f, 0.9f, 1.0f); + selectionBlurOuterColorIntensity = glm::vec4(0.09411764f * 1.15f, 0.56862745f * 1.15f, 0.96862745098f * 1.15f, 1.0f); + selectionBlurOuterSize = 1.65f; + selectionBlurOuterBorderSize = 0.5f; + selectionBlurInnerColorIntensity = glm::vec4(0.46666667f, 0.90588235f, 1.0f, 1.0f); + selectionBlurInnerSize = 1.45f; + selectionBlurInnerBorderSize = 0.95f; + + vtxCount = sizeof(cfGameIconPosVtxs) / (Shader3D::cuVertexAttrSize); + + //! texture and vertex coordinates + posVtxs = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, sizeof(cfGameIconPosVtxs)); + texCoords = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, sizeof(cfGameIconTexCoords)); + + if(posVtxs) + { + memcpy((f32*)posVtxs, cfGameIconPosVtxs, sizeof(cfGameIconPosVtxs)); + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, (f32*)posVtxs, sizeof(cfGameIconPosVtxs)); + } + if(texCoords) + { + memcpy((f32*)texCoords, cfGameIconTexCoords, sizeof(cfGameIconTexCoords)); + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, (f32*)texCoords, sizeof(cfGameIconTexCoords)); + } + + //! create vertexes for the mirror frame + texCoordsMirror = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, sizeof(cfGameIconTexCoords)); + + if(texCoordsMirror) + { + for(u32 i = 0; i < vtxCount; i++) + { + texCoordsMirror[i*2 + 0] = texCoords[i*2 + 0] * cfIconMirrorScale - ((cfIconMirrorScale - 1.0f) - (cfIconMirrorScale - 1.0f) * 0.5f); + texCoordsMirror[i*2 + 1] = texCoords[i*2 + 1] * cfIconMirrorScale - ((cfIconMirrorScale - 1.0f) - (cfIconMirrorScale - 1.0f) * 0.5f); + } + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, texCoordsMirror, sizeof(cfGameIconTexCoords)); + } + + //! setup stroke of the icon + strokePosVtxs = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, sizeof(cfGameIconStrokeVtxs)); + if(strokePosVtxs) + { + memcpy(strokePosVtxs, cfGameIconStrokeVtxs, sizeof(cfGameIconStrokeVtxs)); + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, strokePosVtxs, sizeof(cfGameIconStrokeVtxs)); + } + strokeTexCoords = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, cuGameIconStrokeVtxCount * Shader::cuTexCoordAttrSize); + if(strokeTexCoords) + { + for(size_t i = 0, n = 0; i < cuGameIconStrokeVtxCount; n += 2, i += 3) + { + strokeTexCoords[n] = (1.0f + strokePosVtxs[i]) * 0.5f; + strokeTexCoords[n+1] = 1.0f - (1.0f + strokePosVtxs[i+1]) * 0.5f; + } + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, strokeTexCoords, cuGameIconStrokeVtxCount * Shader::cuTexCoordAttrSize); + } + strokeColorVtxs = (u8*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, cuGameIconStrokeVtxCount * Shader::cuColorAttrSize); + if(strokeColorVtxs) + { + for(size_t i = 0; i < (cuGameIconStrokeVtxCount * Shader::cuColorAttrSize); i++) + strokeColorVtxs[i] = 0xff; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, strokeColorVtxs, cuGameIconStrokeVtxCount * Shader::cuColorAttrSize); + } +} + +GameIcon::~GameIcon() +{ + //! remove image so it can not be drawn anymore from this point on + imageData = NULL; + + //! main image vertexes + if(posVtxs) + { + free((void*)posVtxs); + posVtxs = NULL; + } + if(texCoords) + { + free((void*)texCoords); + texCoords = NULL; + } + //! mirror image vertexes + if(texCoordsMirror) + { + free(texCoordsMirror); + texCoordsMirror = NULL; + } + //! stroke image vertexes + if(strokePosVtxs) + { + free(strokePosVtxs); + strokePosVtxs = NULL; + } + if(strokeTexCoords) + { + free(strokeTexCoords); + strokeTexCoords = NULL; + } + if(strokeColorVtxs) + { + free(strokeColorVtxs); + strokeColorVtxs = NULL; + } +} + +bool GameIcon::checkRayIntersection(const glm::vec3 & rayOrigin, const glm::vec3 & rayDirFrac) +{ + //! since we always face the camera we can just check the AABB intersection + //! otherwise an OOB intersection would be required + + f32 currPosX = getCenterX() * Application::instance()->getVideo()->getWidthScaleFactor() * 2.0f; + f32 currPosY = getCenterY() * Application::instance()->getVideo()->getHeightScaleFactor() * 2.0f; + f32 currPosZ = getDepth() * Application::instance()->getVideo()->getDepthScaleFactor() * 2.0f; + f32 currScaleX = getScaleX() * (f32)getWidth() * Application::instance()->getVideo()->getWidthScaleFactor(); + f32 currScaleY = getScaleY() * (f32)getHeight() * Application::instance()->getVideo()->getHeightScaleFactor(); + f32 currScaleZ = getScaleZ() * (f32)getWidth() * Application::instance()->getVideo()->getDepthScaleFactor(); + //! lb is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner + glm::vec3 lb(currPosX - currScaleX, currPosY - currScaleY, currPosZ - currScaleZ); + glm::vec3 rt(currPosX + currScaleX, currPosY + currScaleY, currPosZ + currScaleZ); + + float t1 = (lb.x - rayOrigin.x) * rayDirFrac.x; + float t2 = (rt.x - rayOrigin.x) * rayDirFrac.x; + float t3 = (lb.y - rayOrigin.y) * rayDirFrac.y; + float t4 = (rt.y - rayOrigin.y) * rayDirFrac.y; + float t5 = (lb.z - rayOrigin.z) * rayDirFrac.z; + float t6 = (rt.z - rayOrigin.z) * rayDirFrac.z; + + float tmin = std::max(std::max(std::min(t1, t2), std::min(t3, t4)), std::min(t5, t6)); + float tmax = std::min(std::min(std::max(t1, t2), std::max(t3, t4)), std::max(t5, t6)); + + //! if tmax < 0, ray (line) is intersecting AABB, but whole AABB is behing us + if (tmax < 0) + { + //t = tmax; + return false; + } + + //! if tmin > tmax, ray doesn't intersect AABB + if (tmin > tmax) + { + //t = tmax; + return false; + } + + //t = tmin; + return true; +} + +void GameIcon::draw(CVideo *pVideo, const glm::mat4 & projectionMtx, const glm::mat4 & viewMtx, const glm::mat4 & modelView) +{ + //! first setup 2D GUI positions + f32 currPosX = getCenterX() * pVideo->getWidthScaleFactor() * 2.0f; + f32 currPosY = getCenterY() * pVideo->getHeightScaleFactor() * 2.0f; + f32 currPosZ = getDepth() * pVideo->getDepthScaleFactor() * 2.0f; + f32 currScaleX = getScaleX() * (f32)getWidth() * pVideo->getWidthScaleFactor(); + f32 currScaleY = getScaleY() * (f32)getHeight() * pVideo->getHeightScaleFactor(); + f32 currScaleZ = getScaleZ() * (f32)getWidth() * pVideo->getDepthScaleFactor(); + f32 strokeScaleX = pVideo->getWidthScaleFactor() * strokeWidth * 0.25f + cfIconMirrorScale; + f32 strokeScaleY = pVideo->getHeightScaleFactor() * strokeWidth * 0.25f + cfIconMirrorScale; + + for(int iDraw = 0; iDraw < 2; iDraw++) + { + glm::vec4 * alphaFadeOut; + glm::mat4 m_iconView; + glm::mat4 m_mirrorView; + glm::mat4 m_strokeView; + + if(iDraw == RENDER_REFLECTION) + { + //! Reflection render + if(!bRenderReflection) + continue; + m_iconView = glm::translate(modelView, glm::vec3(currPosX, -currScaleY * 2.0f - currPosY, currPosZ + cosf(DegToRad(rotationX)) * currScaleZ * 2.0f)); + m_iconView = glm::rotate(m_iconView, DegToRad(rotationX), glm::vec3(1.0f, 0.0f, 0.0f)); + m_iconView = glm::scale(m_iconView, glm::vec3(currScaleX, -currScaleY, currScaleZ)); + + colorIntensity[3] = reflectionAlpha * getAlpha(); + selectionBlurOuterColorIntensity[3] = colorIntensity[3] * 0.7f; + selectionBlurInnerColorIntensity[3] = colorIntensity[3] * 0.7f; + alphaFadeOut = &alphaFadeOutRefl; + + GX2SetCullOnlyControl(GX2_FRONT_FACE_CCW, GX2_ENABLE, GX2_DISABLE); + } + else + { + //! Normal render + m_iconView = glm::translate(modelView, glm::vec3(currPosX,currPosY, currPosZ)); + m_iconView = glm::rotate(m_iconView, DegToRad(rotationX), glm::vec3(1.0f, 0.0f, 0.0f)); + m_iconView = glm::scale(m_iconView, glm::vec3(currScaleX, currScaleY, currScaleZ)); + + colorIntensity[3] = getAlpha(); + selectionBlurOuterColorIntensity[3] = colorIntensity[3]; + selectionBlurInnerColorIntensity[3] = colorIntensity[3]; + alphaFadeOut = &alphaFadeOutNorm; + } + + m_mirrorView = glm::scale(m_iconView, glm::vec3(cfIconMirrorScale, cfIconMirrorScale, cfIconMirrorScale)); + + colorIntensityMirror[3] = cfIconMirrorAlpha * colorIntensity[3]; + + if(!bIconLast) + { + Shader3D::instance()->setShaders(); + Shader3D::instance()->setProjectionMtx(projectionMtx); + Shader3D::instance()->setViewMtx(viewMtx); + Shader3D::instance()->setTextureAndSampler(imageData->getTexture(), imageData->getSampler()); + Shader3D::instance()->setAlphaFadeOut(*alphaFadeOut); + Shader3D::instance()->setDistanceFadeOut(distanceFadeout); + + //! render the real symbol + Shader3D::instance()->setModelViewMtx(m_iconView); + Shader3D::instance()->setColorIntensity(colorIntensity); + Shader3D::instance()->setAttributeBuffer(vtxCount, posVtxs, texCoords); + Shader3D::instance()->draw(GX2_PRIMITIVE_QUADS, vtxCount); + } + + if(bSelected) + { + strokeFractalEnable = 0; + + GX2SetDepthOnlyControl(GX2_ENABLE, GX2_DISABLE, GX2_COMPARE_LEQUAL); + m_strokeView = glm::scale(m_iconView, glm::vec3(selectionBlurOuterSize, selectionBlurOuterSize, 0.0f)); + ShaderFractalColor::instance()->setShaders(); + ShaderFractalColor::instance()->setProjectionMtx(projectionMtx); + ShaderFractalColor::instance()->setViewMtx(viewMtx); + ShaderFractalColor::instance()->setModelViewMtx(m_strokeView); + ShaderFractalColor::instance()->setFractalColor(strokeFractalEnable); + ShaderFractalColor::instance()->setBlurBorder(selectionBlurOuterBorderSize); + ShaderFractalColor::instance()->setColorIntensity(selectionBlurOuterColorIntensity); + ShaderFractalColor::instance()->setAlphaFadeOut(*alphaFadeOut); + ShaderFractalColor::instance()->setAttributeBuffer(); + ShaderFractalColor::instance()->draw(); + + m_strokeView = glm::scale(m_iconView, glm::vec3(selectionBlurInnerSize, selectionBlurInnerSize, 0.0f)); + ShaderFractalColor::instance()->setBlurBorder(selectionBlurInnerBorderSize); + ShaderFractalColor::instance()->setColorIntensity(selectionBlurInnerColorIntensity); + ShaderFractalColor::instance()->draw(); + GX2SetDepthOnlyControl(GX2_ENABLE, GX2_ENABLE, GX2_COMPARE_LEQUAL); + } + + if(iDraw == RENDER_NORMAL && bRenderStroke) + { + strokeFractalEnable = 1; + //! now render the icon stroke + //! make the stroke a little bigger than the mirror, just by the line width on each side + m_strokeView = glm::scale(m_iconView, glm::vec3(strokeScaleX, strokeScaleY, cfIconMirrorScale)); + + ShaderFractalColor::instance()->setShaders(); + ShaderFractalColor::instance()->setLineWidth(strokeWidth); + ShaderFractalColor::instance()->setProjectionMtx(projectionMtx); + ShaderFractalColor::instance()->setViewMtx(viewMtx); + ShaderFractalColor::instance()->setModelViewMtx(m_strokeView); + ShaderFractalColor::instance()->setFractalColor(strokeFractalEnable); + ShaderFractalColor::instance()->setBlurBorder(strokeBlurBorder); + ShaderFractalColor::instance()->setColorIntensity(colorIntensity); + ShaderFractalColor::instance()->setAlphaFadeOut(*alphaFadeOut); + ShaderFractalColor::instance()->setAttributeBuffer(cuGameIconStrokeVtxCount, strokePosVtxs, strokeTexCoords, strokeColorVtxs); + ShaderFractalColor::instance()->draw(GX2_PRIMITIVE_LINE_STRIP, cuGameIconStrokeVtxCount); + + } + + //! render the background mirror frame + Shader3D::instance()->setShaders(); + Shader3D::instance()->setProjectionMtx(projectionMtx); + Shader3D::instance()->setViewMtx(viewMtx); + Shader3D::instance()->setTextureAndSampler(imageData->getTexture(), imageData->getSampler()); + Shader3D::instance()->setAlphaFadeOut(*alphaFadeOut); + Shader3D::instance()->setDistanceFadeOut(distanceFadeout); + Shader3D::instance()->setModelViewMtx(m_mirrorView); + Shader3D::instance()->setColorIntensity(colorIntensityMirror); + Shader3D::instance()->setAttributeBuffer(vtxCount, posVtxs, texCoordsMirror); + Shader3D::instance()->draw(GX2_PRIMITIVE_QUADS, vtxCount); + + if(bIconLast) + { + Shader3D::instance()->setShaders(); + Shader3D::instance()->setProjectionMtx(projectionMtx); + Shader3D::instance()->setViewMtx(viewMtx); + Shader3D::instance()->setTextureAndSampler(imageData->getTexture(), imageData->getSampler()); + Shader3D::instance()->setAlphaFadeOut(*alphaFadeOut); + Shader3D::instance()->setDistanceFadeOut(distanceFadeout); + + //! render the real symbol + Shader3D::instance()->setModelViewMtx(m_iconView); + Shader3D::instance()->setColorIntensity(colorIntensity); + Shader3D::instance()->setAttributeBuffer(vtxCount, posVtxs, texCoords); + Shader3D::instance()->draw(GX2_PRIMITIVE_QUADS, vtxCount); + } + + //! return back normal culling + if(iDraw == RENDER_REFLECTION) + { + GX2SetCullOnlyControl(GX2_FRONT_FACE_CCW, GX2_DISABLE, GX2_ENABLE); + } + } +} diff --git a/src/gui/GameIcon.h b/src/gui/GameIcon.h new file mode 100644 index 0000000..238060c --- /dev/null +++ b/src/gui/GameIcon.h @@ -0,0 +1,85 @@ +#ifndef _GAME_ICON_H_ +#define _GAME_ICON_H_ + +#include "GuiImageAsync.h" +#include "video/shaders/Shader3D.h" + +class GameIcon : public GuiImageAsync +{ +public: + GameIcon(const std::string & filename, GuiImageData *preloadImage); + virtual ~GameIcon(); + + void setRotationX(f32 r) { + rotationX = r; + } + void setColorIntensity(const glm::vec4 & color) { + colorIntensity = color; + colorIntensityMirror = colorIntensity; + selectionBlurOuterColorIntensity = color * glm::vec4(0.09411764f * 1.15f, 0.56862745f * 1.15f, 0.96862745098f * 1.15f, 1.0f); + selectionBlurInnerColorIntensity = color * glm::vec4(0.46666667f, 0.90588235f, 1.0f, 1.0f); + } + const glm::vec4 & getColorIntensity() const { + return colorIntensity; + } + void setAlphaFadeOutNorm(const glm::vec4 & a) { + alphaFadeOutNorm = a; + } + void setAlphaFadeOutRefl(const glm::vec4 & a) { + alphaFadeOutRefl = a; + } + void setRenderReflection(bool enable) { + bRenderReflection = enable; + } + void setSelected(bool enable) { + bSelected = enable; + } + void setStrokeRender(bool enable) { + bRenderStroke = enable; + } + void setRenderIconLast(bool enable) { + bIconLast = enable; + } + void draw(CVideo *pVideo) { + static const glm::mat4 identity(1.0f); + draw(pVideo, identity, identity, identity); + } + void draw(CVideo *pVideo, const glm::mat4 & projection, const glm::mat4 & view, const glm::mat4 & modelView); + + bool checkRayIntersection(const glm::vec3 & rayOrigin, const glm::vec3 & rayDirFrac); +private: + enum eRenderState + { + RENDER_REFLECTION, + RENDER_NORMAL + }; + + bool bSelected; + bool bRenderStroke; + bool bRenderReflection; + bool bIconLast; + glm::vec4 colorIntensity; + glm::vec4 colorIntensityMirror; + glm::vec4 alphaFadeOutNorm; + glm::vec4 alphaFadeOutRefl; + + f32 reflectionAlpha; + f32 strokeWidth; + f32 rotationX; + f32 rgbReduction; + f32 distanceFadeout; + f32 *texCoordsMirror; + f32 *strokePosVtxs; + f32 *strokeTexCoords; + u8 *strokeColorVtxs; + int strokeFractalEnable; + f32 strokeBlurBorder; + glm::vec4 selectionBlurOuterColorIntensity; + f32 selectionBlurOuterSize; + f32 selectionBlurOuterBorderSize; + glm::vec4 selectionBlurInnerColorIntensity; + f32 selectionBlurInnerSize; + f32 selectionBlurInnerBorderSize; +}; + +#endif // _GAME_ICON_H_ diff --git a/src/gui/GameIconModel.h b/src/gui/GameIconModel.h new file mode 100644 index 0000000..97621ea --- /dev/null +++ b/src/gui/GameIconModel.h @@ -0,0 +1,760 @@ +#ifndef ICON_MODEL_H_ +#define ICON_MODEL_H_ + +static const float cfGameIconPosVtxs[] = { +-0.844501f,-0.861263f,0.050154f,-0.802664f,-0.8797f,0.054004f,-0.809968f,-0.828995f,0.061777f,-0.864233f,-0.822169f,0.054004f, +-0.802664f,-0.8797f,0.054004f,-0.726455f,-0.89991f,0.058224f,-0.730326f,-0.842312f,0.067487f,-0.809968f,-0.828995f,0.061777f, +-0.809968f,-0.828995f,0.061777f,-0.730326f,-0.842312f,0.067487f,-0.738488f,-0.760488f,0.074426f,-0.824221f,-0.752861f,0.067487f, +-0.864233f,-0.822169f,0.054004f,-0.809968f,-0.828995f,0.061777f,-0.824221f,-0.752861f,0.067487f,-0.885862f,-0.749245f,0.058224f, +-0.726455f,-0.89991f,0.058224f,-0.612405f,-0.916988f,0.061789f,-0.614352f,-0.854962f,0.071886f,-0.730326f,-0.842312f,0.067487f, +-0.612405f,-0.916988f,0.061789f,-0.392243f,-0.928623f,0.064218f,-0.39312f,-0.8642f,0.074693f,-0.614352f,-0.854962f,0.071886f, +-0.614352f,-0.854962f,0.071886f,-0.39312f,-0.8642f,0.074693f,-0.395094f,-0.775509f,0.082561f,-0.618732f,-0.768902f,0.079479f, +-0.730326f,-0.842312f,0.067487f,-0.614352f,-0.854962f,0.071886f,-0.618732f,-0.768902f,0.079479f,-0.738488f,-0.760488f,0.074426f, +-0.738488f,-0.760488f,0.074426f,-0.618732f,-0.768902f,0.079479f,-0.624085f,-0.648442f,0.084918f,-0.747494f,-0.64344f,0.079479f, +-0.618732f,-0.768902f,0.079479f,-0.395094f,-0.775509f,0.082561f,-0.397505f,-0.652534f,0.088189f,-0.624085f,-0.648442f,0.084918f, +-0.624085f,-0.648442f,0.084918f,-0.397505f,-0.652534f,0.088189f,-0.399478f,-0.422739f,0.09157f,-0.628465f,-0.420911f,0.088189f, +-0.747494f,-0.64344f,0.079479f,-0.624085f,-0.648442f,0.084918f,-0.628465f,-0.420911f,0.088189f,-0.754564f,-0.418675f,0.082561f, +-0.885862f,-0.749245f,0.058224f,-0.824221f,-0.752861f,0.067487f,-0.837759f,-0.639347f,0.071886f,-0.90414f,-0.637528f,0.061789f, +-0.824221f,-0.752861f,0.067487f,-0.738488f,-0.760488f,0.074426f,-0.747494f,-0.64344f,0.079479f,-0.837759f,-0.639347f,0.071886f, +-0.837759f,-0.639347f,0.071886f,-0.747494f,-0.64344f,0.079479f,-0.754564f,-0.418675f,0.082561f,-0.847646f,-0.416846f,0.074693f, +-0.90414f,-0.637528f,0.061789f,-0.837759f,-0.639347f,0.071886f,-0.847646f,-0.416846f,0.074693f,-0.916591f,-0.416033f,0.064218f, +-0.399478f,-0.422739f,0.09157f,-0.397505f,-0.652534f,0.088189f,0.002274f,-0.653898f,0.089279f,0.002265f,-0.423349f,0.092698f, +-0.397505f,-0.652534f,0.088189f,-0.395094f,-0.775509f,0.082561f,0.002284f,-0.777711f,0.083588f,0.002274f,-0.653898f,0.089279f, +0.002274f,-0.653898f,0.089279f,0.002284f,-0.777711f,0.083588f,0.399509f,-0.775509f,0.082561f,0.401892f,-0.652534f,0.088189f, +0.002265f,-0.423349f,0.092698f,0.002274f,-0.653898f,0.089279f,0.401892f,-0.652534f,0.088189f,0.403842f,-0.422739f,0.09157f, +-0.395094f,-0.775509f,0.082561f,-0.39312f,-0.8642f,0.074693f,0.002293f,-0.867279f,0.075629f,0.002284f,-0.777711f,0.083588f, +-0.39312f,-0.8642f,0.074693f,-0.392243f,-0.928623f,0.064218f,0.002297f,-0.932501f,0.065028f,0.002293f,-0.867279f,0.075629f, +0.002293f,-0.867279f,0.075629f,0.002297f,-0.932501f,0.065028f,0.396693f,-0.928623f,0.064218f,0.397559f,-0.8642f,0.074693f, +0.002284f,-0.777711f,0.083588f,0.002293f,-0.867279f,0.075629f,0.397559f,-0.8642f,0.074693f,0.399509f,-0.775509f,0.082561f, +-0.399478f,-0.422739f,0.09157f,0.002265f,-0.423349f,0.092698f,0.002263f,-0.013572f,0.093837f,-0.400136f,-0.013589f,0.092698f, +0.002265f,-0.423349f,0.092698f,0.403842f,-0.422739f,0.09157f,0.404492f,-0.013589f,0.092698f,0.002263f,-0.013572f,0.093837f, +0.002263f,-0.013572f,0.093837f,0.404492f,-0.013589f,0.092698f,0.403842f,0.396564f,0.09157f,0.002265f,0.397221f,0.092698f, +-0.400136f,-0.013589f,0.092698f,0.002263f,-0.013572f,0.093837f,0.002265f,0.397221f,0.092698f,-0.399478f,0.396564f,0.09157f, +-0.754564f,0.392188f,0.082561f,-0.847646f,0.390218f,0.074693f,-0.850941f,-0.013754f,0.075629f,-0.756921f,-0.013703f,0.083588f, +-0.847646f,0.390218f,0.074693f,-0.916591f,0.389343f,0.064218f,-0.920742f,-0.013776f,0.065028f,-0.850941f,-0.013754f,0.075629f, +-0.850941f,-0.013754f,0.075629f,-0.920742f,-0.013776f,0.065028f,-0.916591f,-0.416033f,0.064218f,-0.847646f,-0.416846f,0.074693f, +-0.756921f,-0.013703f,0.083588f,-0.850941f,-0.013754f,0.075629f,-0.847646f,-0.416846f,0.074693f,-0.754564f,-0.418675f,0.082561f, +-0.754564f,0.392188f,0.082561f,-0.756921f,-0.013703f,0.083588f,-0.629925f,-0.01364f,0.089279f,-0.628465f,0.394595f,0.088189f, +-0.756921f,-0.013703f,0.083588f,-0.754564f,-0.418675f,0.082561f,-0.628465f,-0.420911f,0.088189f,-0.629925f,-0.01364f,0.089279f, +-0.629925f,-0.01364f,0.089279f,-0.628465f,-0.420911f,0.088189f,-0.399478f,-0.422739f,0.09157f,-0.400136f,-0.013589f,0.092698f, +-0.628465f,0.394595f,0.088189f,-0.629925f,-0.01364f,0.089279f,-0.400136f,-0.013589f,0.092698f,-0.399478f,0.396564f,0.09157f, +-0.844501f,0.846382f,0.050154f,-0.802664f,0.865969f,0.054004f,-0.814648f,0.914535f,0.037876f,-0.871108f,0.872793f,0.036675f, +-0.802664f,0.865969f,0.054004f,-0.726455f,0.887439f,0.058224f,-0.733131f,0.94538f,0.040237f,-0.814648f,0.914535f,0.037876f, +-0.814648f,0.914535f,0.037876f,-0.733131f,0.94538f,0.040237f,-0.74278f,0.982563f,0.019733f,-0.830745f,0.945555f,0.018815f, +-0.871108f,0.872793f,0.036675f,-0.814648f,0.914535f,0.037876f,-0.830745f,0.945555f,0.018815f,-0.894756f,0.896267f,0.018385f, +-0.726455f,0.887439f,0.058224f,-0.612405f,0.905582f,0.061789f,-0.615909f,0.968735f,0.042517f,-0.733131f,0.94538f,0.040237f, +-0.612405f,0.905582f,0.061789f,-0.392243f,0.917941f,0.064218f,-0.393822f,0.983443f,0.044197f,-0.615909f,0.968735f,0.042517f, +-0.615909f,0.968735f,0.042517f,-0.393822f,0.983443f,0.044197f,-0.396235f,1.025424f,0.021594f,-0.621266f,1.009264f,0.020771f, +-0.733131f,0.94538f,0.040237f,-0.615909f,0.968735f,0.042517f,-0.621266f,1.009264f,0.020771f,-0.74278f,0.982563f,0.019733f, +-0.621266f,1.009264f,0.020771f,-0.396235f,1.025424f,0.021594f,-0.398382f,1.047552f,0.0f,-0.626031f,1.030658f,0.0f, +-0.74278f,0.982563f,0.019733f,-0.621266f,1.009264f,0.020771f,-0.626031f,1.030658f,0.0f,-0.750636f,1.002556f,0.0f, +-0.830745f,0.945555f,0.018815f,-0.74278f,0.982563f,0.019733f,-0.750636f,1.002556f,0.0f,-0.842153f,0.963302f,0.0f, +-0.894756f,0.896267f,0.018385f,-0.830745f,0.945555f,0.018815f,-0.842153f,0.963302f,0.0f,-0.909674f,0.911075f,0.0f, +-0.398382f,1.047552f,0.0f,-0.396235f,1.025424f,0.021594f,0.002279f,1.030811f,0.021869f,0.00227f,1.053183f,0.0f, +0.002279f,1.030811f,0.021869f,-0.396235f,1.025424f,0.021594f,-0.393822f,0.983443f,0.044197f,0.00229f,0.988345f,0.044757f, +0.400637f,1.025424f,0.021594f,0.002279f,1.030811f,0.021869f,0.00229f,0.988345f,0.044757f,0.398253f,0.983443f,0.044197f, +0.00227f,1.053183f,0.0f,0.002279f,1.030811f,0.021869f,0.400637f,1.025424f,0.021594f,0.402758f,1.047552f,0.0f, +-0.393822f,0.983443f,0.044197f,-0.392243f,0.917941f,0.064218f,0.002297f,0.922061f,0.065028f,0.00229f,0.988345f,0.044757f, +0.00229f,0.988345f,0.044757f,0.002297f,0.922061f,0.065028f,0.396693f,0.917941f,0.064218f,0.398253f,0.983443f,0.044197f, +0.396693f,-0.928623f,0.064218f,0.002297f,-0.932501f,0.065028f,0.00229f,-0.994896f,0.044757f,0.398253f,-0.990281f,0.044197f, +0.002297f,-0.932501f,0.065028f,-0.392243f,-0.928623f,0.064218f,-0.393822f,-0.990281f,0.044197f,0.00229f,-0.994896f,0.044757f, +0.00229f,-0.994896f,0.044757f,-0.393822f,-0.990281f,0.044197f,-0.396235f,-1.0298f,0.021594f,0.002279f,-1.034871f,0.021869f, +0.398253f,-0.990281f,0.044197f,0.00229f,-0.994896f,0.044757f,0.002279f,-1.034871f,0.021869f,0.400637f,-1.0298f,0.021594f, +-0.396235f,-1.0298f,0.021594f,-0.398382f,-1.050629f,0.0f,0.00227f,-1.05593f,0.0f,0.002279f,-1.034871f,0.021869f, +0.002279f,-1.034871f,0.021869f,0.00227f,-1.05593f,0.0f,0.402758f,-1.050629f,0.0f,0.400637f,-1.0298f,0.021594f, +-0.909674f,-0.922159f,0.0f,-0.842153f,-0.971323f,0.0f,-0.830745f,-0.954616f,0.018815f,-0.894756f,-0.90822f,0.018385f, +-0.842153f,-0.971323f,0.0f,-0.750636f,-1.008273f,0.0f,-0.74278f,-0.989453f,0.019733f,-0.830745f,-0.954616f,0.018815f, +-0.830745f,-0.954616f,0.018815f,-0.74278f,-0.989453f,0.019733f,-0.733131f,-0.954452f,0.040237f,-0.814648f,-0.925416f,0.037876f, +-0.894756f,-0.90822f,0.018385f,-0.830745f,-0.954616f,0.018815f,-0.814648f,-0.925416f,0.037876f,-0.871108f,-0.886124f,0.036675f, +-0.750636f,-1.008273f,0.0f,-0.626031f,-1.034726f,0.0f,-0.621266f,-1.014588f,0.020771f,-0.74278f,-0.989453f,0.019733f, +-0.626031f,-1.034726f,0.0f,-0.398382f,-1.050629f,0.0f,-0.396235f,-1.0298f,0.021594f,-0.621266f,-1.014588f,0.020771f, +-0.621266f,-1.014588f,0.020771f,-0.396235f,-1.0298f,0.021594f,-0.393822f,-0.990281f,0.044197f,-0.615909f,-0.976437f,0.042517f, +-0.74278f,-0.989453f,0.019733f,-0.621266f,-1.014588f,0.020771f,-0.615909f,-0.976437f,0.042517f,-0.733131f,-0.954452f,0.040237f, +-0.615909f,-0.976437f,0.042517f,-0.393822f,-0.990281f,0.044197f,-0.392243f,-0.928623f,0.064218f,-0.612405f,-0.916988f,0.061789f, +-0.733131f,-0.954452f,0.040237f,-0.615909f,-0.976437f,0.042517f,-0.612405f,-0.916988f,0.061789f,-0.726455f,-0.89991f,0.058224f, +-0.814648f,-0.925416f,0.037876f,-0.733131f,-0.954452f,0.040237f,-0.726455f,-0.89991f,0.058224f,-0.802664f,-0.8797f,0.054004f, +-0.871108f,-0.886124f,0.036675f,-0.814648f,-0.925416f,0.037876f,-0.802664f,-0.8797f,0.054004f,-0.844501f,-0.861263f,0.050154f, +0.846982f,-0.861263f,0.050154f,0.87333f,-0.886124f,0.036675f,0.914973f,-0.833367f,0.037876f,0.866523f,-0.822169f,0.054004f, +0.914973f,-0.833367f,0.037876f,0.87333f,-0.886124f,0.036675f,0.896749f,-0.90822f,0.018385f,0.94592f,-0.848408f,0.018815f, +0.945745f,-0.755482f,0.040237f,0.914973f,-0.833367f,0.037876f,0.94592f,-0.848408f,0.018815f,0.982841f,-0.764498f,0.019733f, +0.866523f,-0.822169f,0.054004f,0.914973f,-0.833367f,0.037876f,0.945745f,-0.755482f,0.040237f,0.887941f,-0.749245f,0.058224f, +0.896749f,-0.90822f,0.018385f,0.911522f,-0.922159f,0.0f,0.963626f,-0.859068f,0.0f,0.94592f,-0.848408f,0.018815f, +0.94592f,-0.848408f,0.018815f,0.963626f,-0.859068f,0.0f,1.002787f,-0.771839f,0.0f,0.982841f,-0.764498f,0.019733f, +0.945745f,-0.755482f,0.040237f,0.982841f,-0.764498f,0.019733f,1.009478f,-0.645808f,0.020771f,0.969045f,-0.640802f,0.042517f, +0.982841f,-0.764498f,0.019733f,1.002787f,-0.771839f,0.0f,1.030822f,-0.650261f,0.0f,1.009478f,-0.645808f,0.020771f, +1.009478f,-0.645808f,0.020771f,1.030822f,-0.650261f,0.0f,1.047675f,-0.421723f,0.0f,1.025601f,-0.419734f,0.021594f, +1.009478f,-0.645808f,0.020771f,1.025601f,-0.419734f,0.021594f,0.983719f,-0.417497f,0.044197f,0.969045f,-0.640802f,0.042517f, +0.887941f,-0.749245f,0.058224f,0.945745f,-0.755482f,0.040237f,0.969045f,-0.640802f,0.042517f,0.906041f,-0.637528f,0.061789f, +0.906041f,-0.637528f,0.061789f,0.969045f,-0.640802f,0.042517f,0.983719f,-0.417497f,0.044197f,0.918372f,-0.416033f,0.064218f, +0.918372f,-0.416033f,0.064218f,0.983719f,-0.417497f,0.044197f,0.98861f,-0.013736f,0.044757f,0.922482f,-0.013776f,0.065028f, +0.98861f,-0.013736f,0.044757f,0.983719f,-0.417497f,0.044197f,1.025601f,-0.419734f,0.021594f,1.030975f,-0.013673f,0.021869f, +0.983719f,0.390919f,0.044197f,0.98861f,-0.013736f,0.044757f,1.030975f,-0.013673f,0.021869f,1.025601f,0.393327f,0.021594f, +0.922482f,-0.013776f,0.065028f,0.98861f,-0.013736f,0.044757f,0.983719f,0.390919f,0.044197f,0.918372f,0.389343f,0.064218f, +1.025601f,-0.419734f,0.021594f,1.047675f,-0.421723f,0.0f,1.053293f,-0.013618f,0.0f,1.030975f,-0.013673f,0.021869f, +1.030975f,-0.013673f,0.021869f,1.053293f,-0.013618f,0.0f,1.047675f,0.39547f,0.0f,1.025601f,0.393327f,0.021594f, +-0.909674f,-0.922159f,0.0f,-0.894756f,-0.90822f,0.018385f,-0.944409f,-0.848408f,0.018815f,-0.962289f,-0.859068f,0.0f, +-0.944409f,-0.848408f,0.018815f,-0.894756f,-0.90822f,0.018385f,-0.871108f,-0.886124f,0.036675f,-0.913159f,-0.833367f,0.037876f, +-0.981692f,-0.764498f,0.019733f,-0.944409f,-0.848408f,0.018815f,-0.913159f,-0.833367f,0.037876f,-0.944233f,-0.755482f,0.040237f, +-0.962289f,-0.859068f,0.0f,-0.944409f,-0.848408f,0.018815f,-0.981692f,-0.764498f,0.019733f,-1.001834f,-0.771839f,0.0f, +-0.871108f,-0.886124f,0.036675f,-0.844501f,-0.861263f,0.050154f,-0.864233f,-0.822169f,0.054004f,-0.913159f,-0.833367f,0.037876f, +-0.913159f,-0.833367f,0.037876f,-0.864233f,-0.822169f,0.054004f,-0.885862f,-0.749245f,0.058224f,-0.944233f,-0.755482f,0.040237f, +-0.981692f,-0.764498f,0.019733f,-0.944233f,-0.755482f,0.040237f,-0.967761f,-0.640802f,0.042517f,-1.008591f,-0.645808f,0.020771f, +-0.944233f,-0.755482f,0.040237f,-0.885862f,-0.749245f,0.058224f,-0.90414f,-0.637528f,0.061789f,-0.967761f,-0.640802f,0.042517f, +-0.967761f,-0.640802f,0.042517f,-0.90414f,-0.637528f,0.061789f,-0.916591f,-0.416033f,0.064218f,-0.982578f,-0.417497f,0.044197f, +-0.967761f,-0.640802f,0.042517f,-0.982578f,-0.417497f,0.044197f,-1.024871f,-0.419734f,0.021594f,-1.008591f,-0.645808f,0.020771f, +-1.001834f,-0.771839f,0.0f,-0.981692f,-0.764498f,0.019733f,-1.008591f,-0.645808f,0.020771f,-1.030143f,-0.650261f,0.0f, +-1.030143f,-0.650261f,0.0f,-1.008591f,-0.645808f,0.020771f,-1.024871f,-0.419734f,0.021594f,-1.047163f,-0.421723f,0.0f, +-1.047163f,0.39547f,0.0f,-1.052836f,-0.013618f,0.0f,-1.030298f,-0.013673f,0.021869f,-1.024871f,0.393327f,0.021594f, +-1.052836f,-0.013618f,0.0f,-1.047163f,-0.421723f,0.0f,-1.024871f,-0.419734f,0.021594f,-1.030298f,-0.013673f,0.021869f, +-1.030298f,-0.013673f,0.021869f,-1.024871f,-0.419734f,0.021594f,-0.982578f,-0.417497f,0.044197f,-0.987517f,-0.013736f,0.044757f, +-1.024871f,0.393327f,0.021594f,-1.030298f,-0.013673f,0.021869f,-0.987517f,-0.013736f,0.044757f,-0.982578f,0.390919f,0.044197f, +-0.982578f,-0.417497f,0.044197f,-0.916591f,-0.416033f,0.064218f,-0.920742f,-0.013776f,0.065028f,-0.987517f,-0.013736f,0.044757f, +-0.987517f,-0.013736f,0.044757f,-0.920742f,-0.013776f,0.065028f,-0.916591f,0.389343f,0.064218f,-0.982578f,0.390919f,0.044197f, +0.396693f,0.917941f,0.064218f,0.616423f,0.905582f,0.061789f,0.619893f,0.968735f,0.042517f,0.398253f,0.983443f,0.044197f, +0.616423f,0.905582f,0.061789f,0.729904f,0.887439f,0.058224f,0.736514f,0.94538f,0.040237f,0.619893f,0.968735f,0.042517f, +0.619893f,0.968735f,0.042517f,0.736514f,0.94538f,0.040237f,0.746069f,0.982563f,0.019733f,0.625198f,1.009264f,0.020771f, +0.400637f,1.025424f,0.021594f,0.398253f,0.983443f,0.044197f,0.619893f,0.968735f,0.042517f,0.625198f,1.009264f,0.020771f, +0.729904f,0.887439f,0.058224f,0.805551f,0.865969f,0.054004f,0.817418f,0.914535f,0.037876f,0.736514f,0.94538f,0.040237f, +0.805551f,0.865969f,0.054004f,0.846982f,0.846382f,0.050154f,0.87333f,0.872793f,0.036675f,0.817418f,0.914535f,0.037876f, +0.817418f,0.914535f,0.037876f,0.87333f,0.872793f,0.036675f,0.896749f,0.896267f,0.018385f,0.833359f,0.945555f,0.018815f, +0.736514f,0.94538f,0.040237f,0.817418f,0.914535f,0.037876f,0.833359f,0.945555f,0.018815f,0.746069f,0.982563f,0.019733f, +0.833359f,0.945555f,0.018815f,0.896749f,0.896267f,0.018385f,0.911522f,0.911075f,0.0f,0.844656f,0.963302f,0.0f, +0.746069f,0.982563f,0.019733f,0.833359f,0.945555f,0.018815f,0.844656f,0.963302f,0.0f,0.753849f,1.002556f,0.0f, +0.625198f,1.009264f,0.020771f,0.746069f,0.982563f,0.019733f,0.753849f,1.002556f,0.0f,0.629917f,1.030658f,0.0f, +0.400637f,1.025424f,0.021594f,0.625198f,1.009264f,0.020771f,0.629917f,1.030658f,0.0f,0.402758f,1.047552f,0.0f, +0.396693f,-0.928623f,0.064218f,0.398253f,-0.990281f,0.044197f,0.619893f,-0.976437f,0.042517f,0.616423f,-0.916988f,0.061789f, +0.619893f,-0.976437f,0.042517f,0.398253f,-0.990281f,0.044197f,0.400637f,-1.0298f,0.021594f,0.625198f,-1.014588f,0.020771f, +0.736514f,-0.954452f,0.040237f,0.619893f,-0.976437f,0.042517f,0.625198f,-1.014588f,0.020771f,0.746069f,-0.989453f,0.019733f, +0.616423f,-0.916988f,0.061789f,0.619893f,-0.976437f,0.042517f,0.736514f,-0.954452f,0.040237f,0.729904f,-0.89991f,0.058224f, +0.400637f,-1.0298f,0.021594f,0.402758f,-1.050629f,0.0f,0.629917f,-1.034726f,0.0f,0.625198f,-1.014588f,0.020771f, +0.625198f,-1.014588f,0.020771f,0.629917f,-1.034726f,0.0f,0.753849f,-1.008273f,0.0f,0.746069f,-0.989453f,0.019733f, +0.736514f,-0.954452f,0.040237f,0.746069f,-0.989453f,0.019733f,0.833359f,-0.954616f,0.018815f,0.817418f,-0.925416f,0.037876f, +0.746069f,-0.989453f,0.019733f,0.753849f,-1.008273f,0.0f,0.844656f,-0.971323f,0.0f,0.833359f,-0.954616f,0.018815f, +0.833359f,-0.954616f,0.018815f,0.844656f,-0.971323f,0.0f,0.911522f,-0.922159f,0.0f,0.896749f,-0.90822f,0.018385f, +0.833359f,-0.954616f,0.018815f,0.896749f,-0.90822f,0.018385f,0.87333f,-0.886124f,0.036675f,0.817418f,-0.925416f,0.037876f, +0.729904f,-0.89991f,0.058224f,0.736514f,-0.954452f,0.040237f,0.817418f,-0.925416f,0.037876f,0.805551f,-0.8797f,0.054004f, +0.805551f,-0.8797f,0.054004f,0.817418f,-0.925416f,0.037876f,0.87333f,-0.886124f,0.036675f,0.846982f,-0.861263f,0.050154f, +0.403842f,-0.422739f,0.09157f,0.401892f,-0.652534f,0.088189f,0.62799f,-0.648441f,0.084918f,0.632327f,-0.420911f,0.088189f, +0.401892f,-0.652534f,0.088189f,0.399509f,-0.775509f,0.082561f,0.622688f,-0.768902f,0.079479f,0.62799f,-0.648441f,0.084918f, +0.62799f,-0.648441f,0.084918f,0.622688f,-0.768902f,0.079479f,0.741819f,-0.760488f,0.074426f,0.750737f,-0.64344f,0.079479f, +0.632327f,-0.420911f,0.088189f,0.62799f,-0.648441f,0.084918f,0.750737f,-0.64344f,0.079479f,0.757739f,-0.418675f,0.082561f, +0.399509f,-0.775509f,0.082561f,0.397559f,-0.8642f,0.074693f,0.618351f,-0.854962f,0.071886f,0.622688f,-0.768902f,0.079479f, +0.397559f,-0.8642f,0.074693f,0.396693f,-0.928623f,0.064218f,0.616423f,-0.916988f,0.061789f,0.618351f,-0.854962f,0.071886f, +0.618351f,-0.854962f,0.071886f,0.616423f,-0.916988f,0.061789f,0.729904f,-0.89991f,0.058224f,0.733736f,-0.842312f,0.067487f, +0.622688f,-0.768902f,0.079479f,0.618351f,-0.854962f,0.071886f,0.733736f,-0.842312f,0.067487f,0.741819f,-0.760488f,0.074426f, +0.741819f,-0.760488f,0.074426f,0.733736f,-0.842312f,0.067487f,0.812784f,-0.828995f,0.061777f,0.826898f,-0.752861f,0.067487f, +0.733736f,-0.842312f,0.067487f,0.729904f,-0.89991f,0.058224f,0.805551f,-0.8797f,0.054004f,0.812784f,-0.828995f,0.061777f, +0.812784f,-0.828995f,0.061777f,0.805551f,-0.8797f,0.054004f,0.846982f,-0.861263f,0.050154f,0.866523f,-0.822169f,0.054004f, +0.826898f,-0.752861f,0.067487f,0.812784f,-0.828995f,0.061777f,0.866523f,-0.822169f,0.054004f,0.887941f,-0.749245f,0.058224f, +0.757739f,-0.418675f,0.082561f,0.750737f,-0.64344f,0.079479f,0.840305f,-0.639347f,0.071886f,0.850096f,-0.416846f,0.074693f, +0.750737f,-0.64344f,0.079479f,0.741819f,-0.760488f,0.074426f,0.826898f,-0.752861f,0.067487f,0.840305f,-0.639347f,0.071886f, +0.840305f,-0.639347f,0.071886f,0.826898f,-0.752861f,0.067487f,0.887941f,-0.749245f,0.058224f,0.906041f,-0.637528f,0.061789f, +0.850096f,-0.416846f,0.074693f,0.840305f,-0.639347f,0.071886f,0.906041f,-0.637528f,0.061789f,0.918372f,-0.416033f,0.064218f, +0.403842f,0.396564f,0.09157f,0.404492f,-0.013589f,0.092698f,0.633773f,-0.01364f,0.08928f,0.632327f,0.394595f,0.088189f, +0.404492f,-0.013589f,0.092698f,0.403842f,-0.422739f,0.09157f,0.632327f,-0.420911f,0.088189f,0.633773f,-0.01364f,0.08928f, +0.633773f,-0.01364f,0.08928f,0.632327f,-0.420911f,0.088189f,0.757739f,-0.418675f,0.082561f,0.760073f,-0.013703f,0.083588f, +0.632327f,0.394595f,0.088189f,0.633773f,-0.01364f,0.08928f,0.760073f,-0.013703f,0.083588f,0.757739f,0.392188f,0.082561f, +0.757739f,-0.418675f,0.082561f,0.850096f,-0.416846f,0.074693f,0.853359f,-0.013754f,0.075629f,0.760073f,-0.013703f,0.083588f, +0.850096f,-0.416846f,0.074693f,0.918372f,-0.416033f,0.064218f,0.922482f,-0.013776f,0.065028f,0.853359f,-0.013754f,0.075629f, +0.853359f,-0.013754f,0.075629f,0.922482f,-0.013776f,0.065028f,0.918372f,0.389343f,0.064218f,0.850096f,0.390218f,0.074693f, +0.760073f,-0.013703f,0.083588f,0.853359f,-0.013754f,0.075629f,0.850096f,0.390218f,0.074693f,0.757739f,0.392188f,0.082561f, +-1.047163f,0.39547f,0.0f,-1.024871f,0.393327f,0.021594f,-1.008591f,0.622221f,0.020771f,-1.030143f,0.626951f,0.0f, +-1.008591f,0.622221f,0.020771f,-1.024871f,0.393327f,0.021594f,-0.982578f,0.390919f,0.044197f,-0.967761f,0.616903f,0.042517f, +-0.981692f,0.744767f,0.019733f,-1.008591f,0.622221f,0.020771f,-0.967761f,0.616903f,0.042517f,-0.944233f,0.735189f,0.040237f, +-1.030143f,0.626951f,0.0f,-1.008591f,0.622221f,0.020771f,-0.981692f,0.744767f,0.019733f,-1.001834f,0.752565f,0.0f, +-0.982578f,0.390919f,0.044197f,-0.916591f,0.389343f,0.064218f,-0.90414f,0.613425f,0.061789f,-0.967761f,0.616903f,0.042517f, +-0.967761f,0.616903f,0.042517f,-0.90414f,0.613425f,0.061789f,-0.885862f,0.728563f,0.058224f,-0.944233f,0.735189f,0.040237f, +-0.981692f,0.744767f,0.019733f,-0.944233f,0.735189f,0.040237f,-0.913159f,0.816749f,0.037876f,-0.944409f,0.832727f,0.018815f, +-0.944233f,0.735189f,0.040237f,-0.885862f,0.728563f,0.058224f,-0.864233f,0.804853f,0.054004f,-0.913159f,0.816749f,0.037876f, +-0.913159f,0.816749f,0.037876f,-0.864233f,0.804853f,0.054004f,-0.844501f,0.846382f,0.050154f,-0.871108f,0.872793f,0.036675f, +-0.913159f,0.816749f,0.037876f,-0.871108f,0.872793f,0.036675f,-0.894756f,0.896267f,0.018385f,-0.944409f,0.832727f,0.018815f, +-1.001834f,0.752565f,0.0f,-0.981692f,0.744767f,0.019733f,-0.944409f,0.832727f,0.018815f,-0.962289f,0.844051f,0.0f, +-0.962289f,0.844051f,0.0f,-0.944409f,0.832727f,0.018815f,-0.894756f,0.896267f,0.018385f,-0.909674f,0.911075f,0.0f, +0.918372f,0.389343f,0.064218f,0.983719f,0.390919f,0.044197f,0.969045f,0.616903f,0.042517f,0.906041f,0.613425f,0.061789f, +0.969045f,0.616903f,0.042517f,0.983719f,0.390919f,0.044197f,1.025601f,0.393327f,0.021594f,1.009478f,0.622221f,0.020771f, +0.945745f,0.735189f,0.040237f,0.969045f,0.616903f,0.042517f,1.009478f,0.622221f,0.020771f,0.982841f,0.744767f,0.019733f, +0.906041f,0.613425f,0.061789f,0.969045f,0.616903f,0.042517f,0.945745f,0.735189f,0.040237f,0.887941f,0.728563f,0.058224f, +1.025601f,0.393327f,0.021594f,1.047675f,0.39547f,0.0f,1.030822f,0.626951f,0.0f,1.009478f,0.622221f,0.020771f, +1.009478f,0.622221f,0.020771f,1.030822f,0.626951f,0.0f,1.002787f,0.752565f,0.0f,0.982841f,0.744767f,0.019733f, +0.945745f,0.735189f,0.040237f,0.982841f,0.744767f,0.019733f,0.94592f,0.832727f,0.018815f,0.914973f,0.816749f,0.037876f, +0.982841f,0.744767f,0.019733f,1.002787f,0.752565f,0.0f,0.963626f,0.844051f,0.0f,0.94592f,0.832727f,0.018815f, +0.94592f,0.832727f,0.018815f,0.963626f,0.844051f,0.0f,0.911522f,0.911075f,0.0f,0.896749f,0.896267f,0.018385f, +0.94592f,0.832727f,0.018815f,0.896749f,0.896267f,0.018385f,0.87333f,0.872793f,0.036675f,0.914973f,0.816749f,0.037876f, +0.887941f,0.728563f,0.058224f,0.945745f,0.735189f,0.040237f,0.914973f,0.816749f,0.037876f,0.866523f,0.804853f,0.054004f, +0.866523f,0.804853f,0.054004f,0.914973f,0.816749f,0.037876f,0.87333f,0.872793f,0.036675f,0.846982f,0.846382f,0.050154f, +0.396693f,0.917941f,0.064218f,0.397559f,0.849503f,0.074693f,0.618351f,0.83969f,0.071886f,0.616423f,0.905582f,0.061789f, +0.397559f,0.849503f,0.074693f,0.399509f,0.756465f,0.082561f,0.622688f,0.749446f,0.079479f,0.618351f,0.83969f,0.071886f, +0.618351f,0.83969f,0.071886f,0.622688f,0.749446f,0.079479f,0.741819f,0.740507f,0.074426f,0.733736f,0.826251f,0.067487f, +0.616423f,0.905582f,0.061789f,0.618351f,0.83969f,0.071886f,0.733736f,0.826251f,0.067487f,0.729904f,0.887439f,0.058224f, +0.399509f,0.756465f,0.082561f,0.401892f,0.629367f,0.088189f,0.62799f,0.625019f,0.084918f,0.622688f,0.749446f,0.079479f, +0.401892f,0.629367f,0.088189f,0.403842f,0.396564f,0.09157f,0.632327f,0.394595f,0.088189f,0.62799f,0.625019f,0.084918f, +0.62799f,0.625019f,0.084918f,0.632327f,0.394595f,0.088189f,0.757739f,0.392188f,0.082561f,0.750737f,0.619705f,0.079479f, +0.622688f,0.749446f,0.079479f,0.62799f,0.625019f,0.084918f,0.750737f,0.619705f,0.079479f,0.741819f,0.740507f,0.074426f, +0.741819f,0.740507f,0.074426f,0.750737f,0.619705f,0.079479f,0.840305f,0.615357f,0.071886f,0.826898f,0.732405f,0.067487f, +0.750737f,0.619705f,0.079479f,0.757739f,0.392188f,0.082561f,0.850096f,0.390218f,0.074693f,0.840305f,0.615357f,0.071886f, +0.840305f,0.615357f,0.071886f,0.850096f,0.390218f,0.074693f,0.918372f,0.389343f,0.064218f,0.906041f,0.613425f,0.061789f, +0.826898f,0.732405f,0.067487f,0.840305f,0.615357f,0.071886f,0.906041f,0.613425f,0.061789f,0.887941f,0.728563f,0.058224f, +0.729904f,0.887439f,0.058224f,0.733736f,0.826251f,0.067487f,0.812784f,0.812104f,0.061777f,0.805551f,0.865969f,0.054004f, +0.733736f,0.826251f,0.067487f,0.741819f,0.740507f,0.074426f,0.826898f,0.732405f,0.067487f,0.812784f,0.812104f,0.061777f, +0.812784f,0.812104f,0.061777f,0.826898f,0.732405f,0.067487f,0.887941f,0.728563f,0.058224f,0.866523f,0.804853f,0.054004f, +0.805551f,0.865969f,0.054004f,0.812784f,0.812104f,0.061777f,0.866523f,0.804853f,0.054004f,0.846982f,0.846382f,0.050154f, +0.399509f,0.756465f,0.082561f,0.397559f,0.849503f,0.074693f,0.002293f,0.852774f,0.075629f,0.002284f,0.758804f,0.083588f, +0.397559f,0.849503f,0.074693f,0.396693f,0.917941f,0.064218f,0.002297f,0.922061f,0.065028f,0.002293f,0.852774f,0.075629f, +0.002293f,0.852774f,0.075629f,0.002297f,0.922061f,0.065028f,-0.392243f,0.917941f,0.064218f,-0.39312f,0.849503f,0.074693f, +0.002284f,0.758804f,0.083588f,0.002293f,0.852774f,0.075629f,-0.39312f,0.849503f,0.074693f,-0.395094f,0.756465f,0.082561f, +0.399509f,0.756465f,0.082561f,0.002284f,0.758804f,0.083588f,0.002274f,0.630816f,0.089279f,0.401892f,0.629367f,0.088189f, +0.002284f,0.758804f,0.083588f,-0.395094f,0.756465f,0.082561f,-0.397505f,0.629367f,0.088189f,0.002274f,0.630816f,0.089279f, +0.002274f,0.630816f,0.089279f,-0.397505f,0.629367f,0.088189f,-0.399478f,0.396564f,0.09157f,0.002265f,0.397221f,0.092698f, +0.401892f,0.629367f,0.088189f,0.002274f,0.630816f,0.089279f,0.002265f,0.397221f,0.092698f,0.403842f,0.396564f,0.09157f, +-0.916591f,0.389343f,0.064218f,-0.847646f,0.390218f,0.074693f,-0.837759f,0.615357f,0.071886f,-0.90414f,0.613425f,0.061789f, +-0.847646f,0.390218f,0.074693f,-0.754564f,0.392188f,0.082561f,-0.747494f,0.619705f,0.079479f,-0.837759f,0.615357f,0.071886f, +-0.837759f,0.615357f,0.071886f,-0.747494f,0.619705f,0.079479f,-0.738488f,0.740507f,0.074426f,-0.824221f,0.732405f,0.067487f, +-0.90414f,0.613425f,0.061789f,-0.837759f,0.615357f,0.071886f,-0.824221f,0.732405f,0.067487f,-0.885862f,0.728563f,0.058224f, +-0.754564f,0.392188f,0.082561f,-0.628465f,0.394595f,0.088189f,-0.624085f,0.625019f,0.084918f,-0.747494f,0.619705f,0.079479f, +-0.628465f,0.394595f,0.088189f,-0.399478f,0.396564f,0.09157f,-0.397505f,0.629367f,0.088189f,-0.624085f,0.625019f,0.084918f, +-0.624085f,0.625019f,0.084918f,-0.397505f,0.629367f,0.088189f,-0.395094f,0.756465f,0.082561f,-0.618732f,0.749446f,0.079479f, +-0.747494f,0.619705f,0.079479f,-0.624085f,0.625019f,0.084918f,-0.618732f,0.749446f,0.079479f,-0.738488f,0.740507f,0.074426f, +-0.738488f,0.740507f,0.074426f,-0.618732f,0.749446f,0.079479f,-0.614352f,0.83969f,0.071886f,-0.730326f,0.826251f,0.067487f, +-0.618732f,0.749446f,0.079479f,-0.395094f,0.756465f,0.082561f,-0.39312f,0.849503f,0.074693f,-0.614352f,0.83969f,0.071886f, +-0.614352f,0.83969f,0.071886f,-0.39312f,0.849503f,0.074693f,-0.392243f,0.917941f,0.064218f,-0.612405f,0.905582f,0.061789f, +-0.730326f,0.826251f,0.067487f,-0.614352f,0.83969f,0.071886f,-0.612405f,0.905582f,0.061789f,-0.726455f,0.887439f,0.058224f, +-0.885862f,0.728563f,0.058224f,-0.824221f,0.732405f,0.067487f,-0.809968f,0.812104f,0.061777f,-0.864233f,0.804853f,0.054004f, +-0.824221f,0.732405f,0.067487f,-0.738488f,0.740507f,0.074426f,-0.730326f,0.826251f,0.067487f,-0.809968f,0.812104f,0.061777f, +-0.809968f,0.812104f,0.061777f,-0.730326f,0.826251f,0.067487f,-0.726455f,0.887439f,0.058224f,-0.802664f,0.865969f,0.054004f, +-0.864233f,0.804853f,0.054004f,-0.809968f,0.812104f,0.061777f,-0.802664f,0.865969f,0.054004f,-0.844501f,0.846382f,0.050154f, +}; + +static const float cfGameIconTexCoords[] = { +0.098918f,0.907702f,0.118783f,0.916444f,0.115314f,0.892403f,0.089549f,0.889167f, +0.118783f,0.916444f,0.154967f,0.926026f,0.153129f,0.898717f,0.115314f,0.892403f, +0.115314f,0.892403f,0.153129f,0.898717f,0.149254f,0.859921f,0.108547f,0.856305f, +0.089549f,0.889167f,0.115314f,0.892403f,0.108547f,0.856305f,0.07928f,0.854591f, +0.154967f,0.926026f,0.209119f,0.934124f,0.208194f,0.904715f,0.153129f,0.898717f, +0.209119f,0.934124f,0.313652f,0.93964f,0.313236f,0.909095f,0.208194f,0.904715f, +0.208194f,0.904715f,0.313236f,0.909095f,0.312299f,0.867044f,0.206115f,0.863911f, +0.153129f,0.898717f,0.208194f,0.904715f,0.206115f,0.863911f,0.149254f,0.859921f, +0.149254f,0.859921f,0.206115f,0.863911f,0.203573f,0.806797f,0.144978f,0.804425f, +0.206115f,0.863911f,0.312299f,0.867044f,0.311154f,0.808737f,0.203573f,0.806797f, +0.203573f,0.806797f,0.311154f,0.808737f,0.310217f,0.699784f,0.201493f,0.698917f, +0.144978f,0.804425f,0.203573f,0.806797f,0.201493f,0.698917f,0.141621f,0.697857f, +0.07928f,0.854591f,0.108547f,0.856305f,0.102119f,0.802484f,0.070602f,0.801622f, +0.108547f,0.856305f,0.149254f,0.859921f,0.144978f,0.804425f,0.102119f,0.802484f, +0.102119f,0.802484f,0.144978f,0.804425f,0.141621f,0.697857f,0.097425f,0.69699f, +0.070602f,0.801622f,0.102119f,0.802484f,0.097425f,0.69699f,0.064689f,0.696604f, +0.310217f,0.699784f,0.311154f,0.808737f,0.500971f,0.809384f,0.500967f,0.700073f, +0.311154f,0.808737f,0.312299f,0.867044f,0.500976f,0.868088f,0.500971f,0.809384f, +0.500971f,0.809384f,0.500976f,0.868088f,0.68958f,0.867044f,0.690711f,0.808737f, +0.500967f,0.700073f,0.500971f,0.809384f,0.690711f,0.808737f,0.691637f,0.699784f, +0.312299f,0.867044f,0.313236f,0.909095f,0.50098f,0.910555f,0.500976f,0.868088f, +0.313236f,0.909095f,0.313652f,0.93964f,0.500982f,0.941479f,0.50098f,0.910555f, +0.50098f,0.910555f,0.500982f,0.941479f,0.688243f,0.93964f,0.688654f,0.909095f, +0.500976f,0.868088f,0.50098f,0.910555f,0.688654f,0.909095f,0.68958f,0.867044f, +0.310217f,0.699784f,0.500967f,0.700073f,0.500965f,0.505784f,0.309905f,0.505792f, +0.500967f,0.700073f,0.691637f,0.699784f,0.691946f,0.505792f,0.500965f,0.505784f, +0.500965f,0.505784f,0.691946f,0.505792f,0.691637f,0.311325f,0.500967f,0.311013f, +0.309905f,0.505792f,0.500965f,0.505784f,0.500967f,0.311013f,0.310217f,0.311325f, +0.141621f,0.3134f,0.097425f,0.314333f,0.09586f,0.50587f,0.140502f,0.505846f, +0.097425f,0.314333f,0.064689f,0.314748f,0.062719f,0.505881f,0.09586f,0.50587f, +0.09586f,0.50587f,0.062719f,0.505881f,0.064689f,0.696604f,0.097425f,0.69699f, +0.140502f,0.505846f,0.09586f,0.50587f,0.097425f,0.69699f,0.141621f,0.697857f, +0.141621f,0.3134f,0.140502f,0.505846f,0.2008f,0.505816f,0.201493f,0.312259f, +0.140502f,0.505846f,0.141621f,0.697857f,0.201493f,0.698917f,0.2008f,0.505816f, +0.2008f,0.505816f,0.201493f,0.698917f,0.310217f,0.699784f,0.309905f,0.505792f, +0.201493f,0.312259f,0.2008f,0.505816f,0.309905f,0.505792f,0.310217f,0.311325f, +0.098918f,0.098051f,0.118783f,0.088764f,0.115314f,0.070013f,0.089549f,0.088764f, +0.118783f,0.088764f,0.154967f,0.078585f,0.153129f,0.056238f,0.115314f,0.070013f, +0.115314f,0.070013f,0.153129f,0.056238f,0.14647f,0.030613f,0.104205f,0.048635f, +0.089549f,0.088764f,0.115314f,0.070013f,0.104205f,0.048635f,0.073229f,0.072587f, +0.154967f,0.078585f,0.209119f,0.069983f,0.208194f,0.045626f,0.153129f,0.056238f, +0.209119f,0.069983f,0.313652f,0.064123f,0.313236f,0.038853f,0.208194f,0.045626f, +0.208194f,0.045626f,0.313236f,0.038853f,0.31157f,0.009921f,0.204497f,0.017695f, +0.153129f,0.056238f,0.208194f,0.045626f,0.204497f,0.017695f,0.14647f,0.030613f, +0.204497f,0.017695f,0.31157f,0.009921f,0.269666f,0.0f,0.202648f,0.01068f, +0.14647f,0.030613f,0.204497f,0.017695f,0.202648f,0.01068f,0.135631f,0.02136f, +0.104205f,0.048635f,0.14647f,0.030613f,0.135631f,0.02136f,0.100033f,0.042615f, +0.073229f,0.072587f,0.104205f,0.048635f,0.100033f,0.042615f,0.064435f,0.06387f, +0.269666f,0.0f,0.31157f,0.009921f,0.500973f,0.007329f,0.500969f,0.0f, +0.500973f,0.007329f,0.31157f,0.009921f,0.313236f,0.038853f,0.50098f,0.036595f, +0.6903f,0.009921f,0.500973f,0.007329f,0.50098f,0.036595f,0.688654f,0.038853f, +0.500969f,0.0f,0.500973f,0.007329f,0.6903f,0.009921f,0.732272f,0.0f, +0.313236f,0.038853f,0.313652f,0.064123f,0.500982f,0.062169f,0.50098f,0.036595f, +0.50098f,0.036595f,0.500982f,0.062169f,0.688243f,0.064123f,0.688654f,0.038853f, +0.688243f,0.93964f,0.500982f,0.941479f,0.50098f,0.965553f,0.688654f,0.963427f, +0.500982f,0.941479f,0.313652f,0.93964f,0.313236f,0.963427f,0.50098f,0.965553f, +0.50098f,0.965553f,0.313236f,0.963427f,0.31157f,0.990661f,0.500973f,0.993101f, +0.688654f,0.963427f,0.50098f,0.965553f,0.500973f,0.993101f,0.6903f,0.990661f, +0.31157f,0.990661f,0.269666f,1.0f,0.500969f,1.0f,0.500973f,0.993101f, +0.500973f,0.993101f,0.500969f,1.0f,0.732272f,1.0f,0.6903f,0.990661f, +0.064435f,0.939877f,0.100033f,0.959885f,0.104205f,0.954218f,0.073229f,0.931672f, +0.100033f,0.959885f,0.135631f,0.979893f,0.14647f,0.971183f,0.104205f,0.954218f, +0.104205f,0.954218f,0.14647f,0.971183f,0.153129f,0.947062f,0.115314f,0.934095f, +0.073229f,0.931672f,0.104205f,0.954218f,0.115314f,0.934095f,0.089549f,0.916444f, +0.135631f,0.979893f,0.202648f,0.989946f,0.204497f,0.983343f,0.14647f,0.971183f, +0.202648f,0.989946f,0.269666f,1.0f,0.31157f,0.990661f,0.204497f,0.983343f, +0.204497f,0.983343f,0.31157f,0.990661f,0.313236f,0.963427f,0.208194f,0.957052f, +0.14647f,0.971183f,0.204497f,0.983343f,0.208194f,0.957052f,0.153129f,0.947062f, +0.208194f,0.957052f,0.313236f,0.963427f,0.313652f,0.93964f,0.209119f,0.934124f, +0.153129f,0.947062f,0.208194f,0.957052f,0.209119f,0.934124f,0.154967f,0.926026f, +0.115314f,0.934095f,0.153129f,0.947062f,0.154967f,0.926026f,0.118783f,0.916444f, +0.089549f,0.916444f,0.115314f,0.934095f,0.118783f,0.916444f,0.098918f,0.907702f, +0.902043f,0.907702f,0.91132f,0.916444f,0.930054f,0.892403f,0.91132f,0.889167f, +0.930054f,0.892403f,0.91132f,0.916444f,0.927482f,0.931672f,0.951411f,0.902768f, +0.943816f,0.856305f,0.930054f,0.892403f,0.951411f,0.902768f,0.969416f,0.862518f, +0.91132f,0.889167f,0.930054f,0.892403f,0.943816f,0.856305f,0.92149f,0.854591f, +0.927482f,0.931672f,0.93619f,0.939877f,0.957425f,0.906662f,0.951411f,0.902768f, +0.951411f,0.902768f,0.957425f,0.906662f,0.97866f,0.873446f,0.969416f,0.862518f, +0.943816f,0.856305f,0.969416f,0.862518f,0.982322f,0.805934f,0.954418f,0.802484f, +0.969416f,0.862518f,0.97866f,0.873446f,0.98933f,0.807659f,0.982322f,0.805934f, +0.982322f,0.805934f,0.98933f,0.807659f,1.0f,0.741872f,0.990089f,0.698531f, +0.982322f,0.805934f,0.990089f,0.698531f,0.961185f,0.69699f,0.954418f,0.802484f, +0.92149f,0.854591f,0.943816f,0.856305f,0.954418f,0.802484f,0.930084f,0.801622f, +0.930084f,0.801622f,0.954418f,0.802484f,0.961185f,0.69699f,0.935938f,0.696604f, +0.935938f,0.696604f,0.961185f,0.69699f,0.96344f,0.50587f,0.93789f,0.505881f, +0.96344f,0.50587f,0.961185f,0.69699f,0.990089f,0.698531f,0.992677f,0.505827f, +0.961185f,0.314333f,0.96344f,0.50587f,0.992677f,0.505827f,0.990089f,0.312674f, +0.93789f,0.505881f,0.96344f,0.50587f,0.961185f,0.314333f,0.935938f,0.314748f, +0.990089f,0.698531f,1.0f,0.741872f,1.0f,0.505805f,0.992677f,0.505827f, +0.992677f,0.505827f,1.0f,0.505805f,1.0f,0.269739f,0.990089f,0.312674f, +0.064435f,0.939877f,0.073229f,0.931672f,0.049066f,0.902768f,0.042992f,0.906662f, +0.049066f,0.902768f,0.073229f,0.931672f,0.089549f,0.916444f,0.070633f,0.892403f, +0.030884f,0.862518f,0.049066f,0.902768f,0.070633f,0.892403f,0.056735f,0.856305f, +0.042992f,0.906662f,0.049066f,0.902768f,0.030884f,0.862518f,0.021549f,0.873446f, +0.089549f,0.916444f,0.098918f,0.907702f,0.089549f,0.889167f,0.070633f,0.892403f, +0.070633f,0.892403f,0.089549f,0.889167f,0.07928f,0.854591f,0.056735f,0.856305f, +0.030884f,0.862518f,0.056735f,0.856305f,0.046029f,0.802484f,0.017852f,0.805934f, +0.056735f,0.856305f,0.07928f,0.854591f,0.070602f,0.801622f,0.046029f,0.802484f, +0.046029f,0.802484f,0.070602f,0.801622f,0.064689f,0.696604f,0.039196f,0.69699f, +0.046029f,0.802484f,0.039196f,0.69699f,0.010008f,0.698531f,0.017852f,0.805934f, +0.021549f,0.873446f,0.030884f,0.862518f,0.017852f,0.805934f,0.010774f,0.807659f, +0.010774f,0.807659f,0.017852f,0.805934f,0.010008f,0.698531f,0.0f,0.741872f, +0.0f,0.269739f,0.0f,0.505805f,0.007394f,0.505827f,0.010008f,0.312673f, +0.0f,0.505805f,0.0f,0.741872f,0.010008f,0.698531f,0.007394f,0.505827f, +0.007394f,0.505827f,0.010008f,0.698531f,0.039196f,0.69699f,0.036918f,0.50587f, +0.010008f,0.312673f,0.007394f,0.505827f,0.036918f,0.50587f,0.039196f,0.314333f, +0.039196f,0.69699f,0.064689f,0.696604f,0.062719f,0.505881f,0.036918f,0.50587f, +0.036918f,0.50587f,0.062719f,0.505881f,0.064689f,0.314748f,0.039196f,0.314333f, +0.688243f,0.064123f,0.792572f,0.069983f,0.793487f,0.045626f,0.688654f,0.038853f, +0.792572f,0.069983f,0.846453f,0.078585f,0.848273f,0.056238f,0.793487f,0.045626f, +0.793487f,0.045626f,0.848273f,0.056238f,0.854867f,0.030613f,0.797148f,0.017695f, +0.6903f,0.009921f,0.688654f,0.038853f,0.793487f,0.045626f,0.797148f,0.017695f, +0.846453f,0.078585f,0.882371f,0.088764f,0.885805f,0.070013f,0.848273f,0.056238f, +0.882371f,0.088764f,0.902043f,0.098051f,0.91132f,0.088764f,0.885805f,0.070013f, +0.885805f,0.070013f,0.91132f,0.088764f,0.927482f,0.072587f,0.896806f,0.048635f, +0.848273f,0.056238f,0.885805f,0.070013f,0.896806f,0.048635f,0.854867f,0.030613f, +0.896806f,0.048635f,0.927482f,0.072587f,0.93619f,0.06387f,0.900938f,0.042615f, +0.854867f,0.030613f,0.896806f,0.048635f,0.900938f,0.042615f,0.865686f,0.02136f, +0.797148f,0.017695f,0.854867f,0.030613f,0.865686f,0.02136f,0.798979f,0.01068f, +0.6903f,0.009921f,0.797148f,0.017695f,0.798979f,0.01068f,0.732272f,0.0f, +0.688243f,0.93964f,0.688654f,0.963427f,0.793487f,0.957052f,0.792572f,0.934124f, +0.793487f,0.957052f,0.688654f,0.963427f,0.6903f,0.990661f,0.797148f,0.983343f, +0.848273f,0.947062f,0.793487f,0.957052f,0.797148f,0.983343f,0.854867f,0.971183f, +0.792572f,0.934124f,0.793487f,0.957052f,0.848273f,0.947062f,0.846453f,0.926026f, +0.6903f,0.990661f,0.732272f,1.0f,0.798979f,0.989946f,0.797148f,0.983343f, +0.797148f,0.983343f,0.798979f,0.989946f,0.865686f,0.979893f,0.854867f,0.971183f, +0.848273f,0.947062f,0.854867f,0.971183f,0.896806f,0.954218f,0.885805f,0.934095f, +0.854867f,0.971183f,0.865686f,0.979893f,0.900938f,0.959885f,0.896806f,0.954218f, +0.896806f,0.954218f,0.900938f,0.959885f,0.93619f,0.939877f,0.927482f,0.931672f, +0.896806f,0.954218f,0.927482f,0.931672f,0.91132f,0.916444f,0.885805f,0.934095f, +0.846453f,0.926026f,0.848273f,0.947062f,0.885805f,0.934095f,0.882371f,0.916444f, +0.882371f,0.916444f,0.885805f,0.934095f,0.91132f,0.916444f,0.902043f,0.907702f, +0.691637f,0.699784f,0.690711f,0.808737f,0.798063f,0.806796f,0.800123f,0.698917f, +0.690711f,0.808737f,0.68958f,0.867044f,0.795546f,0.863911f,0.798063f,0.806796f, +0.798063f,0.806796f,0.795546f,0.863911f,0.85211f,0.859921f,0.856345f,0.804425f, +0.800123f,0.698917f,0.798063f,0.806796f,0.856345f,0.804425f,0.859669f,0.697857f, +0.68958f,0.867044f,0.688654f,0.909095f,0.793487f,0.904715f,0.795546f,0.863911f, +0.688654f,0.909095f,0.688243f,0.93964f,0.792572f,0.934124f,0.793487f,0.904715f, +0.793487f,0.904715f,0.792572f,0.934124f,0.846453f,0.926026f,0.848273f,0.898717f, +0.795546f,0.863911f,0.793487f,0.904715f,0.848273f,0.898717f,0.85211f,0.859921f, +0.85211f,0.859921f,0.848273f,0.898717f,0.885805f,0.892403f,0.892507f,0.856305f, +0.848273f,0.898717f,0.846453f,0.926026f,0.882371f,0.916444f,0.885805f,0.892403f, +0.885805f,0.892403f,0.882371f,0.916444f,0.902043f,0.907702f,0.91132f,0.889167f, +0.892507f,0.856305f,0.885805f,0.892403f,0.91132f,0.889167f,0.92149f,0.854591f, +0.859669f,0.697857f,0.856345f,0.804425f,0.898872f,0.802484f,0.903521f,0.69699f, +0.856345f,0.804425f,0.85211f,0.859921f,0.892507f,0.856305f,0.898872f,0.802484f, +0.898872f,0.802484f,0.892507f,0.856305f,0.92149f,0.854591f,0.930084f,0.801622f, +0.903521f,0.69699f,0.898872f,0.802484f,0.930084f,0.801622f,0.935938f,0.696604f, +0.691637f,0.311325f,0.691946f,0.505792f,0.800809f,0.505816f,0.800123f,0.312259f, +0.691946f,0.505792f,0.691637f,0.699784f,0.800123f,0.698917f,0.800809f,0.505816f, +0.800809f,0.505816f,0.800123f,0.698917f,0.859669f,0.697857f,0.860777f,0.505846f, +0.800123f,0.312259f,0.800809f,0.505816f,0.860777f,0.505846f,0.859669f,0.3134f, +0.859669f,0.697857f,0.903521f,0.69699f,0.90507f,0.50587f,0.860777f,0.505846f, +0.903521f,0.69699f,0.935938f,0.696604f,0.93789f,0.505881f,0.90507f,0.50587f, +0.90507f,0.50587f,0.93789f,0.505881f,0.935938f,0.314748f,0.903521f,0.314333f, +0.860777f,0.505846f,0.90507f,0.50587f,0.903521f,0.314333f,0.859669f,0.3134f, +0.0f,0.269739f,0.010008f,0.312673f,0.017852f,0.203923f,0.010774f,0.202091f, +0.017852f,0.203923f,0.010008f,0.312673f,0.039196f,0.314333f,0.046029f,0.207588f, +0.030884f,0.14549f,0.017852f,0.203923f,0.046029f,0.207588f,0.056735f,0.152091f, +0.010774f,0.202091f,0.017852f,0.203923f,0.030884f,0.14549f,0.021549f,0.134442f, +0.039196f,0.314333f,0.064689f,0.314748f,0.070602f,0.208504f,0.046029f,0.207588f, +0.046029f,0.207588f,0.070602f,0.208504f,0.07928f,0.153913f,0.056735f,0.152091f, +0.030884f,0.14549f,0.056735f,0.152091f,0.070632f,0.114303f,0.049066f,0.103292f, +0.056735f,0.152091f,0.07928f,0.153913f,0.089549f,0.117742f,0.070632f,0.114303f, +0.070632f,0.114303f,0.089549f,0.117742f,0.098918f,0.098051f,0.089549f,0.088764f, +0.070632f,0.114303f,0.089549f,0.088764f,0.073229f,0.072587f,0.049066f,0.103292f, +0.021549f,0.134442f,0.030884f,0.14549f,0.049066f,0.103292f,0.042992f,0.099156f, +0.042992f,0.099156f,0.049066f,0.103292f,0.073229f,0.072587f,0.064435f,0.06387f, +0.935938f,0.314748f,0.961185f,0.314333f,0.954418f,0.207588f,0.930084f,0.208504f, +0.954418f,0.207588f,0.961185f,0.314333f,0.990089f,0.312674f,0.982322f,0.203923f, +0.943816f,0.152092f,0.954418f,0.207588f,0.982322f,0.203923f,0.969416f,0.145491f, +0.930084f,0.208504f,0.954418f,0.207588f,0.943816f,0.152092f,0.92149f,0.153913f, +0.990089f,0.312674f,1.0f,0.269739f,0.98933f,0.202091f,0.982322f,0.203923f, +0.982322f,0.203923f,0.98933f,0.202091f,0.97866f,0.134442f,0.969416f,0.145491f, +0.943816f,0.152092f,0.969416f,0.145491f,0.951411f,0.103292f,0.930054f,0.114304f, +0.969416f,0.145491f,0.97866f,0.134442f,0.957425f,0.099156f,0.951411f,0.103292f, +0.951411f,0.103292f,0.957425f,0.099156f,0.93619f,0.06387f,0.927482f,0.072587f, +0.951411f,0.103292f,0.927482f,0.072587f,0.91132f,0.088764f,0.930054f,0.114304f, +0.92149f,0.153913f,0.943816f,0.152092f,0.930054f,0.114304f,0.91132f,0.117742f, +0.91132f,0.117742f,0.930054f,0.114304f,0.91132f,0.088764f,0.902043f,0.098051f, +0.688243f,0.064123f,0.688654f,0.096571f,0.793487f,0.101224f,0.792572f,0.069983f, +0.688654f,0.096571f,0.68958f,0.140684f,0.795546f,0.144012f,0.793487f,0.101224f, +0.793487f,0.101224f,0.795546f,0.144012f,0.85211f,0.14825f,0.848273f,0.107596f, +0.792572f,0.069983f,0.793487f,0.101224f,0.848273f,0.107596f,0.846453f,0.078585f, +0.68958f,0.140684f,0.690711f,0.200945f,0.798063f,0.203007f,0.795546f,0.144012f, +0.690711f,0.200945f,0.691637f,0.311325f,0.800123f,0.312259f,0.798063f,0.203007f, +0.798063f,0.203007f,0.800123f,0.312259f,0.859669f,0.3134f,0.856345f,0.205526f, +0.795546f,0.144012f,0.798063f,0.203007f,0.856345f,0.205526f,0.85211f,0.14825f, +0.85211f,0.14825f,0.856345f,0.205526f,0.898872f,0.207588f,0.892507f,0.152092f, +0.856345f,0.205526f,0.859669f,0.3134f,0.903521f,0.314333f,0.898872f,0.207588f, +0.898872f,0.207588f,0.903521f,0.314333f,0.935938f,0.314748f,0.930084f,0.208504f, +0.892507f,0.152092f,0.898872f,0.207588f,0.930084f,0.208504f,0.92149f,0.153913f, +0.846453f,0.078585f,0.848273f,0.107596f,0.885805f,0.114304f,0.882371f,0.088764f, +0.848273f,0.107596f,0.85211f,0.14825f,0.892507f,0.152092f,0.885805f,0.114304f, +0.885805f,0.114304f,0.892507f,0.152092f,0.92149f,0.153913f,0.91132f,0.117742f, +0.882371f,0.088764f,0.885805f,0.114304f,0.91132f,0.117742f,0.902043f,0.098051f, +0.68958f,0.140684f,0.688654f,0.096571f,0.50098f,0.095021f,0.500976f,0.139575f, +0.688654f,0.096571f,0.688243f,0.064123f,0.500982f,0.062169f,0.50098f,0.095021f, +0.50098f,0.095021f,0.500982f,0.062169f,0.313652f,0.064123f,0.313236f,0.096571f, +0.500976f,0.139575f,0.50098f,0.095021f,0.313236f,0.096571f,0.312299f,0.140684f, +0.68958f,0.140684f,0.500976f,0.139575f,0.500971f,0.200258f,0.690711f,0.200945f, +0.500976f,0.139575f,0.312299f,0.140684f,0.311154f,0.200945f,0.500971f,0.200258f, +0.500971f,0.200258f,0.311154f,0.200945f,0.310217f,0.311325f,0.500967f,0.311013f, +0.690711f,0.200945f,0.500971f,0.200258f,0.500967f,0.311013f,0.691637f,0.311325f, +0.064689f,0.314748f,0.097425f,0.314333f,0.102119f,0.207588f,0.070602f,0.208504f, +0.097425f,0.314333f,0.141621f,0.3134f,0.144978f,0.205526f,0.102119f,0.207588f, +0.102119f,0.207588f,0.144978f,0.205526f,0.149254f,0.14825f,0.108547f,0.152092f, +0.070602f,0.208504f,0.102119f,0.207588f,0.108547f,0.152092f,0.07928f,0.153913f, +0.141621f,0.3134f,0.201493f,0.312259f,0.203573f,0.203007f,0.144978f,0.205526f, +0.201493f,0.312259f,0.310217f,0.311325f,0.311154f,0.200945f,0.203573f,0.203007f, +0.203573f,0.203007f,0.311154f,0.200945f,0.312299f,0.140684f,0.206115f,0.144012f, +0.144978f,0.205526f,0.203573f,0.203007f,0.206115f,0.144012f,0.149254f,0.14825f, +0.149254f,0.14825f,0.206115f,0.144012f,0.208194f,0.101224f,0.153129f,0.107596f, +0.206115f,0.144012f,0.312299f,0.140684f,0.313236f,0.096571f,0.208194f,0.101224f, +0.208194f,0.101224f,0.313236f,0.096571f,0.313652f,0.064123f,0.209119f,0.069983f, +0.153129f,0.107596f,0.208194f,0.101224f,0.209119f,0.069983f,0.154967f,0.078585f, +0.07928f,0.153913f,0.108547f,0.152092f,0.115314f,0.114304f,0.089549f,0.117742f, +0.108547f,0.152092f,0.149254f,0.14825f,0.153129f,0.107596f,0.115314f,0.114304f, +0.115314f,0.114304f,0.153129f,0.107596f,0.154967f,0.078585f,0.118783f,0.088764f, +0.089549f,0.117742f,0.115314f,0.114304f,0.118783f,0.088764f,0.098918f,0.098051f, +}; + +static const float cfGameIconNormals[] = { +-0.210457f,-0.226211f,0.951071f,-0.137777f,-0.231234f,0.963093f,-0.113627f,-0.120055f,0.986243f,-0.216181f,-0.146015f,0.965373f, +-0.137777f,-0.231234f,0.963093f,-0.083714f,-0.234126f,0.968595f,-0.06603f,-0.119508f,0.990635f,-0.113627f,-0.120055f,0.986243f, +-0.113627f,-0.120055f,0.986243f,-0.06603f,-0.119508f,0.990635f,-0.062379f,-0.064577f,0.995961f,-0.113032f,-0.068284f,0.991242f, +-0.216181f,-0.146015f,0.965373f,-0.113627f,-0.120055f,0.986243f,-0.113032f,-0.068284f,0.991242f,-0.219508f,-0.086774f,0.971744f, +-0.083714f,-0.234126f,0.968595f,-0.036722f,-0.235389f,0.971207f,-0.028482f,-0.119193f,0.992463f,-0.06603f,-0.119508f,0.990635f, +-0.036722f,-0.235389f,0.971207f,-0.010823f,-0.235649f,0.971778f,-0.008321f,-0.119124f,0.992845f,-0.028482f,-0.119193f,0.992463f, +-0.028482f,-0.119193f,0.992463f,-0.008321f,-0.119124f,0.992845f,-0.007465f,-0.063717f,0.99794f,-0.026099f,-0.06375f,0.997625f, +-0.06603f,-0.119508f,0.990635f,-0.028482f,-0.119193f,0.992463f,-0.026099f,-0.06375f,0.997625f,-0.062379f,-0.064577f,0.995961f, +-0.062379f,-0.064577f,0.995961f,-0.026099f,-0.06375f,0.997625f,-0.025391f,-0.025563f,0.999351f,-0.061589f,-0.026301f,0.997755f, +-0.026099f,-0.06375f,0.997625f,-0.007465f,-0.063717f,0.99794f,-0.007172f,-0.02556f,0.999648f,-0.025391f,-0.025563f,0.999351f, +-0.025391f,-0.025563f,0.999351f,-0.007172f,-0.02556f,0.999648f,-0.007161f,-0.00707f,0.999949f,-0.025395f,-0.007088f,0.999652f, +-0.061589f,-0.026301f,0.997755f,-0.025391f,-0.025563f,0.999351f,-0.025395f,-0.007088f,0.999652f,-0.061548f,-0.00739f,0.998077f, +-0.219508f,-0.086774f,0.971744f,-0.113032f,-0.068284f,0.991242f,-0.112752f,-0.028685f,0.993209f,-0.22077f,-0.037047f,0.974622f, +-0.113032f,-0.068284f,0.991242f,-0.062379f,-0.064577f,0.995961f,-0.061589f,-0.026301f,0.997755f,-0.112752f,-0.028685f,0.993209f, +-0.112752f,-0.028685f,0.993209f,-0.061589f,-0.026301f,0.997755f,-0.061548f,-0.00739f,0.998077f,-0.112673f,-0.008234f,0.993598f, +-0.22077f,-0.037047f,0.974622f,-0.112752f,-0.028685f,0.993209f,-0.112673f,-0.008234f,0.993598f,-0.221f,-0.010721f,0.975215f, +-0.007161f,-0.00707f,0.999949f,-0.007172f,-0.02556f,0.999648f,0.0f,-0.025624f,0.999672f,0.0f,-0.007089f,0.999975f, +-0.007172f,-0.02556f,0.999648f,-0.007465f,-0.063717f,0.99794f,0.0f,-0.06378f,0.997964f,0.0f,-0.025624f,0.999672f, +0.0f,-0.025624f,0.999672f,0.0f,-0.06378f,0.997964f,0.007472f,-0.063716f,0.99794f,0.007179f,-0.025559f,0.999648f, +0.0f,-0.007089f,0.999975f,0.0f,-0.025624f,0.999672f,0.007179f,-0.025559f,0.999648f,0.007169f,-0.00707f,0.999949f, +-0.007465f,-0.063717f,0.99794f,-0.008321f,-0.119124f,0.992845f,0.0f,-0.119133f,0.992878f,0.0f,-0.06378f,0.997964f, +-0.008321f,-0.119124f,0.992845f,-0.010823f,-0.235649f,0.971778f,0.0f,-0.235564f,0.971859f,0.0f,-0.119133f,0.992878f, +0.0f,-0.119133f,0.992878f,0.0f,-0.235564f,0.971859f,0.010835f,-0.23565f,0.971778f,0.008329f,-0.119124f,0.992845f, +0.0f,-0.06378f,0.997964f,0.0f,-0.119133f,0.992878f,0.008329f,-0.119124f,0.992845f,0.007472f,-0.063716f,0.99794f, +-0.007161f,-0.00707f,0.999949f,0.0f,-0.007089f,0.999975f,0.0f,0.0f,1.0f,-0.007181f,0.0f,0.999974f, +0.0f,-0.007089f,0.999975f,0.007169f,-0.00707f,0.999949f,0.007189f,0.0f,0.999974f,0.0f,0.0f,1.0f, +0.0f,0.0f,1.0f,0.007189f,0.0f,0.999974f,0.00717f,0.007027f,0.99995f,0.0f,0.007045f,0.999975f, +-0.007181f,0.0f,0.999974f,0.0f,0.0f,1.0f,0.0f,0.007045f,0.999975f,-0.007163f,0.007027f,0.99995f, +-0.061553f,0.007347f,0.998077f,-0.112675f,0.008187f,0.993598f,-0.112665f,0.0f,0.993633f,-0.061598f,0.0f,0.998101f, +-0.112675f,0.008187f,0.993598f,-0.220997f,0.010655f,0.975216f,-0.220914f,-1.0E-6f,0.975293f,-0.112665f,0.0f,0.993633f, +-0.112665f,0.0f,0.993633f,-0.220914f,-1.0E-6f,0.975293f,-0.221f,-0.010721f,0.975215f,-0.112673f,-0.008234f,0.993598f, +-0.061598f,0.0f,0.998101f,-0.112665f,0.0f,0.993633f,-0.112673f,-0.008234f,0.993598f,-0.061548f,-0.00739f,0.998077f, +-0.061553f,0.007347f,0.998077f,-0.061598f,0.0f,0.998101f,-0.025456f,0.0f,0.999676f,-0.025398f,0.007046f,0.999653f, +-0.061598f,0.0f,0.998101f,-0.061548f,-0.00739f,0.998077f,-0.025395f,-0.007088f,0.999652f,-0.025456f,0.0f,0.999676f, +-0.025456f,0.0f,0.999676f,-0.025395f,-0.007088f,0.999652f,-0.007161f,-0.00707f,0.999949f,-0.007181f,0.0f,0.999974f, +-0.025398f,0.007046f,0.999653f,-0.025456f,0.0f,0.999676f,-0.007181f,0.0f,0.999974f,-0.007163f,0.007027f,0.99995f, +-0.211482f,0.213152f,0.953856f,-0.138447f,0.218126f,0.966051f,-0.198978f,0.347214f,0.916433f,-0.296456f,0.298724f,0.907126f, +-0.138447f,0.218126f,0.966051f,-0.084089f,0.221062f,0.971628f,-0.117212f,0.361162f,0.925107f,-0.198978f,0.347214f,0.916433f, +-0.198978f,0.347214f,0.916433f,-0.117212f,0.361162f,0.925107f,-0.168084f,0.541107f,0.823985f,-0.282777f,0.494303f,0.822011f, +-0.296456f,0.298724f,0.907126f,-0.198978f,0.347214f,0.916433f,-0.282777f,0.494303f,0.822011f,-0.402197f,0.405178f,0.821017f, +-0.084089f,0.221062f,0.971628f,-0.036885f,0.222305f,0.974279f,-0.050723f,0.367918f,0.928474f,-0.117212f,0.361162f,0.925107f, +-0.036885f,0.222305f,0.974279f,-0.010867f,0.22256f,0.974858f,-0.014805f,0.369601f,0.929073f,-0.050723f,0.367918f,0.928474f, +-0.050723f,0.367918f,0.928474f,-0.014805f,0.369601f,0.929073f,-0.020782f,0.568602f,0.822351f,-0.072149f,0.563165f,0.823189f, +-0.117212f,0.361162f,0.925107f,-0.050723f,0.367918f,0.928474f,-0.072149f,0.563165f,0.823189f,-0.168084f,0.541107f,0.823985f, +-0.072149f,0.563165f,0.823189f,-0.020782f,0.568602f,0.822351f,-0.025372f,0.696348f,0.717256f,-0.088478f,0.684053f,0.724047f, +-0.168084f,0.541107f,0.823985f,-0.072149f,0.563165f,0.823189f,-0.088478f,0.684053f,0.724047f,-0.20294f,0.64707f,0.734926f, +-0.282777f,0.494303f,0.822011f,-0.168084f,0.541107f,0.823985f,-0.20294f,0.64707f,0.734926f,-0.333245f,0.577074f,0.745609f, +-0.402197f,0.405178f,0.821017f,-0.282777f,0.494303f,0.822011f,-0.333245f,0.577074f,0.745609f,-0.466013f,0.469045f,0.75022f, +-0.025372f,0.696348f,0.717256f,-0.020782f,0.568602f,0.822351f,0.0f,0.568694f,0.822549f,-2.0E-6f,0.698486f,0.715623f, +0.0f,0.568694f,0.822549f,-0.020782f,0.568602f,0.822351f,-0.014805f,0.369601f,0.929073f,0.0f,0.369504f,0.929229f, +0.020804f,0.568602f,0.82235f,0.0f,0.568694f,0.822549f,0.0f,0.369504f,0.929229f,0.01482f,0.369601f,0.929072f, +-2.0E-6f,0.698486f,0.715623f,0.0f,0.568694f,0.822549f,0.020804f,0.568602f,0.82235f,0.025388f,0.696365f,0.717239f, +-0.014805f,0.369601f,0.929073f,-0.010867f,0.22256f,0.974858f,0.0f,0.222477f,0.974938f,0.0f,0.369504f,0.929229f, +0.0f,0.369504f,0.929229f,0.0f,0.222477f,0.974938f,0.010878f,0.222561f,0.974858f,0.01482f,0.369601f,0.929072f, +0.010835f,-0.23565f,0.971778f,0.0f,-0.235564f,0.971859f,0.0f,-0.389089f,0.9212f,0.014687f,-0.38921f,0.921032f, +0.0f,-0.235564f,0.971859f,-0.010823f,-0.235649f,0.971778f,-0.014671f,-0.38921f,0.921032f,0.0f,-0.389089f,0.9212f, +0.0f,-0.389089f,0.9212f,-0.014671f,-0.38921f,0.921032f,-0.020367f,-0.591835f,0.805802f,0.0f,-0.591896f,0.806014f, +0.014687f,-0.38921f,0.921032f,0.0f,-0.389089f,0.9212f,0.0f,-0.591896f,0.806014f,0.020387f,-0.591837f,0.8058f, +-0.020367f,-0.591835f,0.805802f,-0.024675f,-0.717705f,0.69591f,-2.0E-6f,-0.719788f,0.694194f,0.0f,-0.591896f,0.806014f, +0.0f,-0.591896f,0.806014f,-2.0E-6f,-0.719788f,0.694194f,0.02469f,-0.717725f,0.695889f,0.020387f,-0.591837f,0.8058f, +-0.46128f,-0.48965f,0.739908f,-0.32814f,-0.599132f,0.730319f,-0.27855f,-0.517113f,0.809323f,-0.397988f,-0.425903f,0.812534f, +-0.32814f,-0.599132f,0.730319f,-0.198659f,-0.669215f,0.716021f,-0.165045f,-0.564346f,0.808872f,-0.27855f,-0.517113f,0.809323f, +-0.27855f,-0.517113f,0.809323f,-0.165045f,-0.564346f,0.808872f,-0.116165f,-0.380579f,0.917423f,-0.197289f,-0.366449f,0.909281f, +-0.397988f,-0.425903f,0.812534f,-0.27855f,-0.517113f,0.809323f,-0.197289f,-0.366449f,0.909281f,-0.294472f,-0.315809f,0.901971f, +-0.198659f,-0.669215f,0.716021f,-0.086339f,-0.705672f,0.703258f,-0.070739f,-0.586438f,0.806899f,-0.165045f,-0.564346f,0.808872f, +-0.086339f,-0.705672f,0.703258f,-0.024675f,-0.717705f,0.69591f,-0.020367f,-0.591835f,0.805802f,-0.070739f,-0.586438f,0.806899f, +-0.070739f,-0.586438f,0.806899f,-0.020367f,-0.591835f,0.805802f,-0.014671f,-0.38921f,0.921032f,-0.050259f,-0.387507f,0.920496f, +-0.165045f,-0.564346f,0.808872f,-0.070739f,-0.586438f,0.806899f,-0.050259f,-0.387507f,0.920496f,-0.116165f,-0.380579f,0.917423f, +-0.050259f,-0.387507f,0.920496f,-0.014671f,-0.38921f,0.921032f,-0.010823f,-0.235649f,0.971778f,-0.036722f,-0.235389f,0.971207f, +-0.116165f,-0.380579f,0.917423f,-0.050259f,-0.387507f,0.920496f,-0.036722f,-0.235389f,0.971207f,-0.083714f,-0.234126f,0.968595f, +-0.197289f,-0.366449f,0.909281f,-0.116165f,-0.380579f,0.917423f,-0.083714f,-0.234126f,0.968595f,-0.137777f,-0.231234f,0.963093f, +-0.294472f,-0.315809f,0.901971f,-0.197289f,-0.366449f,0.909281f,-0.137777f,-0.231234f,0.963093f,-0.210457f,-0.226211f,0.951071f, +0.212501f,-0.226048f,0.950655f,0.297154f,-0.315494f,0.901201f,0.347306f,-0.209845f,0.913971f,0.218237f,-0.145906f,0.964927f, +0.347306f,-0.209845f,0.913971f,0.297154f,-0.315494f,0.901201f,0.401261f,-0.425239f,0.811271f,0.493682f,-0.297695f,0.817102f, +0.362206f,-0.121013f,0.924209f,0.347306f,-0.209845f,0.913971f,0.493682f,-0.297695f,0.817102f,0.542487f,-0.173678f,0.821915f, +0.218237f,-0.145906f,0.964927f,0.347306f,-0.209845f,0.913971f,0.362206f,-0.121013f,0.924209f,0.221558f,-0.086713f,0.971284f, +0.401261f,-0.425239f,0.811271f,0.464547f,-0.488911f,0.738351f,0.57643f,-0.348399f,0.739153f,0.493682f,-0.297695f,0.817102f, +0.493682f,-0.297695f,0.817102f,0.57643f,-0.348399f,0.739153f,0.648687f,-0.208869f,0.731832f,0.542487f,-0.173678f,0.821915f, +0.362206f,-0.121013f,0.924209f,0.542487f,-0.173678f,0.821915f,0.564441f,-0.072486f,0.822285f,0.368823f,-0.050932f,0.928103f, +0.542487f,-0.173678f,0.821915f,0.648687f,-0.208869f,0.731832f,0.685633f,-0.08861f,0.722534f,0.564441f,-0.072486f,0.822285f, +0.564441f,-0.072486f,0.822285f,0.685633f,-0.08861f,0.722534f,0.697362f,-0.024953f,0.716285f,0.569527f,-0.020487f,0.821717f, +0.564441f,-0.072486f,0.822285f,0.569527f,-0.020487f,0.821717f,0.370348f,-0.014597f,0.928778f,0.368823f,-0.050932f,0.928103f, +0.221558f,-0.086713f,0.971284f,0.362206f,-0.121013f,0.924209f,0.368823f,-0.050932f,0.928103f,0.222823f,-0.037022f,0.974156f, +0.222823f,-0.037022f,0.974156f,0.368823f,-0.050932f,0.928103f,0.370348f,-0.014597f,0.928778f,0.223053f,-0.010715f,0.974747f, +0.223053f,-0.010715f,0.974747f,0.370348f,-0.014597f,0.928778f,0.37024f,-1.0E-6f,0.928936f,0.222967f,-1.0E-6f,0.974826f, +0.37024f,-1.0E-6f,0.928936f,0.370348f,-0.014597f,0.928778f,0.569527f,-0.020487f,0.821717f,0.569586f,-1.0E-6f,0.821932f, +0.37035f,0.014508f,0.928779f,0.37024f,-1.0E-6f,0.928936f,0.569586f,-1.0E-6f,0.821932f,0.569522f,0.020364f,0.821724f, +0.222967f,-1.0E-6f,0.974826f,0.37024f,-1.0E-6f,0.928936f,0.37035f,0.014508f,0.928779f,0.223051f,0.010649f,0.974749f, +0.569527f,-0.020487f,0.821717f,0.697362f,-0.024953f,0.716285f,0.699353f,1.1E-5f,0.714776f,0.569586f,-1.0E-6f,0.821932f, +0.569586f,-1.0E-6f,0.821932f,0.699353f,1.1E-5f,0.714776f,0.697248f,0.024864f,0.716398f,0.569522f,0.020364f,0.821724f, +-0.46128f,-0.48965f,0.739908f,-0.397988f,-0.425903f,0.812534f,-0.490028f,-0.298377f,0.819051f,-0.572885f,-0.349196f,0.741529f, +-0.490028f,-0.298377f,0.819051f,-0.397988f,-0.425903f,0.812534f,-0.294472f,-0.315809f,0.901971f,-0.344264f,-0.210118f,0.915059f, +-0.538747f,-0.174169f,0.824268f,-0.490028f,-0.298377f,0.819051f,-0.344264f,-0.210118f,0.915059f,-0.359131f,-0.12118f,0.925386f, +-0.572885f,-0.349196f,0.741529f,-0.490028f,-0.298377f,0.819051f,-0.538747f,-0.174169f,0.824268f,-0.645088f,-0.209547f,0.734814f, +-0.294472f,-0.315809f,0.901971f,-0.210457f,-0.226211f,0.951071f,-0.216181f,-0.146015f,0.965373f,-0.344264f,-0.210118f,0.915059f, +-0.344264f,-0.210118f,0.915059f,-0.216181f,-0.146015f,0.965373f,-0.219508f,-0.086774f,0.971744f,-0.359131f,-0.12118f,0.925386f, +-0.538747f,-0.174169f,0.824268f,-0.359131f,-0.12118f,0.925386f,-0.365721f,-0.051004f,0.929326f,-0.560687f,-0.072708f,0.82483f, +-0.359131f,-0.12118f,0.925386f,-0.219508f,-0.086774f,0.971744f,-0.22077f,-0.037047f,0.974622f,-0.365721f,-0.051004f,0.929326f, +-0.365721f,-0.051004f,0.929326f,-0.22077f,-0.037047f,0.974622f,-0.221f,-0.010721f,0.975215f,-0.367244f,-0.014617f,0.93001f, +-0.365721f,-0.051004f,0.929326f,-0.367244f,-0.014617f,0.93001f,-0.565774f,-0.020551f,0.824304f,-0.560687f,-0.072708f,0.82483f, +-0.645088f,-0.209547f,0.734814f,-0.538747f,-0.174169f,0.824268f,-0.560687f,-0.072708f,0.82483f,-0.682094f,-0.088945f,0.725836f, +-0.682094f,-0.088945f,0.725836f,-0.560687f,-0.072708f,0.82483f,-0.565774f,-0.020551f,0.824304f,-0.69385f,-0.025062f,0.719683f, +-0.693736f,0.024972f,0.719796f,-0.695847f,1.1E-5f,0.71819f,-0.565837f,-1.0E-6f,0.824517f,-0.565768f,0.020427f,0.824311f, +-0.695847f,1.1E-5f,0.71819f,-0.69385f,-0.025062f,0.719683f,-0.565774f,-0.020551f,0.824304f,-0.565837f,-1.0E-6f,0.824517f, +-0.565837f,-1.0E-6f,0.824517f,-0.565774f,-0.020551f,0.824304f,-0.367244f,-0.014617f,0.93001f,-0.36714f,-1.0E-6f,0.930166f, +-0.565768f,0.020427f,0.824311f,-0.565837f,-1.0E-6f,0.824517f,-0.36714f,-1.0E-6f,0.930166f,-0.367245f,0.014528f,0.930011f, +-0.367244f,-0.014617f,0.93001f,-0.221f,-0.010721f,0.975215f,-0.220914f,-1.0E-6f,0.975293f,-0.36714f,-1.0E-6f,0.930166f, +-0.36714f,-1.0E-6f,0.930166f,-0.220914f,-1.0E-6f,0.975293f,-0.220997f,0.010655f,0.975216f,-0.367245f,0.014528f,0.930011f, +0.010878f,0.222561f,0.974858f,0.037001f,0.222307f,0.974274f,0.050884f,0.367932f,0.92846f,0.01482f,0.369601f,0.929072f, +0.037001f,0.222307f,0.974274f,0.084603f,0.221056f,0.971585f,0.117939f,0.361173f,0.92501f,0.050884f,0.367932f,0.92846f, +0.050884f,0.367932f,0.92846f,0.117939f,0.361173f,0.92501f,0.169134f,0.541105f,0.823771f,0.072381f,0.563194f,0.823149f, +0.020804f,0.568602f,0.82235f,0.01482f,0.369601f,0.929072f,0.050884f,0.367932f,0.92846f,0.072381f,0.563194f,0.823149f, +0.084603f,0.221056f,0.971585f,0.139597f,0.218066f,0.965898f,0.200629f,0.347092f,0.91612f,0.117939f,0.361173f,0.92501f, +0.139597f,0.218066f,0.965898f,0.213531f,0.212993f,0.953435f,0.299149f,0.298419f,0.906342f,0.200629f,0.347092f,0.91612f, +0.200629f,0.347092f,0.91612f,0.299149f,0.298419f,0.906342f,0.405489f,0.404531f,0.819716f,0.285031f,0.494036f,0.821393f, +0.117939f,0.361173f,0.92501f,0.200629f,0.347092f,0.91612f,0.285031f,0.494036f,0.821393f,0.169134f,0.541105f,0.823771f, +0.285031f,0.494036f,0.821393f,0.405489f,0.404531f,0.819716f,0.4693f,0.468325f,0.748619f,0.335556f,0.576804f,0.744781f, +0.169134f,0.541105f,0.823771f,0.285031f,0.494036f,0.821393f,0.335556f,0.576804f,0.744781f,0.204073f,0.64709f,0.734595f, +0.072381f,0.563194f,0.823149f,0.169134f,0.541105f,0.823771f,0.204073f,0.64709f,0.734595f,0.088715f,0.684119f,0.723955f, +0.020804f,0.568602f,0.82235f,0.072381f,0.563194f,0.823149f,0.088715f,0.684119f,0.723955f,0.025388f,0.696365f,0.717239f, +0.010835f,-0.23565f,0.971778f,0.014687f,-0.38921f,0.921032f,0.050418f,-0.38752f,0.920482f,0.036837f,-0.235391f,0.971203f, +0.050418f,-0.38752f,0.920482f,0.014687f,-0.38921f,0.921032f,0.020387f,-0.591837f,0.8058f,0.070967f,-0.586467f,0.806858f, +0.116885f,-0.380591f,0.917327f,0.050418f,-0.38752f,0.920482f,0.070967f,-0.586467f,0.806858f,0.166076f,-0.564345f,0.808662f, +0.036837f,-0.235391f,0.971203f,0.050418f,-0.38752f,0.920482f,0.116885f,-0.380591f,0.917327f,0.084225f,-0.234121f,0.968552f, +0.020387f,-0.591837f,0.8058f,0.02469f,-0.717725f,0.695889f,0.086571f,-0.705739f,0.703163f,0.070967f,-0.586467f,0.806858f, +0.070967f,-0.586467f,0.806858f,0.086571f,-0.705739f,0.703163f,0.199773f,-0.669232f,0.715695f,0.166076f,-0.564345f,0.808662f, +0.116885f,-0.380591f,0.917327f,0.166076f,-0.564345f,0.808662f,0.280776f,-0.516844f,0.808725f,0.198928f,-0.366325f,0.908974f, +0.166076f,-0.564345f,0.808662f,0.199773f,-0.669232f,0.715695f,0.33043f,-0.598851f,0.729516f,0.280776f,-0.516844f,0.808725f, +0.280776f,-0.516844f,0.808725f,0.33043f,-0.598851f,0.729516f,0.464547f,-0.488911f,0.738351f,0.401261f,-0.425239f,0.811271f, +0.280776f,-0.516844f,0.808725f,0.401261f,-0.425239f,0.811271f,0.297154f,-0.315494f,0.901201f,0.198928f,-0.366325f,0.908974f, +0.084225f,-0.234121f,0.968552f,0.116885f,-0.380591f,0.917327f,0.198928f,-0.366325f,0.908974f,0.138923f,-0.231173f,0.962943f, +0.138923f,-0.231173f,0.962943f,0.198928f,-0.366325f,0.908974f,0.297154f,-0.315494f,0.901201f,0.212501f,-0.226048f,0.950655f, +0.007169f,-0.00707f,0.999949f,0.007179f,-0.025559f,0.999648f,0.025473f,-0.02556f,0.999349f,0.025479f,-0.007087f,0.99965f, +0.007179f,-0.025559f,0.999648f,0.007472f,-0.063716f,0.99794f,0.02618f,-0.063744f,0.997623f,0.025473f,-0.02556f,0.999349f, +0.025473f,-0.02556f,0.999349f,0.02618f,-0.063744f,0.997623f,0.062764f,-0.064559f,0.995938f,0.061979f,-0.026292f,0.997731f, +0.025479f,-0.007087f,0.99965f,0.025473f,-0.02556f,0.999349f,0.061979f,-0.026292f,0.997731f,0.061944f,-0.007387f,0.998052f, +0.007472f,-0.063716f,0.99794f,0.008329f,-0.119124f,0.992845f,0.028568f,-0.119188f,0.992461f,0.02618f,-0.063744f,0.997623f, +0.008329f,-0.119124f,0.992845f,0.010835f,-0.23565f,0.971778f,0.036837f,-0.235391f,0.971203f,0.028568f,-0.119188f,0.992461f, +0.028568f,-0.119188f,0.992461f,0.036837f,-0.235391f,0.971203f,0.084225f,-0.234121f,0.968552f,0.066426f,-0.119489f,0.990611f, +0.02618f,-0.063744f,0.997623f,0.028568f,-0.119188f,0.992461f,0.066426f,-0.119489f,0.990611f,0.062764f,-0.064559f,0.995938f, +0.062764f,-0.064559f,0.995938f,0.066426f,-0.119489f,0.990611f,0.114563f,-0.120018f,0.98614f,0.113981f,-0.068259f,0.991135f, +0.066426f,-0.119489f,0.990611f,0.084225f,-0.234121f,0.968552f,0.138923f,-0.231173f,0.962943f,0.114563f,-0.120018f,0.98614f, +0.114563f,-0.120018f,0.98614f,0.138923f,-0.231173f,0.962943f,0.212501f,-0.226048f,0.950655f,0.218237f,-0.145906f,0.964927f, +0.113981f,-0.068259f,0.991135f,0.114563f,-0.120018f,0.98614f,0.218237f,-0.145906f,0.964927f,0.221558f,-0.086713f,0.971284f, +0.061944f,-0.007387f,0.998052f,0.061979f,-0.026292f,0.997731f,0.113708f,-0.028673f,0.9931f,0.113635f,-0.008231f,0.993489f, +0.061979f,-0.026292f,0.997731f,0.062764f,-0.064559f,0.995938f,0.113981f,-0.068259f,0.991135f,0.113708f,-0.028673f,0.9931f, +0.113708f,-0.028673f,0.9931f,0.113981f,-0.068259f,0.991135f,0.221558f,-0.086713f,0.971284f,0.222823f,-0.037022f,0.974156f, +0.113635f,-0.008231f,0.993489f,0.113708f,-0.028673f,0.9931f,0.222823f,-0.037022f,0.974156f,0.223053f,-0.010715f,0.974747f, +0.00717f,0.007027f,0.99995f,0.007189f,0.0f,0.999974f,0.025542f,0.0f,0.999674f,0.025482f,0.007044f,0.999651f, +0.007189f,0.0f,0.999974f,0.007169f,-0.00707f,0.999949f,0.025479f,-0.007087f,0.99965f,0.025542f,0.0f,0.999674f, +0.025542f,0.0f,0.999674f,0.025479f,-0.007087f,0.99965f,0.061944f,-0.007387f,0.998052f,0.061996f,0.0f,0.998076f, +0.025482f,0.007044f,0.999651f,0.025542f,0.0f,0.999674f,0.061996f,0.0f,0.998076f,0.061948f,0.007344f,0.998052f, +0.061944f,-0.007387f,0.998052f,0.113635f,-0.008231f,0.993489f,0.11363f,0.0f,0.993523f,0.061996f,0.0f,0.998076f, +0.113635f,-0.008231f,0.993489f,0.223053f,-0.010715f,0.974747f,0.222967f,-1.0E-6f,0.974826f,0.11363f,0.0f,0.993523f, +0.11363f,0.0f,0.993523f,0.222967f,-1.0E-6f,0.974826f,0.223051f,0.010649f,0.974749f,0.113637f,0.008184f,0.993489f, +0.061996f,0.0f,0.998076f,0.11363f,0.0f,0.993523f,0.113637f,0.008184f,0.993489f,0.061948f,0.007344f,0.998052f, +-0.693736f,0.024972f,0.719796f,-0.565768f,0.020427f,0.824311f,-0.560511f,0.071322f,0.82507f,-0.681667f,0.087549f,0.726406f, +-0.560511f,0.071322f,0.82507f,-0.565768f,0.020427f,0.824311f,-0.367245f,0.014528f,0.930011f,-0.365644f,0.050051f,0.929408f, +-0.53875f,0.167715f,0.825603f,-0.560511f,0.071322f,0.82507f,-0.365644f,0.050051f,0.929408f,-0.359059f,0.116722f,0.925987f, +-0.681667f,0.087549f,0.726406f,-0.560511f,0.071322f,0.82507f,-0.53875f,0.167715f,0.825603f,-0.644943f,0.202621f,0.736881f, +-0.367245f,0.014528f,0.930011f,-0.220997f,0.010655f,0.975216f,-0.220758f,0.036362f,0.974651f,-0.365644f,0.050051f,0.929408f, +-0.365644f,0.050051f,0.929408f,-0.220758f,0.036362f,0.974651f,-0.219543f,0.083629f,0.972012f,-0.359059f,0.116722f,0.925987f, +-0.53875f,0.167715f,0.825603f,-0.359059f,0.116722f,0.925987f,-0.34505f,0.199733f,0.917086f,-0.491757f,0.284219f,0.82304f, +-0.359059f,0.116722f,0.925987f,-0.219543f,0.083629f,0.972012f,-0.216564f,0.138788f,0.966353f,-0.34505f,0.199733f,0.917086f, +-0.34505f,0.199733f,0.917086f,-0.216564f,0.138788f,0.966353f,-0.211482f,0.213152f,0.953856f,-0.296456f,0.298724f,0.907126f, +-0.34505f,0.199733f,0.917086f,-0.296456f,0.298724f,0.907126f,-0.402197f,0.405178f,0.821017f,-0.491757f,0.284219f,0.82304f, +-0.644943f,0.202621f,0.736881f,-0.53875f,0.167715f,0.825603f,-0.491757f,0.284219f,0.82304f,-0.574618f,0.33479f,0.746813f, +-0.574618f,0.33479f,0.746813f,-0.491757f,0.284219f,0.82304f,-0.402197f,0.405178f,0.821017f,-0.466013f,0.469045f,0.75022f, +0.223051f,0.010649f,0.974749f,0.37035f,0.014508f,0.928779f,0.368745f,0.04998f,0.928186f,0.222811f,0.036337f,0.974184f, +0.368745f,0.04998f,0.928186f,0.37035f,0.014508f,0.928779f,0.569522f,0.020364f,0.821724f,0.564266f,0.071105f,0.822525f, +0.362133f,0.116561f,0.92481f,0.368745f,0.04998f,0.928186f,0.564266f,0.071105f,0.822525f,0.54249f,0.167243f,0.823246f, +0.222811f,0.036337f,0.974184f,0.368745f,0.04998f,0.928186f,0.362133f,0.116561f,0.92481f,0.221593f,0.083571f,0.971552f, +0.569522f,0.020364f,0.821724f,0.697248f,0.024864f,0.716398f,0.685209f,0.08722f,0.723105f,0.564266f,0.071105f,0.822525f, +0.564266f,0.071105f,0.822525f,0.685209f,0.08722f,0.723105f,0.648546f,0.20196f,0.733894f,0.54249f,0.167243f,0.823246f, +0.362133f,0.116561f,0.92481f,0.54249f,0.167243f,0.823246f,0.495412f,0.283564f,0.821071f,0.348093f,0.199473f,0.915992f, +0.54249f,0.167243f,0.823246f,0.648546f,0.20196f,0.733894f,0.578173f,0.334012f,0.744414f,0.495412f,0.283564f,0.821071f, +0.495412f,0.283564f,0.821071f,0.578173f,0.334012f,0.744414f,0.4693f,0.468325f,0.748619f,0.405489f,0.404531f,0.819716f, +0.495412f,0.283564f,0.821071f,0.405489f,0.404531f,0.819716f,0.299149f,0.298419f,0.906342f,0.348093f,0.199473f,0.915992f, +0.221593f,0.083571f,0.971552f,0.362133f,0.116561f,0.92481f,0.348093f,0.199473f,0.915992f,0.218621f,0.138683f,0.965905f, +0.218621f,0.138683f,0.965905f,0.348093f,0.199473f,0.915992f,0.299149f,0.298419f,0.906342f,0.213531f,0.212993f,0.953435f, +0.010878f,0.222561f,0.974858f,0.008351f,0.113056f,0.993554f,0.028645f,0.113157f,0.993164f,0.037001f,0.222307f,0.974274f, +0.008351f,0.113056f,0.993554f,0.007491f,0.061287f,0.998092f,0.026239f,0.061352f,0.997771f,0.028645f,0.113157f,0.993164f, +0.028645f,0.113157f,0.993164f,0.026239f,0.061352f,0.997771f,0.062873f,0.062197f,0.996082f,0.066588f,0.113508f,0.991303f, +0.037001f,0.222307f,0.974274f,0.028645f,0.113157f,0.993164f,0.066588f,0.113508f,0.991303f,0.084603f,0.221056f,0.971585f, +0.007491f,0.061287f,0.998092f,0.007187f,0.025058f,0.99966f,0.025494f,0.025072f,0.999361f,0.026239f,0.061352f,0.997771f, +0.007187f,0.025058f,0.99966f,0.00717f,0.007027f,0.99995f,0.025482f,0.007044f,0.999651f,0.025494f,0.025072f,0.999361f, +0.025494f,0.025072f,0.999361f,0.025482f,0.007044f,0.999651f,0.061948f,0.007344f,0.998052f,0.062015f,0.025807f,0.997742f, +0.026239f,0.061352f,0.997771f,0.025494f,0.025072f,0.999361f,0.062015f,0.025807f,0.997742f,0.062873f,0.062197f,0.996082f, +0.062873f,0.062197f,0.996082f,0.062015f,0.025807f,0.997742f,0.113738f,0.028159f,0.993112f,0.114097f,0.065833f,0.991286f, +0.062015f,0.025807f,0.997742f,0.061948f,0.007344f,0.998052f,0.113637f,0.008184f,0.993489f,0.113738f,0.028159f,0.993112f, +0.113738f,0.028159f,0.993112f,0.113637f,0.008184f,0.993489f,0.223051f,0.010649f,0.974749f,0.222811f,0.036337f,0.974184f, +0.114097f,0.065833f,0.991286f,0.113738f,0.028159f,0.993112f,0.222811f,0.036337f,0.974184f,0.221593f,0.083571f,0.971552f, +0.084603f,0.221056f,0.971585f,0.066588f,0.113508f,0.991303f,0.114794f,0.114134f,0.986811f,0.139597f,0.218066f,0.965898f, +0.066588f,0.113508f,0.991303f,0.062873f,0.062197f,0.996082f,0.114097f,0.065833f,0.991286f,0.114794f,0.114134f,0.986811f, +0.114794f,0.114134f,0.986811f,0.114097f,0.065833f,0.991286f,0.221593f,0.083571f,0.971552f,0.218621f,0.138683f,0.965905f, +0.139597f,0.218066f,0.965898f,0.114794f,0.114134f,0.986811f,0.218621f,0.138683f,0.965905f,0.213531f,0.212993f,0.953435f, +0.007491f,0.061287f,0.998092f,0.008351f,0.113056f,0.993554f,0.0f,0.113048f,0.99359f,0.0f,0.061335f,0.998117f, +0.008351f,0.113056f,0.993554f,0.010878f,0.222561f,0.974858f,0.0f,0.222477f,0.974938f,0.0f,0.113048f,0.99359f, +0.0f,0.113048f,0.99359f,0.0f,0.222477f,0.974938f,-0.010867f,0.22256f,0.974858f,-0.008343f,0.113057f,0.993554f, +0.0f,0.061335f,0.998117f,0.0f,0.113048f,0.99359f,-0.008343f,0.113057f,0.993554f,-0.007484f,0.061287f,0.998092f, +0.007491f,0.061287f,0.998092f,0.0f,0.061335f,0.998117f,0.0f,0.025116f,0.999685f,0.007187f,0.025058f,0.99966f, +0.0f,0.061335f,0.998117f,-0.007484f,0.061287f,0.998092f,-0.00718f,0.025059f,0.99966f,0.0f,0.025116f,0.999685f, +0.0f,0.025116f,0.999685f,-0.00718f,0.025059f,0.99966f,-0.007163f,0.007027f,0.99995f,0.0f,0.007045f,0.999975f, +0.007187f,0.025058f,0.99966f,0.0f,0.025116f,0.999685f,0.0f,0.007045f,0.999975f,0.00717f,0.007027f,0.99995f, +-0.220997f,0.010655f,0.975216f,-0.112675f,0.008187f,0.993598f,-0.112781f,0.02817f,0.993221f,-0.220758f,0.036362f,0.974651f, +-0.112675f,0.008187f,0.993598f,-0.061553f,0.007347f,0.998077f,-0.061625f,0.025816f,0.997765f,-0.112781f,0.02817f,0.993221f, +-0.112781f,0.02817f,0.993221f,-0.061625f,0.025816f,0.997765f,-0.062487f,0.062214f,0.996105f,-0.113147f,0.065858f,0.991393f, +-0.220758f,0.036362f,0.974651f,-0.112781f,0.02817f,0.993221f,-0.113147f,0.065858f,0.991393f,-0.219543f,0.083629f,0.972012f, +-0.061553f,0.007347f,0.998077f,-0.025398f,0.007046f,0.999653f,-0.025412f,0.025076f,0.999363f,-0.061625f,0.025816f,0.997765f, +-0.025398f,0.007046f,0.999653f,-0.007163f,0.007027f,0.99995f,-0.00718f,0.025059f,0.99966f,-0.025412f,0.025076f,0.999363f, +-0.025412f,0.025076f,0.999363f,-0.00718f,0.025059f,0.99966f,-0.007484f,0.061287f,0.998092f,-0.026157f,0.061358f,0.997773f, +-0.061625f,0.025816f,0.997765f,-0.025412f,0.025076f,0.999363f,-0.026157f,0.061358f,0.997773f,-0.062487f,0.062214f,0.996105f, +-0.062487f,0.062214f,0.996105f,-0.026157f,0.061358f,0.997773f,-0.028558f,0.113162f,0.993166f,-0.066192f,0.113526f,0.991328f, +-0.026157f,0.061358f,0.997773f,-0.007484f,0.061287f,0.998092f,-0.008343f,0.113057f,0.993554f,-0.028558f,0.113162f,0.993166f, +-0.028558f,0.113162f,0.993166f,-0.008343f,0.113057f,0.993554f,-0.010867f,0.22256f,0.974858f,-0.036885f,0.222305f,0.974279f, +-0.066192f,0.113526f,0.991328f,-0.028558f,0.113162f,0.993166f,-0.036885f,0.222305f,0.974279f,-0.084089f,0.221062f,0.971628f, +-0.219543f,0.083629f,0.972012f,-0.113147f,0.065858f,0.991393f,-0.113857f,0.11417f,0.986915f,-0.216564f,0.138788f,0.966353f, +-0.113147f,0.065858f,0.991393f,-0.062487f,0.062214f,0.996105f,-0.066192f,0.113526f,0.991328f,-0.113857f,0.11417f,0.986915f, +-0.113857f,0.11417f,0.986915f,-0.066192f,0.113526f,0.991328f,-0.084089f,0.221062f,0.971628f,-0.138447f,0.218126f,0.966051f, +-0.216564f,0.138788f,0.966353f,-0.113857f,0.11417f,0.986915f,-0.138447f,0.218126f,0.966051f,-0.211482f,0.213152f,0.953856f, +}; + +const float cfGameIconStrokeVtxs[] = +{ +-0.376756459475,1.046143651009f,0.0f, +-0.512206375599f,1.039104461670f,0.0f, +-0.613150417805f,1.029256582260f,0.0f, +-0.688333272934f,1.016606807709f,0.0f, +-0.746499598026f,1.001162052155f,0.0f, +-0.796394228935f,0.982929229736,0.0f, +-0.839153468609,0.961680650711,0.0f, +-0.875913500786,0.93718868494,0.0f, +-0.907810747623,0.909225344658,0.0f, +-0.93598151207,0.877562940121,0.0f, +-0.960655272007,0.840993285179,0.0f, +-0.982061386108,0.79830801487,0.0f, +-1.00042927265,0.748299062252,0.0f, +-1.015988588333,0.689758002758,0.0f, +-1.028732180595,0.613717556,0.0f, +-1.038653135300,0.511210441589,0.0f, +-1.045744538307,0.373269081116,0.0f, +-1.049999356270,0.190926194191,0.0f, +-1.051417708397,-1.349482312799E-002,0.0f, +-1.049999356270,-0.217670500278,0.0f, +-1.04574441910,-0.399277359247,0.0f, +-1.038653135300,-0.535992026329,0.0f, +-1.028732180595,-0.636890649796,0.0f, +-1.015988588333,-0.711049556732,0.0f, +-1.00042927265,-0.767545044422,0.0f, +-0.982061386108,-0.815453350544,0.0f, +-0.960655212402,-0.856050789356,0.0f, +-0.93598151207,-0.890613555908,0.0f, +-0.907810747623,-0.920418143272,0.0f, +-0.875913500786,-0.946740865707,0.0f, +-0.839153468609,-0.969795942307,0.0f, +-0.796394228935,-0.989797830582,0.0f, +-0.746499598026,-1.006960868835,0.0f, +-0.688333272934,-1.021499633789,0.0f, +-0.613150477409,-1.033407211304,0.0f, +-0.512206375599,-1.042677521706,0.0f, +-0.376756429672,-1.049303770065,0.0f, +-0.19805586338,-1.053279519081,0.0f, +2.249561250210E-003,-1.054604768753,0.0f, +0.202514111996,-1.053279519081,0.0f, +0.381092041731,-1.049303770065,0.0f, +0.516337633133,-1.042677521706,0.0f, +0.617013633251,-1.033407211304,0.0f, +0.691882967949,-1.021499633789,0.0f, +0.749708354473,-1.006960868835,0.0f, +0.79925262928,-0.989797830582,0.0f, +0.841663658619,-0.969795942307,0.0f, +0.87808907032,-0.946740865707,0.0f, +0.909676492214,-0.920418143272,0.0f, +0.93757379055,-0.890613555908,0.0f, +0.962008118629,-0.856050789356,0.0f, +0.983206510544,-0.815453350544,0.0f, +1.001396179199,-0.767545044422,0.0f, +1.016804218292,-0.711049556732,0.0f, +1.029423952103,-0.636890649796,0.0f, +1.039248347282,-0.535992026329,0.0f, +1.046270728111,-0.399277359247,0.0f, +1.050484061241,-0.217670500278,0.0f, +1.051888465881,-1.349482685328E-002,0.0f, +1.050484061241,0.190926194191,0.0f, +1.046270728111,0.373269081116,0.0f, +1.039248347282,0.511210441589,0.0f, +1.029423952103,0.613717556,0.0f, +1.016804218292,0.689758002758,0.0f, +1.001396059990,0.748299002647,0.0f, +0.983206450939,0.79830801487,0.0f, +0.962008118629,0.840993225574,0.0f, +0.93757379055,0.877562940121,0.0f, +0.909676492214,0.909225344658,0.0f, +0.87808907032,0.93718868494,0.0f, +0.841663658619,0.961680650711,0.0f, +0.79925262928,0.982929229736,0.0f, +0.749708354473,1.001162052155,0.0f, +0.691882967949,1.016606807709,0.0f, +0.617013692856,1.029256582260,0.0f, +0.516337633133,1.039104580879,0.0f, +0.381092071533,1.046143770218,0.0f, +0.202514111996,1.050367355347,0.0f, +2.249561250210E-003,1.051775097847,0.0f, +-0.19805586338,1.050367236137,0.0f, +-0.376756459475,1.046143651009,0.0f +}; + +const unsigned int cuGameIconStrokeVtxCount = sizeof(cfGameIconStrokeVtxs) / (sizeof(float) * 3); + +#endif diff --git a/src/gui/GridBackground.cpp b/src/gui/GridBackground.cpp new file mode 100644 index 0000000..d027ab8 --- /dev/null +++ b/src/gui/GridBackground.cpp @@ -0,0 +1,100 @@ +#include "GridBackground.h" +#include "video/CVideo.h" +#include "video/shaders/Shader3D.h" + +static const float bgRepeat = 1000.0f; +static const float bgTexRotate = 39.0f; + +GridBackground::GridBackground(GuiImageData *img) + : GuiImage(img) +{ + colorIntensity = glm::vec4(1.0f, 1.0f, 1.0f, 0.9f); + alphaFadeOut = glm::vec4(0.0f); + distanceFadeOut = 0.15f; + + vtxCount = 4; + + //! texture and vertex coordinates + f32 *m_posVtxs = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, vtxCount * Shader3D::cuVertexAttrSize); + f32 *m_texCoords = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, vtxCount * Shader3D::cuTexCoordAttrSize); + + if(m_posVtxs) + { + int i = 0; + m_posVtxs[i++] = -1.0f; m_posVtxs[i++] = 0.0f; m_posVtxs[i++] = 1.0f; + m_posVtxs[i++] = 1.0f; m_posVtxs[i++] = 0.0f; m_posVtxs[i++] = 1.0f; + m_posVtxs[i++] = 1.0f; m_posVtxs[i++] = 0.0f; m_posVtxs[i++] = -1.0f; + m_posVtxs[i++] = -1.0f; m_posVtxs[i++] = 0.0f; m_posVtxs[i++] = -1.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, m_posVtxs, vtxCount * Shader3D::cuVertexAttrSize); + } + + if(m_texCoords) + { + glm::vec2 texCoordVec[4]; + texCoordVec[0][0] = -0.5f * bgRepeat; texCoordVec[0][1] = 0.5f * bgRepeat; + texCoordVec[1][0] = 0.5f * bgRepeat; texCoordVec[1][1] = 0.5f * bgRepeat; + texCoordVec[2][0] = 0.5f * bgRepeat; texCoordVec[2][1] = -0.5f * bgRepeat; + texCoordVec[3][0] = -0.5f * bgRepeat; texCoordVec[3][1] = -0.5f * bgRepeat; + + const float cosRot = cosf(DegToRad(bgTexRotate)); + const float sinRot = sinf(DegToRad(bgTexRotate)); + + glm::mat2 texRotateMtx({ + cosRot, -sinRot, + sinRot, cosRot + }); + + for(int i = 0; i < 4; i++) { + texCoordVec[i] = texRotateMtx * texCoordVec[i]; + m_texCoords[i*2 + 0] = texCoordVec[i][0]; + m_texCoords[i*2 + 1] = texCoordVec[i][1]; + } + + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, m_texCoords, vtxCount * Shader3D::cuTexCoordAttrSize); + } + + //! assign to internal variables which are const but oh well + posVtxs = m_posVtxs; + texCoords = m_texCoords; +} + +GridBackground::~GridBackground() +{ + //! remove image so it can not be drawn anymore from this point on + imageData = NULL; + + //! main image vertexes + if(posVtxs) + { + free((void*)posVtxs); + posVtxs = NULL; + } + if(texCoords) + { + free((void*)texCoords); + texCoords = NULL; + } +} + +void GridBackground::draw(CVideo *pVideo, const glm::mat4 & modelView) +{ + //! first setup 2D GUI positions + f32 currScaleX = bgRepeat * scaleX * (f32)getWidth() * pVideo->getWidthScaleFactor(); + f32 currScaleY = 1.0f; + f32 currScaleZ = bgRepeat * scaleZ * (f32)getHeight() * pVideo->getDepthScaleFactor(); + + m_modelView = glm::scale(modelView, glm::vec3(currScaleX, currScaleY, currScaleZ)); + + colorIntensity[3] = getAlpha(); + + Shader3D::instance()->setShaders(); + Shader3D::instance()->setTextureAndSampler(imageData->getTexture(), imageData->getSampler()); + Shader3D::instance()->setProjectionMtx(pVideo->getProjectionMtx()); + Shader3D::instance()->setViewMtx(pVideo->getViewMtx()); + Shader3D::instance()->setModelViewMtx(m_modelView); + Shader3D::instance()->setDistanceFadeOut(distanceFadeOut); + Shader3D::instance()->setAlphaFadeOut(alphaFadeOut); + Shader3D::instance()->setColorIntensity(colorIntensity); + Shader3D::instance()->setAttributeBuffer(vtxCount, posVtxs, texCoords); + Shader3D::instance()->draw(GX2_PRIMITIVE_QUADS, vtxCount); +} diff --git a/src/gui/GridBackground.h b/src/gui/GridBackground.h new file mode 100644 index 0000000..198506a --- /dev/null +++ b/src/gui/GridBackground.h @@ -0,0 +1,30 @@ +#ifndef _GRID_BACKGROUND_H_ +#define _GRID_BACKGROUND_H_ + +#include "GuiImage.h" +#include "video/shaders/Shader.h" + +class GridBackground : public GuiImage +{ +public: + GridBackground(GuiImageData *imgData); + virtual ~GridBackground(); + + void setColorIntensity(const glm::vec4 & color) { + colorIntensity = color; + } + const glm::vec4 & getColorIntensity() const { + return colorIntensity; + } + void setDistanceFadeOut(const float & a) { + distanceFadeOut = a; + } + void draw(CVideo *pVideo, const glm::mat4 & modelView); +private: + glm::mat4 m_modelView; + glm::vec4 colorIntensity; + glm::vec4 alphaFadeOut; + float distanceFadeOut; +}; + +#endif // _GRID_BACKGROUND_H_ diff --git a/src/gui/Gui.h b/src/gui/Gui.h new file mode 100644 index 0000000..fb841c5 --- /dev/null +++ b/src/gui/Gui.h @@ -0,0 +1,30 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 __GUI_H +#define __GUI_H + +#include "GuiElement.h" +#include "GuiImageData.h" +#include "GuiImage.h" +#include "GuiFrame.h" +#include "GuiController.h" +#include "GuiText.h" +#include "GuiSound.h" +#include "GuiButton.h" +#include "GuiTrigger.h" + +#endif diff --git a/src/gui/GuiButton.cpp b/src/gui/GuiButton.cpp new file mode 100644 index 0000000..ae05a8d --- /dev/null +++ b/src/gui/GuiButton.cpp @@ -0,0 +1,301 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include "GuiButton.h" +#include "GuiTrigger.h" +#include "GuiController.h" + +/** + * Constructor for the GuiButton class. + */ + +GuiButton::GuiButton(f32 w, f32 h) +{ + width = w; + height = h; + image = NULL; + imageOver = NULL; + imageHold = NULL; + imageClick = NULL; + icon = NULL; + iconOver = NULL; + + for(int i = 0; i < 4; i++) + { + label[i] = NULL; + labelOver[i] = NULL; + labelHold[i] = NULL; + labelClick[i] = NULL; + } + for(int i = 0; i < iMaxGuiTriggers; i++) + { + trigger[i] = NULL; + } + + soundOver = NULL; + soundHold = NULL; + soundClick = NULL; + clickedTrigger = NULL; + heldTrigger = NULL; + selectable = true; + holdable = false; + clickable = true; +} + +/** + * Destructor for the GuiButton class. + */ +GuiButton::~GuiButton() +{ +} + +void GuiButton::setImage(GuiImage* img) +{ + image = img; + if(img) img->setParent(this); +} +void GuiButton::setImageOver(GuiImage* img) +{ + imageOver = img; + if(img) img->setParent(this); +} +void GuiButton::setImageHold(GuiImage* img) +{ + imageHold = img; + if(img) img->setParent(this); +} +void GuiButton::setImageClick(GuiImage* img) +{ + imageClick = img; + if(img) img->setParent(this); +} +void GuiButton::setIcon(GuiImage* img) +{ + icon = img; + if(img) img->setParent(this); +} +void GuiButton::setIconOver(GuiImage* img) +{ + iconOver = img; + if(img) img->setParent(this); +} + +void GuiButton::setLabel(GuiText* txt, int n) +{ + label[n] = txt; + if(txt) txt->setParent(this); +} +void GuiButton::setLabelOver(GuiText* txt, int n) +{ + labelOver[n] = txt; + if(txt) txt->setParent(this); +} +void GuiButton::setLabelHold(GuiText* txt, int n) +{ + labelHold[n] = txt; + if(txt) txt->setParent(this); +} +void GuiButton::setLabelClick(GuiText* txt, int n) +{ + labelClick[n] = txt; + if(txt) txt->setParent(this); +} +void GuiButton::setSoundOver(GuiSound * snd) +{ + soundOver = snd; +} +void GuiButton::setSoundHold(GuiSound * snd) +{ + soundHold = snd; +} + +void GuiButton::setSoundClick(GuiSound * snd) +{ + soundClick = snd; +} + +void GuiButton::setTrigger(GuiTrigger * t, int idx) +{ + if(idx >= 0 && idx < iMaxGuiTriggers) + { + trigger[idx] = t; + } + else + { + for(int i = 0; i < iMaxGuiTriggers; i++) + { + if(!trigger[i]) + { + trigger[i] = t; + break; + } + } + } +} + +void GuiButton::resetState(void) +{ + clickedTrigger = NULL; + heldTrigger = NULL; + GuiElement::resetState(); +} + +/** + * Draw the button on screen + */ +void GuiButton::draw(CVideo *v) +{ + if(!this->isVisible()) + return; + + // draw image + if((isDrawOverOnlyWhenSelected() && (isStateSet(STATE_SELECTED) && imageOver)) || + (!isDrawOverOnlyWhenSelected() && (isStateSet(STATE_OVER | STATE_SELECTED | STATE_CLICKED | STATE_HELD) && imageOver))) + imageOver->draw(v); + else if(image) + image->draw(v); + + if((isDrawOverOnlyWhenSelected() && (isStateSet(STATE_SELECTED) && iconOver)) || + (!isDrawOverOnlyWhenSelected() && (isStateSet(STATE_OVER | STATE_SELECTED | STATE_CLICKED | STATE_HELD) && iconOver))) + iconOver->draw(v); + else if(icon) + icon->draw(v); + + // draw text + for(int i = 0; i < 4; i++) + { + if(isStateSet(STATE_OVER | STATE_SELECTED | STATE_CLICKED | STATE_HELD) && labelOver[i]) + labelOver[i]->draw(v); + else if(label[i]) + label[i]->draw(v); + } +} + +void GuiButton::update(GuiController * c) +{ + if(!c || isStateSet(STATE_DISABLED|STATE_HIDDEN|STATE_DISABLE_INPUT, c->chan)) + return; + else if(parentElement && (parentElement->isStateSet(STATE_DISABLED|STATE_HIDDEN|STATE_DISABLE_INPUT, c->chan))) + return; + + if(selectable) + { + if(c->data.validPointer && this->isInside(c->data.x, c->data.y)) + { + if(!isStateSet(STATE_OVER, c->chan)) + { + setState(STATE_OVER, c->chan); + + //if(this->isRumbleActive()) + // this->rumble(t->chan); + + if(soundOver) + soundOver->Play(); + + if(effectsOver && !effects) + { + // initiate effects + effects = effectsOver; + effectAmount = effectAmountOver; + effectTarget = effectTargetOver; + } + + pointedOn(this, c); + } + } + else if(isStateSet(STATE_OVER, c->chan)) + { + this->clearState(STATE_OVER, c->chan); + pointedOff(this, c); + + if(effectTarget == effectTargetOver && effectAmount == effectAmountOver) + { + // initiate effects (in reverse) + effects = effectsOver; + effectAmount = -effectAmountOver; + effectTarget = 100; + } + } + } + + for(int i = 0; i < iMaxGuiTriggers; i++) + { + if(!trigger[i]) + continue; + + // button triggers + if(clickable) + { + + int isClicked = trigger[i]->clicked(c); + + if( !clickedTrigger && (isClicked != GuiTrigger::CLICKED_NONE) + && (trigger[i]->isClickEverywhere() || (isStateSet(STATE_SELECTED | STATE_OVER, c->chan) && trigger[i]->isSelectionClickEverywhere()) || this->isInside(c->data.x, c->data.y))) + { + if(soundClick) + soundClick->Play(); + + clickedTrigger = trigger[i]; + + if(!isStateSet(STATE_CLICKED, c->chan)){ + if(isClicked == GuiTrigger::CLICKED_TOUCH){ + setState(STATE_CLICKED_TOUCH, c->chan); + }else{ + setState(STATE_CLICKED, c->chan); + } + } + + clicked(this, c, trigger[i]); + } + else if((isStateSet(STATE_CLICKED, c->chan) || isStateSet(STATE_CLICKED_TOUCH, c->chan)) && (clickedTrigger == trigger[i]) && !isStateSet(STATE_HELD, c->chan) && !trigger[i]->held(c) && ((isClicked == GuiTrigger::CLICKED_NONE) || trigger[i]->released(c))) + { + if((isStateSet(STATE_CLICKED_TOUCH, c->chan) && this->isInside(c->data.x, c->data.y)) || (isStateSet(STATE_CLICKED, c->chan))){ + clickedTrigger = NULL; + clearState(STATE_CLICKED, c->chan); + released(this, c, trigger[i]); + } + } + } + + if(holdable) + { + bool isHeld = trigger[i]->held(c); + + if( (!heldTrigger || heldTrigger == trigger[i]) && isHeld + && (trigger[i]->isHoldEverywhere() || (isStateSet(STATE_SELECTED | STATE_OVER, c->chan) && trigger[i]->isSelectionClickEverywhere()) || this->isInside(c->data.x, c->data.y))) + { + heldTrigger = trigger[i]; + + if(!isStateSet(STATE_HELD, c->chan)) + setState(STATE_HELD, c->chan); + + held(this, c, trigger[i]); + } + else if(isStateSet(STATE_HELD, c->chan) && (heldTrigger == trigger[i]) && (!isHeld || trigger[i]->released(c))) + { + //! click is removed at this point and converted to held + if(clickedTrigger == trigger[i]) + { + clickedTrigger = NULL; + clearState(STATE_CLICKED, c->chan); + } + heldTrigger = NULL; + clearState(STATE_HELD, c->chan); + released(this, c, trigger[i]); + } + } + } +} diff --git a/src/gui/GuiButton.h b/src/gui/GuiButton.h new file mode 100644 index 0000000..0e08d42 --- /dev/null +++ b/src/gui/GuiButton.h @@ -0,0 +1,117 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 GUI_BUTTON_H_ +#define GUI_BUTTON_H_ + +#include "GuiElement.h" +#include "GuiText.h" +#include "GuiController.h" +#include "GuiImage.h" +#include "GuiSound.h" +#include "GuiTrigger.h" + +//!Display, manage, and manipulate buttons in the GUI. Buttons can have images, icons, text, and sound set (all of which are optional) +class GuiButton : public GuiElement +{ + public: + //!Constructor + //!\param w Width + //!\param h Height + GuiButton(f32 w, f32 h); + //!Destructor + virtual ~GuiButton(); + //!Sets the button's image + //!\param i Pointer to GuiImage object + void setImage(GuiImage* i); + //!Sets the button's image on over + //!\param i Pointer to GuiImage object + void setImageOver(GuiImage* i); + + void setIcon(GuiImage* i); + void setIconOver(GuiImage* i); + //!Sets the button's image on hold + //!\param i Pointer to GuiImage object + void setImageHold(GuiImage* i); + //!Sets the button's image on click + //!\param i Pointer to GuiImage object + void setImageClick(GuiImage* i); + //!Sets the button's label + //!\param t Pointer to GuiText object + //!\param n Index of label to set (optional, default is 0) + void setLabel(GuiText* t, int n = 0); + //!Sets the button's label on over (eg: different colored text) + //!\param t Pointer to GuiText object + //!\param n Index of label to set (optional, default is 0) + void setLabelOver(GuiText* t, int n = 0); + //!Sets the button's label on hold + //!\param t Pointer to GuiText object + //!\param n Index of label to set (optional, default is 0) + void setLabelHold(GuiText* t, int n = 0); + //!Sets the button's label on click + //!\param t Pointer to GuiText object + //!\param n Index of label to set (optional, default is 0) + void setLabelClick(GuiText* t, int n = 0); + //!Sets the sound to play on over + //!\param s Pointer to GuiSound object + void setSoundOver(GuiSound * s); + //!Sets the sound to play on hold + //!\param s Pointer to GuiSound object + void setSoundHold(GuiSound * s); + //!Sets the sound to play on click + //!\param s Pointer to GuiSound object + void setSoundClick(GuiSound * s); + //!Set a new GuiTrigger for the element + //!\param i Index of trigger array to set + //!\param t Pointer to GuiTrigger + void setTrigger(GuiTrigger * t, int idx = -1); + //! + void resetState(void); + //!Constantly called to draw the GuiButton + void draw(CVideo *video); + //!Constantly called to allow the GuiButton to respond to updated input data + //!\param t Pointer to a GuiTrigger, containing the current input data from PAD/WPAD + void update(GuiController * c); + + sigslot::signal2 selected; + sigslot::signal2 deSelected; + sigslot::signal2 pointedOn; + sigslot::signal2 pointedOff; + sigslot::signal3 clicked; + sigslot::signal3 held; + sigslot::signal3 released; + protected: + static const int iMaxGuiTriggers = 10; + + GuiImage * image; //!< Button image (default) + GuiImage * imageOver; //!< Button image for STATE_SELECTED + GuiImage * imageHold; //!< Button image for STATE_HELD + GuiImage * imageClick; //!< Button image for STATE_CLICKED + GuiImage * icon; + GuiImage * iconOver; + GuiText * label[4]; //!< Label(s) to display (default) + GuiText * labelOver[4]; //!< Label(s) to display for STATE_SELECTED + GuiText * labelHold[4]; //!< Label(s) to display for STATE_HELD + GuiText * labelClick[4]; //!< Label(s) to display for STATE_CLICKED + GuiSound * soundOver; //!< Sound to play for STATE_SELECTED + GuiSound * soundHold; //!< Sound to play for STATE_HELD + GuiSound * soundClick; //!< Sound to play for STATE_CLICKED + GuiTrigger * trigger[iMaxGuiTriggers]; //!< GuiTriggers (input actions) that this element responds to + GuiTrigger * clickedTrigger; + GuiTrigger * heldTrigger; +}; + +#endif diff --git a/src/gui/GuiCheckBox.cpp b/src/gui/GuiCheckBox.cpp new file mode 100644 index 0000000..73654ea --- /dev/null +++ b/src/gui/GuiCheckBox.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** + * Copyright (C) 2016 Maschell + * + * 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 . + ****************************************************************************/ +#include "GuiCheckBox.h" +#include "GuiImage.h" +#include "GuiImageData.h" +/** + * Constructor for the GuiCheckBox class. + */ + +GuiCheckBox::GuiCheckBox(bool checked) + : GuiToggle(checked,50,50) + ,checkbox_imgdata(Resources::GetImageData("checkbox.png")) + ,checkbox_img(checkbox_imgdata) + ,checkbox_selected_imgdata(Resources::GetImageData("checkbox_selected.png")) + ,checkbox_selected_img(checkbox_selected_imgdata) + ,highlighted_imgdata(Resources::GetImageData("checkbox_highlighted.png")) + ,highlighted_img(highlighted_imgdata) +{ + checkbox_selected_img.setScale(height/checkbox_selected_img.getHeight()); + checkbox_img.setScale(height/checkbox_img.getHeight()); + highlighted_img.setScale(height/highlighted_img.getHeight()); + + setImage(&checkbox_img); + setIconOver(&highlighted_img); +} + +/** + * Destructor for the GuiButton class. + */ +GuiCheckBox::~GuiCheckBox() +{ + Resources::RemoveImageData(checkbox_imgdata); + Resources::RemoveImageData(checkbox_selected_imgdata); + Resources::RemoveImageData(highlighted_imgdata); +} + + +void GuiCheckBox::update(GuiController * c){ + if(bChanged){ + if(selected){ + GuiButton::setImage(&checkbox_selected_img); + }else{ + GuiButton::setImage(&checkbox_img); + } + bChanged = false; + } + GuiToggle::update(c); +} + diff --git a/src/gui/GuiCheckBox.h b/src/gui/GuiCheckBox.h new file mode 100644 index 0000000..f5683fc --- /dev/null +++ b/src/gui/GuiCheckBox.h @@ -0,0 +1,47 @@ +/**************************************************************************** + * Copyright (C) 2016 Maschell + * + * 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 GUI_CHECKBOX_H_ +#define GUI_CHECKBOX_H_ + +#include "GuiToggle.h" +#include "GuiImage.h" +#include "GuiImageData.h" + +//!A simple CheckBox +class GuiCheckBox : public GuiToggle +{ + public: + //!Constructor + //!\param checked Checked + GuiCheckBox(bool checked); + //!Destructor + virtual ~GuiCheckBox(); + protected: + + GuiImageData * checkbox_imgdata; + GuiImage checkbox_img; + + GuiImageData * checkbox_selected_imgdata; + GuiImage checkbox_selected_img; + + GuiImageData * highlighted_imgdata; + GuiImage highlighted_img; + + void update(GuiController * c); +}; + +#endif diff --git a/src/gui/GuiController.h b/src/gui/GuiController.h new file mode 100644 index 0000000..c9cc443 --- /dev/null +++ b/src/gui/GuiController.h @@ -0,0 +1,78 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 GUI_CONTROLLER_H_ +#define GUI_CONTROLLER_H_ + +#include +#include "GuiTrigger.h" + +class GuiController +{ +public: + //!Constructor + GuiController(int channel) + : chan(channel) + { + memset(&lastData, 0, sizeof(lastData)); + memset(&data, 0, sizeof(data)); + + switch(chan) + { + default: + case GuiTrigger::CHANNEL_1: + chanIdx = 0; + break; + case GuiTrigger::CHANNEL_2: + chanIdx = 1; + break; + case GuiTrigger::CHANNEL_3: + chanIdx = 2; + break; + case GuiTrigger::CHANNEL_4: + chanIdx = 3; + break; + case GuiTrigger::CHANNEL_5: + chanIdx = 4; + break; + } + } + + //!Destructor + virtual ~GuiController() {} + + virtual bool update(int width, int height) = 0; + + typedef struct + { + unsigned int buttons_h; + unsigned int buttons_d; + unsigned int buttons_r; + bool validPointer; + bool touched; + float pointerAngle; + int x; + int y; + } PadData; + + int chan; + int chanIdx; + PadData data; + PadData lastData; + +}; + +#endif diff --git a/src/gui/GuiDragListener.cpp b/src/gui/GuiDragListener.cpp new file mode 100644 index 0000000..796d8f2 --- /dev/null +++ b/src/gui/GuiDragListener.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** + * Copyright (C) 2016 Maschell + * based on GuiButton by dimok + * + * 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 . + ****************************************************************************/ +#include "GuiDragListener.h" +#include "GuiController.h" +#include "utils/logger.h" + +/** + * Constructor for the GuiDragListener class. + */ + +GuiDragListener::GuiDragListener(f32 w,f32 h){ + width = w; + height = h; + for(int i = 0; i < iMaxGuiTriggers; i++) + { + trigger[i] = NULL; + } +} + +/** + * Destructor for the GuiDragListener class. + */ +GuiDragListener::~GuiDragListener(){ +} + +void GuiDragListener::setTrigger(GuiTrigger * t, int idx){ + if(idx >= 0 && idx < iMaxGuiTriggers) + { + trigger[idx] = t; + } + else + { + for(int i = 0; i < iMaxGuiTriggers; i++) + { + if(!trigger[i]) + { + trigger[i] = t; + break; + } + } + } +} + +void GuiDragListener::update(GuiController * c){ + if(!c || isStateSet(STATE_DISABLED|STATE_HIDDEN|STATE_DISABLE_INPUT, c->chan)) + return; + else if(parentElement && (parentElement->isStateSet(STATE_DISABLED|STATE_HIDDEN|STATE_DISABLE_INPUT, c->chan))) + return; + + for(int i = 0; i < iMaxGuiTriggers; i++){ + if(!trigger[i]){ + continue; + } + + bool isHeld = trigger[i]->held(c); + + + if(isHeld && this->isInside(c->data.x, c->data.y)){ + int dx = c->data.x - c->lastData.x; + int dy = c->data.y - c->lastData.y; + + if(dx == 0 && dy == 0) continue; + + dragged(this, c, trigger[i],dx,dy); + } + } +} diff --git a/src/gui/GuiDragListener.h b/src/gui/GuiDragListener.h new file mode 100644 index 0000000..e0750e0 --- /dev/null +++ b/src/gui/GuiDragListener.h @@ -0,0 +1,50 @@ +/**************************************************************************** + * Copyright (C) 2016 Maschell + * + * 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 GUI_DRAG_LISTENER_H_ +#define GUI_DRAG_LISTENER_H_ + +#include "GuiElement.h" +#include "GuiController.h" +#include "GuiTrigger.h" +#include "GuiButton.h" + +class GuiDragListener : public GuiElement +{ + public: + //!Constructor + //!\param w Width + //!\param h Height + GuiDragListener(f32 w,f32 h); + //!Destructor + virtual ~GuiDragListener(); + //!Set a new GuiTrigger for the element + //!\param i Index of trigger array to set + //!\param t Pointer to GuiTrigger + void setTrigger(GuiTrigger * t, int idx = -1); + + //!Constantly called to allow the GuiDragListener to respond to updated input data + //!\param t Pointer to a GuiTrigger, containing the current input data from PAD/WPAD + void update(GuiController * c); + + sigslot::signal5 dragged; + protected: + static const int iMaxGuiTriggers = 10; + + GuiTrigger * trigger[iMaxGuiTriggers]; //!< GuiTriggers (input actions) that this element responds to +}; + +#endif diff --git a/src/gui/GuiElement.cpp b/src/gui/GuiElement.cpp new file mode 100644 index 0000000..e79253b --- /dev/null +++ b/src/gui/GuiElement.cpp @@ -0,0 +1,343 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include "GuiElement.h" + +//! TODO remove this! +static int screenwidth = 1280; +static int screenheight = 720; + +/** + * Constructor for the Object class. + */ +GuiElement::GuiElement() +{ + xoffset = 0.0f; + yoffset = 0.0f; + zoffset = 0.0f; + width = 0.0f; + height = 0.0f; + alpha = 1.0f; + scaleX = 1.0f; + scaleY = 1.0f; + scaleZ = 1.0f; + for(int i = 0; i < 4; i++) + state[i] = STATE_DEFAULT; + stateChan = -1; + parentElement = NULL; + rumble = true; + selectable = false; + clickable = false; + holdable = false; + drawOverOnlyWhenSelected = false; + visible = true; + yoffsetDyn = 0; + xoffsetDyn = 0; + alphaDyn = -1; + scaleDyn = 1; + effects = EFFECT_NONE; + effectAmount = 0; + effectTarget = 0; + effectsOver = EFFECT_NONE; + effectAmountOver = 0; + effectTargetOver = 0; + angle = 0.0f; + + // default alignment - align to top left + alignment = (ALIGN_CENTER | ALIGN_MIDDLE); +} + +/** + * Get the left position of the GuiElement. + * @see SetLeft() + * @return Left position in pixel. + */ +f32 GuiElement::getLeft() +{ + f32 pWidth = 0; + f32 pLeft = 0; + f32 pScaleX = 1.0f; + + if(parentElement) + { + pWidth = parentElement->getWidth(); + pLeft = parentElement->getLeft(); + pScaleX = parentElement->getScaleX(); + } + + pLeft += xoffsetDyn; + + f32 x = pLeft; + + //! TODO: the conversion from int to float and back to int is bad for performance, change that + if(alignment & ALIGN_CENTER) + { + x = pLeft + pWidth * 0.5f * pScaleX - width * 0.5f * getScaleX(); + } + else if(alignment & ALIGN_RIGHT) + { + x = pLeft + pWidth * pScaleX - width * getScaleX(); + } + + return x + xoffset; +} + +/** + * Get the top position of the GuiElement. + * @see SetTop() + * @return Top position in pixel. + */ +f32 GuiElement::getTop() +{ + f32 pHeight = 0; + f32 pTop = 0; + f32 pScaleY = 1.0f; + + if(parentElement) + { + pHeight = parentElement->getHeight(); + pTop = parentElement->getTop(); + pScaleY = parentElement->getScaleY(); + } + + pTop += yoffsetDyn; + + f32 y = pTop; + + //! TODO: the conversion from int to float and back to int is bad for performance, change that + if(alignment & ALIGN_MIDDLE) + { + y = pTop + pHeight * 0.5f * pScaleY - height * 0.5f * getScaleY(); + } + else if(alignment & ALIGN_BOTTOM) + { + y = pTop + pHeight * pScaleY - height * getScaleY(); + } + + return y + yoffset; +} + +void GuiElement::setEffect(int eff, int amount, int target) +{ + if(eff & EFFECT_SLIDE_IN) + { + // these calculations overcompensate a little + if(eff & EFFECT_SLIDE_TOP) + { + if(eff & EFFECT_SLIDE_FROM) + yoffsetDyn = (int) -getHeight()*scaleY; + else + yoffsetDyn = -screenheight; + } + else if(eff & EFFECT_SLIDE_LEFT) + { + if(eff & EFFECT_SLIDE_FROM) + xoffsetDyn = (int) -getWidth()*scaleX; + else + xoffsetDyn = -screenwidth; + } + else if(eff & EFFECT_SLIDE_BOTTOM) + { + if(eff & EFFECT_SLIDE_FROM) + yoffsetDyn = (int) getHeight()*scaleY; + else + yoffsetDyn = screenheight; + } + else if(eff & EFFECT_SLIDE_RIGHT) + { + if(eff & EFFECT_SLIDE_FROM) + xoffsetDyn = (int) getWidth()*scaleX; + else + xoffsetDyn = screenwidth; + } + } + if((eff & EFFECT_FADE) && amount > 0) + { + alphaDyn = 0; + } + else if((eff & EFFECT_FADE) && amount < 0) + { + alphaDyn = alpha; + } + effects |= eff; + effectAmount = amount; + effectTarget = target; +} + +//!Sets an effect to be enabled on wiimote cursor over +//!\param e Effect to enable +//!\param a Amount of the effect (usage varies on effect) +//!\param t Target amount of the effect (usage varies on effect) +void GuiElement::setEffectOnOver(int e, int a, int t) +{ + effectsOver |= e; + effectAmountOver = a; + effectTargetOver = t; +} + +void GuiElement::resetEffects() +{ + yoffsetDyn = 0; + xoffsetDyn = 0; + alphaDyn = -1; + scaleDyn = 1; + effects = EFFECT_NONE; + effectAmount = 0; + effectTarget = 0; + effectsOver = EFFECT_NONE; + effectAmountOver = 0; + effectTargetOver = 0; +} +void GuiElement::updateEffects() +{ + if(!this->isVisible() && parentElement) + return; + + if(effects & (EFFECT_SLIDE_IN | EFFECT_SLIDE_OUT | EFFECT_SLIDE_FROM)) + { + if(effects & EFFECT_SLIDE_IN) + { + if(effects & EFFECT_SLIDE_LEFT) + { + xoffsetDyn += effectAmount; + + if(xoffsetDyn >= 0) + { + xoffsetDyn = 0; + effects = 0; + effectFinished(this); + } + } + else if(effects & EFFECT_SLIDE_RIGHT) + { + xoffsetDyn -= effectAmount; + + if(xoffsetDyn <= 0) + { + xoffsetDyn = 0; + effects = 0; + effectFinished(this); + } + } + else if(effects & EFFECT_SLIDE_TOP) + { + yoffsetDyn += effectAmount; + + if(yoffsetDyn >= 0) + { + yoffsetDyn = 0; + effects = 0; + effectFinished(this); + } + } + else if(effects & EFFECT_SLIDE_BOTTOM) + { + yoffsetDyn -= effectAmount; + + if(yoffsetDyn <= 0) + { + yoffsetDyn = 0; + effects = 0; + effectFinished(this); + } + } + } + else + { + if(effects & EFFECT_SLIDE_LEFT) + { + xoffsetDyn -= effectAmount; + + if(xoffsetDyn <= -screenwidth) { + effects = 0; // shut off effect + effectFinished(this); + } + else if((effects & EFFECT_SLIDE_FROM) && xoffsetDyn <= -getWidth()) { + effects = 0; // shut off effect + effectFinished(this); + } + } + else if(effects & EFFECT_SLIDE_RIGHT) + { + xoffsetDyn += effectAmount; + + if(xoffsetDyn >= screenwidth) { + effects = 0; // shut off effect + effectFinished(this); + } + else if((effects & EFFECT_SLIDE_FROM) && xoffsetDyn >= getWidth()*scaleX) { + effects = 0; // shut off effect + effectFinished(this); + } + } + else if(effects & EFFECT_SLIDE_TOP) + { + yoffsetDyn -= effectAmount; + + if(yoffsetDyn <= -screenheight) { + effects = 0; // shut off effect + effectFinished(this); + } + else if((effects & EFFECT_SLIDE_FROM) && yoffsetDyn <= -getHeight()) { + effects = 0; // shut off effect + effectFinished(this); + } + } + else if(effects & EFFECT_SLIDE_BOTTOM) + { + yoffsetDyn += effectAmount; + + if(yoffsetDyn >= screenheight) { + effects = 0; // shut off effect + effectFinished(this); + } + else if((effects & EFFECT_SLIDE_FROM) && yoffsetDyn >= getHeight()) { + effects = 0; // shut off effect + effectFinished(this); + } + } + } + } + else if(effects & EFFECT_FADE) + { + alphaDyn += effectAmount * (1.0f / 255.0f); + + if(effectAmount < 0 && alphaDyn <= 0) + { + alphaDyn = 0; + effects = 0; // shut off effect + effectFinished(this); + } + else if(effectAmount > 0 && alphaDyn >= alpha) + { + alphaDyn = alpha; + effects = 0; // shut off effect + effectFinished(this); + } + } + else if(effects & EFFECT_SCALE) + { + scaleDyn += effectAmount * 0.01f; + + if((effectAmount < 0 && scaleDyn <= (effectTarget * 0.01f)) + || (effectAmount > 0 && scaleDyn >= (effectTarget * 0.01f))) + { + scaleDyn = effectTarget * 0.01f; + effects = 0; // shut off effect + effectFinished(this); + } + } +} diff --git a/src/gui/GuiElement.h b/src/gui/GuiElement.h new file mode 100644 index 0000000..1981078 --- /dev/null +++ b/src/gui/GuiElement.h @@ -0,0 +1,529 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 GUI_ELEMENT_H_ +#define GUI_ELEMENT_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sigslot.h" +#include "glm/glm.hpp" +#include "glm/gtc/matrix_transform.hpp" + +#include "dynamic_libs/gx2_types.h" +#include "resources/Resources.h" +#include "system/AsyncDeleter.h" +#include "utils/logger.h" + +enum +{ + EFFECT_NONE = 0x00, + EFFECT_SLIDE_TOP = 0x01, + EFFECT_SLIDE_BOTTOM = 0x02, + EFFECT_SLIDE_RIGHT = 0x04, + EFFECT_SLIDE_LEFT = 0x08, + EFFECT_SLIDE_IN = 0x10, + EFFECT_SLIDE_OUT = 0x20, + EFFECT_SLIDE_FROM = 0x40, + EFFECT_FADE = 0x80, + EFFECT_SCALE = 0x100, + EFFECT_COLOR_TRANSITION = 0x200 +}; + +enum +{ + ALIGN_LEFT = 0x01, + ALIGN_CENTER = 0x02, + ALIGN_RIGHT = 0x04, + ALIGN_TOP = 0x10, + ALIGN_MIDDLE = 0x20, + ALIGN_BOTTOM = 0x40, + ALIGN_TOP_LEFT = ALIGN_LEFT | ALIGN_TOP, + ALIGN_TOP_CENTER = ALIGN_CENTER | ALIGN_TOP, + ALIGN_TOP_RIGHT = ALIGN_RIGHT | ALIGN_TOP, + ALIGN_CENTERED = ALIGN_CENTER | ALIGN_MIDDLE, +}; + +//!Forward declaration +class GuiController; +class CVideo; + +//!Primary GUI class. Most other classes inherit from this class. +class GuiElement : public AsyncDeleter::Element +{ + public: + //!Constructor + GuiElement(); + //!Destructor + virtual ~GuiElement() {} + //!Set the element's parent + //!\param e Pointer to parent element + virtual void setParent(GuiElement * e) { parentElement = e; } + //!Gets the element's parent + //!\return Pointer to parent element + virtual GuiElement * getParent() { return parentElement; } + //!Gets the current leftmost coordinate of the element + //!Considers horizontal alignment, x offset, width, and parent element's GetLeft() / GetWidth() values + //!\return left coordinate + virtual f32 getLeft(); + //!Gets the current topmost coordinate of the element + //!Considers vertical alignment, y offset, height, and parent element's GetTop() / GetHeight() values + //!\return top coordinate + virtual f32 getTop(); + //!Gets the current Z coordinate of the element + //!\return Z coordinate + virtual f32 getDepth() + { + f32 zParent = 0.0f; + + if(parentElement) + zParent = parentElement->getDepth(); + + return zParent+zoffset; + } + + virtual f32 getCenterX(void) + { + f32 pCenterX = 0.0f; + + if(parentElement) + pCenterX = parentElement->getCenterX(); + + pCenterX += xoffset + xoffsetDyn; + + if(alignment & ALIGN_LEFT) + { + f32 pWidth = 0.0f; + f32 pScale = 0.0f; + + if(parentElement) + { + pWidth = parentElement->getWidth(); + pScale = parentElement->getScaleX(); + } + + pCenterX -= pWidth * 0.5f * pScale - width * 0.5f * getScaleX(); + } + else if(alignment & ALIGN_RIGHT) + { + f32 pWidth = 0.0f; + f32 pScale = 0.0f; + + if(parentElement) + { + pWidth = parentElement->getWidth(); + pScale = parentElement->getScaleX(); + } + + pCenterX += pWidth * 0.5f * pScale - width * 0.5f * getScaleX(); + } + return pCenterX; + } + + virtual f32 getCenterY(void) + { + f32 pCenterY = 0.0f; + + if(parentElement) + pCenterY = parentElement->getCenterY(); + + pCenterY += yoffset + yoffsetDyn; + + if(alignment & ALIGN_TOP) + { + f32 pHeight = 0.0f; + f32 pScale = 0.0f; + + if(parentElement) + { + pHeight = parentElement->getHeight(); + pScale = parentElement->getScaleY(); + } + + pCenterY += pHeight * 0.5f * pScale - height * 0.5f * getScaleY(); + } + else if(alignment & ALIGN_BOTTOM) + { + f32 pHeight = 0.0f; + f32 pScale = 0.0f; + + if(parentElement) + { + pHeight = parentElement->getHeight(); + pScale = parentElement->getScaleY(); + } + + pCenterY -= pHeight * 0.5f * pScale - height * 0.5f * getScaleY(); + } + return pCenterY; + } + //!Gets elements xoffset + virtual f32 getOffsetX() { return xoffset; } + //!Gets elements yoffset + virtual f32 getOffsetY() { return yoffset; } + //!Gets the current width of the element. Does not currently consider the scale + //!\return width + virtual f32 getWidth() { return width; }; + //!Gets the height of the element. Does not currently consider the scale + //!\return height + virtual f32 getHeight() { return height; } + //!Sets the size (width/height) of the element + //!\param w Width of element + //!\param h Height of element + virtual void setSize(f32 w, f32 h) + { + width = w; + height = h; + } + //!Sets the element's visibility + //!\param v Visibility (true = visible) + virtual void setVisible(bool v) + { + visible = v; + visibleChanged(this, v); + } + //!Checks whether or not the element is visible + //!\return true if visible, false otherwise + virtual bool isVisible() const { return !isStateSet(STATE_HIDDEN) && visible; }; + //!Checks whether or not the element is selectable + //!\return true if selectable, false otherwise + virtual bool isSelectable() + { + return !isStateSet(STATE_DISABLED) && selectable; + } + virtual bool isDrawOverOnlyWhenSelected() + { + return drawOverOnlyWhenSelected; + } + virtual void setdrawOverOnlyWhenSelected(bool s) { drawOverOnlyWhenSelected = s; } + //!Checks whether or not the element is clickable + //!\return true if clickable, false otherwise + virtual bool isClickable() + { + return !isStateSet(STATE_DISABLED) && clickable; + } + //!Checks whether or not the element is holdable + //!\return true if holdable, false otherwise + virtual bool isHoldable() { return !isStateSet(STATE_DISABLED) && holdable; } + //!Sets whether or not the element is selectable + //!\param s Selectable + virtual void setSelectable(bool s) { selectable = s; } + //!Sets whether or not the element is clickable + //!\param c Clickable + virtual void setClickable(bool c) { clickable = c; } + //!Sets whether or not the element is holdable + //!\param c Holdable + virtual void setHoldable(bool d) { holdable = d; } + //!Sets the element's state + //!\param s State (STATE_DEFAULT, STATE_SELECTED, STATE_CLICKED, STATE_DISABLED) + //!\param c Controller channel (0-3, -1 = none) + virtual void setState(int s, int c = -1) + { + if(c >= 0 && c < 4) + { + state[c] |= s; + } + else + { + for(int i = 0; i < 4; i++) + state[i] |= s; + } + stateChan = c; + stateChanged(this, s, c); + } + virtual void clearState(int s, int c = -1) + { + if(c >= 0 && c < 4) + { + state[c] &= ~s; + } + else + { + for(int i = 0; i < 4; i++) + state[i] &= ~s; + } + stateChan = c; + stateChanged(this, s, c); + } + virtual bool isStateSet(int s, int c = -1) const + { + if(c >= 0 && c < 4) + { + return (state[c] & s) != 0; + } + else + { + for(int i = 0; i < 4; i++) + if((state[i] & s) != 0) + return true; + + return false; + } + } + //!Gets the element's current state + //!\return state + virtual int getState(int c = 0) { return state[c]; }; + //!Gets the controller channel that last changed the element's state + //!\return Channel number (0-3, -1 = no channel) + virtual int getStateChan() { return stateChan; }; + //!Resets the element's state to STATE_DEFAULT + virtual void resetState() + { + for(int i = 0; i < 4; i++) + state[i] = STATE_DEFAULT; + stateChan = -1; + } + //!Sets the element's alpha value + //!\param a alpha value + virtual void setAlpha(f32 a) { alpha = a; } + //!Gets the element's alpha value + //!Considers alpha, alphaDyn, and the parent element's getAlpha() value + //!\return alpha + virtual f32 getAlpha() + { + f32 a; + + if(alphaDyn >= 0) + a = alphaDyn; + else + a = alpha; + + if(parentElement) + a = (a * parentElement->getAlpha()); + + return a; + } + //!Sets the element's scale + //!\param s scale (1 is 100%) + virtual void setScale(float s) + { + scaleX = s; + scaleY = s; + scaleZ = s; + } + //!Sets the element's scale + //!\param s scale (1 is 100%) + virtual void setScaleX(float s) { scaleX = s; } + //!Sets the element's scale + //!\param s scale (1 is 100%) + virtual void setScaleY(float s) { scaleY = s; } + //!Sets the element's scale + //!\param s scale (1 is 100%) + virtual void setScaleZ(float s) { scaleZ = s; } + //!Gets the element's current scale + //!Considers scale, scaleDyn, and the parent element's getScale() value + virtual float getScale() + { + float s = 0.5f * (scaleX+scaleY) * scaleDyn; + + if(parentElement) + s *= parentElement->getScale(); + + return s; + } + //!Gets the element's current scale + //!Considers scale, scaleDyn, and the parent element's getScale() value + virtual float getScaleX() + { + float s = scaleX * scaleDyn; + + if(parentElement) + s *= parentElement->getScaleX(); + + return s; + } + //!Gets the element's current scale + //!Considers scale, scaleDyn, and the parent element's getScale() value + virtual float getScaleY() + { + float s = scaleY * scaleDyn; + + if(parentElement) + s *= parentElement->getScaleY(); + + return s; + } + //!Gets the element's current scale + //!Considers scale, scaleDyn, and the parent element's getScale() value + virtual float getScaleZ() + { + float s = scaleZ; + + if(parentElement) + s *= parentElement->getScaleZ(); + + return s; + } + //!Checks whether rumble was requested by the element + //!\return true is rumble was requested, false otherwise + virtual bool isRumbleActive() { return rumble; } + //!Sets whether or not the element is requesting a rumble event + //!\param r true if requesting rumble, false if not + virtual void setRumble(bool r) { rumble = r; } + //!Set an effect for the element + //!\param e Effect to enable + //!\param a Amount of the effect (usage varies on effect) + //!\param t Target amount of the effect (usage varies on effect) + virtual void setEffect(int e, int a, int t=0); + //!Sets an effect to be enabled on wiimote cursor over + //!\param e Effect to enable + //!\param a Amount of the effect (usage varies on effect) + //!\param t Target amount of the effect (usage varies on effect) + virtual void setEffectOnOver(int e, int a, int t=0); + //!Shortcut to SetEffectOnOver(EFFECT_SCALE, 4, 110) + virtual void setEffectGrow() { setEffectOnOver(EFFECT_SCALE, 4, 110); } + //!Reset all applied effects + virtual void resetEffects(); + //!Gets the current element effects + //!\return element effects + virtual int getEffect() const { return effects; } + //!\return true if element animation is on going + virtual bool isAnimated() const { return (parentElement != 0) && (getEffect() > 0); } + //!Checks whether the specified coordinates are within the element's boundaries + //!\param x X coordinate + //!\param y Y coordinate + //!\return true if contained within, false otherwise + virtual bool isInside(f32 x, f32 y) + { + return ( x > (this->getCenterX() - getScaleX() * getWidth() * 0.5f) + && x < (this->getCenterX() + getScaleX() * getWidth() * 0.5f) + && y > (this->getCenterY() - getScaleY() * getHeight() * 0.5f) + && y < (this->getCenterY() + getScaleY() * getHeight() * 0.5f)); + } + //!Sets the element's position + //!\param x X coordinate + //!\param y Y coordinate + virtual void setPosition(f32 x, f32 y) + { + xoffset = x; + yoffset = y; + } + //!Sets the element's position + //!\param x X coordinate + //!\param y Y coordinate + //!\param z Z coordinate + virtual void setPosition(f32 x, f32 y, f32 z) + { + xoffset = x; + yoffset = y; + zoffset = z; + } + //!Gets whether or not the element is in STATE_SELECTED + //!\return true if selected, false otherwise + virtual int getSelected() { return -1; } + //!Sets the element's alignment respective to its parent element + //!Bitwise ALIGN_LEFT | ALIGN_RIGHT | ALIGN_CENTRE, ALIGN_TOP, ALIGN_BOTTOM, ALIGN_MIDDLE) + //!\param align Alignment + virtual void setAlignment(int a) { alignment = a; } + //!Gets the element's alignment + virtual int getAlignment() const { return alignment; } + //!Angle of the object + virtual void setAngle(f32 a) { angle = a; } + //!Angle of the object + virtual f32 getAngle() const { f32 r_angle = angle; if(parentElement) r_angle += parentElement->getAngle(); return r_angle; } + //!Called constantly to allow the element to respond to the current input data + //!\param t Pointer to a GuiController, containing the current input data from PAD/WPAD/VPAD + virtual void update(GuiController * t) { } + //!Called constantly to redraw the element + virtual void draw(CVideo * v) { } + //!Called constantly to process stuff in the element + virtual void process() { } + + //!Updates the element's effects (dynamic values) + //!Called by Draw(), used for animation purposes + virtual void updateEffects(); + + typedef struct _POINT { + s32 x; + s32 y; + } POINT; + + enum + { + STATE_DEFAULT = 0, + STATE_SELECTED = 0x01, + STATE_CLICKED = 0x02, + STATE_HELD = 0x04, + STATE_OVER = 0x08, + STATE_HIDDEN = 0x10, + STATE_DISABLE_INPUT = 0x20, + STATE_CLICKED_TOUCH = 0x40, + STATE_DISABLED = 0x80 + }; + + //! Switch pointer from control to screen position + POINT PtrToScreen(POINT p) + { + //! TODO for 3D + //POINT r = { p.x + getLeft(), p.y + getTop() }; + return p; + } + //! Switch pointer screen to control position + POINT PtrToControl(POINT p) + { + //! TODO for 3D + //POINT r = { p.x - getLeft(), p.y - getTop() }; + return p; + } + //! Signals + sigslot::signal2 visibleChanged; + sigslot::signal3 stateChanged; + sigslot::signal1 effectFinished; + protected: + bool rumble; //!< Wiimote rumble (on/off) - set to on when this element requests a rumble event + bool visible; //!< Visibility of the element. If false, Draw() is skipped + bool selectable; //!< Whether or not this element selectable (can change to SELECTED state) + bool clickable; //!< Whether or not this element is clickable (can change to CLICKED state) + bool holdable; //!< Whether or not this element is holdable (can change to HELD state) + bool drawOverOnlyWhenSelected; //!< Whether or not this element is holdable (can change to HELD state) + f32 width; //!< Element width + f32 height; //!< Element height + f32 xoffset; //!< Element X offset + f32 yoffset; //!< Element Y offset + f32 zoffset; //!< Element Z offset + f32 alpha; //!< Element alpha value (0-255) + f32 angle; //!< Angle of the object (0-360) + f32 scaleX; //!< Element scale (1 = 100%) + f32 scaleY; //!< Element scale (1 = 100%) + f32 scaleZ; //!< Element scale (1 = 100%) + int alignment; //!< Horizontal element alignment, respective to parent element + int state[4]; //!< Element state (DEFAULT, SELECTED, CLICKED, DISABLED) + int stateChan; //!< Which controller channel is responsible for the last change in state + GuiElement * parentElement; //!< Parent element + + //! TODO: Move me to some Animator class + int xoffsetDyn; //!< Element X offset, dynamic (added to xoffset value for animation effects) + int yoffsetDyn; //!< Element Y offset, dynamic (added to yoffset value for animation effects) + f32 alphaDyn; //!< Element alpha, dynamic (multiplied by alpha value for blending/fading effects) + f32 scaleDyn; //!< Element scale, dynamic (multiplied by alpha value for blending/fading effects) + int effects; //!< Currently enabled effect(s). 0 when no effects are enabled + int effectAmount; //!< Effect amount. Used by different effects for different purposes + int effectTarget; //!< Effect target amount. Used by different effects for different purposes + int effectsOver; //!< Effects to enable when wiimote cursor is over this element. Copied to effects variable on over event + int effectAmountOver; //!< EffectAmount to set when wiimote cursor is over this element + int effectTargetOver; //!< EffectTarget to set when wiimote cursor is over this element +}; + +#endif diff --git a/src/gui/GuiFrame.cpp b/src/gui/GuiFrame.cpp new file mode 100644 index 0000000..ac37917 --- /dev/null +++ b/src/gui/GuiFrame.cpp @@ -0,0 +1,230 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include "GuiFrame.h" + +GuiFrame::GuiFrame(GuiFrame *p) +{ + parent = p; + width = 0; + height = 0; + dim = false; + + if(parent) + parent->append(this); +} + +GuiFrame::GuiFrame(f32 w, f32 h, GuiFrame *p) +{ + parent = p; + width = w; + height = h; + dim = false; + + if(parent) + parent->append(this); +} + +GuiFrame::~GuiFrame() +{ + closing(this); + + if(parent) + parent->remove(this); +} + +void GuiFrame::append(GuiElement* e) +{ + if (e == NULL) + return; + + remove(e); + elements.push_back(e); + e->setParent(this); +} + +void GuiFrame::insert(GuiElement* e, u32 index) +{ + if (e == NULL || (index >= elements.size())) + return; + + remove(e); + elements.insert(elements.begin()+index, e); + e->setParent(this); +} + +void GuiFrame::remove(GuiElement* e) +{ + if (e == NULL) + return; + + for (u32 i = 0; i < elements.size(); ++i) + { + if(e == elements[i]) + { + elements.erase(elements.begin()+i); + break; + } + } +} + +void GuiFrame::removeAll() +{ + elements.clear(); +} + +void GuiFrame::close() +{ + //Application::instance()->pushForDelete(this); +} + +void GuiFrame::dimBackground(bool d) +{ + dim = d; +} + +GuiElement* GuiFrame::getGuiElementAt(u32 index) const +{ + if (index >= elements.size()) + return NULL; + return elements[index]; +} + +u32 GuiFrame::getSize() +{ + return elements.size(); +} + +void GuiFrame::resetState() +{ + GuiElement::resetState(); + + for (u32 i = 0; i < elements.size(); ++i) + { + elements[i]->resetState(); + } +} + +void GuiFrame::setState(int s, int c) +{ + GuiElement::setState(s, c); + + for (u32 i = 0; i < elements.size(); ++i) + { + elements[i]->setState(s, c); + } +} + +void GuiFrame::clearState(int s, int c) +{ + GuiElement::clearState(s, c); + + for (u32 i = 0; i < elements.size(); ++i) + { + elements[i]->clearState(s, c); + } +} + +void GuiFrame::setVisible(bool v) +{ + visible = v; + + for (u32 i = 0; i < elements.size(); ++i) + { + elements[i]->setVisible(v); + } +} + +int GuiFrame::getSelected() +{ + // find selected element + int found = -1; + for (u32 i = 0; i < elements.size(); ++i) + { + if(elements[i]->isStateSet(STATE_SELECTED | STATE_OVER)) + { + found = i; + break; + } + } + return found; +} + +void GuiFrame::draw(CVideo * v) +{ + if(!this->isVisible() && parentElement) + return; + + if(parentElement && dim == true) + { + //GXColor dimColor = (GXColor){0, 0, 0, 0x70}; + //Menu_DrawRectangle(0, 0, GetZPosition(), screenwidth,screenheight, &dimColor, false, true); + } + + //! render appended items next frame but allow stop of render if size is reached + u32 size = elements.size(); + + for (u32 i = 0; i < size && i < elements.size(); ++i) + { + elements[i]->draw(v); + } +} + +void GuiFrame::updateEffects() +{ + if(!this->isVisible() && parentElement) + return; + + GuiElement::updateEffects(); + + //! render appended items next frame but allow stop of render if size is reached + u32 size = elements.size(); + + for (u32 i = 0; i < size && i < elements.size(); ++i) + { + elements[i]->updateEffects(); + } +} + +void GuiFrame::process() +{ + if(!this->isVisible() && parentElement) + return; + + GuiElement::process(); + + //! render appended items next frame but allow stop of render if size is reached + u32 size = elements.size(); + + for (u32 i = 0; i < size && i < elements.size(); ++i) + { + elements[i]->process(); + } +} + +void GuiFrame::update(GuiController * c) +{ + if(isStateSet(STATE_DISABLED) && parentElement) + return; + + //! update appended items next frame + u32 size = elements.size(); + + for (u32 i = 0; i < size && i < elements.size(); ++i) + { + elements[i]->update(c); + } +} diff --git a/src/gui/GuiFrame.h b/src/gui/GuiFrame.h new file mode 100644 index 0000000..e0a5c36 --- /dev/null +++ b/src/gui/GuiFrame.h @@ -0,0 +1,98 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 GUI_FRAME_H_ +#define GUI_FRAME_H_ + +#include +#include "GuiElement.h" +#include "sigslot.h" + +//!Allows GuiElements to be grouped together into a "window" +class GuiFrame : public GuiElement +{ + public: + //!Constructor + GuiFrame(GuiFrame *parent = 0); + //!\overload + //!\param w Width of window + //!\param h Height of window + GuiFrame(f32 w, f32 h, GuiFrame *parent = 0); + //!Destructor + virtual ~GuiFrame(); + //!Appends a GuiElement to the GuiFrame + //!\param e The GuiElement to append. If it is already in the GuiFrame, it is removed first + void append(GuiElement* e); + //!Inserts a GuiElement into the GuiFrame at the specified index + //!\param e The GuiElement to insert. If it is already in the GuiFrame, it is removed first + //!\param i Index in which to insert the element + void insert(GuiElement* e, u32 i); + //!Removes the specified GuiElement from the GuiFrame + //!\param e GuiElement to be removed + void remove(GuiElement* e); + //!Removes all GuiElements + void removeAll(); + //!Bring element to front of the window + void bringToFront(GuiElement *e) { remove(e); append(e); } + //!Returns the GuiElement at the specified index + //!\param index The index of the element + //!\return A pointer to the element at the index, NULL on error (eg: out of bounds) + GuiElement* getGuiElementAt(u32 index) const; + //!Returns the size of the list of elements + //!\return The size of the current element list + u32 getSize(); + //!Sets the visibility of the window + //!\param v visibility (true = visible) + void setVisible(bool v); + //!Resets the window's state to STATE_DEFAULT + void resetState(); + //!Sets the window's state + //!\param s State + void setState(int s, int c = -1); + void clearState(int s, int c = -1); + //!Gets the index of the GuiElement inside the window that is currently selected + //!\return index of selected GuiElement + int getSelected(); + //!Dim the Window's background + void dimBackground(bool d); + //!Draws all the elements in this GuiFrame + void draw(CVideo * v); + //!Updates the window and all elements contains within + //!Allows the GuiFrame and all elements to respond to the input data specified + //!\param t Pointer to a GuiTrigger, containing the current input data from PAD/WPAD + void update(GuiController * t); + //!virtual Close Window - this will put the object on the delete queue in MainWindow + virtual void close(); + //!virtual show window function + virtual void show() {} + //!virtual hide window function + virtual void hide() {} + //!virtual enter main loop function (blocking) + virtual void exec() {} + //!virtual updateEffects which is called by the main loop + virtual void updateEffects(); + //!virtual process which is called by the main loop + virtual void process(); + //! Signals + //! On Closing + sigslot::signal1 closing; + protected: + bool dim; //! Enable/disable dim of a window only + GuiFrame *parent; //!< Parent Window + std::vector elements; //!< Contains all elements within the GuiFrame +}; + +#endif diff --git a/src/gui/GuiImage.cpp b/src/gui/GuiImage.cpp new file mode 100644 index 0000000..344b770 --- /dev/null +++ b/src/gui/GuiImage.cpp @@ -0,0 +1,289 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include "GuiImage.h" +#include "video/CVideo.h" +#include "video/shaders/Texture2DShader.h" +#include "video/shaders/ColorShader.h" + +static const f32 fPiDiv180 = ((f32)M_PI / 180.0f); + +GuiImage::GuiImage(GuiImageData * img) +{ + if(img && img->getTexture()) + { + width = img->getWidth(); + height = img->getHeight(); + } + + internalInit(width, height); + imageData = img; +} + +GuiImage::GuiImage(int w, int h, const GX2Color & c, int type) +{ + internalInit(w, h); + imgType = type; + colorCount = ColorShader::cuColorVtxsSize / ColorShader::cuColorAttrSize; + + colorVtxs = (u8 *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, colorCount * ColorShader::cuColorAttrSize); + if(colorVtxs) + { + for(u32 i = 0; i < colorCount; i++) + setImageColor(c, i); + } +} + +GuiImage::GuiImage(int w, int h, const GX2Color *c, u32 color_count, int type) +{ + internalInit(w, h); + imgType = type; + colorCount = ColorShader::cuColorVtxsSize / ColorShader::cuColorAttrSize; + if(colorCount < color_count) + colorCount = color_count; + + colorVtxs = (u8 *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, colorCount * ColorShader::cuColorAttrSize); + if(colorVtxs) + { + for(u32 i = 0; i < colorCount; i++) + { + // take the last as reference if not enough colors defined + int idx = (i < color_count) ? i : (color_count - 1); + setImageColor(c[idx], i); + } + } +} + +/** + * Destructor for the GuiImage class. + */ +GuiImage::~GuiImage() +{ + if(colorVtxs) { + free(colorVtxs); + colorVtxs = NULL; + } +} + +void GuiImage::internalInit(int w, int h) +{ + imageData = NULL; + width = w; + height = h; + tileHorizontal = -1; + tileVertical = -1; + imgType = IMAGE_TEXTURE; + colorVtxsDirty = false; + colorVtxs = NULL; + colorCount = 0; + posVtxs = NULL; + texCoords = NULL; + vtxCount = 4; + primitive = GX2_PRIMITIVE_QUADS; + + imageAngle = 0.0f; + blurDirection = glm::vec3(0.0f); + positionOffsets = glm::vec3(0.0f); + scaleFactor = glm::vec3(1.0f); + colorIntensity = glm::vec4(1.0f); +} + +void GuiImage::setImageData(GuiImageData * img) +{ + imageData = img; + width = 0; + height = 0; + if(img && img->getTexture()) + { + width = img->getWidth(); + height = img->getHeight(); + } + imgType = IMAGE_TEXTURE; +} + +GX2Color GuiImage::getPixel(int x, int y) +{ + if(!imageData || this->getWidth() <= 0 || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight()) + return (GX2Color){0, 0, 0, 0}; + + u32 pitch = imageData->getTexture()->surface.pitch; + u32 *imagePtr = (u32*)imageData->getTexture()->surface.image_data; + + u32 color_u32 = imagePtr[y * pitch + x]; + GX2Color color; + color.r = (color_u32 >> 24) & 0xFF; + color.g = (color_u32 >> 16) & 0xFF; + color.b = (color_u32 >> 8) & 0xFF; + color.a = (color_u32 >> 0) & 0xFF; + return color; +} + +void GuiImage::setPixel(int x, int y, const GX2Color & color) +{ + if(!imageData || this->getWidth() <= 0 || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight()) + return; + + + u32 pitch = imageData->getTexture()->surface.pitch; + u32 *imagePtr = (u32*)imageData->getTexture()->surface.image_data; + imagePtr[y * pitch + x] = (color.r << 24) | (color.g << 16) | (color.b << 8) | (color.a << 0); +} + +void GuiImage::setImageColor(const GX2Color & c, int idx) +{ + if(!colorVtxs) { + return; + } + + if(idx >= 0 && idx < (int)colorCount) + { + colorVtxs[(idx << 2) + 0] = c.r; + colorVtxs[(idx << 2) + 1] = c.g; + colorVtxs[(idx << 2) + 2] = c.b; + colorVtxs[(idx << 2) + 3] = c.a; + colorVtxsDirty = true; + } + else if(colorVtxs) + { + for(u32 i = 0; i < (ColorShader::cuColorVtxsSize / sizeof(u8)); i += 4) + { + colorVtxs[i + 0] = c.r; + colorVtxs[i + 1] = c.g; + colorVtxs[i + 2] = c.b; + colorVtxs[i + 3] = c.a; + } + colorVtxsDirty = true; + } +} + +void GuiImage::setSize(int w, int h) +{ + width = w; + height = h; +} + +void GuiImage::setPrimitiveVertex(s32 prim, const f32 *posVtx, const f32 *texCoord, u32 vtxcount) +{ + primitive = prim; + vtxCount = vtxcount; + posVtxs = posVtx; + texCoords = texCoord; + + if(imgType == IMAGE_COLOR) + { + u8 * newColorVtxs = (u8 *) memalign(0x40, ColorShader::cuColorAttrSize * vtxCount); + + for(u32 i = 0; i < vtxCount; i++) + { + int newColorIdx = (i << 2); + int colorIdx = (i < colorCount) ? (newColorIdx) : ((colorCount - 1) << 2); + + newColorVtxs[newColorIdx + 0] = colorVtxs[colorIdx + 0]; + newColorVtxs[newColorIdx + 1] = colorVtxs[colorIdx + 1]; + newColorVtxs[newColorIdx + 2] = colorVtxs[colorIdx + 2]; + newColorVtxs[newColorIdx + 3] = colorVtxs[colorIdx + 3]; + } + + free(colorVtxs); + colorVtxs = newColorVtxs; + colorCount = vtxCount; + colorVtxsDirty = true; + } +} + +void GuiImage::draw(CVideo *pVideo) +{ + if(!this->isVisible() || tileVertical == 0 || tileHorizontal == 0) + return; + + f32 currScaleX = getScaleX(); + f32 currScaleY = getScaleY(); + + positionOffsets[0] = getCenterX() * pVideo->getWidthScaleFactor() * 2.0f; + positionOffsets[1] = getCenterY() * pVideo->getHeightScaleFactor() * 2.0f; + positionOffsets[2] = getDepth() * pVideo->getDepthScaleFactor() * 2.0f; + + scaleFactor[0] = currScaleX * getWidth() * pVideo->getWidthScaleFactor(); + scaleFactor[1] = currScaleY * getHeight() * pVideo->getHeightScaleFactor(); + scaleFactor[2] = getScaleZ(); + + //! add other colors intensities parameters + colorIntensity[3] = getAlpha(); + + //! angle of the object + imageAngle = DegToRad(getAngle()); + +// if(image && tileHorizontal > 0 && tileVertical > 0) +// { +// for(int n=0; n 0) +// { +// for(int i=0; i 0) +// { +// for(int i=0; isetShaders(); + ColorShader::instance()->setAttributeBuffer(colorVtxs, posVtxs, vtxCount); + ColorShader::instance()->setAngle(imageAngle); + ColorShader::instance()->setOffset(positionOffsets); + ColorShader::instance()->setScale(scaleFactor); + ColorShader::instance()->setColorIntensity(colorIntensity); + ColorShader::instance()->draw(primitive, vtxCount); + } + else if(imageData) + { + Texture2DShader::instance()->setShaders(); + Texture2DShader::instance()->setAttributeBuffer(texCoords, posVtxs, vtxCount); + Texture2DShader::instance()->setAngle(imageAngle); + Texture2DShader::instance()->setOffset(positionOffsets); + Texture2DShader::instance()->setScale(scaleFactor); + Texture2DShader::instance()->setColorIntensity(colorIntensity); + Texture2DShader::instance()->setBlurring(blurDirection); + Texture2DShader::instance()->setTextureAndSampler(imageData->getTexture(), imageData->getSampler()); + Texture2DShader::instance()->draw(primitive, vtxCount); + } +} diff --git a/src/gui/GuiImage.h b/src/gui/GuiImage.h new file mode 100644 index 0000000..88f7fbe --- /dev/null +++ b/src/gui/GuiImage.h @@ -0,0 +1,110 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 GUI_IMAGE_H_ +#define GUI_IMAGE_H_ + +#include "video/shaders/Shader.h" +#include "GuiElement.h" +#include "GuiImageData.h" + +//!Display, manage, and manipulate images in the GUI +class GuiImage : public GuiElement +{ +public: + enum ImageTypes + { + IMAGE_TEXTURE, + IMAGE_COLOR + }; + + //!\overload + //!\param img Pointer to GuiImageData element + GuiImage(GuiImageData * img); + //!\overload + //!Creates an image filled with the specified color + //!\param w Image width + //!\param h Image height + //!\param c Array with 4 x image color (BL, BR, TL, TR) + GuiImage(int w, int h, const GX2Color & c, int imgType = IMAGE_COLOR); + GuiImage(int w, int h, const GX2Color * c, u32 colorCount = 1, int imgType = IMAGE_COLOR); + //!Destructor + virtual ~GuiImage(); + //!Sets the number of times to draw the image horizontally + //!\param t Number of times to draw the image + void setTileHorizontal(int t) { tileHorizontal = t; } + //!Sets the number of times to draw the image vertically + //!\param t Number of times to draw the image + void setTileVertical(int t) { tileVertical = t; } + //!Constantly called to draw the image + void draw(CVideo *pVideo); + //!Gets the image data + //!\return pointer to image data + GuiImageData * getImageData() const { return imageData; } + //!Sets up a new image using the GuiImageData object specified + //!\param img Pointer to GuiImageData object + void setImageData(GuiImageData * img); + //!Gets the pixel color at the specified coordinates of the image + //!\param x X coordinate + //!\param y Y coordinate + GX2Color getPixel(int x, int y); + //!Sets the pixel color at the specified coordinates of the image + //!\param x X coordinate + //!\param y Y coordinate + //!\param color Pixel color + void setPixel(int x, int y, const GX2Color & color); + //!Change ImageColor + void setImageColor(const GX2Color & c, int idx = -1); + //!Change ImageColor + void setSize(int w, int h); + + void setPrimitiveVertex(s32 prim, const f32 *pos, const f32 *tex, u32 count); + + void setBlurDirection(u8 dir, f32 value) + { + if(dir < 2) { + blurDirection[dir] = value; + } + } + void setColorIntensity(const glm::vec4 & col) + { + colorIntensity = col; + } +protected: + void internalInit(int w, int h); + + int imgType; //!< Type of image data (IMAGE_TEXTURE, IMAGE_COLOR, IMAGE_DATA) + GuiImageData * imageData; //!< Poiner to image data. May be shared with GuiImageData data + int tileHorizontal; //!< Number of times to draw (tile) the image horizontally + int tileVertical; //!< Number of times to draw (tile) the image vertically + + //! Internally used variables for rendering + u8 *colorVtxs; + u32 colorCount; + bool colorVtxsDirty; + glm::vec3 positionOffsets; + glm::vec3 scaleFactor; + glm::vec4 colorIntensity; + f32 imageAngle; + glm::vec3 blurDirection; + + const f32 * posVtxs; + const f32 * texCoords; + u32 vtxCount; + s32 primitive; +}; + +#endif diff --git a/src/gui/GuiImageAsync.cpp b/src/gui/GuiImageAsync.cpp new file mode 100644 index 0000000..f798997 --- /dev/null +++ b/src/gui/GuiImageAsync.cpp @@ -0,0 +1,173 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include +#include "GuiImageAsync.h" +#include "fs/fs_utils.h" + +std::vector GuiImageAsync::imageQueue; +CThread * GuiImageAsync::pThread = NULL; +CMutex * GuiImageAsync::pMutex = NULL; +u32 GuiImageAsync::threadRefCounter = 0; +bool GuiImageAsync::bExitRequested = false; +GuiImageAsync * GuiImageAsync::pInUse = NULL; + +GuiImageAsync::GuiImageAsync(const u8 *imageBuffer, const u32 & imageBufferSize, GuiImageData * preloadImg) + : GuiImage(preloadImg) + , imgData(NULL) + , imgBuffer(imageBuffer) + , imgBufferSize(imageBufferSize) +{ + threadInit(); + threadAddImage(this); +} + +GuiImageAsync::GuiImageAsync(const std::string & file, GuiImageData * preloadImg) + : GuiImage(preloadImg) + , imgData(NULL) + , filename(file) + , imgBuffer(NULL) + , imgBufferSize(0) +{ + threadInit(); + threadAddImage(this); +} + +GuiImageAsync::~GuiImageAsync() +{ + threadRemoveImage(this); + while(pInUse == this) + usleep(1000); + + if (imgData) + delete imgData; + + //threadExit(); +} + +void GuiImageAsync::threadAddImage(GuiImageAsync *Image) +{ + pMutex->lock(); + imageQueue.push_back(Image); + pMutex->unlock(); + pThread->resumeThread(); +} + +void GuiImageAsync::threadRemoveImage(GuiImageAsync *image) +{ + pMutex->lock(); + for(u32 i = 0; i < imageQueue.size(); ++i) + { + if(imageQueue[i] == image) + { + imageQueue.erase(imageQueue.begin() + i); + break; + } + } + pMutex->unlock(); +} + +void GuiImageAsync::clearQueue() +{ + pMutex->lock(); + imageQueue.clear(); + pMutex->unlock(); +} + +void GuiImageAsync::guiImageAsyncThread(CThread *thread, void *arg) +{ + while(!bExitRequested) + { + if(imageQueue.empty() && !bExitRequested) + pThread->suspendThread(); + + if(!imageQueue.empty() && !bExitRequested) + { + pMutex->lock(); + pInUse = imageQueue.front(); + imageQueue.erase(imageQueue.begin()); + pMutex->unlock(); + + if (!pInUse) + continue; + + + if(pInUse->imgBuffer && pInUse->imgBufferSize) + { + pInUse->imgData = new GuiImageData(pInUse->imgBuffer, pInUse->imgBufferSize); + } + else + { + u8 *buffer = NULL; + u32 bufferSize = 0; + + int iResult = LoadFileToMem(pInUse->filename.c_str(), &buffer, &bufferSize); + if(iResult > 0) + { + pInUse->imgData = new GuiImageData(buffer, bufferSize, GX2_TEX_CLAMP_MIRROR); + + //! free original image buffer which is converted to texture now and not needed anymore + free(buffer); + } + } + + if(pInUse->imgData) + { + if(pInUse->imgData->getTexture()) + { + pInUse->width = pInUse->imgData->getWidth(); + pInUse->height = pInUse->imgData->getHeight(); + pInUse->imageData = pInUse->imgData; + } + else + { + delete pInUse->imgData; + pInUse->imgData = NULL; + } + } + pInUse->imageLoaded(pInUse); + pInUse = NULL; + } + } +} + +void GuiImageAsync::threadInit() +{ + if (pThread == NULL) + { + bExitRequested = false; + pMutex = new CMutex(); + pThread = CThread::create(GuiImageAsync::guiImageAsyncThread, NULL, CThread::eAttributeAffCore1 | CThread::eAttributePinnedAff, 10); + pThread->resumeThread(); + } + + ++threadRefCounter; +} + +void GuiImageAsync::threadExit() +{ + if(threadRefCounter) + --threadRefCounter; + + if(/*(threadRefCounter == 0) &&*/ (pThread != NULL)) + { + bExitRequested = true; + delete pThread; + delete pMutex; + pThread = NULL; + pMutex = NULL; + } +} diff --git a/src/gui/GuiImageAsync.h b/src/gui/GuiImageAsync.h new file mode 100644 index 0000000..bf2622a --- /dev/null +++ b/src/gui/GuiImageAsync.h @@ -0,0 +1,62 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 _GUIIMAGEASYNC_H_ +#define _GUIIMAGEASYNC_H_ + +#include +#include "GuiImage.h" +#include "system/CThread.h" +#include "system/CMutex.h" +#include "dynamic_libs/os_functions.h" + +class GuiImageAsync : public GuiImage +{ + public: + GuiImageAsync(const u8 *imageBuffer, const u32 & imageBufferSize, GuiImageData * preloadImg); + GuiImageAsync(const std::string & filename, GuiImageData * preloadImg); + virtual ~GuiImageAsync(); + + static void clearQueue(); + static void removeFromQueue(GuiImageAsync * image) { + threadRemoveImage(image); + } + + //! don't forget to LOCK GUI if using this asynchron call + sigslot::signal1 imageLoaded; + static void threadExit(); + + private: + static void threadInit(); + + GuiImageData *imgData; + std::string filename; + const u8 *imgBuffer; + const u32 imgBufferSize; + + static void guiImageAsyncThread(CThread *thread, void *arg); + static void threadAddImage(GuiImageAsync* Image); + static void threadRemoveImage(GuiImageAsync* Image); + + static std::vector imageQueue; + static CThread *pThread; + static CMutex * pMutex; + static u32 threadRefCounter; + static GuiImageAsync * pInUse; + static bool bExitRequested; +}; + +#endif /*_GUIIMAGEASYNC_H_*/ diff --git a/src/gui/GuiImageData.cpp b/src/gui/GuiImageData.cpp new file mode 100644 index 0000000..7e9a790 --- /dev/null +++ b/src/gui/GuiImageData.cpp @@ -0,0 +1,207 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include +#include +#include "GuiImageData.h" +#include "system/memory.h" +/** + * Constructor for the GuiImageData class. + */ +GuiImageData::GuiImageData() +{ + texture = NULL; + sampler = NULL; + memoryType = eMemTypeMEM2; +} + +/** + * Constructor for the GuiImageData class. + */ +GuiImageData::GuiImageData(const u8 * img, int imgSize, int textureClamp, int textureFormat) +{ + texture = NULL; + sampler = NULL; + loadImage(img, imgSize, textureClamp, textureFormat); +} + +/** + * Destructor for the GuiImageData class. + */ +GuiImageData::~GuiImageData() +{ + releaseData(); +} + +void GuiImageData::releaseData(void) +{ + if(texture) { + if(texture->surface.image_data) + { + switch(memoryType) + { + default: + case eMemTypeMEM2: + free(texture->surface.image_data); + break; + case eMemTypeMEM1: + MEM1_free(texture->surface.image_data); + break; + case eMemTypeMEMBucket: + MEMBucket_free(texture->surface.image_data); + break; + } + } + delete texture; + texture = NULL; + } + if(sampler) { + delete sampler; + sampler = NULL; + } +} + +void GuiImageData::loadImage(const u8 *img, int imgSize, int textureClamp, int textureFormat) +{ + if(!img || (imgSize < 8)) + return; + + releaseData(); + gdImagePtr gdImg = 0; + + if (img[0] == 0xFF && img[1] == 0xD8) + { + //! not needed for now therefore comment out to safe ELF size + //! if needed uncomment, adds 200 kb to the ELF size + // IMAGE_JPEG + gdImg = gdImageCreateFromJpegPtr(imgSize, (u8*) img); + } + else if (img[0] == 'B' && img[1] == 'M') + { + // IMAGE_BMP + gdImg = gdImageCreateFromBmpPtr(imgSize, (u8*) img); + } + else if (img[0] == 0x89 && img[1] == 'P' && img[2] == 'N' && img[3] == 'G') + { + // IMAGE_PNG + gdImg = gdImageCreateFromPngPtr(imgSize, (u8*) img); + } + //!This must be last since it can also intefere with outher formats + else if(img[0] == 0x00) + { + // Try loading TGA image + gdImg = gdImageCreateFromTgaPtr(imgSize, (u8*) img); + } + + if(gdImg == 0) + return; + + u32 width = (gdImageSX(gdImg)); + u32 height = (gdImageSY(gdImg)); + + //! Initialize texture + texture = new GX2Texture; + GX2InitTexture(texture, width, height, 1, 0, textureFormat, GX2_SURFACE_DIM_2D, GX2_TILE_MODE_LINEAR_ALIGNED); + + //! if this fails something went horribly wrong + if(texture->surface.image_size == 0) { + delete texture; + texture = NULL; + gdImageDestroy(gdImg); + return; + } + + //! allocate memory for the surface + memoryType = eMemTypeMEM2; + texture->surface.image_data = memalign(texture->surface.align, texture->surface.image_size); + //! try MEM1 on failure + if(!texture->surface.image_data) { + memoryType = eMemTypeMEM1; + texture->surface.image_data = MEM1_alloc(texture->surface.image_size, texture->surface.align); + } + //! try MEM bucket on failure + if(!texture->surface.image_data) { + memoryType = eMemTypeMEMBucket; + texture->surface.image_data = MEMBucket_alloc(texture->surface.image_size, texture->surface.align); + } + //! check if memory is available for image + if(!texture->surface.image_data) { + gdImageDestroy(gdImg); + delete texture; + texture = NULL; + return; + } + //! set mip map data pointer + texture->surface.mip_data = NULL; + //! convert image to texture + switch(textureFormat) + { + default: + case GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM: + gdImageToUnormR8G8B8A8(gdImg, (u32*)texture->surface.image_data, texture->surface.width, texture->surface.height, texture->surface.pitch); + break; + case GX2_SURFACE_FORMAT_TCS_R5_G6_B5_UNORM: + gdImageToUnormR5G6B5(gdImg, (u16*)texture->surface.image_data, texture->surface.width, texture->surface.height, texture->surface.pitch); + break; + } + + //! free memory of image as its not needed anymore + gdImageDestroy(gdImg); + + //! invalidate the memory + GX2Invalidate(GX2_INVALIDATE_CPU_TEXTURE, texture->surface.image_data, texture->surface.image_size); + //! initialize the sampler + sampler = new GX2Sampler; + GX2InitSampler(sampler, textureClamp, GX2_TEX_XY_FILTER_BILINEAR); +} + +void GuiImageData::gdImageToUnormR8G8B8A8(gdImagePtr gdImg, u32 *imgBuffer, u32 width, u32 height, u32 pitch) +{ + for(u32 y = 0; y < height; ++y) + { + for(u32 x = 0; x < width; ++x) + { + u32 pixel = gdImageGetPixel(gdImg, x, y); + + u8 a = 254 - 2*((u8)gdImageAlpha(gdImg, pixel)); + if(a == 254) a++; + + u8 r = gdImageRed(gdImg, pixel); + u8 g = gdImageGreen(gdImg, pixel); + u8 b = gdImageBlue(gdImg, pixel); + + imgBuffer[y * pitch + x] = (r << 24) | (g << 16) | (b << 8) | (a); + } + } +} + +//! TODO: figure out why this seems to not work correct yet +void GuiImageData::gdImageToUnormR5G6B5(gdImagePtr gdImg, u16 *imgBuffer, u32 width, u32 height, u32 pitch) +{ + for(u32 y = 0; y < height; ++y) + { + for(u32 x = 0; x < width; ++x) + { + u32 pixel = gdImageGetPixel(gdImg, x, y); + + u8 r = gdImageRed(gdImg, pixel); + u8 g = gdImageGreen(gdImg, pixel); + u8 b = gdImageBlue(gdImg, pixel); + + imgBuffer[y * pitch + x] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); + } + } +} diff --git a/src/gui/GuiImageData.h b/src/gui/GuiImageData.h new file mode 100644 index 0000000..03bc1df --- /dev/null +++ b/src/gui/GuiImageData.h @@ -0,0 +1,67 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 GUI_IMAGEDATA_H_ +#define GUI_IMAGEDATA_H_ + +#include +#include +#include "dynamic_libs/gx2_functions.h" +#include "system/AsyncDeleter.h" + +class GuiImageData : public AsyncDeleter::Element +{ +public: + //!Constructor + GuiImageData(); + //!\param img Image data + //!\param imgSize The image size + GuiImageData(const u8 * img, int imgSize, int textureClamp = GX2_TEX_CLAMP_CLAMP, int textureFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM); + //!Destructor + virtual ~GuiImageData(); + //!Load image from buffer + //!\param img Image data + //!\param imgSize The image size + void loadImage(const u8 * img, int imgSize, int textureClamp = GX2_TEX_CLAMP_CLAMP, int textureFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM); + //! getter functions + const GX2Texture * getTexture() const { return texture; }; + const GX2Sampler * getSampler() const { return sampler; }; + //!Gets the image width + //!\return image width + int getWidth() const { if(texture) return texture->surface.width; else return 0; }; + //!Gets the image height + //!\return image height + int getHeight() const { if(texture) return texture->surface.height; else return 0; }; + //! release memory of the image data + void releaseData(void); +private: + void gdImageToUnormR8G8B8A8(gdImagePtr gdImg, u32 *imgBuffer, u32 width, u32 height, u32 pitch); + void gdImageToUnormR5G6B5(gdImagePtr gdImg, u16 *imgBuffer, u32 width, u32 height, u32 pitch); + + GX2Texture *texture; + GX2Sampler *sampler; + + enum eMemoryTypes + { + eMemTypeMEM2, + eMemTypeMEM1, + eMemTypeMEMBucket + }; + + u8 memoryType; +}; + +#endif diff --git a/src/gui/GuiMainWindowScreen.h b/src/gui/GuiMainWindowScreen.h new file mode 100644 index 0000000..0047b33 --- /dev/null +++ b/src/gui/GuiMainWindowScreen.h @@ -0,0 +1,30 @@ +/**************************************************************************** + * Copyright (C) 2016 Maschell + * + * 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 GUI_MAIN_WINDOW_SCREEN_H_ +#define GUI_MAIN_WINDOW_SCREEN_H_ + +#include "Gui.h" +#include "sigslot.h" + +class GuiMainWindowScreen : public GuiFrame +{ +public: + GuiMainWindowScreen(int w, int h) : GuiFrame(w, h) {} + virtual ~GuiMainWindowScreen() {} +}; + +#endif /* GUI_MAIN_WINDOW_SCREEN_H_ */ diff --git a/src/gui/GuiParticleImage.cpp b/src/gui/GuiParticleImage.cpp new file mode 100644 index 0000000..e39930f --- /dev/null +++ b/src/gui/GuiParticleImage.cpp @@ -0,0 +1,128 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include "GuiParticleImage.h" +#include "video/CVideo.h" +#include "video/shaders/ColorShader.h" + +#define CIRCLE_VERTEX_COUNT 36 + +static inline f32 getRandZeroToOneF32() +{ + return (rand() % 10000) * 0.0001f; +} + +static inline f32 getRandMinusOneToOneF32() +{ + return getRandZeroToOneF32() * 2.0f - 1.0f; +} + +GuiParticleImage::GuiParticleImage(int w, int h, u32 particleCount) + : GuiImage(NULL) +{ + width = w; + height = h; + imgType = IMAGE_COLOR; + + posVertexs = (f32 *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ColorShader::cuVertexAttrSize * CIRCLE_VERTEX_COUNT); + colorVertexs = (u8 *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ColorShader::cuColorAttrSize * CIRCLE_VERTEX_COUNT); + + for(u32 i = 0; i < CIRCLE_VERTEX_COUNT; i++) + { + posVertexs[i * 3 + 0] = cosf(DegToRad(i * 360.0f / CIRCLE_VERTEX_COUNT)); + posVertexs[i * 3 + 1] = sinf(DegToRad(i * 360.0f / CIRCLE_VERTEX_COUNT)); + posVertexs[i * 3 + 2] = 0.0f; + + colorVertexs[i * 4 + 0] = 0xff; + colorVertexs[i * 4 + 1] = 0xff; + colorVertexs[i * 4 + 2] = 0xff; + colorVertexs[i * 4 + 3] = 0xff; + } + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, posVertexs, ColorShader::cuVertexAttrSize * CIRCLE_VERTEX_COUNT); + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, colorVertexs, ColorShader::cuColorAttrSize * CIRCLE_VERTEX_COUNT); + + particles.resize(particleCount); + + for(u32 i = 0; i < particleCount; i++) + { + particles[i].position.x = getRandMinusOneToOneF32() * getWidth() * 0.5f; + particles[i].position.y = getRandMinusOneToOneF32() * getHeight() * 0.5f; + particles[i].position.z = 0.0f; + particles[i].colors = glm::vec4(1.0f, 1.0f, 1.0f, (getRandZeroToOneF32() * 0.6f) + 0.05f); + particles[i].radius = getRandZeroToOneF32() * 30.0f + 60.0f; + particles[i].speed = (getRandZeroToOneF32() * 0.4f) + 0.6f; + particles[i].direction = getRandMinusOneToOneF32(); + } +} + +GuiParticleImage::~GuiParticleImage() +{ + free(posVertexs); + free(colorVertexs); +} + +void GuiParticleImage::draw(CVideo *pVideo) +{ + if(!this->isVisible()) + return; + + + f32 currScaleX = getScaleX(); + f32 currScaleY = getScaleY(); + + positionOffsets[2] = getDepth() * pVideo->getDepthScaleFactor() * 2.0f; + + scaleFactor[2] = getScaleZ(); + + //! add other colors intensities parameters + colorIntensity[3] = getAlpha(); + + for(u32 i = 0; i < particles.size(); ++i) + { + if(particles[i].position.y > (getHeight() * 0.5f + 30.0f)) + { + particles[i].position.x = getRandMinusOneToOneF32() * getWidth() * 0.5f; + particles[i].position.y = -getHeight() * 0.5f - 30.0f; + particles[i].colors = glm::vec4(1.0f, 1.0f, 1.0f, (getRandZeroToOneF32() * 0.6f) + 0.05f); + particles[i].radius = getRandZeroToOneF32() * 30.0f + 60.0f; + particles[i].speed = (getRandZeroToOneF32() * 0.4f) + 0.6f; + particles[i].direction = getRandMinusOneToOneF32(); + } + if(particles[i].position.x < (-getWidth() * 0.5f - 50.0f)) + { + particles[i].position.x = -particles[i].position.x; + } + + + particles[i].direction += getRandMinusOneToOneF32() * 0.03f; + particles[i].position.x += particles[i].speed * particles[i].direction; + particles[i].position.y += particles[i].speed; + + positionOffsets[0] = (getCenterX() + particles[i].position.x) * pVideo->getWidthScaleFactor() * 2.0f; + positionOffsets[1] = (getCenterY() + particles[i].position.y) * pVideo->getHeightScaleFactor() * 2.0f; + + scaleFactor[0] = currScaleX * particles[i].radius * pVideo->getWidthScaleFactor(); + scaleFactor[1] = currScaleY * particles[i].radius * pVideo->getHeightScaleFactor(); + + ColorShader::instance()->setShaders(); + ColorShader::instance()->setAttributeBuffer(colorVertexs, posVertexs, CIRCLE_VERTEX_COUNT); + ColorShader::instance()->setAngle(0.0f); + ColorShader::instance()->setOffset(positionOffsets); + ColorShader::instance()->setScale(scaleFactor); + ColorShader::instance()->setColorIntensity(colorIntensity * particles[i].colors); + ColorShader::instance()->draw(GX2_PRIMITIVE_TRIANGLE_FAN, CIRCLE_VERTEX_COUNT); + } +} diff --git a/src/gui/GuiParticleImage.h b/src/gui/GuiParticleImage.h new file mode 100644 index 0000000..eb7565b --- /dev/null +++ b/src/gui/GuiParticleImage.h @@ -0,0 +1,45 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 _GUI_PARTICLE_IMAGE_H_ +#define _GUI_PARTICLE_IMAGE_H_ + +#include "GuiImage.h" + +class GuiParticleImage : public GuiImage, public sigslot::has_slots<> +{ +public: + GuiParticleImage(int w, int h, u32 particleCount); + virtual ~GuiParticleImage(); + + void draw(CVideo *pVideo); +private: + f32 *posVertexs; + u8 *colorVertexs; + + typedef struct + { + glm::vec3 position; + glm::vec4 colors; + f32 radius; + f32 speed; + f32 direction; + } Particle; + + std::vector particles; +}; + +#endif // _GUI_ICON_GRID_H_ diff --git a/src/gui/GuiSelectBox.cpp b/src/gui/GuiSelectBox.cpp new file mode 100644 index 0000000..827dc61 --- /dev/null +++ b/src/gui/GuiSelectBox.cpp @@ -0,0 +1,303 @@ +/**************************************************************************** + * Copyright (C) 2016 Maschell + * + * 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 . + ****************************************************************************/ +#include +#include +#include "GuiSelectBox.h" +#include "GuiImage.h" +#include "GuiTrigger.h" +#include "GuiImageData.h" +#include "utils/StringTools.h" +/** + * Constructor for the GuiCheckBox class. + */ + +GuiSelectBox::GuiSelectBox(std::string caption,GuiFrame *parent) + : GuiFrame(300,300,parent) + ,selected(0) + ,captionText(caption) + ,topValueImageData(Resources::GetImageData("gameSettingsButton.png")) + ,topValueImage(topValueImageData) + ,topValueImageSelectedData(Resources::GetImageData("gameSettingsButtonSelected.png")) + ,topValueImageSelected(topValueImageSelectedData) + ,topValueButton(topValueImage.getWidth(),topValueImage.getHeight()) + ,valueImageData(Resources::GetImageData("gameSettingsButtonEx.png")) + ,valueSelectedImageData(Resources::GetImageData("gameSettingsButtonExSelected.png")) + ,valueHighlightedImageData(Resources::GetImageData("gameSettingsButtonExHighlighted.png")) + ,touchTrigger(GuiTrigger::CHANNEL_1, GuiTrigger::VPAD_TOUCH) + ,wpadTouchTrigger(GuiTrigger::CHANNEL_2 | GuiTrigger::CHANNEL_3 | GuiTrigger::CHANNEL_4 | GuiTrigger::CHANNEL_5, GuiTrigger::BUTTON_A) + ,buttonATrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_A, true) + ,buttonBTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_B, true) + ,buttonUpTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_UP | GuiTrigger::STICK_L_UP, true) + ,buttonDownTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_DOWN | GuiTrigger::STICK_L_DOWN, true) + ,DPADButtons(5,5) + ,buttonClickSound(Resources::GetSound("settings_click_2.mp3")) + { + showValues = false; + bChanged = false; + bSelectedChanged = false; + opened = false; + topValueText.setFontSize(32); + topValueText.setAlignment(ALIGN_LEFT); + topValueText.setPosition(10,-7); + topValueButton.setLabel(&topValueText); + topValueButton.setImage(&topValueImage); + topValueButton.setIconOver(&topValueImageSelected); + topValueButton.setTrigger(&touchTrigger); + topValueButton.setTrigger(&wpadTouchTrigger); + topValueButton.setSoundClick(buttonClickSound); + topValueButton.clicked.connect(this, &GuiSelectBox::OnTopValueClicked); + + valuesFrame.setState(STATE_HIDDEN); + + DPADButtons.setTrigger(&buttonBTrigger); + DPADButtons.setTrigger(&buttonATrigger); + DPADButtons.setTrigger(&buttonDownTrigger); + DPADButtons.setTrigger(&buttonUpTrigger); + DPADButtons.clicked.connect(this, &GuiSelectBox::OnDPADClick); + DPADButtons.setState(STATE_DISABLE_INPUT); + + append(&DPADButtons); + append(&valuesFrame); + append(&topValueButton); + + showValues = false; + bChanged = true; +} + +void GuiSelectBox::OnValueClicked(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) +{ + for(u32 i = 0; i < valueButtons.size(); ++i){ + if(valueButtons[i].valueButton == button){ + selected = i; + SelectValue(i); + break; + } + } +} + +void GuiSelectBox::SelectValue(u32 value){ + if(value < valueButtons.size()){ + const wchar_t* w_text = valueButtons[value].valueButtonText->getText(); + std::wstring ws(w_text); + std::string text(ws.begin(), ws.end()); + topValueText.setText(getCaptionWithValue(text).c_str()); + + std::string real_value = buttonToValue[valueButtons[value].valueButton]; + if(real_value.compare(std::string()) == 0) real_value = ""; + + valueChanged(this,real_value); + ShowHideValues(false); + } +} +std::string GuiSelectBox::getCaptionWithValue(std::string value){ + u32 pad = (38 - captionText.size() -2); + if(pad > value.size()) + value.insert(0, pad - value.size(), ' '); + return strfmt("%s: %s",captionText.c_str(),value.c_str()); +} + +void GuiSelectBox::OnTopValueClicked(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) +{ + ShowHideValues(!showValues); +} + +void GuiSelectBox::ShowHideValues(bool showhide) +{ + showValues = showhide; + bChanged = true; +} + +void GuiSelectBox::OnDPADClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) +{ + if(opened == true){ + if(trigger == &buttonATrigger) + { + //! do not auto launch when wiimote is pointing to screen and presses A + if((controller->chan & (GuiTrigger::CHANNEL_2 | GuiTrigger::CHANNEL_3 | GuiTrigger::CHANNEL_4 | GuiTrigger::CHANNEL_5)) && controller->data.validPointer) + { + return; + } + SelectValue(selected); + } + else if(trigger == &buttonBTrigger) + { + if(button == &DPADButtons){ + ShowHideValues(false); + }else{ + } + }else if(trigger == &buttonUpTrigger){ + if(selected > 0 ) selected--; + bSelectedChanged = true; + } + else if(trigger == &buttonDownTrigger){ + selected++; + if(selected >= valueButtons.size()) selected = valueButtons.size() - 1; + bSelectedChanged = true; + } + } +} + +void GuiSelectBox::Init(std::map values, int valueID) +{ + if((u32)valueID >= values.size()){ + valueID = 0; + } + + selected = valueID; + bSelectedChanged = true; + + DeleteValueData(); + + valueButtons.resize(values.size()); + + int i = 0; + f32 imgScale = 1.0f; + std::map::iterator itr; + for(itr = values.begin(); itr != values.end(); itr++) { + if(i == valueID){ + topValueText.setText(getCaptionWithValue(itr->first).c_str()); + } + + valueButtons[i].valueButtonImg = new GuiImage(valueImageData); + + valueButtons[i].valueButtonCheckedImg = new GuiImage(valueSelectedImageData); + valueButtons[i].valueButtonHighlightedImg = new GuiImage(valueHighlightedImageData); + valueButtons[i].valueButton = new GuiButton(valueButtons[i].valueButtonImg->getWidth() * imgScale, valueButtons[i].valueButtonImg->getHeight() * imgScale); + valueButtons[i].valueButtonText = new GuiText(itr->first.c_str(),32,glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); + + valueButtons[i].valueButtonText->setMaxWidth(valueButtons[i].valueButtonImg->getWidth() * imgScale - 20.0f, GuiText::WRAP); + valueButtons[i].valueButtonText->setPosition(0, 0); + + valueButtons[i].valueButtonImg->setScale(imgScale); + valueButtons[i].valueButtonCheckedImg->setScale(imgScale); + + valueButtons[i].valueButton->setImage(valueButtons[i].valueButtonImg); + valueButtons[i].valueButton->setIconOver(valueButtons[i].valueButtonHighlightedImg); + valueButtons[i].valueButton->setTrigger(&touchTrigger); + valueButtons[i].valueButton->setTrigger(&wpadTouchTrigger); + valueButtons[i].valueButton->clicked.connect(this,&GuiSelectBox::OnValueClicked); + valueButtons[i].valueButton->setSoundClick(buttonClickSound); + valueButtons[i].valueButton->setLabel(valueButtons[i].valueButtonText); + + //valueButtons[i].valueButton->setState(STATE_HIDDEN); //Wont get disabled soon enough + + buttonToValue[valueButtons[i].valueButton] = itr->second; + + valueButtons[i].valueButton->setPosition(0, (((valueButtons[i].valueButtonImg->getHeight()*getScale()) * (i))+ (topValueImage.getHeight()-5)*getScale())*-1.0f); + valuesFrame.append(valueButtons[i].valueButton); + + i++; + } + //Collapse the thing! + showValues = false; + bChanged = true; +} + +void GuiSelectBox::DeleteValueData() +{ + for(u32 i = 0; i < valueButtons.size(); ++i) + { + valuesFrame.remove(valueButtons[i].valueButton); + delete valueButtons[i].valueButtonImg; + delete valueButtons[i].valueButtonCheckedImg; + delete valueButtons[i].valueButtonHighlightedImg; + delete valueButtons[i].valueButton; + delete valueButtons[i].valueButtonText; + } + buttonToValue.clear(); + valueButtons.clear(); +} + +/** + * Destructor for the GuiButton class. + */ +GuiSelectBox::~GuiSelectBox() +{ + DeleteValueData(); + bChanged = false; + selected = 0; + showValues = false; + Resources::RemoveSound(buttonClickSound); + Resources::RemoveImageData(topValueImageData); + Resources::RemoveImageData(topValueImageSelectedData); + Resources::RemoveImageData(valueImageData); + Resources::RemoveImageData(valueHighlightedImageData); + Resources::RemoveImageData(valueSelectedImageData); +} + + +void GuiSelectBox::setState(int s, int c) +{ + GuiElement::setState(s, c); +} + +void GuiSelectBox::OnValueCloseEffectFinish(GuiElement *element) +{ + valuesFrame.effectFinished.disconnect(this); +} + +f32 GuiSelectBox::getTopValueHeight() { + return topValueImage.getHeight(); +} + +f32 GuiSelectBox::getTopValueWidth() { + return topValueImage.getWidth(); +} + +void GuiSelectBox::OnValueOpenEffectFinish(GuiElement *element) +{ + valuesFrame.effectFinished.disconnect(this); + opened = true; +} + +void GuiSelectBox::update(GuiController * c){ + if(bChanged){ + showhide(this,showValues); + if(showValues){ + for(u32 i = 0; i < valueButtons.size(); ++i){ //TODO: only set when it really changed + if(i == selected){ + valueButtons[i].valueButton->setImage(valueButtons[i].valueButtonCheckedImg); + }else{ + valueButtons[i].valueButton->setImage(valueButtons[i].valueButtonImg); + } + } + valuesFrame.clearState(STATE_HIDDEN); + DPADButtons.clearState(STATE_DISABLE_INPUT); + valuesFrame.setEffect(EFFECT_FADE, 10, 255); + valuesFrame.effectFinished.connect(this, &GuiSelectBox::OnValueCloseEffectFinish); + }else{ + opened = false; + valuesFrame.setState(STATE_HIDDEN); + DPADButtons.setState(STATE_DISABLE_INPUT); + valuesFrame.setEffect(EFFECT_FADE, -10, 0); + valuesFrame.effectFinished.connect(this, &GuiSelectBox::OnValueOpenEffectFinish); + } + + bChanged = false; + } + if(bSelectedChanged){ + for(u32 i = 0; i < valueButtons.size(); ++i){ + if(i == selected){ + valueButtons[i].valueButton->setState(STATE_SELECTED); + }else{ + valueButtons[i].valueButton->clearState(STATE_SELECTED); + } + } + } + topValueButton.setState(getState()); + GuiFrame::update(c); +} diff --git a/src/gui/GuiSelectBox.h b/src/gui/GuiSelectBox.h new file mode 100644 index 0000000..1e8557e --- /dev/null +++ b/src/gui/GuiSelectBox.h @@ -0,0 +1,104 @@ +/**************************************************************************** + * Copyright (C) 2016 Maschell + * + * 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 GUI_SELECTBOX_H_ +#define GUI_SELECTBOX_H_ + +#include "Gui.h" +#include "GuiImage.h" +#include "GuiImageData.h" + +//!A simple CheckBox +class GuiSelectBox : public GuiFrame, public sigslot::has_slots<> + +{ + public: + //!Constructor + //!\param checked Checked + GuiSelectBox(std::string caption,GuiFrame *parent = 0); + //!Destructor + virtual ~GuiSelectBox(); + + sigslot::signal2 valueChanged; + sigslot::signal2 showhide; + void OnTopValueClicked(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); + void Init(std::map values, int valueID); + + void setState(int s, int c = -1); + + virtual f32 getTopValueHeight(); + virtual f32 getTopValueWidth(); + + protected: + void DeleteValueData(); + void update(GuiController * c); + + void OnValueClicked(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); + + void OnDPADClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); + void OnValueOpenEffectFinish(GuiElement *element); + void OnValueCloseEffectFinish(GuiElement *element); + void ShowHideValues(bool showhide); + void SelectValue(u32 value); + + u32 selected; + bool bChanged; + bool bSelectedChanged; + bool showValues; + bool opened; + std::string captionText; + GuiFrame valuesFrame; + GuiImageData *topValueImageData; + GuiImage topValueImage; + GuiImageData *topValueImageSelectedData; + GuiImage topValueImageSelected; + + GuiButton topValueButton; + GuiImageData * valueImageData; + GuiImageData * valueSelectedImageData; + GuiImageData * valueHighlightedImageData; + GuiText topValueText; + + GuiTrigger touchTrigger; + GuiTrigger wpadTouchTrigger; + + GuiTrigger buttonATrigger; + GuiTrigger buttonBTrigger; + GuiTrigger buttonLeftTrigger; + GuiTrigger buttonRightTrigger; + GuiTrigger buttonUpTrigger; + GuiTrigger buttonDownTrigger; + + GuiButton DPADButtons; + + GuiSound* buttonClickSound; + + std::string getCaptionWithValue(std::string value); + typedef struct + { + GuiImage *valueButtonImg; + GuiImage *valueButtonCheckedImg; + GuiImage *valueButtonHighlightedImg; + GuiButton *valueButton; + GuiText *valueButtonText; + } SelectBoxValueButton; + + std::map buttonToValue; + std::vector valueButtons; + +}; + +#endif diff --git a/src/gui/GuiSound.cpp b/src/gui/GuiSound.cpp new file mode 100644 index 0000000..502a8a2 --- /dev/null +++ b/src/gui/GuiSound.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include "GuiSound.h" +#include "sounds/SoundHandler.hpp" +#include "dynamic_libs/os_functions.h" + +GuiSound::GuiSound(const char * filepath) +{ + voice = -1; + Load(filepath); +} + +GuiSound::GuiSound(const u8 * snd, s32 length) +{ + voice = -1; + Load(snd, length); +} + +GuiSound::~GuiSound() +{ + if(voice >= 0) + { + SoundHandler::instance()->RemoveDecoder(voice); + } +} + + +bool GuiSound::Load(const char * filepath) +{ + if(voice >= 0) + { + SoundHandler::instance()->RemoveDecoder(voice); + voice = -1; + } + + //! find next free decoder + for(int i = 0; i < MAX_DECODERS; i++) + { + SoundDecoder * decoder = SoundHandler::instance()->getDecoder(i); + if(decoder == NULL) + { + SoundHandler::instance()->AddDecoder(i, filepath); + decoder = SoundHandler::instance()->getDecoder(i); + if(decoder) + { + voice = i; + SoundHandler::instance()->ThreadSignal(); + } + break; + } + } + + if(voice < 0) + return false; + + return true; +} + +bool GuiSound::Load(const u8 * snd, s32 len) +{ + if(voice >= 0) + { + SoundHandler::instance()->RemoveDecoder(voice); + voice = -1; + } + + if(!snd) + return false; + + //! find next free decoder + for(int i = 0; i < MAX_DECODERS; i++) + { + SoundDecoder * decoder = SoundHandler::instance()->getDecoder(i); + if(decoder == NULL) + { + SoundHandler::instance()->AddDecoder(i, snd, len); + decoder = SoundHandler::instance()->getDecoder(i); + if(decoder) + { + voice = i; + SoundHandler::instance()->ThreadSignal(); + } + break; + } + } + + if(voice < 0) + return false; + + return true; +} + +void GuiSound::Play() +{ + Stop(); + + Voice * v = SoundHandler::instance()->getVoice(voice); + if(v) + v->setState(Voice::STATE_START); + + +} + +void GuiSound::Stop() +{ + Voice * v = SoundHandler::instance()->getVoice(voice); + if(v) + { + if((v->getState() != Voice::STATE_STOP) && (v->getState() != Voice::STATE_STOPPED)) + v->setState(Voice::STATE_STOP); + + while(v->getState() != Voice::STATE_STOPPED) + usleep(1000); + } + + SoundDecoder * decoder = SoundHandler::instance()->getDecoder(voice); + if(decoder) + { + decoder->Lock(); + decoder->Rewind(); + decoder->ClearBuffer(); + SoundHandler::instance()->ThreadSignal(); + decoder->Unlock(); + } +} + +void GuiSound::Pause() +{ + if(!IsPlaying()) + return; + + Voice * v = SoundHandler::instance()->getVoice(voice); + if(v) + v->setState(Voice::STATE_STOP); +} + +void GuiSound::Resume() +{ + if(IsPlaying()) + return; + + Voice * v = SoundHandler::instance()->getVoice(voice); + if(v) + v->setState(Voice::STATE_START); +} + +bool GuiSound::IsPlaying() +{ + Voice * v = SoundHandler::instance()->getVoice(voice); + if(v) + return v->getState() == Voice::STATE_PLAYING; + + return false; + +} + +void GuiSound::SetVolume(u32 vol) +{ + if(vol > 100) + vol = 100; + + u32 volumeConv = ( (0x8000 * vol) / 100 ) << 16; + + Voice * v = SoundHandler::instance()->getVoice(voice); + if(v) + v->setVolume(volumeConv); +} + +void GuiSound::SetLoop(bool l) +{ + SoundDecoder * decoder = SoundHandler::instance()->getDecoder(voice); + if(decoder) + decoder->SetLoop(l); +} + +void GuiSound::Rewind() +{ + Stop(); +} diff --git a/src/gui/GuiSound.h b/src/gui/GuiSound.h new file mode 100644 index 0000000..bb72a3b --- /dev/null +++ b/src/gui/GuiSound.h @@ -0,0 +1,60 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 GUI_SOUND_H_ +#define GUI_SOUND_H_ + +#include +#include "system/AsyncDeleter.h" + +//!Sound conversion and playback. A wrapper for other sound libraries - ASND, libmad, ltremor, etc +class GuiSound : public AsyncDeleter::Element +{ + public: + //!Constructor + //!\param sound Pointer to the sound data + //!\param filesize Length of sound data + GuiSound(const char * filepath); + GuiSound(const u8 * sound, int length); + //!Destructor + virtual ~GuiSound(); + //!Load a file and replace the old one + bool Load(const char * filepath); + //!Load a file and replace the old one + bool Load(const u8 * snd, s32 len); + //!Start sound playback + void Play(); + //!Stop sound playback + void Stop(); + //!Pause sound playback + void Pause(); + //!Resume sound playback + void Resume(); + //!Checks if the sound is currently playing + //!\return true if sound is playing, false otherwise + bool IsPlaying(); + //!Rewind the music + void Rewind(); + //!Set sound volume + //!\param v Sound volume (0-100) + void SetVolume(u32 v); + //!\param l Loop (true to loop) + void SetLoop(bool l); + protected: + s32 voice; //!< Currently assigned ASND voice channel +}; + +#endif diff --git a/src/gui/GuiSwitch.cpp b/src/gui/GuiSwitch.cpp new file mode 100644 index 0000000..206a456 --- /dev/null +++ b/src/gui/GuiSwitch.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** + * Copyright (C) 2016 Maschell + * + * 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 . + ****************************************************************************/ +#include "GuiSwitch.h" +#include "GuiImage.h" +#include "GuiImageData.h" +/** + * Constructor for the GuiSwitch class. + */ + +GuiSwitch::GuiSwitch(bool checked,f32 switchscale) + : GuiToggle(checked,90*switchscale,38*switchscale) + ,switchbase_imgdata(Resources::GetImageData("switchIconBase.png")) + ,switchbase_img(switchbase_imgdata) + ,switchbase_highlighted_imgdata(Resources::GetImageData("switchIconBaseHighlighted.png")) + ,switchbase_highlighted_img(switchbase_highlighted_imgdata) + ,switchOn_imgdata(Resources::GetImageData("switchIconOn.png")) + ,switchOn_img(switchOn_imgdata) + ,switchOff_imgdata(Resources::GetImageData("switchIconOff.png")) + ,switchOff_img(switchOff_imgdata) +{ + f32 scale = 0.0; + if(switchbase_img.getHeight() > switchbase_img.getWidth()){ + scale = height*switchscale/switchbase_img.getHeight(); + }else{ + scale = width/switchbase_img.getWidth(); + } + + switchbase_img.setScale(scale); + switchbase_highlighted_img.setScale(scale); + switchOn_img.setScale(scale); + switchOff_img.setScale(scale); + + switchOn_img.setParent(this); + switchOn_img.setPosition((width/4.0),0); + switchOff_img.setParent(this); + switchOff_img.setPosition(-((width/4.0)),0); + setImage(&switchbase_img); + setIconOver(&switchbase_highlighted_img); +} +/** + * Destructor for the GuiButton class. + */ +GuiSwitch::~GuiSwitch() +{ + Resources::RemoveImageData(switchbase_imgdata); + Resources::RemoveImageData(switchbase_highlighted_imgdata); + Resources::RemoveImageData(switchOn_imgdata); + Resources::RemoveImageData(switchOff_imgdata); +} + +void GuiSwitch::draw(CVideo *v){ + GuiToggle::draw(v); + if(getValue()){ + switchOn_img.draw(v); + }else{ + switchOff_img.draw(v); + } +} diff --git a/src/gui/GuiSwitch.h b/src/gui/GuiSwitch.h new file mode 100644 index 0000000..4988d2d --- /dev/null +++ b/src/gui/GuiSwitch.h @@ -0,0 +1,51 @@ +/**************************************************************************** + * Copyright (C) 2016 Maschell + * + * 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 GUI_SWTICH_H_ +#define GUI_SWTICH_H_ + +#include "GuiToggle.h" +#include "GuiImage.h" +#include "GuiImageData.h" + +//!A simple switch +class GuiSwitch : public GuiToggle +{ + public: + //!Constructor + //!\param checked Checked + GuiSwitch(bool checked,f32 switchscale = 1.0f); + //!Destructor + virtual ~GuiSwitch(); + + protected: + + GuiImageData * switchbase_imgdata; + GuiImage switchbase_img; + + GuiImageData * switchbase_highlighted_imgdata; + GuiImage switchbase_highlighted_img; + + GuiImageData * switchOn_imgdata; + GuiImage switchOn_img; + + GuiImageData * switchOff_imgdata; + GuiImage switchOff_img; + + void draw(CVideo * v); +}; + +#endif diff --git a/src/gui/GuiText.cpp b/src/gui/GuiText.cpp new file mode 100644 index 0000000..ab54e42 --- /dev/null +++ b/src/gui/GuiText.cpp @@ -0,0 +1,615 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include "GuiText.h" +#include "FreeTypeGX.h" +#include "video/CVideo.h" + +FreeTypeGX * GuiText::presentFont = NULL; +int GuiText::presetSize = 28; +int GuiText::presetInternalRenderingScale = 2.0f; //Lets render the font at the doubled size. This make it even smoother! +int GuiText::presetMaxWidth = 0xFFFF; +int GuiText::presetAlignment = ALIGN_CENTER | ALIGN_MIDDLE; +GX2ColorF32 GuiText::presetColor = (GX2ColorF32){ 1.0f, 1.0f, 1.0f, 1.0f }; + +#define TEXT_SCROLL_DELAY 6 +#define TEXT_SCROLL_INITIAL_DELAY 10 +#define MAX_LINES_TO_DRAW 10 + +/** + * Constructor for the GuiText class. + */ + +GuiText::GuiText() +{ + text = NULL; + size = presetSize; + currentSize = size; + color = glm::vec4(presetColor.r, presetColor.g, presetColor.b, presetColor.a); + alpha = presetColor.a; + alignment = presetAlignment; + maxWidth = presetMaxWidth; + wrapMode = 0; + textWidth = 0; + font = presentFont; + linestodraw = MAX_LINES_TO_DRAW; + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + textScrollDelay = TEXT_SCROLL_DELAY; + defaultBlur = 4.0f; + blurGlowIntensity = 0.0f; + blurAlpha = 0.0f; + blurGlowColor = glm::vec4(0.0f); + internalRenderingScale = presetInternalRenderingScale; +} + +GuiText::GuiText(const char * t, int s, const glm::vec4 & c) +{ + text = NULL; + size = s; + currentSize = size; + color = c; + alpha = c[3]; + alignment = ALIGN_CENTER | ALIGN_MIDDLE; + maxWidth = presetMaxWidth; + wrapMode = 0; + textWidth = 0; + font = presentFont; + linestodraw = MAX_LINES_TO_DRAW; + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + textScrollDelay = TEXT_SCROLL_DELAY; + defaultBlur = 4.0f; + blurGlowIntensity = 0.0f; + blurAlpha = 0.0f; + blurGlowColor = glm::vec4(0.0f); + internalRenderingScale = presetInternalRenderingScale; + + if(t) + { + text = FreeTypeGX::charToWideChar(t); + if(!text) + return; + + textWidth = font->getWidth(text, currentSize); + } +} + +GuiText::GuiText(const wchar_t * t, int s, const glm::vec4 & c) +{ + text = NULL; + size = s; + currentSize = size; + color = c; + alpha = c[3]; + alignment = ALIGN_CENTER | ALIGN_MIDDLE; + maxWidth = presetMaxWidth; + wrapMode = 0; + textWidth = 0; + font = presentFont; + linestodraw = MAX_LINES_TO_DRAW; + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + textScrollDelay = TEXT_SCROLL_DELAY; + defaultBlur = 4.0f; + blurGlowIntensity = 0.0f; + blurAlpha = 0.0f; + blurGlowColor = glm::vec4(0.0f); + internalRenderingScale = presetInternalRenderingScale; + + if(t) + { + text = new (std::nothrow) wchar_t[wcslen(t)+1]; + if(!text) + return; + + wcscpy(text, t); + + textWidth = font->getWidth(text, currentSize); + } +} + +/** + * Constructor for the GuiText class, uses presets + */ +GuiText::GuiText(const char * t) +{ + text = NULL; + size = presetSize; + currentSize = size; + color = glm::vec4(presetColor.r, presetColor.g, presetColor.b, presetColor.a); + alpha = presetColor.a; + alignment = presetAlignment; + maxWidth = presetMaxWidth; + wrapMode = 0; + textWidth = 0; + font = presentFont; + linestodraw = MAX_LINES_TO_DRAW; + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + textScrollDelay = TEXT_SCROLL_DELAY; + defaultBlur = 4.0f; + blurGlowIntensity = 0.0f; + blurAlpha = 0.0f; + blurGlowColor = glm::vec4(0.0f); + internalRenderingScale = presetInternalRenderingScale; + + if(t) + { + text = FreeTypeGX::charToWideChar(t); + if(!text) + return; + + textWidth = font->getWidth(text, currentSize); + } +} + + +/** + * Destructor for the GuiText class. + */ +GuiText::~GuiText() +{ + if(text) + delete [] text; + text = NULL; + + clearDynamicText(); +} + +void GuiText::setText(const char * t) +{ + if(text) + delete [] text; + text = NULL; + + clearDynamicText(); + + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + + if(t) + { + text = FreeTypeGX::charToWideChar(t); + if(!text) + return; + + textWidth = font->getWidth(text, currentSize); + } +} + +void GuiText::setTextf(const char *format, ...) +{ + if(!format) + { + setText((char *) NULL); + return; + } + + int max_len = strlen(format) + 8192; + char *tmp = new char[max_len]; + va_list va; + va_start(va, format); + if((vsnprintf(tmp, max_len, format, va) >= 0) && tmp) + { + setText(tmp); + } + va_end(va); + + if(tmp) + delete [] tmp; +} + + +void GuiText::setText(const wchar_t * t) +{ + if(text) + delete [] text; + text = NULL; + + clearDynamicText(); + + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + + if(t) + { + text = new (std::nothrow) wchar_t[wcslen(t)+1]; + if(!text) + return; + + wcscpy(text, t); + + textWidth = font->getWidth(text, currentSize); + } +} + +void GuiText::clearDynamicText() +{ + for(u32 i = 0; i < textDyn.size(); i++) + { + if(textDyn[i]) + delete [] textDyn[i]; + } + textDyn.clear(); + textDynWidth.clear(); +} + +void GuiText::setPresets(int sz, const glm::vec4 & c, int w, int a) +{ + presetSize = sz; + presetColor = (GX2ColorF32) { (f32)c.r / 255.0f, (f32)c.g / 255.0f, (f32)c.b / 255.0f, (f32)c.a / 255.0f }; + presetMaxWidth = w; + presetAlignment = a; +} + +void GuiText::setPresetFont(FreeTypeGX *f) +{ + presentFont = f; +} + +void GuiText::setFontSize(int s) +{ + size = s; +} + +void GuiText::setMaxWidth(int width, int w) +{ + maxWidth = width; + wrapMode = w; + + if(w == SCROLL_HORIZONTAL) + { + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + textScrollDelay = TEXT_SCROLL_DELAY; + } + + clearDynamicText(); +} + +void GuiText::setColor(const glm::vec4 & c) +{ + color = c; + alpha = c[3]; +} + +void GuiText::setBlurGlowColor(float blur, const glm::vec4 & c) +{ + blurGlowColor = c; + blurGlowIntensity = blur; + blurAlpha = c[3]; +} + +int GuiText::getTextWidth(int ind) +{ + if(ind < 0 || ind >= (int) textDyn.size()) + return this->getTextWidth(); + + return font->getWidth(textDyn[ind], currentSize); +} + +const wchar_t * GuiText::getDynText(int ind) +{ + if(ind < 0 || ind >= (int) textDyn.size()) + return text; + + return textDyn[ind]; +} + +/** + * Change font + */ +bool GuiText::setFont(FreeTypeGX *f) +{ + if(!f) + return false; + + font = f; + textWidth = font->getWidth(text, currentSize); + return true; +} + +std::string GuiText::toUTF8(void) const +{ + if(!text) + return std::string(); + + char *pUtf8 = FreeTypeGX::wideCharToUTF8(text); + if(!pUtf8) + return std::string(); + + std::string strOutput(pUtf8); + + delete [] pUtf8; + + return strOutput; +} + +void GuiText::makeDottedText() +{ + int pos = textDyn.size(); + textDyn.resize(pos + 1); + + int i = 0, currentWidth = 0; + textDyn[pos] = new (std::nothrow) wchar_t[maxWidth]; + if(!textDyn[pos]) { + textDyn.resize(pos); + return; + } + + while (text[i]) + { + currentWidth += font->getCharWidth(text[i], currentSize, i > 0 ? text[i - 1] : 0); + if (currentWidth >= maxWidth && i > 2) + { + textDyn[pos][i - 2] = '.'; + textDyn[pos][i - 1] = '.'; + textDyn[pos][i] = '.'; + i++; + break; + } + + textDyn[pos][i] = text[i]; + + i++; + } + textDyn[pos][i] = 0; +} + +void GuiText::scrollText(u32 frameCount) +{ + if (textDyn.size() == 0) + { + int pos = textDyn.size(); + int i = 0, currentWidth = 0; + textDyn.resize(pos + 1); + + textDyn[pos] = new (std::nothrow) wchar_t[maxWidth]; + if(!textDyn[pos]) { + textDyn.resize(pos); + return; + } + + while (text[i] && currentWidth < maxWidth) + { + textDyn[pos][i] = text[i]; + + currentWidth += font->getCharWidth(text[i], currentSize, i > 0 ? text[i - 1] : 0); + + ++i; + } + textDyn[pos][i] = 0; + + return; + } + + if (frameCount % textScrollDelay != 0) + { + return; + } + + if (textScrollInitialDelay) + { + --textScrollInitialDelay; + return; + } + + int stringlen = wcslen(text); + + ++textScrollPos; + if (textScrollPos > stringlen) + { + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + } + + int ch = textScrollPos; + int pos = textDyn.size() - 1; + + if (!textDyn[pos]) + textDyn[pos] = new (std::nothrow) wchar_t[maxWidth]; + + if(!textDyn[pos]) { + textDyn.resize(pos); + return; + } + + int i = 0, currentWidth = 0; + + while (currentWidth < maxWidth) + { + if (ch > stringlen - 1) + { + textDyn[pos][i++] = ' '; + currentWidth += font->getCharWidth(L' ', currentSize, ch > 0 ? text[ch - 1] : 0); + textDyn[pos][i++] = ' '; + currentWidth += font->getCharWidth(L' ', currentSize, L' '); + textDyn[pos][i++] = ' '; + currentWidth += font->getCharWidth(L' ', currentSize, L' '); + ch = 0; + + if(currentWidth >= maxWidth) + break; + } + + textDyn[pos][i] = text[ch]; + currentWidth += font->getCharWidth(text[ch], currentSize, ch > 0 ? text[ch - 1] : 0); + ++ch; + ++i; + } + textDyn[pos][i] = 0; +} + +void GuiText::wrapText() +{ + if (textDyn.size() > 0) return; + + int i = 0; + int ch = 0; + int linenum = 0; + int lastSpace = -1; + int lastSpaceIndex = -1; + int currentWidth = 0; + + while (text[ch] && linenum < linestodraw) + { + if (linenum >= (int) textDyn.size()) + { + textDyn.resize(linenum + 1); + textDyn[linenum] = new (std::nothrow) wchar_t[maxWidth]; + if(!textDyn[linenum]) { + textDyn.resize(linenum); + break; + } + } + + textDyn[linenum][i] = text[ch]; + textDyn[linenum][i + 1] = 0; + + currentWidth += font->getCharWidth(text[ch], currentSize, ch > 0 ? text[ch - 1] : 0x0000); + + if (currentWidth >= maxWidth || (text[ch] == '\n')) + { + if(text[ch] == '\n') + { + lastSpace = -1; + lastSpaceIndex = -1; + } + else if (lastSpace >= 0) + { + textDyn[linenum][lastSpaceIndex] = 0; // discard space, and everything after + ch = lastSpace; // go backwards to the last space + lastSpace = -1; // we have used this space + lastSpaceIndex = -1; + } + + if (linenum + 1 == linestodraw && text[ch + 1] != 0x0000) + { + if(i < 2) + i = 2; + + textDyn[linenum][i - 2] = '.'; + textDyn[linenum][i - 1] = '.'; + textDyn[linenum][i] = '.'; + textDyn[linenum][i + 1] = 0; + } + + currentWidth = 0; + ++linenum; + i = -1; + } + if (text[ch] == ' ' && i >= 0) + { + lastSpace = ch; + lastSpaceIndex = i; + } + ++ch; + ++i; + } +} + +/** + * Draw the text on screen + */ +void GuiText::draw(CVideo *pVideo) +{ + if(!text) + return; + + if(!isVisible()) + return; + + color[3] = getAlpha(); + blurGlowColor[3] = blurAlpha * getAlpha(); + + float finalRenderingScale = 2.0f * internalRenderingScale; + + int newSize = size * getScale() * finalRenderingScale; + int normal_size = size * getScale(); + + if(newSize != currentSize) + { + currentSize = normal_size; + + if(text) + textWidth = font->getWidth(text, normal_size); + } + + f32 x_pos = getCenterX() * finalRenderingScale; + f32 y_pos = getCenterY() * finalRenderingScale; + + if(maxWidth > 0 && maxWidth <= textWidth) + { + if(wrapMode == DOTTED) // text dotted + { + if(textDyn.size() == 0) + makeDottedText(); + + if(textDynWidth.size() != textDyn.size()) + { + textDynWidth.resize(textDyn.size()); + + for(u32 i = 0; i < textDynWidth.size(); i++) + textDynWidth[i] = font->getWidth(textDyn[i], newSize); + } + + + if(textDyn.size() > 0) + font->drawText(pVideo, x_pos, y_pos, getDepth(), textDyn[textDyn.size()-1], newSize, color, alignment, textDynWidth[textDyn.size()-1], defaultBlur, blurGlowIntensity, blurGlowColor,finalRenderingScale); + } + + else if(wrapMode == SCROLL_HORIZONTAL) + { + scrollText(pVideo->getFrameCount()); + + if(textDyn.size() > 0) + font->drawText(pVideo, x_pos, y_pos, getDepth(), textDyn[textDyn.size()-1], newSize, color, alignment, maxWidth*finalRenderingScale, defaultBlur, blurGlowIntensity, blurGlowColor,finalRenderingScale); + + } + else if(wrapMode == WRAP) + { + int lineheight = newSize + 6; + int yoffset = 0; + int voffset = 0; + + if(textDyn.size() == 0) + wrapText(); + + if(textDynWidth.size() != textDyn.size()) + { + textDynWidth.resize(textDyn.size()); + + for(u32 i = 0; i < textDynWidth.size(); i++) + textDynWidth[i] = font->getWidth(textDyn[i], newSize); + } + + if(alignment & ALIGN_MIDDLE) + voffset = (lineheight * (textDyn.size()-1)) >> 1; + + for(u32 i = 0; i < textDyn.size(); i++) + { + font->drawText(pVideo, x_pos, y_pos + voffset + yoffset, getDepth(), textDyn[i], newSize, color, alignment, textDynWidth[i], defaultBlur, blurGlowIntensity, blurGlowColor,finalRenderingScale); + yoffset -= lineheight; + } + } + } + else + { + uint16_t newtextWidth = font->getWidth(text, newSize); + font->drawText(pVideo, x_pos, y_pos, getDepth(), text, newSize, color, alignment, newtextWidth, defaultBlur, blurGlowIntensity, blurGlowColor,finalRenderingScale); + } +} diff --git a/src/gui/GuiText.h b/src/gui/GuiText.h new file mode 100644 index 0000000..5fb8acd --- /dev/null +++ b/src/gui/GuiText.h @@ -0,0 +1,141 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 GUI_TEXT_H_ +#define GUI_TEXT_H_ + +#include "GuiElement.h" +//!Forward declaration +class FreeTypeGX; + +//!Display, manage, and manipulate text in the GUI +class GuiText : public GuiElement +{ +public: + //!Constructor + GuiText(); + //!\param t Text + //!\param s Font size + //!\param c Font color + GuiText(const char * t, int s, const glm::vec4 & c); + //!\overload + //!\param t Text + //!\param s Font size + //!\param c Font color + GuiText(const wchar_t * t, int s, const glm::vec4 & c); + //!\overload + //!\Assumes SetPresets() has been called to setup preferred text attributes + //!\param t Text + GuiText(const char * t); + //!Destructor + virtual ~GuiText(); + //!Sets the text of the GuiText element + //!\param t Text + virtual void setText(const char * t); + virtual void setText(const wchar_t * t); + virtual void setTextf(const char *format, ...) __attribute__((format(printf,2,3))); + //!Sets up preset values to be used by GuiText(t) + //!Useful when printing multiple text elements, all with the same attributes set + //!\param sz Font size + //!\param c Font color + //!\param w Maximum width of texture image (for text wrapping) + //!\param wrap Wrapmode when w>0 + //!\param a Text alignment + static void setPresets(int sz, const glm::vec4 & c, int w, int a); + static void setPresetFont(FreeTypeGX *font); + //!Sets the font size + //!\param s Font size + void setFontSize(int s); + //!Sets the maximum width of the drawn texture image + //!If the text exceeds this, it is wrapped to the next line + //!\param w Maximum width + //!\param m WrapMode + void setMaxWidth(int w = 0, int m = WRAP); + //!Sets the font color + //!\param c Font color + void setColor(const glm::vec4 & c); + + void setBlurGlowColor(float blurIntensity, const glm::vec4 & c); + + void setTextBlur(float blur) { defaultBlur = blur; } + //!Get the original text as char + virtual const wchar_t * getText() const { return text; } + virtual std::string toUTF8(void) const; + //!Get the Horizontal Size of Text + int getTextWidth() { return textWidth; } + int getTextWidth(int ind); + //!Get the max textwidth + int getTextMaxWidth() { return maxWidth; } + //!Get fontsize + int getFontSize() { return size; }; + //!Set max lines to draw + void setLinesToDraw(int l) { linestodraw = l; } + //!Get current Textline (for position calculation) + const wchar_t * getDynText(int ind = 0); + virtual const wchar_t * getTextLine(int ind) { return getDynText(ind); }; + //!Change the font + bool setFont(FreeTypeGX *font); + //! virtual function used in child classes + virtual int getStartWidth() { return 0; }; + //!Constantly called to draw the text + void draw(CVideo *pVideo); + //! text enums + enum + { + WRAP, + DOTTED, + SCROLL_HORIZONTAL, + SCROLL_NONE + }; +protected: + static FreeTypeGX * presentFont; + static int presetSize; + static int presetMaxWidth; + static int presetInternalRenderingScale; + static int presetAlignment; + static GX2ColorF32 presetColor; + + //!Clear the dynamic text + void clearDynamicText(); + //!Create a dynamic dotted text if the text is too long + void makeDottedText(); + //!Scroll the text once + void scrollText(u32 frameCount); + //!Wrap the text to several lines + void wrapText(); + + wchar_t * text; + std::vector textDyn; + std::vector textDynWidth; + int wrapMode; //!< Wrapping toggle + int textScrollPos; //!< Current starting index of text string for scrolling + int textScrollInitialDelay; //!< Delay to wait before starting to scroll + int textScrollDelay; //!< Scrolling speed + int size; //!< Font size + int maxWidth; //!< Maximum width of the generated text object (for text wrapping) + FreeTypeGX *font; + int textWidth; + int currentSize; + int linestodraw; + glm::vec4 color; + float defaultBlur; + float blurGlowIntensity; + float blurAlpha; + glm::vec4 blurGlowColor; + float internalRenderingScale; +}; + +#endif diff --git a/src/gui/GuiToggle.cpp b/src/gui/GuiToggle.cpp new file mode 100644 index 0000000..03d5b37 --- /dev/null +++ b/src/gui/GuiToggle.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** + * Copyright (C) 2016 Maschell + * + * 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 . + ****************************************************************************/ +#include "GuiToggle.h" +/** + * Constructor for the GuiToggle class. + */ + +GuiToggle::GuiToggle(bool checked,f32 width,f32 height) + : GuiButton(width,height) +{ + bChanged = false; + selected = false; + clicked.connect(this,&GuiToggle::OnToggleClick); +} + +/** + * Destructor for the GuiButton class. + */ +GuiToggle::~GuiToggle() +{ + bChanged = false; + selected = false; +} + +void GuiToggle::OnToggleClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger){ + if(!isStateSet(STATE_DISABLED | STATE_HIDDEN | STATE_DISABLE_INPUT)){ + log_print("Clicked on Toggle: "); + if(selected){ + log_print("Uncheck\n"); + setUnchecked(); + }else{ + log_print("Check\n"); + setChecked(); + } + } +} + +void GuiToggle::update(GuiController * c){ + GuiButton::update(c); +} + diff --git a/src/gui/GuiToggle.h b/src/gui/GuiToggle.h new file mode 100644 index 0000000..c6dc213 --- /dev/null +++ b/src/gui/GuiToggle.h @@ -0,0 +1,59 @@ +/**************************************************************************** + * Copyright (C) 2016 Maschell + * + * 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 GUI_TOGGLE_H_ +#define GUI_TOGGLE_H_ + +#include "GuiButton.h" +#include "GuiFrame.h" + +//!A simple CheckBox +class GuiToggle : public GuiButton, public sigslot::has_slots<> +{ + public: + //!Constructor + //!\param checked Checked + GuiToggle(bool checked,f32 width,f32 height); + //!Destructor + virtual ~GuiToggle(); + void setValue(bool checked){ + if(selected != checked){ + selected = checked; + bChanged=true; + valueChanged(this,selected); + } + } + void setChecked(){ + setValue(true); + + } + void setUnchecked(){ + setValue(false); + } + bool getValue(){ + return selected; + } + sigslot::signal2 valueChanged; + void OnToggleClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); + protected: + + bool selected; + bool bChanged; + + void update(GuiController * c); +}; + +#endif diff --git a/src/gui/GuiTrigger.cpp b/src/gui/GuiTrigger.cpp new file mode 100644 index 0000000..74e9d05 --- /dev/null +++ b/src/gui/GuiTrigger.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include "GuiElement.h" +#include "GuiController.h" +#include "GuiTrigger.h" + +/** + * Constructor for the GuiTrigger class. + */ +GuiTrigger::GuiTrigger() + : chan(CHANNEL_ALL) + , btns(BUTTON_NONE) + , bClickEverywhere(false) + , bHoldEverywhere(false) + , bSelectionClickEverywhere(false) + , bLastTouched(false) +{ +} + +GuiTrigger::GuiTrigger(u32 ch, u32 btn, bool clickEverywhere, bool holdEverywhere, bool selectionClickEverywhere) + : chan(ch) + , btns(btn) + , bClickEverywhere(clickEverywhere) + , bHoldEverywhere(holdEverywhere) + , bSelectionClickEverywhere(selectionClickEverywhere) + , bLastTouched(false) +{ +} + +/** + * Destructor for the GuiTrigger class. + */ +GuiTrigger::~GuiTrigger() +{ +} + +/** + * Sets a simple trigger. Requires: + * - Element is selected + * - Trigger button is pressed + */ +void GuiTrigger::setTrigger(u32 ch, u32 btn) +{ + chan = ch; + btns = btn; +} + +bool GuiTrigger::left(const GuiController *controller) const +{ + if((controller->chan & chan) == 0) { + return false; + } + if((controller->data.buttons_h | controller->data.buttons_d) & (BUTTON_LEFT | STICK_L_LEFT)) + { + return true; + } + return false; +} + +bool GuiTrigger::right(const GuiController *controller) const +{ + if((controller->chan & chan) == 0) { + return false; + } + if((controller->data.buttons_h | controller->data.buttons_d) & (BUTTON_RIGHT | STICK_L_RIGHT)) + { + return true; + } + return false; +} + +bool GuiTrigger::up(const GuiController *controller) const +{ + if((controller->chan & chan) == 0) { + return false; + } + if((controller->data.buttons_h | controller->data.buttons_d) & (BUTTON_UP | STICK_L_UP)) + { + return true; + } + return false; +} + +bool GuiTrigger::down(const GuiController *controller) const +{ + if((controller->chan & chan) == 0) { + return false; + } + if((controller->data.buttons_h | controller->data.buttons_d) & (BUTTON_DOWN | STICK_L_DOWN)) + { + return true; + } + return false; +} + +int GuiTrigger::clicked(const GuiController *controller) const +{ + if((controller->chan & chan) == 0) { + return CLICKED_NONE; + } + + int bResult = CLICKED_NONE; + + if(controller->data.touched && controller->data.validPointer && (btns & VPAD_TOUCH) && !controller->lastData.touched) + { + bResult = CLICKED_TOUCH; + } + + if(controller->data.buttons_d & btns) + { + bResult = CLICKED_BUTTON; + } + return bResult; +} + +bool GuiTrigger::held(const GuiController *controller) const +{ + if((controller->chan & chan) == 0) { + return false; + } + + bool bResult = false; + + if(controller->data.touched && (btns & VPAD_TOUCH) && controller->data.validPointer && controller->lastData.touched && controller->lastData.validPointer) + { + bResult = true; + } + + if(controller->data.buttons_h & btns) + { + bResult = true; + } + + return bResult; +} + +bool GuiTrigger::released(const GuiController *controller) const +{ + if((controller->chan & chan) == 0) { + return false; + } + + if(clicked(controller) || held(controller)) + return false; + + bool bResult = false; + + if(!controller->data.touched && (btns & VPAD_TOUCH) && controller->lastData.touched && controller->lastData.validPointer) + { + bResult = true; + } + + if(controller->data.buttons_r & btns) + { + bResult = true; + } + + return bResult; +} + diff --git a/src/gui/GuiTrigger.h b/src/gui/GuiTrigger.h new file mode 100644 index 0000000..ea84b67 --- /dev/null +++ b/src/gui/GuiTrigger.h @@ -0,0 +1,106 @@ +/*************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 GUI_TRIGGER_H_ +#define GUI_TRIGGER_H_ + +#include "dynamic_libs/os_functions.h" + + +//!Menu input trigger management. Determine if action is neccessary based on input data by comparing controller input data to a specific trigger element. +class GuiTrigger +{ +public: + enum eClicked{ + CLICKED_NONE = 0x00, + CLICKED_TOUCH = 0x01, + CLICKED_BUTTON = 0x02, + }; + enum eChannels { + CHANNEL_1 = 0x01, + CHANNEL_2 = 0x02, + CHANNEL_3 = 0x04, + CHANNEL_4 = 0x08, + CHANNEL_5 = 0x10, + CHANNEL_ALL = 0xFF + }; + enum eButtons { + BUTTON_NONE = 0x0000, + VPAD_TOUCH = 0x80000000, + BUTTON_Z = 0x20000, + BUTTON_C = 0x10000, + BUTTON_A = 0x8000, + BUTTON_B = 0x4000, + BUTTON_X = 0x2000, + BUTTON_Y = 0x1000, + BUTTON_1 = BUTTON_Y, + BUTTON_2 = BUTTON_X, + BUTTON_LEFT = 0x0800, + BUTTON_RIGHT = 0x0400, + BUTTON_UP = 0x0200, + BUTTON_DOWN = 0x0100, + BUTTON_ZL = 0x0080, + BUTTON_ZR = 0x0040, + BUTTON_L = 0x0020, + BUTTON_R = 0x0010, + BUTTON_PLUS = 0x0008, + BUTTON_MINUS = 0x0004, + BUTTON_HOME = 0x0002, + BUTTON_SYNC = 0x0001, + STICK_R_LEFT = 0x04000000, + STICK_R_RIGHT = 0x02000000, + STICK_R_UP = 0x01000000, + STICK_R_DOWN = 0x00800000, + STICK_L_LEFT = 0x40000000, + STICK_L_RIGHT = 0x20000000, + STICK_L_UP = 0x10000000, + STICK_L_DOWN = 0x08000000 + }; + + //!Constructor + GuiTrigger(); + //!Constructor + GuiTrigger(u32 ch, u32 btns, bool clickEverywhere = false, bool holdEverywhere = false, bool selectionClickEverywhere = false); + //!Destructor + virtual ~GuiTrigger(); + //!Sets a simple trigger. Requires: element is selected, and trigger button is pressed + void setTrigger(u32 ch, u32 btns); + + void setClickEverywhere(bool b) { bClickEverywhere = b; } + void setHoldOnly(bool b) { bHoldEverywhere = b; } + void setSelectionClickEverywhere(bool b) { bSelectionClickEverywhere = b; } + + bool isClickEverywhere() const { return bClickEverywhere; } + bool isHoldEverywhere() const { return bHoldEverywhere; } + bool isSelectionClickEverywhere() const { return bSelectionClickEverywhere; } + + bool left(const GuiController *controller) const; + bool right(const GuiController *controller) const; + bool up(const GuiController *controller) const; + bool down(const GuiController *controller) const; + int clicked(const GuiController *controller) const; + bool held(const GuiController *controller) const; + bool released(const GuiController *controller) const; +private: + u32 chan; + u32 btns; + bool bClickEverywhere; + bool bHoldEverywhere; + bool bSelectionClickEverywhere; + bool bLastTouched; +}; + +#endif diff --git a/src/gui/Scrollbar.cpp b/src/gui/Scrollbar.cpp new file mode 100644 index 0000000..84979b2 --- /dev/null +++ b/src/gui/Scrollbar.cpp @@ -0,0 +1,277 @@ +/*************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "Scrollbar.h" +#include "resources/Resources.h" + +Scrollbar::Scrollbar(int h) + : touchTrigger(GuiTrigger::CHANNEL_1, GuiTrigger::VPAD_TOUCH) + , wpadTouchTrigger(GuiTrigger::CHANNEL_2 | GuiTrigger::CHANNEL_3 | GuiTrigger::CHANNEL_4 | GuiTrigger::CHANNEL_5, GuiTrigger::BUTTON_A) +{ + SelItem = 0; + SelInd = 0; + PageSize = 0; + EntrieCount = 0; + ScrollSpeed = 15; + ScrollState = 0; + + listChanged.connect(this, &Scrollbar::setScrollboxPosition); + + btnSoundClick = Resources::GetSound("button_click.mp3"); + scrollbarLine = Resources::GetImageData("scrollbarLine.png"); + arrowDown = Resources::GetImageData("scrollbarArrowDown.png"); + arrowUp = Resources::GetImageData("scrollbarArrowUp.png"); + scrollbarBox = Resources::GetImageData("scrollbarButton.png"); + + height = h; + width = scrollbarBox->getWidth(); + + MaxHeight = height * 0.5f - (scrollbarBox ? (scrollbarBox->getHeight() * 0.5f) : 0) - (arrowUp ? arrowUp->getHeight() : 0); + MinHeight = -height * 0.5f + (scrollbarBox ? (scrollbarBox->getHeight() * 0.5f) : 0) + (arrowDown ? arrowDown->getHeight() : 0); + + scrollbarLineImg = new GuiImage(scrollbarLine); + scrollbarLineImg->setParent(this); + scrollbarLineImg->setAlignment(ALIGN_CENTER | ALIGN_MIDDLE); + scrollbarLineImg->setPosition(0, 0); + + arrowDownImg = new GuiImage(arrowDown); + arrowUpImg = new GuiImage(arrowUp); + scrollbarBoxImg = new GuiImage(scrollbarBox); + + arrowUpBtn = new GuiButton(arrowUpImg->getWidth(), arrowUpImg->getHeight()); + arrowUpBtn->setParent(this); + arrowUpBtn->setImage(arrowUpImg); + arrowUpBtn->setAlignment(ALIGN_CENTER | ALIGN_TOP); + arrowUpBtn->setPosition(0, 0); + arrowUpBtn->setTrigger(&touchTrigger, 0); + arrowUpBtn->setTrigger(&wpadTouchTrigger, 1); + arrowUpBtn->setSoundClick(btnSoundClick); + arrowUpBtn->setEffectGrow(); + arrowUpBtn->clicked.connect(this, &Scrollbar::OnUpButtonClick); + + arrowDownBtn = new GuiButton(arrowDownImg->getWidth(), arrowDownImg->getHeight()); + arrowDownBtn->setParent(this); + arrowDownBtn->setImage(arrowDownImg); + arrowDownBtn->setAlignment(ALIGN_CENTER | ALIGN_BOTTOM); + arrowDownBtn->setPosition(0, 0); + arrowDownBtn->setTrigger(&touchTrigger, 0); + arrowDownBtn->setTrigger(&wpadTouchTrigger, 1); + arrowDownBtn->setSoundClick(btnSoundClick); + arrowDownBtn->setEffectGrow(); + arrowDownBtn->clicked.connect(this, &Scrollbar::OnDownButtonClick); + + scrollbarBoxBtn = new GuiButton(scrollbarBoxImg->getWidth(), height); + scrollbarBoxBtn->setParent(this); + scrollbarBoxBtn->setImage(scrollbarBoxImg); + scrollbarBoxBtn->setAlignment(ALIGN_CENTER | ALIGN_TOP); + scrollbarBoxBtn->setPosition(0, MaxHeight); + scrollbarBoxBtn->setHoldable(true); + scrollbarBoxBtn->setTrigger(&touchTrigger, 0); + scrollbarBoxBtn->setTrigger(&wpadTouchTrigger, 1); + scrollbarBoxBtn->setEffectGrow(); + scrollbarBoxBtn->held.connect(this, &Scrollbar::OnBoxButtonHold); +} + +Scrollbar::~Scrollbar() +{ + Resources::RemoveSound(btnSoundClick); + Resources::RemoveImageData(scrollbarLine); + Resources::RemoveImageData(arrowDown); + Resources::RemoveImageData(arrowUp); + Resources::RemoveImageData(scrollbarBox); + + delete arrowUpBtn; + delete arrowDownBtn; + delete scrollbarBoxBtn; + + delete scrollbarLineImg; + + delete arrowDownImg; + delete arrowUpImg; + delete scrollbarBoxImg; +} + +void Scrollbar::ScrollOneUp() +{ + if(SelItem == 0 && SelInd > 0) + { + // move list up by 1 + --SelInd; + } + else if(SelInd+SelItem > 0) + { + --SelItem; + } +} + +void Scrollbar::ScrollOneDown() +{ + if(SelInd+SelItem + 1 < EntrieCount) + { + if(SelItem == PageSize-1) + { + // move list down by 1 + SelInd++; + } + else + { + SelItem++; + } + } +} + +void Scrollbar::OnUpButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) +{ + if(ScrollState < ScrollSpeed) + return; + + ScrollOneUp(); + + ScrollState = 0; + listChanged(SelItem, SelInd); +} + +void Scrollbar::OnDownButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) +{ + if(ScrollState < ScrollSpeed) + return; + + ScrollOneDown(); + + ScrollState = 0; + listChanged(SelItem, SelInd); +} + +void Scrollbar::OnBoxButtonHold(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) +{ + if(EntrieCount == 0) + return; + + if(!controller->data.validPointer) + return; + + int y = controller->data.y - this->getCenterY(); + + int positionWiimote = LIMIT(y - MinHeight, 0, MaxHeight - MinHeight); + + int newSelected = (EntrieCount - 1) - (int) ((float) positionWiimote / (float) (MaxHeight-MinHeight) * (float) (EntrieCount-1)); + + int diff = newSelected-SelInd-SelItem; + + if(newSelected <= 0) + { + SelItem = 0; + SelInd = 0; + } + else if(newSelected >= EntrieCount-1) + { + SelItem = (PageSize-1 < EntrieCount-1) ? PageSize-1 : EntrieCount-1; + SelInd = EntrieCount-PageSize; + } + else if(newSelected < PageSize && SelInd == 0 && diff < 0) + { + SelItem = std::max(SelItem+diff, 0); + } + else if(EntrieCount-newSelected < PageSize && SelInd == EntrieCount-PageSize && diff > 0) + { + SelItem = std::min(SelItem+diff, PageSize-1); + } + else + { + SelInd = LIMIT(SelInd+diff, 0, ((EntrieCount-PageSize < 0) ? 0 : EntrieCount-PageSize)); + } + + ScrollState = 0; + listChanged(SelItem, SelInd); +} + +void Scrollbar::SetPageSize(int size) +{ + if(PageSize == size) + return; + + PageSize = size; + listChanged(SelItem, SelInd); +} + +void Scrollbar::SetSelectedItem(int pos) +{ + if(SelItem == pos) + return; + + SelItem = LIMIT(pos, 0, EntrieCount-1); + listChanged(SelItem, SelInd); +} + +void Scrollbar::SetSelectedIndex(int pos) +{ + if(SelInd == pos) + return; + + SelInd = pos; + listChanged(SelItem, SelInd); +} + +void Scrollbar::SetEntrieCount(int cnt) +{ + if(EntrieCount == cnt) + return; + + EntrieCount = cnt; + listChanged(SelItem, SelInd); +} + +void Scrollbar::setScrollboxPosition(int SelItem, int SelInd) +{ + int position = MaxHeight-(MaxHeight-MinHeight)*(SelInd+SelItem)/(EntrieCount-1); + + if(position < MinHeight || (SelInd+SelItem >= EntrieCount-1)) + position = MinHeight; + else if(position > MaxHeight || (SelInd+SelItem) == 0) + position = MaxHeight; + + scrollbarBoxBtn->setPosition(0, position); +} + +void Scrollbar::draw(CVideo * video) +{ + scrollbarLineImg->draw(video); + arrowUpBtn->draw(video); + arrowDownBtn->draw(video); + scrollbarBoxBtn->draw(video); + + updateEffects(); +} + +void Scrollbar::update(GuiController * t) +{ + if(this->isStateSet(STATE_DISABLED)) + return; + + arrowUpBtn->update(t); + arrowDownBtn->update(t); + scrollbarBoxBtn->update(t); + + ++ScrollState; +} + diff --git a/src/gui/Scrollbar.h b/src/gui/Scrollbar.h new file mode 100644 index 0000000..cd7fc94 --- /dev/null +++ b/src/gui/Scrollbar.h @@ -0,0 +1,84 @@ +/*************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef SCROLLBAR_HPP_ +#define SCROLLBAR_HPP_ + +#include "gui/GuiElement.h" +#include "gui/GuiButton.h" + +class Scrollbar : public GuiElement, public sigslot::has_slots<> +{ + public: + Scrollbar(int height); + virtual ~Scrollbar(); + void ScrollOneUp(); + void ScrollOneDown(); + int GetSelectedItem() { return SelItem; } + int GetSelectedIndex() { return SelInd; } + void draw(CVideo * video); + void update(GuiController * t); + + //! Signals + sigslot::signal2 listChanged; + //! Slots + void SetPageSize(int size); + void SetRowSize(int size); + void SetSelectedItem(int pos); + void SetSelectedIndex(int pos); + void SetEntrieCount(int cnt); + protected: + void setScrollboxPosition(int SelItem, int SelInd); + void OnUpButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); + void OnDownButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); + void OnBoxButtonHold(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); + + u32 ScrollState; + u16 ScrollSpeed; + + int MinHeight; + int MaxHeight; + int SelItem; + int SelInd; + int PageSize; + int EntrieCount; + int pressedChan; + + GuiButton * arrowUpBtn; + GuiButton * arrowDownBtn; + GuiButton * scrollbarBoxBtn; + GuiImage * scrollbarLineImg; + GuiImage * arrowDownImg; + GuiImage * arrowUpImg; + GuiImage * scrollbarBoxImg; + GuiImageData * scrollbarLine; + GuiImageData * arrowDown; + GuiImageData * arrowUp; + GuiImageData * scrollbarBox; + GuiSound * btnSoundClick; + + GuiTrigger touchTrigger; + GuiTrigger wpadTouchTrigger; +}; + +#endif diff --git a/src/gui/VPadController.h b/src/gui/VPadController.h new file mode 100644 index 0000000..5223774 --- /dev/null +++ b/src/gui/VPadController.h @@ -0,0 +1,63 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 VPAD_CONTROLLER_H_ +#define VPAD_CONTROLLER_H_ + +#include "GuiController.h" +#include "dynamic_libs/vpad_functions.h" + +class VPadController : public GuiController +{ +public: + //!Constructor + VPadController(int channel) + : GuiController(channel) + { + memset(&vpad, 0, sizeof(vpad)); + } + + //!Destructor + virtual ~VPadController() {} + + bool update(int width, int height) + { + lastData = data; + + int vpadError = -1; + VPADRead(0, &vpad, 1, &vpadError); + + if(vpadError == 0) + { + data.buttons_r = vpad.btns_r; + data.buttons_h = vpad.btns_h; + data.buttons_d = vpad.btns_d; + data.validPointer = !vpad.tpdata.invalid; + data.touched = vpad.tpdata.touched; + //! calculate the screen offsets + data.x = -(width >> 1) + ((int)(vpad.tpdata1.x * ((width)/1211.0f)*width) >> 12)-30; + data.y = -(height >> 1) + ((int)(vpad.tpdata1.y * ((height)/653.0f)*height) >> 12)-35; + + return true; + } + return false; + } + +private: + VPADData vpad; +}; + +#endif diff --git a/src/gui/WPadController.h b/src/gui/WPadController.h new file mode 100644 index 0000000..26d1d98 --- /dev/null +++ b/src/gui/WPadController.h @@ -0,0 +1,179 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 WPAD_CONTROLLER_H_ +#define WPAD_CONTROLLER_H_ + +#include "GuiController.h" +#include "dynamic_libs/padscore_functions.h" + +class WPadController : public GuiController +{ +public: + //!Constructor + WPadController(int channel) + : GuiController(channel) + { + memset(&kpadData, 0, sizeof(kpadData)); + } + + //!Destructor + virtual ~WPadController() {} + + u32 remapWiiMoteButtons(u32 buttons) + { + u32 conv_buttons = 0; + + if(buttons & WPAD_BUTTON_LEFT) + conv_buttons |= GuiTrigger::BUTTON_LEFT; + + if(buttons & WPAD_BUTTON_RIGHT) + conv_buttons |= GuiTrigger::BUTTON_RIGHT; + + if(buttons & WPAD_BUTTON_DOWN) + conv_buttons |= GuiTrigger::BUTTON_DOWN; + + if(buttons & WPAD_BUTTON_UP) + conv_buttons |= GuiTrigger::BUTTON_UP; + + if(buttons & WPAD_BUTTON_PLUS) + conv_buttons |= GuiTrigger::BUTTON_PLUS; + + if(buttons & WPAD_BUTTON_2) + conv_buttons |= GuiTrigger::BUTTON_2; + + if(buttons & WPAD_BUTTON_1) + conv_buttons |= GuiTrigger::BUTTON_1; + + if(buttons & WPAD_BUTTON_B) + conv_buttons |= GuiTrigger::BUTTON_B; + + if(buttons & WPAD_BUTTON_A) + conv_buttons |= GuiTrigger::BUTTON_A; + + if(buttons & WPAD_BUTTON_MINUS) + conv_buttons |= GuiTrigger::BUTTON_MINUS; + + if(buttons & WPAD_BUTTON_Z) + conv_buttons |= GuiTrigger::BUTTON_Z; + + if(buttons & WPAD_BUTTON_C) + conv_buttons |= GuiTrigger::BUTTON_C; + + if(buttons & WPAD_BUTTON_HOME) + conv_buttons |= GuiTrigger::BUTTON_HOME; + + return conv_buttons; + } + u32 remapClassicButtons(u32 buttons) + { + u32 conv_buttons = 0; + + if(buttons & WPAD_CLASSIC_BUTTON_LEFT) + conv_buttons |= GuiTrigger::BUTTON_LEFT; + + if(buttons & WPAD_CLASSIC_BUTTON_RIGHT) + conv_buttons |= GuiTrigger::BUTTON_RIGHT; + + if(buttons & WPAD_CLASSIC_BUTTON_DOWN) + conv_buttons |= GuiTrigger::BUTTON_DOWN; + + if(buttons & WPAD_CLASSIC_BUTTON_UP) + conv_buttons |= GuiTrigger::BUTTON_UP; + + if(buttons & WPAD_CLASSIC_BUTTON_PLUS) + conv_buttons |= GuiTrigger::BUTTON_PLUS; + + if(buttons & WPAD_CLASSIC_BUTTON_X) + conv_buttons |= GuiTrigger::BUTTON_X; + + if(buttons & WPAD_CLASSIC_BUTTON_Y) + conv_buttons |= GuiTrigger::BUTTON_Y; + + if(buttons & WPAD_CLASSIC_BUTTON_B) + conv_buttons |= GuiTrigger::BUTTON_B; + + if(buttons & WPAD_CLASSIC_BUTTON_A) + conv_buttons |= GuiTrigger::BUTTON_A; + + if(buttons & WPAD_CLASSIC_BUTTON_MINUS) + conv_buttons |= GuiTrigger::BUTTON_MINUS; + + if(buttons & WPAD_CLASSIC_BUTTON_HOME) + conv_buttons |= GuiTrigger::BUTTON_HOME; + + if(buttons & WPAD_CLASSIC_BUTTON_ZR) + conv_buttons |= GuiTrigger::BUTTON_ZR; + + if(buttons & WPAD_CLASSIC_BUTTON_ZL) + conv_buttons |= GuiTrigger::BUTTON_ZL; + + if(buttons & WPAD_CLASSIC_BUTTON_R) + conv_buttons |= GuiTrigger::BUTTON_R; + + if(buttons & WPAD_CLASSIC_BUTTON_L) + conv_buttons |= GuiTrigger::BUTTON_L; + + return conv_buttons; + } + + bool update(int width, int height) + { + lastData = data; + + u32 controller_type; + + //! check if the controller is connected + if(WPADProbe(chanIdx-1, &controller_type) != 0) + return false; + + KPADRead(chanIdx-1, &kpadData, 1); + + if(kpadData.device_type <= 1) + { + data.buttons_r = remapWiiMoteButtons(kpadData.btns_r); + data.buttons_h = remapWiiMoteButtons(kpadData.btns_h); + data.buttons_d = remapWiiMoteButtons(kpadData.btns_d); + } + else + { + data.buttons_r = remapClassicButtons(kpadData.classic.btns_r); + data.buttons_h = remapClassicButtons(kpadData.classic.btns_h); + data.buttons_d = remapClassicButtons(kpadData.classic.btns_d); + } + + data.validPointer = (kpadData.pos_valid == 1 || kpadData.pos_valid == 2) && (kpadData.pos_x >= -1.0f && kpadData.pos_x <= 1.0f) && (kpadData.pos_y >= -1.0f && kpadData.pos_y <= 1.0f); + //! calculate the screen offsets if pointer is valid else leave old value + if(data.validPointer) + { + data.x = (width >> 1) * kpadData.pos_x; + data.y = (height >> 1) * (-kpadData.pos_y); + + if(kpadData.angle_y > 0.0f) + data.pointerAngle = (-kpadData.angle_x + 1.0f) * 0.5f * 180.0f; + else + data.pointerAngle = (kpadData.angle_x + 1.0f) * 0.5f * 180.0f - 180.0f; + } + + return true; + } + +private: + KPADData kpadData; + u32 lastButtons; +}; + +#endif diff --git a/src/gui/sigslot.h b/src/gui/sigslot.h new file mode 100644 index 0000000..d1f3844 --- /dev/null +++ b/src/gui/sigslot.h @@ -0,0 +1,2731 @@ +// sigslot.h: Signal/Slot classes +// +// Written by Sarah Thompson (sarah@telergy.com) 2002. +// +// License: Public domain. You are free to use this code however you like, with the proviso that +// the author takes on no responsibility or liability for any use. +// +// QUICK DOCUMENTATION +// +// (see also the full documentation at http://sigslot.sourceforge.net/) +// +// #define switches +// SIGSLOT_PURE_ISO - Define this to force ISO C++ compliance. This also disables +// all of the thread safety support on platforms where it is +// available. +// +// SIGSLOT_USE_POSIX_THREADS - Force use of Posix threads when using a C++ compiler other than +// gcc on a platform that supports Posix threads. (When using gcc, +// this is the default - use SIGSLOT_PURE_ISO to disable this if +// necessary) +// +// SIGSLOT_DEFAULT_MT_POLICY - Where thread support is enabled, this defaults to multi_threaded_global. +// Otherwise, the default is single_threaded. #define this yourself to +// override the default. In pure ISO mode, anything other than +// single_threaded will cause a compiler error. +// +// PLATFORM NOTES +// +// Win32 - On Win32, the WIN32 symbol must be #defined. Most mainstream +// compilers do this by default, but you may need to define it +// yourself if your build environment is less standard. This causes +// the Win32 thread support to be compiled in and used automatically. +// +// Unix/Linux/BSD, etc. - If you're using gcc, it is assumed that you have Posix threads +// available, so they are used automatically. You can override this +// (as under Windows) with the SIGSLOT_PURE_ISO switch. If you're using +// something other than gcc but still want to use Posix threads, you +// need to #define SIGSLOT_USE_POSIX_THREADS. +// +// ISO C++ - If none of the supported platforms are detected, or if +// SIGSLOT_PURE_ISO is defined, all multithreading support is turned off, +// along with any code that might cause a pure ISO C++ environment to +// complain. Before you ask, gcc -ansi -pedantic won't compile this +// library, but gcc -ansi is fine. Pedantic mode seems to throw a lot of +// errors that aren't really there. If you feel like investigating this, +// please contact the author. +// +// +// THREADING MODES +// +// single_threaded - Your program is assumed to be single threaded from the point of view +// of signal/slot usage (i.e. all objects using signals and slots are +// created and destroyed from a single thread). Behaviour if objects are +// destroyed concurrently is undefined (i.e. you'll get the occasional +// segmentation fault/memory exception). +// +// multi_threaded_global - Your program is assumed to be multi threaded. Objects using signals and +// slots can be safely created and destroyed from any thread, even when +// connections exist. In multi_threaded_global mode, this is achieved by a +// single global mutex (actually a critical section on Windows because they +// are faster). This option uses less OS resources, but results in more +// opportunities for contention, possibly resulting in more context switches +// than are strictly necessary. +// +// multi_threaded_local - Behaviour in this mode is essentially the same as multi_threaded_global, +// except that each signal, and each object that inherits has_slots, all +// have their own mutex/critical section. In practice, this means that +// mutex collisions (and hence context switches) only happen if they are +// absolutely essential. However, on some platforms, creating a lot of +// mutexes can slow down the whole OS, so use this option with care. +// +// USING THE LIBRARY +// +// See the full documentation at http://sigslot.sourceforge.net/ +// +// +#ifndef SIGSLOT_H__ +#define SIGSLOT_H__ + +#include +#include + +#define _SIGSLOT_SINGLE_THREADED + +#ifndef SIGSLOT_DEFAULT_MT_POLICY +# ifdef _SIGSLOT_SINGLE_THREADED +# define SIGSLOT_DEFAULT_MT_POLICY single_threaded +# else +# define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local +# endif +#endif + + +namespace sigslot { + + class single_threaded + { + public: + single_threaded() + { + ; + } + + virtual ~single_threaded() + { + ; + } + + virtual void lock() + { + ; + } + + virtual void unlock() + { + ; + } + }; + +#ifdef _SIGSLOT_HAS_WIN32_THREADS + // The multi threading policies only get compiled in if they are enabled. + class multi_threaded_global + { + public: + multi_threaded_global() + { + static bool isinitialised = false; + + if(!isinitialised) + { + InitializeCriticalSection(get_critsec()); + isinitialised = true; + } + } + + multi_threaded_global(const multi_threaded_global&) + { + ; + } + + virtual ~multi_threaded_global() + { + ; + } + + virtual void lock() + { + EnterCriticalSection(get_critsec()); + } + + virtual void unlock() + { + LeaveCriticalSection(get_critsec()); + } + + private: + CRITICAL_SECTION* get_critsec() + { + static CRITICAL_SECTION g_critsec; + return &g_critsec; + } + }; + + class multi_threaded_local + { + public: + multi_threaded_local() + { + InitializeCriticalSection(&m_critsec); + } + + multi_threaded_local(const multi_threaded_local&) + { + InitializeCriticalSection(&m_critsec); + } + + virtual ~multi_threaded_local() + { + DeleteCriticalSection(&m_critsec); + } + + virtual void lock() + { + EnterCriticalSection(&m_critsec); + } + + virtual void unlock() + { + LeaveCriticalSection(&m_critsec); + } + + private: + CRITICAL_SECTION m_critsec; + }; +#endif // _SIGSLOT_HAS_WIN32_THREADS + +#ifdef _SIGSLOT_HAS_POSIX_THREADS + // The multi threading policies only get compiled in if they are enabled. + class multi_threaded_global + { + public: + multi_threaded_global() + { + pthread_mutex_init(get_mutex(), NULL); + } + + multi_threaded_global(const multi_threaded_global&) + { + ; + } + + virtual ~multi_threaded_global() + { + ; + } + + virtual void lock() + { + pthread_mutex_lock(get_mutex()); + } + + virtual void unlock() + { + pthread_mutex_unlock(get_mutex()); + } + + private: + pthread_mutex_t* get_mutex() + { + static pthread_mutex_t g_mutex; + return &g_mutex; + } + }; + + class multi_threaded_local + { + public: + multi_threaded_local() + { + pthread_mutex_init(&m_mutex, NULL); + } + + multi_threaded_local(const multi_threaded_local&) + { + pthread_mutex_init(&m_mutex, NULL); + } + + virtual ~multi_threaded_local() + { + pthread_mutex_destroy(&m_mutex); + } + + virtual void lock() + { + pthread_mutex_lock(&m_mutex); + } + + virtual void unlock() + { + pthread_mutex_unlock(&m_mutex); + } + + private: + pthread_mutex_t m_mutex; + }; +#endif // _SIGSLOT_HAS_POSIX_THREADS + +#ifdef _SIGSLOT_HAS_LWP_THREADS + + class multi_threaded_global + { + public: + multi_threaded_global() + { + ; + } + + multi_threaded_global(const multi_threaded_global&) + { + ; + } + + virtual ~multi_threaded_global() + { + ; + } + + virtual void lock() + { + ; + } + + virtual void unlock() + { + ; + } + }; + + class multi_threaded_local + { + public: + multi_threaded_local() + { + ; + } + + multi_threaded_local(const multi_threaded_local&) + { + ; + } + + virtual ~multi_threaded_local() + { + } + + virtual void lock() + { + ; + } + + virtual void unlock() + { + ; + } + }; + +#endif // _SIGSLOT_HAS_LWP_THREADS + + template + class lock_block + { + public: + mt_policy *m_mutex; + + lock_block(mt_policy *mtx) + : m_mutex(mtx) + { + m_mutex->lock(); + } + + ~lock_block() + { + m_mutex->unlock(); + } + }; + + template + class has_slots; + + template + class _connection_base0 + { + public: + virtual ~_connection_base0() { ; } + virtual has_slots* getdest() const = 0; + virtual void emit() = 0; + virtual _connection_base0* clone() = 0; + virtual _connection_base0* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base1 + { + public: + virtual ~_connection_base1() { ; } + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type) = 0; + virtual _connection_base1* clone() = 0; + virtual _connection_base1* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base2 + { + public: + virtual ~_connection_base2() { ; } + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type) = 0; + virtual _connection_base2* clone() = 0; + virtual _connection_base2* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base3 + { + public: + virtual ~_connection_base3() { ; } + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type) = 0; + virtual _connection_base3* clone() = 0; + virtual _connection_base3* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base4 + { + public: + virtual ~_connection_base4() { ; } + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type) = 0; + virtual _connection_base4* clone() = 0; + virtual _connection_base4* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base5 + { + public: + virtual ~_connection_base5() { ; } + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type) = 0; + virtual _connection_base5* clone() = 0; + virtual _connection_base5* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base6 + { + public: + virtual ~_connection_base6() { ; } + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, + arg6_type) = 0; + virtual _connection_base6* clone() = 0; + virtual _connection_base6* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base7 + { + public: + virtual ~_connection_base7() { ; } + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, + arg6_type, arg7_type) = 0; + virtual _connection_base7* clone() = 0; + virtual _connection_base7* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base8 + { + public: + virtual ~_connection_base8() { ; } + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, + arg6_type, arg7_type, arg8_type) = 0; + virtual _connection_base8* clone() = 0; + virtual _connection_base8* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _signal_base : public mt_policy + { + public: + virtual void slot_disconnect(has_slots* pslot) = 0; + virtual void slot_duplicate(const has_slots* poldslot, has_slots* pnewslot) = 0; + }; + + template + class has_slots : public mt_policy + { + private: + typedef typename std::set<_signal_base *> sender_set; + typedef typename sender_set::const_iterator const_iterator; + + public: + has_slots() + { + ; + } + + has_slots(const has_slots& hs) + : mt_policy(hs) + { + lock_block lock(this); + const_iterator it = hs.m_senders.begin(); + const_iterator itEnd = hs.m_senders.end(); + + while(it != itEnd) + { + (*it)->slot_duplicate(&hs, this); + m_senders.insert(*it); + ++it; + } + } + + void signal_connect(_signal_base* sender) + { + lock_block lock(this); + m_senders.insert(sender); + } + + void signal_disconnect(_signal_base* sender) + { + lock_block lock(this); + m_senders.erase(sender); + } + + virtual ~has_slots() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_senders.begin(); + const_iterator itEnd = m_senders.end(); + + while(it != itEnd) + { + (*it)->slot_disconnect(this); + ++it; + } + + m_senders.erase(m_senders.begin(), m_senders.end()); + } + + private: + sender_set m_senders; + }; + + template + class _signal_base0 : public _signal_base + { + public: + typedef typename std::list<_connection_base0 *> connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base0() + { + ; + } + + _signal_base0(const _signal_base0& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + ~_signal_base0() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + bool connected() + { + return m_connected_slots.size() != 0; + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base1 : public _signal_base + { + public: + typedef typename std::list<_connection_base1 *> connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base1() + { + ; + } + + _signal_base1(const _signal_base1& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base1() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + bool connected() + { + return m_connected_slots.size() != 0; + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base2 : public _signal_base + { + public: + typedef typename std::list<_connection_base2 *> + connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base2() + { + ; + } + + _signal_base2(const _signal_base2& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base2() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + bool connected() + { + return m_connected_slots.size() != 0; + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base3 : public _signal_base + { + public: + typedef std::list<_connection_base3 *> + connections_list; + + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + _signal_base3() + { + ; + } + + _signal_base3(const _signal_base3& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base3() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + bool connected() + { + return m_connected_slots.size() != 0; + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base4 : public _signal_base + { + public: + typedef std::list<_connection_base4 *> connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base4() + { + ; + } + + _signal_base4(const _signal_base4& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base4() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + this->m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + bool connected() + { + return m_connected_slots.size() != 0; + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base5 : public _signal_base + { + public: + typedef std::list<_connection_base5 *> connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base5() + { + ; + } + + _signal_base5(const _signal_base5& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base5() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + bool connected() + { + return m_connected_slots.size() != 0; + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base6 : public _signal_base + { + public: + typedef std::list<_connection_base6 *> connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base6() + { + ; + } + + _signal_base6(const _signal_base6& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base6() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + bool connected() + { + return m_connected_slots.size() != 0; + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base7 : public _signal_base + { + public: + typedef std::list<_connection_base7 *> connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base7() + { + ; + } + + _signal_base7(const _signal_base7& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base7() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + bool connected() + { + return m_connected_slots.size() != 0; + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base8 : public _signal_base + { + public: + typedef std::list<_connection_base8 *> + connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base8() + { + ; + } + + _signal_base8(const _signal_base8& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base8() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + bool connected() + { + return m_connected_slots.size() != 0; + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + + template + class _connection0 : public _connection_base0 + { + public: + _connection0() + { + this->pobject = NULL; + this->pmemfun = NULL; + } + + _connection0(dest_type* pobject, void (dest_type::*pmemfun)()) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection0() + { + ; + } + + virtual _connection_base0* clone() + { + return new _connection0(*this); + } + + virtual _connection_base0* duplicate(has_slots* pnewdest) + { + return new _connection0((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit() + { + (m_pobject->*m_pmemfun)(); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(); + }; + + template + class _connection1 : public _connection_base1 + { + public: + _connection1() + { + this->pobject = NULL; + this->pmemfun = NULL; + } + + _connection1(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection1() + { + ; + } + + virtual _connection_base1* clone() + { + return new _connection1(*this); + } + + virtual _connection_base1* duplicate(has_slots* pnewdest) + { + return new _connection1((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1) + { + (m_pobject->*m_pmemfun)(a1); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type); + }; + + template + class _connection2 : public _connection_base2 + { + public: + _connection2() + { + this->pobject = NULL; + this->pmemfun = NULL; + } + + _connection2(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection2() + { + ; + } + + + virtual _connection_base2* clone() + { + return new _connection2(*this); + } + + virtual _connection_base2* duplicate(has_slots* pnewdest) + { + return new _connection2((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2) + { + (m_pobject->*m_pmemfun)(a1, a2); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type); + }; + + template + class _connection3 : public _connection_base3 + { + public: + _connection3() + { + this->pobject = NULL; + this->pmemfun = NULL; + } + + _connection3(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection3() + { + ; + } + + + virtual _connection_base3* clone() + { + return new _connection3(*this); + } + + virtual _connection_base3* duplicate(has_slots* pnewdest) + { + return new _connection3((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3) + { + (m_pobject->*m_pmemfun)(a1, a2, a3); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type); + }; + + template + class _connection4 : public _connection_base4 + { + public: + _connection4() + { + this->pobject = NULL; + this->pmemfun = NULL; + } + + _connection4(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection4() + { + ; + } + + virtual _connection_base4* clone() + { + return new _connection4(*this); + } + + virtual _connection_base4* duplicate(has_slots* pnewdest) + { + return new _connection4((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, + arg4_type a4) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, + arg4_type); + }; + + template + class _connection5 : public _connection_base5 + { + public: + _connection5() + { + this->pobject = NULL; + this->pmemfun = NULL; + } + + _connection5(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection5() + { + ; + } + + virtual _connection_base5* clone() + { + return new _connection5(*this); + } + + virtual _connection_base5* duplicate(has_slots* pnewdest) + { + return new _connection5((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type); + }; + + template + class _connection6 : public _connection_base6 + { + public: + _connection6() + { + this->pobject = NULL; + this->pmemfun = NULL; + } + + _connection6(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection6() + { + ; + } + + virtual _connection_base6* clone() + { + return new _connection6(*this); + } + + virtual _connection_base6* duplicate(has_slots* pnewdest) + { + return new _connection6((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type); + }; + + template + class _connection7 : public _connection_base7 + { + public: + _connection7() + { + this->pobject = NULL; + this->pmemfun = NULL; + } + + _connection7(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection7() + { + ; + } + + virtual _connection_base7* clone() + { + return new _connection7(*this); + } + + virtual _connection_base7* duplicate(has_slots* pnewdest) + { + return new _connection7((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type); + }; + + template + class _connection8 : public _connection_base8 + { + public: + _connection8() + { + this->pobject = NULL; + this->pmemfun = NULL; + } + + _connection8(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, + arg7_type, arg8_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection8() + { + ; + } + + virtual _connection_base8* clone() + { + return new _connection8(*this); + } + + virtual _connection_base8* duplicate(has_slots* pnewdest) + { + return new _connection8((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7, a8); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, arg8_type); + }; + + template + class signal0 : public _signal_base0 + { + public: + typedef typename _signal_base0::connections_list::const_iterator const_iterator; + signal0() + { + ; + } + + signal0(const signal0& s) + : _signal_base0(s) + { + ; + } + + virtual ~signal0() + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)()) + { + lock_block lock(this); + _connection0* conn = + new _connection0(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit() + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(); + + it = itNext; + } + } + + void operator()() + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(); + + it = itNext; + } + } + }; + + template + class signal1 : public _signal_base1 + { + public: + typedef typename _signal_base1::connections_list::const_iterator const_iterator; + signal1() + { + ; + } + + signal1(const signal1& s) + : _signal_base1(s) + { + ; + } + + virtual ~signal1() + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type)) + { + lock_block lock(this); + _connection1* conn = + new _connection1(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1); + + it = itNext; + } + } + + void operator()(arg1_type a1) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1); + + it = itNext; + } + } + }; + + template + class signal2 : public _signal_base2 + { + public: + typedef typename _signal_base2::connections_list::const_iterator const_iterator; + signal2() + { + ; + } + + signal2(const signal2& s) + : _signal_base2(s) + { + ; + } + + virtual ~signal2() + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type)) + { + lock_block lock(this); + _connection2* conn = new + _connection2(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2); + + it = itNext; + } + } + }; + + template + class signal3 : public _signal_base3 + { + public: + typedef typename _signal_base3::connections_list::const_iterator const_iterator; + signal3() + { + ; + } + + signal3(const signal3& s) + : _signal_base3(s) + { + ; + } + + virtual ~signal3() + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type)) + { + lock_block lock(this); + _connection3* conn = + new _connection3(pclass, + pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3); + + it = itNext; + } + } + }; + + template + class signal4 : public _signal_base4 + { + public: + typedef typename _signal_base4::connections_list::const_iterator const_iterator; + signal4() + { + ; + } + + signal4(const signal4& s) + : _signal_base4(s) + { + ; + } + + virtual ~signal4() + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type)) + { + lock_block lock(this); + _connection4* + conn = new _connection4(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4); + + it = itNext; + } + } + }; + + template + class signal5 : public _signal_base5 + { + public: + typedef typename _signal_base5::connections_list::const_iterator const_iterator; + signal5() + { + ; + } + + signal5(const signal5& s) + : _signal_base5(s) + { + ; + } + + virtual ~signal5() + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type)) + { + lock_block lock(this); + _connection5* conn = new _connection5(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5); + + it = itNext; + } + } + }; + + + template + class signal6 : public _signal_base6 + { + public: + typedef typename _signal_base6::connections_list::const_iterator const_iterator; + signal6() + { + ; + } + + signal6(const signal6& s) + : _signal_base6(s) + { + ; + } + + virtual ~signal6() + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type)) + { + lock_block lock(this); + _connection6* conn = + new _connection6(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6); + + it = itNext; + } + } + }; + + template + class signal7 : public _signal_base7 + { + public: + typedef typename _signal_base7::connections_list::const_iterator const_iterator; + signal7() + { + ; + } + + signal7(const signal7& s) + : _signal_base7(s) + { + ; + } + + virtual ~signal7() + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, + arg7_type)) + { + lock_block lock(this); + _connection7* conn = + new _connection7(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7); + + it = itNext; + } + } + }; + + template + class signal8 : public _signal_base8 + { + public: + typedef typename _signal_base8::connections_list::const_iterator const_iterator; + signal8() + { + ; + } + + signal8(const signal8& s) + : _signal_base8(s) + { + ; + } + + virtual ~signal8() + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, + arg7_type, arg8_type)) + { + lock_block lock(this); + _connection8* conn = + new _connection8(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8); + + it = itNext; + } + } + }; + +}; // namespace sigslot + +#endif // SIGSLOT_H__ diff --git a/src/kernel/kernel_functions.c b/src/kernel/kernel_functions.c new file mode 100644 index 0000000..31f9ad0 --- /dev/null +++ b/src/kernel/kernel_functions.c @@ -0,0 +1,49 @@ +#include +#include "common/common.h" +#include "common/kernel_defs.h" +#include "kernel/kernel_functions.h" +#include "kernel/syscalls.h" + +/* our retain data */ +ReducedCosAppXmlInfo cosAppXmlInfoStruct __attribute__((section(".data"))); +/* + * This function is a kernel hook function. It is called directly from kernel code at position 0xFFF18558. + */ +void my_PrepareTitle(CosAppXmlInfo *xmlKernelInfo) +{ + /** + * DBAT for access to our data region is setup at this point for the 0xC0000000 area. + */ + + //! Copy all data from the XML info + strncpy(cosAppXmlInfoStruct.rpx_name, xmlKernelInfo->rpx_name, FS_MAX_ENTNAME_SIZE); + + cosAppXmlInfoStruct.version_cos_xml = xmlKernelInfo->version_cos_xml; + cosAppXmlInfoStruct.os_version = xmlKernelInfo->os_version; + cosAppXmlInfoStruct.title_id = xmlKernelInfo->title_id; + cosAppXmlInfoStruct.app_type = xmlKernelInfo->app_type; + cosAppXmlInfoStruct.cmdFlags = xmlKernelInfo->cmdFlags; + cosAppXmlInfoStruct.max_size = xmlKernelInfo->max_size; + cosAppXmlInfoStruct.avail_size = xmlKernelInfo->avail_size; + cosAppXmlInfoStruct.codegen_size = xmlKernelInfo->codegen_size; + cosAppXmlInfoStruct.codegen_core = xmlKernelInfo->codegen_core; + cosAppXmlInfoStruct.max_codesize = xmlKernelInfo->max_codesize; + cosAppXmlInfoStruct.overlay_arena = xmlKernelInfo->overlay_arena; + cosAppXmlInfoStruct.default_stack0_size = xmlKernelInfo->default_stack0_size; + cosAppXmlInfoStruct.default_stack1_size = xmlKernelInfo->default_stack1_size; + cosAppXmlInfoStruct.default_stack2_size = xmlKernelInfo->default_stack2_size; + cosAppXmlInfoStruct.default_redzone0_size = xmlKernelInfo->default_redzone0_size; + cosAppXmlInfoStruct.default_redzone1_size = xmlKernelInfo->default_redzone1_size; + cosAppXmlInfoStruct.default_redzone2_size = xmlKernelInfo->default_redzone2_size; + cosAppXmlInfoStruct.exception_stack0_size = xmlKernelInfo->exception_stack0_size; + cosAppXmlInfoStruct.exception_stack1_size = xmlKernelInfo->exception_stack1_size; + cosAppXmlInfoStruct.exception_stack2_size = xmlKernelInfo->exception_stack2_size; + cosAppXmlInfoStruct.sdk_version = xmlKernelInfo->sdk_version; + cosAppXmlInfoStruct.title_version = xmlKernelInfo->title_version; +} + +void SetupKernelCallback(void) +{ + KernelSetupSyscalls(); +} + diff --git a/src/kernel/kernel_functions.h b/src/kernel/kernel_functions.h new file mode 100644 index 0000000..79b89e4 --- /dev/null +++ b/src/kernel/kernel_functions.h @@ -0,0 +1,19 @@ +#ifndef __KERNEL_FUNCTIONS_H_ +#define __KERNEL_FUNCTIONS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "common/kernel_defs.h" +#include "syscalls.h" + +void SetupKernelCallback(void); + +extern ReducedCosAppXmlInfo cosAppXmlInfoStruct; + +#ifdef __cplusplus +} +#endif + +#endif // __KERNEL_FUNCTIONS_H_ diff --git a/src/kernel/kernel_hooks.S b/src/kernel/kernel_hooks.S new file mode 100644 index 0000000..04452c4 --- /dev/null +++ b/src/kernel/kernel_hooks.S @@ -0,0 +1,136 @@ +# Created by dimok +# This stuff may need a change in different kernel versions +# This is only needed when launched directly through browser and not SD card. + +.section ".kernel_code" + .globl SaveAndResetDataBATs_And_SRs_hook +SaveAndResetDataBATs_And_SRs_hook: + # setup CTR to the position we need to return to + mflr r5 + mtctr r5 + # set link register to its original value + mtlr r7 + # setup us a nice DBAT for our code data with same region as our code + mfspr r5, 560 + mtspr 570, r5 + mfspr r5, 561 + mtspr 571, r5 + # restore the original kernel instructions that we replaced + lwz r5, 0x34(r3) + lwz r6, 0x38(r3) + lwz r7, 0x3C(r3) + lwz r8, 0x40(r3) + lwz r9, 0x44(r3) + lwz r10, 0x48(r3) + lwz r11, 0x4C(r3) + lwz r3, 0x50(r3) + isync + mtsr 7, r5 + # jump back to the position in kernel after our patch (from LR) + bctr + +.extern my_PrepareTitle + .globl my_PrepareTitle_hook +my_PrepareTitle_hook: + # store all registers on stack to avoid issues with the call to C functions + stwu r1, -0x90(r1) + # registers for our own usage + # only need r31 and rest is from tests before, just leaving it for later tests + stw r28, 0x20(r1) + stw r29, 0x24(r1) + stw r30, 0x28(r1) + stw r31, 0x2C(r1) + + stw r3, 0x30(r1) + stw r4, 0x34(r1) + stw r5, 0x38(r1) + stw r6, 0x3C(r1) + stw r7, 0x40(r1) + stw r8, 0x44(r1) + stw r9, 0x48(r1) + stw r10, 0x4C(r1) + stw r11, 0x50(r1) + stw r12, 0x54(r1) + stw r13, 0x58(r1) + stw r14, 0x5C(r1) + stw r15, 0x60(r1) + stw r16, 0x64(r1) + stw r17, 0x68(r1) + stw r18, 0x6C(r1) + stw r19, 0x70(r1) + stw r20, 0x74(r1) + stw r21, 0x78(r1) + stw r22, 0x7C(r1) + + # save original DBAT registers + mfdbatu r28, 0 + mfdbatl r29, 0 + + # setup access to our data memory range + lis r3, 0xC000 + ori r3, r3, 0x1FFF + mtdbatu 0, r3 + lis r3, 0x3000 + ori r3, r3, 0x0012 + mtdbatl 0, r3 + + # memory barrier + eieio + isync + + # save the LR from where we came + mflr r31 + + # the cos.xml/app.xml structure is at the location 0x68 of r11 + # there are actually many places that can be hooked for it + # e.g. 0xFFF16130 and r27 points to this structure + addi r3, r11, 0x68 + + bl my_PrepareTitle + + # restore original DBAT registers + mtdbatu 0, r28 + mtdbatl 0, r29 + + # memory barrier + eieio + isync + + # setup LR to jump back to kernel code + mtlr r31 + + # restore all original values of registers from stack + lwz r28, 0x20(r1) + lwz r29, 0x24(r1) + lwz r30, 0x28(r1) + lwz r31, 0x2C(r1) + + lwz r3, 0x30(r1) + lwz r4, 0x34(r1) + lwz r5, 0x38(r1) + lwz r6, 0x3C(r1) + lwz r7, 0x40(r1) + lwz r8, 0x44(r1) + lwz r9, 0x48(r1) + lwz r10, 0x4C(r1) + lwz r11, 0x50(r1) + lwz r12, 0x54(r1) + lwz r13, 0x58(r1) + lwz r14, 0x5C(r1) + lwz r15, 0x60(r1) + lwz r16, 0x64(r1) + lwz r17, 0x68(r1) + lwz r18, 0x6C(r1) + lwz r19, 0x70(r1) + lwz r20, 0x74(r1) + lwz r21, 0x78(r1) + lwz r22, 0x7C(r1) + + # restore the stack + addi r1, r1, 0x90 + + # restore original instruction that we replaced in the kernel + clrlwi r7, r12, 0 + + # jump back + blr diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c new file mode 100644 index 0000000..9685e4a --- /dev/null +++ b/src/kernel/syscalls.c @@ -0,0 +1,255 @@ +#include "common/os_defs.h" +#include "common/kernel_defs.h" +#include "common/common.h" +#include "dynamic_libs/os_functions.h" +#include "utils/utils.h" +#include "syscalls.h" + +extern void my_PrepareTitle_hook(void); + +static unsigned int origPrepareTitleInstr __attribute__((section(".data"))) = 0; + +static void KernelCopyData(unsigned int addr, unsigned int src, unsigned int len) +{ + /* + * Setup a DBAT access with cache inhibited to write through and read directly from memory + */ + unsigned int dbatu0, dbatl0, dbatu1, dbatl1; + // save the original DBAT value + asm volatile("mfdbatu %0, 0" : "=r" (dbatu0)); + asm volatile("mfdbatl %0, 0" : "=r" (dbatl0)); + asm volatile("mfdbatu %0, 1" : "=r" (dbatu1)); + asm volatile("mfdbatl %0, 1" : "=r" (dbatl1)); + + unsigned int target_dbatu0 = 0; + unsigned int target_dbatl0 = 0; + unsigned int target_dbatu1 = 0; + unsigned int target_dbatl1 = 0; + + unsigned char *dst_p = (unsigned char*)addr; + unsigned char *src_p = (unsigned char*)src; + + // we only need DBAT modification for addresses out of our own DBAT range + // as our own DBAT is available everywhere for user and supervisor + // since our own DBAT is on DBAT5 position we don't collide here + if(addr < 0x00800000 || addr >= 0x01000000) + { + target_dbatu0 = (addr & 0x00F00000) | 0xC0000000 | 0x1F; + target_dbatl0 = (addr & 0xFFF00000) | 0x32; + asm volatile("mtdbatu 0, %0" : : "r" (target_dbatu0)); + asm volatile("mtdbatl 0, %0" : : "r" (target_dbatl0)); + dst_p = (unsigned char*)((addr & 0xFFFFFF) | 0xC0000000); + } + if(src < 0x00800000 || src >= 0x01000000) + { + target_dbatu1 = (src & 0x00F00000) | 0xB0000000 | 0x1F; + target_dbatl1 = (src & 0xFFF00000) | 0x32; + + asm volatile("mtdbatu 1, %0" : : "r" (target_dbatu1)); + asm volatile("mtdbatl 1, %0" : : "r" (target_dbatl1)); + src_p = (unsigned char*)((src & 0xFFFFFF) | 0xB0000000); + } + + asm volatile("eieio; isync"); + + unsigned int i; + for(i = 0; i < len; i++) + { + // if we are on the edge to next chunk + if((target_dbatu0 != 0) && (((unsigned int)dst_p & 0x00F00000) != (target_dbatu0 & 0x00F00000))) + { + target_dbatu0 = ((addr + i) & 0x00F00000) | 0xC0000000 | 0x1F; + target_dbatl0 = ((addr + i) & 0xFFF00000) | 0x32; + dst_p = (unsigned char*)(((addr + i) & 0xFFFFFF) | 0xC0000000); + + asm volatile("eieio; isync"); + asm volatile("mtdbatu 0, %0" : : "r" (target_dbatu0)); + asm volatile("mtdbatl 0, %0" : : "r" (target_dbatl0)); + asm volatile("eieio; isync"); + } + if((target_dbatu1 != 0) && (((unsigned int)src_p & 0x00F00000) != (target_dbatu1 & 0x00F00000))) + { + target_dbatu1 = ((src + i) & 0x00F00000) | 0xB0000000 | 0x1F; + target_dbatl1 = ((src + i) & 0xFFF00000) | 0x32; + src_p = (unsigned char*)(((src + i) & 0xFFFFFF) | 0xB0000000); + + asm volatile("eieio; isync"); + asm volatile("mtdbatu 1, %0" : : "r" (target_dbatu1)); + asm volatile("mtdbatl 1, %0" : : "r" (target_dbatl1)); + asm volatile("eieio; isync"); + } + + *dst_p = *src_p; + + ++dst_p; + ++src_p; + } + + /* + * Restore original DBAT value + */ + asm volatile("eieio; isync"); + asm volatile("mtdbatu 0, %0" : : "r" (dbatu0)); + asm volatile("mtdbatl 0, %0" : : "r" (dbatl0)); + asm volatile("mtdbatu 1, %0" : : "r" (dbatu1)); + asm volatile("mtdbatl 1, %0" : : "r" (dbatl1)); + asm volatile("eieio; isync"); +} + +static void KernelReadDBATs(bat_table_t * table) +{ + u32 i = 0; + + asm volatile("eieio; isync"); + + asm volatile("mfspr %0, 536" : "=r" (table->bat[i].h)); + asm volatile("mfspr %0, 537" : "=r" (table->bat[i].l)); + i++; + asm volatile("mfspr %0, 538" : "=r" (table->bat[i].h)); + asm volatile("mfspr %0, 539" : "=r" (table->bat[i].l)); + i++; + asm volatile("mfspr %0, 540" : "=r" (table->bat[i].h)); + asm volatile("mfspr %0, 541" : "=r" (table->bat[i].l)); + i++; + asm volatile("mfspr %0, 542" : "=r" (table->bat[i].h)); + asm volatile("mfspr %0, 543" : "=r" (table->bat[i].l)); + i++; + + asm volatile("mfspr %0, 568" : "=r" (table->bat[i].h)); + asm volatile("mfspr %0, 569" : "=r" (table->bat[i].l)); + i++; + asm volatile("mfspr %0, 570" : "=r" (table->bat[i].h)); + asm volatile("mfspr %0, 571" : "=r" (table->bat[i].l)); + i++; + asm volatile("mfspr %0, 572" : "=r" (table->bat[i].h)); + asm volatile("mfspr %0, 573" : "=r" (table->bat[i].l)); + i++; + asm volatile("mfspr %0, 574" : "=r" (table->bat[i].h)); + asm volatile("mfspr %0, 575" : "=r" (table->bat[i].l)); +} + +static void KernelWriteDBATs(bat_table_t * table) +{ + u32 i = 0; + + asm volatile("eieio; isync"); + + asm volatile("mtspr 536, %0" : : "r" (table->bat[i].h)); + asm volatile("mtspr 537, %0" : : "r" (table->bat[i].l)); + i++; + asm volatile("mtspr 538, %0" : : "r" (table->bat[i].h)); + asm volatile("mtspr 539, %0" : : "r" (table->bat[i].l)); + i++; + asm volatile("mtspr 540, %0" : : "r" (table->bat[i].h)); + asm volatile("mtspr 541, %0" : : "r" (table->bat[i].l)); + i++; + asm volatile("mtspr 542, %0" : : "r" (table->bat[i].h)); + asm volatile("mtspr 543, %0" : : "r" (table->bat[i].l)); + i++; + + asm volatile("mtspr 568, %0" : : "r" (table->bat[i].h)); + asm volatile("mtspr 569, %0" : : "r" (table->bat[i].l)); + i++; + asm volatile("mtspr 570, %0" : : "r" (table->bat[i].h)); + asm volatile("mtspr 571, %0" : : "r" (table->bat[i].l)); + i++; + asm volatile("mtspr 572, %0" : : "r" (table->bat[i].h)); + asm volatile("mtspr 573, %0" : : "r" (table->bat[i].l)); + i++; + asm volatile("mtspr 574, %0" : : "r" (table->bat[i].h)); + asm volatile("mtspr 575, %0" : : "r" (table->bat[i].l)); + + asm volatile("eieio; isync"); +} + +/* Read a 32-bit word with kernel permissions */ +uint32_t __attribute__ ((noinline)) kern_read(const void *addr) +{ + uint32_t result; + asm volatile ( + "li 3,1\n" + "li 4,0\n" + "li 5,0\n" + "li 6,0\n" + "li 7,0\n" + "lis 8,1\n" + "mr 9,%1\n" + "li 0,0x3400\n" + "mr %0,1\n" + "sc\n" + "nop\n" + "mr 1,%0\n" + "mr %0,3\n" + : "=r"(result) + : "b"(addr) + : "memory", "ctr", "lr", "0", "3", "4", "5", "6", "7", "8", "9", "10", + "11", "12" + ); + + return result; +} + +/* Write a 32-bit word with kernel permissions */ +void __attribute__ ((noinline)) kern_write(void *addr, uint32_t value) +{ + asm volatile ( + "li 3,1\n" + "li 4,0\n" + "mr 5,%1\n" + "li 6,0\n" + "li 7,0\n" + "lis 8,1\n" + "mr 9,%0\n" + "mr %1,1\n" + "li 0,0x3500\n" + "sc\n" + "nop\n" + "mr 1,%1\n" + : + : "r"(addr), "r"(value) + : "memory", "ctr", "lr", "0", "3", "4", "5", "6", "7", "8", "9", "10", + "11", "12" + ); +} + +void KernelSetupSyscalls(void) +{ + //! assign 1 so that this variable gets into the retained .data section + static uint8_t ucSyscallsSetupRequired = 1; + if(!ucSyscallsSetupRequired) + return; + + ucSyscallsSetupRequired = 0; + + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x36 * 4)), (unsigned int)KernelReadDBATs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x36 * 4)), (unsigned int)KernelReadDBATs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x36 * 4)), (unsigned int)KernelReadDBATs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x36 * 4)), (unsigned int)KernelReadDBATs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x36 * 4)), (unsigned int)KernelReadDBATs); + + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x37 * 4)), (unsigned int)KernelWriteDBATs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x37 * 4)), (unsigned int)KernelWriteDBATs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x37 * 4)), (unsigned int)KernelWriteDBATs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x37 * 4)), (unsigned int)KernelWriteDBATs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x37 * 4)), (unsigned int)KernelWriteDBATs); + + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x25 * 4)), (unsigned int)KernelCopyData); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x25 * 4)), (unsigned int)KernelCopyData); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x25 * 4)), (unsigned int)KernelCopyData); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x25 * 4)), (unsigned int)KernelCopyData); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x25 * 4)), (unsigned int)KernelCopyData); + + //! write our hook to the + u32 addr_my_PrepareTitle_hook = ((u32)my_PrepareTitle_hook) | 0x48000003; + DCFlushRange(&addr_my_PrepareTitle_hook, sizeof(addr_my_PrepareTitle_hook)); + + SC0x25_KernelCopyData((u32)&origPrepareTitleInstr, (u32)addr_PrepareTitle_hook, 4); + SC0x25_KernelCopyData((u32)addr_PrepareTitle_hook, (u32)OSEffectiveToPhysical(&addr_my_PrepareTitle_hook), 4); +} + + +void KernelRestoreInstructions(void) +{ + if(origPrepareTitleInstr != 0) + SC0x25_KernelCopyData((u32)addr_PrepareTitle_hook, (u32)&origPrepareTitleInstr, 4); +} diff --git a/src/kernel/syscalls.h b/src/kernel/syscalls.h new file mode 100644 index 0000000..344fa39 --- /dev/null +++ b/src/kernel/syscalls.h @@ -0,0 +1,26 @@ + +#ifndef __SYSCALLS_H_ +#define __SYSCALLS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "common/kernel_defs.h" + +void KernelSetupSyscalls(void); +void KernelRestoreInstructions(void); + +void SC0x25_KernelCopyData(unsigned int addr, unsigned int src, unsigned int len); +void SC0x36_KernelReadDBATs(bat_table_t * table); +void SC0x37_KernelWriteDBATs(bat_table_t * table); + +uint32_t __attribute__ ((noinline)) kern_read(const void *addr); +void __attribute__ ((noinline)) kern_write(void *addr, uint32_t value); + +#ifdef __cplusplus +} +#endif + +#endif // __KERNEL_FUNCTIONS_H_ diff --git a/src/kernel/syscalls_asm.S b/src/kernel/syscalls_asm.S new file mode 100644 index 0000000..60bf1fa --- /dev/null +++ b/src/kernel/syscalls_asm.S @@ -0,0 +1,20 @@ +# Created by dimok +# Syscalls for kernel that we use + + .globl SC0x36_KernelReadDBATs +SC0x36_KernelReadDBATs: + li r0, 0x3600 + sc + blr + + .globl SC0x37_KernelWriteDBATs +SC0x37_KernelWriteDBATs: + li r0, 0x3700 + sc + blr + + .globl SC0x25_KernelCopyData +SC0x25_KernelCopyData: + li r0, 0x2500 + sc + blr diff --git a/src/link.ld b/src/link.ld new file mode 100644 index 0000000..30737dc --- /dev/null +++ b/src/link.ld @@ -0,0 +1,43 @@ +OUTPUT(hidtovpad.elf); + +/* Tell linker where our application entry is so the garbage collect can work correct */ +ENTRY(__entry_menu); + +SECTIONS { + . = 0x00802000; + .text : { + *(.kernel_code*); + *(.text*); + /* Tell linker to not garbage collect this section as it is not referenced anywhere */ + KEEP(*(.kernel_code*)); + } + .rodata : { + *(.rodata*); + } + .data : { + *(.data*); + + __sdata_start = .; + *(.sdata*); + __sdata_end = .; + + __sdata2_start = .; + *(.sdata2*); + __sdata2_end = .; + } + .bss : { + __bss_start = .; + *(.bss*); + *(.sbss*); + *(COMMON); + __bss_end = .; + } + __CODE_END = .; + + /DISCARD/ : { + *(*); + } +} + +/******************************************************** FS ********************************************************/ +/* coreinit.rpl difference in addresses 0xFE3C00 */ diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..f40e3c2 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,65 @@ +#include "Application.h" +#include "dynamic_libs/os_functions.h" +#include "dynamic_libs/gx2_functions.h" +#include "dynamic_libs/syshid_functions.h" +#include "dynamic_libs/vpad_functions.h" +#include "dynamic_libs/padscore_functions.h" +#include "dynamic_libs/socket_functions.h" +#include "dynamic_libs/sys_functions.h" +#include "dynamic_libs/ax_functions.h" +#include "dynamic_libs/fs_functions.h" +#include "fs/fs_utils.h" +#include "fs/sd_fat_devoptab.h" +#include "system/memory.h" +#include "utils/logger.h" +#include "utils/utils.h" +#include "common/common.h" + +#include "main.h" +#include "common/common.h" + +#include "utils/logger.h" + +#include "system/memory.h" + +/* Entry point */ +extern "C" int Menu_Main(void){ + //!******************************************************************* + //! Initialize function pointers * + //!******************************************************************* + //! do OS (for acquire) and sockets first so we got logging + InitOSFunctionPointers(); + InitSocketFunctionPointers(); + InitGX2FunctionPointers(); + InitSysFunctionPointers(); + InitVPadFunctionPointers(); + InitPadScoreFunctionPointers(); + InitAXFunctionPointers(); + InitFSFunctionPointers(); + + log_init("192.168.0.181"); + + //Otherwise apply the patches!!! + log_printf("GX2_template\n\n"); + + //!******************************************************************* + //! Initialize heap memory * + //!******************************************************************* + log_print("Initialize memory management\n"); + memoryInitialize(); + + log_printf("Mount SD partition\n"); + mount_sd_fat("sd"); + log_printf("Start main application\n"); + Application::instance()->exec(); + + Application::destroyInstance(); + log_printf("Unmount SD\n"); + unmount_sd_fat("sd"); + memoryRelease(); + + log_print("Going back to the Homebrew launcher\n"); + + log_deinit(); + return EXIT_SUCCESS; +} diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..a0fb71e --- /dev/null +++ b/src/main.h @@ -0,0 +1,19 @@ +#ifndef _MAIN_H_ +#define _MAIN_H_ + +#include "common/types.h" +#include "dynamic_libs/os_functions.h" + +/* Main */ +#ifdef __cplusplus +extern "C" { +#endif + +//! C wrapper for our C++ functions +int Menu_Main(void); +void deInit(void); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/menu/MainWindow.cpp b/src/menu/MainWindow.cpp new file mode 100644 index 0000000..e7f55ab --- /dev/null +++ b/src/menu/MainWindow.cpp @@ -0,0 +1,222 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * Modified by Maschell, 2016 for GX2_GUI_Template + * + * 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 . + ****************************************************************************/ +#include "MainWindow.h" +#include "MainWindowTV.h" +#include "dynamic_libs/os_functions.h" +#include "dynamic_libs/socket_functions.h" +#include "Application.h" +#include "utils/StringTools.h" +#include "utils/logger.h" + +MainWindow::MainWindow(int w, int h) + : width(w) + , height(h) +{ + for(int i = 0; i < 4; i++) + { + std::string filename = strfmt("player%i_point.png", i+1); + pointerImgData[i] = Resources::GetImageData(filename.c_str()); + pointerImg[i] = new GuiImage(pointerImgData[i]); + pointerImg[i]->setScale(1.5f); + pointerValid[i] = false; + } + + SetupMainView(); +} + +MainWindow::~MainWindow() +{ + + while(!tvElements.empty()) + { + delete tvElements[0]; + remove(tvElements[0]); + } + while(!drcElements.empty()) + { + delete drcElements[0]; + remove(drcElements[0]); + } + for(int i = 0; i < 4; i++) + { + delete pointerImg[i]; + Resources::RemoveImageData(pointerImgData[i]); + } +} + +void MainWindow::updateEffects() +{ + //! dont read behind the initial elements in case one was added + u32 tvSize = tvElements.size(); + u32 drcSize = drcElements.size(); + + for(u32 i = 0; (i < drcSize) && (i < drcElements.size()); ++i) + { + drcElements[i]->updateEffects(); + } + + //! only update TV elements that are not updated yet because they are on DRC + for(u32 i = 0; (i < tvSize) && (i < tvElements.size()); ++i) + { + u32 n; + for(n = 0; (n < drcSize) && (n < drcElements.size()); n++) + { + if(tvElements[i] == drcElements[n]) + break; + } + if(n == drcElements.size()) + { + tvElements[i]->updateEffects(); + } + } +} + +void MainWindow::process(){ + //! dont read behind the initial elements in case one was added + u32 tvSize = tvElements.size(); + u32 drcSize = drcElements.size(); + + for(u32 i = 0; (i < drcSize) && (i < drcElements.size()); ++i) + { + drcElements[i]->process(); + } + + //! only update TV elements that are not updated yet because they are on DRC + for(u32 i = 0; (i < tvSize) && (i < tvElements.size()); ++i) + { + u32 n; + for(n = 0; (n < drcSize) && (n < drcElements.size()); n++) + { + if(tvElements[i] == drcElements[n]) + break; + } + if(n == drcElements.size()) + { + tvElements[i]->process(); + } + } +} + +void MainWindow::update(GuiController *controller) +{ + //! dont read behind the initial elements in case one was added + //u32 tvSize = tvElements.size(); + + if(controller->chan & GuiTrigger::CHANNEL_1) + { + u32 drcSize = drcElements.size(); + + for(u32 i = 0; (i < drcSize) && (i < drcElements.size()); ++i) + { + drcElements[i]->update(controller); + } + } + else + { + u32 tvSize = tvElements.size(); + + for(u32 i = 0; (i < tvSize) && (i < tvElements.size()); ++i) + { + tvElements[i]->update(controller); + } + } + +// //! only update TV elements that are not updated yet because they are on DRC +// for(u32 i = 0; (i < tvSize) && (i < tvElements.size()); ++i) +// { +// u32 n; +// for(n = 0; (n < drcSize) && (n < drcElements.size()); n++) +// { +// if(tvElements[i] == drcElements[n]) +// break; +// } +// if(n == drcElements.size()) +// { +// tvElements[i]->update(controller); +// } +// } + + if(controller->chanIdx >= 1 && controller->chanIdx <= 4 && controller->data.validPointer) + { + int wpadIdx = controller->chanIdx - 1; + f32 posX = controller->data.x; + f32 posY = controller->data.y; + pointerImg[wpadIdx]->setPosition(posX, posY); + pointerImg[wpadIdx]->setAngle(controller->data.pointerAngle); + pointerValid[wpadIdx] = true; + } +} + +void MainWindow::drawDrc(CVideo *video) +{ + for(u32 i = 0; i < drcElements.size(); ++i) + { + drcElements[i]->draw(video); + } + + for(int i = 0; i < 4; i++) + { + if(pointerValid[i]) + { + pointerImg[i]->setAlpha(0.5f); + pointerImg[i]->draw(video); + pointerImg[i]->setAlpha(1.0f); + } + } +} + +void MainWindow::drawTv(CVideo *video) +{ + for(u32 i = 0; i < tvElements.size(); ++i) + { + tvElements[i]->draw(video); + } + + for(int i = 0; i < 4; i++) + { + if(pointerValid[i]) + { + pointerImg[i]->draw(video); + pointerValid[i] = false; + } + } +} + +void MainWindow::SetupMainView() +{ + + //DrcFrame = new MainWindowDRC(width,height); + TvFrame = new MainWindowTV(width,height); + DrcFrame = TvFrame; + appendTv(TvFrame); + appendDrc(DrcFrame); +} + +void MainWindow::OnOpenEffectFinish(GuiElement *element) +{ + //! once the menu is open reset its state and allow it to be "clicked/hold" + element->effectFinished.disconnect(this); + element->clearState(GuiElement::STATE_DISABLED); +} + +void MainWindow::OnCloseEffectFinish(GuiElement *element) +{ + //! remove element from draw list and push to delete queue + remove(element); + AsyncDeleter::pushForDelete(element); +} diff --git a/src/menu/MainWindow.h b/src/menu/MainWindow.h new file mode 100644 index 0000000..8f160a3 --- /dev/null +++ b/src/menu/MainWindow.h @@ -0,0 +1,153 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * Modified by Maschell, 2016 for GX2_GUI_Template + * + * 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 _MAIN_WINDOW_H_ +#define _MAIN_WINDOW_H_ + +#include +#include +#include "gui/Gui.h" +#include "system/CMutex.h" +#include "gui/GuiMainWindowScreen.h" + +class CVideo; + +class MainWindow : public sigslot::has_slots<> +{ +public: + MainWindow(int w, int h); + virtual ~MainWindow(); + + void appendTv(GuiElement *e) + { + if(!e) + return; + + removeTv(e); + tvElements.push_back(e); + } + void appendDrc(GuiElement *e) + { + if(!e) + return; + + removeDrc(e); + drcElements.push_back(e); + } + + void append(GuiElement *e) + { + appendTv(e); + appendDrc(e); + } + + void insertTv(u32 pos, GuiElement *e) + { + if(!e) + return; + + removeTv(e); + tvElements.insert(tvElements.begin() + pos, e); + } + void insertDrc(u32 pos, GuiElement *e) + { + if(!e) + return; + + removeDrc(e); + drcElements.insert(drcElements.begin() + pos, e); + } + + void insert(u32 pos, GuiElement *e) + { + insertTv(pos, e); + insertDrc(pos, e); + } + + void removeTv(GuiElement *e) + { + for(u32 i = 0; i < tvElements.size(); ++i) + { + if(e == tvElements[i]) + { + tvElements.erase(tvElements.begin() + i); + break; + } + } + } + void removeDrc(GuiElement *e) + { + for(u32 i = 0; i < drcElements.size(); ++i) + { + if(e == drcElements[i]) + { + drcElements.erase(drcElements.begin() + i); + break; + } + } + } + + void remove(GuiElement *e) + { + removeTv(e); + removeDrc(e); + } + void removeAll() + { + tvElements.clear(); + drcElements.clear(); + } + + void drawDrc(CVideo *video); + void drawTv(CVideo *video); + void update(GuiController *controller); + void updateEffects(); + + void process(); + + void lockGUI() + { + guiMutex.lock(); + } + void unlockGUI() + { + guiMutex.unlock(); + } + +private: + void SetupMainView(void); + + void OnOpenEffectFinish(GuiElement *element); + void OnCloseEffectFinish(GuiElement *element); + + int width, height; + std::vector drcElements; + std::vector tvElements; + + GuiSound *ClickSound; + + GuiMainWindowScreen * TvFrame; + GuiMainWindowScreen * DrcFrame; + + GuiImageData *pointerImgData[4]; + GuiImage *pointerImg[4]; + bool pointerValid[4]; + + CMutex guiMutex; +}; + +#endif //_MAIN_WINDOW_H_ diff --git a/src/menu/MainWindowTV.cpp b/src/menu/MainWindowTV.cpp new file mode 100644 index 0000000..671bcc3 --- /dev/null +++ b/src/menu/MainWindowTV.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * Modified by Maschell, 2016 for GX2_GUI_Template + * + * 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 . + ****************************************************************************/ +#include "MainWindowTV.h" +#include "utils/logger.h" + +MainWindowTV::MainWindowTV(int w, int h) + : GuiMainWindowScreen(w, h) + , width(w) + , height(h) + ,bgImageColor(w, h, (GX2Color){ 0, 0, 0, 0 }) +{ + bgImageColor.setImageColor((GX2Color){ 248, 248, 249, 255 }, 0); + bgImageColor.setImageColor((GX2Color){ 248, 248, 249, 255 }, 1); + bgImageColor.setImageColor((GX2Color){ 248, 248, 249, 255 }, 2); + bgImageColor.setImageColor((GX2Color){ 248, 248, 249, 255 }, 3); + append(&bgImageColor); +} + +MainWindowTV::~MainWindowTV() +{ + remove(&bgImageColor); +} + +void MainWindowTV::draw(CVideo *v){ + GuiMainWindowScreen::draw(v); + //gets called on every frame fro drawing +} + + +void MainWindowTV::update(GuiController * c){ + GuiMainWindowScreen::update(c); + //CONTROLLER UPDATE!!! +} + +void MainWindowTV::process(){ + GuiMainWindowScreen::process(); + //gets called on every frame +} diff --git a/src/menu/MainWindowTV.h b/src/menu/MainWindowTV.h new file mode 100644 index 0000000..c1fe553 --- /dev/null +++ b/src/menu/MainWindowTV.h @@ -0,0 +1,40 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * Modified by Maschell, 2016 for GX2_GUI_Template + * + * 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 _MAIN_WINDOW_TV_H_ +#define _MAIN_WINDOW_TV_H_ + +#include "gui/Gui.h" +#include "gui/GuiMainWindowScreen.h" + +class CVideo; + +class MainWindowTV : public GuiMainWindowScreen{ +public: + MainWindowTV(int w, int h); + virtual ~MainWindowTV(); +private: + int width, height; + + GuiImage bgImageColor; + + void draw(CVideo *v); + void update(GuiController * c); + void process(); +}; + +#endif //_MAIN_WINDOW_TV_H_ diff --git a/src/resources/Resources.cpp b/src/resources/Resources.cpp new file mode 100644 index 0000000..eabee60 --- /dev/null +++ b/src/resources/Resources.cpp @@ -0,0 +1,189 @@ +#include +#include +#include +#include "Resources.h" +#include "filelist.h" +#include "system/AsyncDeleter.h" +#include "fs/fs_utils.h" +#include "gui/GuiImageAsync.h" +#include "gui/GuiSound.h" + +Resources * Resources::instance = NULL; + +void Resources::Clear() +{ + for(int i = 0; RecourceList[i].filename != NULL; ++i) + { + if(RecourceList[i].CustomFile) + { + free(RecourceList[i].CustomFile); + RecourceList[i].CustomFile = NULL; + } + + if(RecourceList[i].CustomFileSize != 0) + RecourceList[i].CustomFileSize = 0; + } + + if(instance) + delete instance; + + instance = NULL; +} + +bool Resources::LoadFiles(const char * path) +{ + if(!path) + return false; + + bool result = false; + Clear(); + + for(int i = 0; RecourceList[i].filename != NULL; ++i) + { + std::string fullpath(path); + fullpath += "/"; + fullpath += RecourceList[i].filename; + + u8 * buffer = NULL; + u32 filesize = 0; + + LoadFileToMem(fullpath.c_str(), &buffer, &filesize); + + RecourceList[i].CustomFile = buffer; + RecourceList[i].CustomFileSize = (u32) filesize; + result |= (buffer != 0); + } + + return result; +} + +const u8 * Resources::GetFile(const char * filename) +{ + for(int i = 0; RecourceList[i].filename != NULL; ++i) + { + if(strcasecmp(filename, RecourceList[i].filename) == 0) + { + return (RecourceList[i].CustomFile ? RecourceList[i].CustomFile : RecourceList[i].DefaultFile); + } + } + + return NULL; +} + +u32 Resources::GetFileSize(const char * filename) +{ + for(int i = 0; RecourceList[i].filename != NULL; ++i) + { + if(strcasecmp(filename, RecourceList[i].filename) == 0) + { + return (RecourceList[i].CustomFile ? RecourceList[i].CustomFileSize : RecourceList[i].DefaultFileSize); + } + } + return 0; +} + +GuiImageData * Resources::GetImageData(const char * filename) +{ + if(!instance) + instance = new Resources; + + std::map >::iterator itr = instance->imageDataMap.find(std::string(filename)); + if(itr != instance->imageDataMap.end()) + { + itr->second.first++; + return itr->second.second; + } + + for(int i = 0; RecourceList[i].filename != NULL; ++i) + { + if(strcasecmp(filename, RecourceList[i].filename) == 0) + { + const u8 * buff = RecourceList[i].CustomFile ? RecourceList[i].CustomFile : RecourceList[i].DefaultFile; + const u32 size = RecourceList[i].CustomFile ? RecourceList[i].CustomFileSize : RecourceList[i].DefaultFileSize; + + if(buff == NULL) + return NULL; + + GuiImageData * image = new GuiImageData(buff, size); + instance->imageDataMap[std::string(filename)].first = 1; + instance->imageDataMap[std::string(filename)].second = image; + + return image; + } + } + + return NULL; +} + +void Resources::RemoveImageData(GuiImageData * image) +{ + std::map >::iterator itr; + + for(itr = instance->imageDataMap.begin(); itr != instance->imageDataMap.end(); itr++) + { + if(itr->second.second == image) + { + itr->second.first--; + + if(itr->second.first == 0) + { + AsyncDeleter::pushForDelete( itr->second.second ); + instance->imageDataMap.erase(itr); + } + break; + } + } +} + +GuiSound * Resources::GetSound(const char * filename) +{ + if(!instance) + instance = new Resources; + + std::map >::iterator itr = instance->soundDataMap.find(std::string(filename)); + if(itr != instance->soundDataMap.end()) + { + itr->second.first++; + return itr->second.second; + } + + for(int i = 0; RecourceList[i].filename != NULL; ++i) + { + if(strcasecmp(filename, RecourceList[i].filename) == 0) + { + const u8 * buff = RecourceList[i].CustomFile ? RecourceList[i].CustomFile : RecourceList[i].DefaultFile; + const u32 size = RecourceList[i].CustomFile ? RecourceList[i].CustomFileSize : RecourceList[i].DefaultFileSize; + + if(buff == NULL) + return NULL; + + GuiSound * sound = new GuiSound(buff, size); + instance->soundDataMap[std::string(filename)].first = 1; + instance->soundDataMap[std::string(filename)].second = sound; + + return sound; + } + } + + return NULL; +} + +void Resources::RemoveSound(GuiSound * sound) +{ + std::map >::iterator itr; + + for(itr = instance->soundDataMap.begin(); itr != instance->soundDataMap.end(); itr++) + { + if(itr->second.second == sound) + { + itr->second.first--; + + if(itr->second.first == 0) + { + AsyncDeleter::pushForDelete( itr->second.second ); + instance->soundDataMap.erase(itr); + } + break; + } + } +} diff --git a/src/resources/Resources.h b/src/resources/Resources.h new file mode 100644 index 0000000..3d0921b --- /dev/null +++ b/src/resources/Resources.h @@ -0,0 +1,34 @@ +#ifndef RECOURCES_H_ +#define RECOURCES_H_ + + +#include + +//! forward declaration +class GuiImageData; +class GuiSound; + +class Resources +{ +public: + static void Clear(); + static bool LoadFiles(const char * path); + static const u8 * GetFile(const char * filename); + static u32 GetFileSize(const char * filename); + + static GuiImageData * GetImageData(const char * filename); + static void RemoveImageData(GuiImageData * image); + + static GuiSound * GetSound(const char * filename); + static void RemoveSound(GuiSound * sound); +private: + static Resources *instance; + + Resources() {} + ~Resources() {} + + std::map > imageDataMap; + std::map > soundDataMap; +}; + +#endif diff --git a/src/resources/filelist.h b/src/resources/filelist.h new file mode 100644 index 0000000..3d9932b --- /dev/null +++ b/src/resources/filelist.h @@ -0,0 +1,40 @@ +/**************************************************************************** + * Loadiine resource files. + * This file is generated automatically. + * Includes 3 files. + * + * NOTE: + * Any manual modification of this file will be overwriten by the generation. + ****************************************************************************/ +#ifndef _FILELIST_H_ +#define _FILELIST_H_ + +#include + +typedef struct _RecourceFile +{ + const char *filename; + const u8 *DefaultFile; + const u32 &DefaultFileSize; + u8 *CustomFile; + u32 CustomFileSize; +} RecourceFile; + +extern const u8 bgMusic_ogg[]; +extern const u32 bgMusic_ogg_size; + +extern const u8 button_click_mp3[]; +extern const u32 button_click_mp3_size; + +extern const u8 font_ttf[]; +extern const u32 font_ttf_size; + +static RecourceFile RecourceList[] = +{ + {"bgMusic.ogg", bgMusic_ogg, bgMusic_ogg_size, NULL, 0}, + {"button_click.mp3", button_click_mp3, button_click_mp3_size, NULL, 0}, + {"font.ttf", font_ttf, font_ttf_size, NULL, 0}, + {NULL, NULL, 0, NULL, 0} +}; + +#endif diff --git a/src/sounds/BufferCircle.cpp b/src/sounds/BufferCircle.cpp new file mode 100644 index 0000000..b0ee705 --- /dev/null +++ b/src/sounds/BufferCircle.cpp @@ -0,0 +1,142 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include "utils/utils.h" +#include "BufferCircle.hpp" + +BufferCircle::BufferCircle() +{ + which = 0; + BufferBlockSize = 0; +} + +BufferCircle::~BufferCircle() +{ + FreeBuffer(); + SoundBuffer.clear(); + BufferSize.clear(); + BufferReady.clear(); +} + +void BufferCircle::SetBufferBlockSize(int size) +{ + if(size < 0) + return; + + BufferBlockSize = size; + + for(int i = 0; i < Size(); i++) + { + if(SoundBuffer[i] != NULL) + free(SoundBuffer[i]); + + SoundBuffer[i] = (u8 *) memalign(32, ALIGN32(BufferBlockSize)); + BufferSize[i] = 0; + BufferReady[i] = false; + } +} + +void BufferCircle::Resize(int size) +{ + while(size < Size()) + RemoveBuffer(Size()-1); + + int oldSize = Size(); + + SoundBuffer.resize(size); + BufferSize.resize(size); + BufferReady.resize(size); + + for(int i = oldSize; i < Size(); i++) + { + if(BufferBlockSize > 0) + SoundBuffer[i] = (u8 *) memalign(32, ALIGN32(BufferBlockSize)); + else + SoundBuffer[i] = NULL; + BufferSize[i] = 0; + BufferReady[i] = false; + } +} + +void BufferCircle::RemoveBuffer(int pos) +{ + if(!Valid(pos)) + return; + + if(SoundBuffer[pos] != NULL) + free(SoundBuffer[pos]); + + SoundBuffer.erase(SoundBuffer.begin()+pos); + BufferSize.erase(BufferSize.begin()+pos); + BufferReady.erase(BufferReady.begin()+pos); +} + +void BufferCircle::ClearBuffer() +{ + for(int i = 0; i < Size(); i++) + { + BufferSize[i] = 0; + BufferReady[i] = false; + } + which = 0; +} + +void BufferCircle::FreeBuffer() +{ + for(int i = 0; i < Size(); i++) + { + if(SoundBuffer[i] != NULL) + free(SoundBuffer[i]); + + SoundBuffer[i] = NULL; + BufferSize[i] = 0; + BufferReady[i] = false; + } +} + +void BufferCircle::LoadNext() +{ + BufferReady[which] = false; + BufferSize[which] = 0; + + which = Next(); +} + +void BufferCircle::SetBufferReady(int pos, bool state) +{ + if(!Valid(pos)) + return; + + BufferReady[pos] = state; +} + +void BufferCircle::SetBufferSize(int pos, int size) +{ + if(!Valid(pos)) + return; + + BufferSize[pos] = size; +} diff --git a/src/sounds/BufferCircle.hpp b/src/sounds/BufferCircle.hpp new file mode 100644 index 0000000..b07c1c4 --- /dev/null +++ b/src/sounds/BufferCircle.hpp @@ -0,0 +1,86 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef BUFFER_CIRCLE_HPP_ +#define BUFFER_CIRCLE_HPP_ + +#include +#include + +class BufferCircle +{ + public: + //!> Constructor + BufferCircle(); + //!> Destructor + ~BufferCircle(); + //!> Set circle size + void Resize(int size); + //!> Get the circle size + int Size() { return SoundBuffer.size(); }; + //!> Set/resize the buffer size + void SetBufferBlockSize(int size); + //!> Remove a buffer + void RemoveBuffer(int pos); + //!> Set all buffers clear + void ClearBuffer(); + //!> Free all buffers + void FreeBuffer(); + //!> Switch to next buffer + void LoadNext(); + //!> Get the current buffer + u8 * GetBuffer() { return GetBuffer(which); }; + //!> Get a buffer at a position + u8 * GetBuffer(int pos) { if(!Valid(pos)) return NULL; else return SoundBuffer[pos]; }; + //!> Get current buffer size + u32 GetBufferSize() { return GetBufferSize(which); }; + //!> Get buffer size at position + u32 GetBufferSize(int pos) { if(!Valid(pos)) return 0; else return BufferSize[pos]; }; + //!> Is current buffer ready + bool IsBufferReady() { return IsBufferReady(which); }; + //!> Is a buffer at a position ready + bool IsBufferReady(int pos) { if(!Valid(pos)) return false; else return BufferReady[pos]; }; + //!> Set a buffer at a position to a ready state + void SetBufferReady(int pos, bool st); + //!> Set the buffersize at a position + void SetBufferSize(int pos, int size); + //!> Get the current position in the circle + u16 Which() { return which; }; + + //!> Get the next location + inline u16 Next() { return (which+1 >= Size()) ? 0 : which+1; } + inline u16 Prev() { if(Size() == 0) return 0; else return ((int)which-1 < 0) ? Size()-1 : which-1; } + protected: + //!> Check if the position is a valid position in the vector + bool Valid(int pos) { return !(pos < 0 || pos >= Size()); }; + + u16 which; + u32 BufferBlockSize; + std::vector SoundBuffer; + std::vector BufferSize; + std::vector BufferReady; +}; + +#endif diff --git a/src/sounds/Mp3Decoder.cpp b/src/sounds/Mp3Decoder.cpp new file mode 100644 index 0000000..1246b4a --- /dev/null +++ b/src/sounds/Mp3Decoder.cpp @@ -0,0 +1,217 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include "dynamic_libs/os_functions.h" +#include "Mp3Decoder.hpp" + +Mp3Decoder::Mp3Decoder(const char * filepath) + : SoundDecoder(filepath) +{ + SoundType = SOUND_MP3; + ReadBuffer = NULL; + mad_timer_reset(&Timer); + mad_stream_init(&Stream); + mad_frame_init(&Frame); + mad_synth_init(&Synth); + + if(!file_fd) + return; + + OpenFile(); +} + +Mp3Decoder::Mp3Decoder(const u8 * snd, int len) + : SoundDecoder(snd, len) +{ + SoundType = SOUND_MP3; + ReadBuffer = NULL; + mad_timer_reset(&Timer); + mad_stream_init(&Stream); + mad_frame_init(&Frame); + mad_synth_init(&Synth); + + if(!file_fd) + return; + + OpenFile(); +} + +Mp3Decoder::~Mp3Decoder() +{ + ExitRequested = true; + while(Decoding) + usleep(100); + + mad_synth_finish(&Synth); + mad_frame_finish(&Frame); + mad_stream_finish(&Stream); + + if(ReadBuffer) + free(ReadBuffer); + ReadBuffer = NULL; +} + +void Mp3Decoder::OpenFile() +{ + GuardPtr = NULL; + ReadBuffer = (u8 *) memalign(32, SoundBlockSize*SoundBlocks); + if(!ReadBuffer) + { + if(file_fd) + delete file_fd; + file_fd = NULL; + return; + } + + u8 dummybuff[4096]; + int ret = Read(dummybuff, 4096, 0); + if(ret <= 0) + { + if(file_fd) + delete file_fd; + file_fd = NULL; + return; + } + + SampleRate = (u32) Frame.header.samplerate; + Format = ((MAD_NCHANNELS(&Frame.header) == 2) ? (FORMAT_PCM_16_BIT | CHANNELS_STEREO) : (FORMAT_PCM_16_BIT | CHANNELS_MONO)); + Rewind(); +} + +int Mp3Decoder::Rewind() +{ + mad_synth_finish(&Synth); + mad_frame_finish(&Frame); + mad_stream_finish(&Stream); + mad_timer_reset(&Timer); + mad_stream_init(&Stream); + mad_frame_init(&Frame); + mad_synth_init(&Synth); + SynthPos = 0; + GuardPtr = NULL; + + if(!file_fd) + return -1; + + return SoundDecoder::Rewind(); +} + +static inline s16 FixedToShort(mad_fixed_t Fixed) +{ + /* Clipping */ + if(Fixed>=MAD_F_ONE) + return(SHRT_MAX); + if(Fixed<=-MAD_F_ONE) + return(-SHRT_MAX); + + Fixed=Fixed>>(MAD_F_FRACBITS-15); + return((s16)Fixed); +} + +int Mp3Decoder::Read(u8 * buffer, int buffer_size, int pos) +{ + if(!file_fd) + return -1; + + if(Format == (FORMAT_PCM_16_BIT | CHANNELS_STEREO)) + buffer_size &= ~0x0003; + else + buffer_size &= ~0x0001; + + u8 * write_pos = buffer; + u8 * write_end = buffer+buffer_size; + + while(1) + { + while(SynthPos < Synth.pcm.length) + { + if(write_pos >= write_end) + return write_pos-buffer; + + *((s16 *) write_pos) = FixedToShort(Synth.pcm.samples[0][SynthPos]); + write_pos += 2; + + if(MAD_NCHANNELS(&Frame.header) == 2) + { + *((s16 *) write_pos) = FixedToShort(Synth.pcm.samples[1][SynthPos]); + write_pos += 2; + } + SynthPos++; + } + + if(Stream.buffer == NULL || Stream.error == MAD_ERROR_BUFLEN) + { + u8 * ReadStart = ReadBuffer; + int ReadSize = SoundBlockSize*SoundBlocks; + int Remaining = 0; + + if(Stream.next_frame != NULL) + { + Remaining = Stream.bufend - Stream.next_frame; + memmove(ReadBuffer, Stream.next_frame, Remaining); + ReadStart += Remaining; + ReadSize -= Remaining; + } + + ReadSize = file_fd->read(ReadStart, ReadSize); + if(ReadSize <= 0) + { + GuardPtr = ReadStart; + memset(GuardPtr, 0, MAD_BUFFER_GUARD); + ReadSize = MAD_BUFFER_GUARD; + } + + CurPos += ReadSize; + mad_stream_buffer(&Stream, ReadBuffer, Remaining+ReadSize); + } + + if(mad_frame_decode(&Frame,&Stream)) + { + if(MAD_RECOVERABLE(Stream.error)) + { + if(Stream.error != MAD_ERROR_LOSTSYNC || !GuardPtr) + continue; + } + else + { + if(Stream.error != MAD_ERROR_BUFLEN) + return -1; + else if(Stream.error == MAD_ERROR_BUFLEN && GuardPtr) + return -1; + } + } + + mad_timer_add(&Timer,Frame.header.duration); + mad_synth_frame(&Synth,&Frame); + SynthPos = 0; + } + return 0; +} diff --git a/src/sounds/Mp3Decoder.hpp b/src/sounds/Mp3Decoder.hpp new file mode 100644 index 0000000..ccc437b --- /dev/null +++ b/src/sounds/Mp3Decoder.hpp @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include + +#include "SoundDecoder.hpp" + +class Mp3Decoder : public SoundDecoder +{ + public: + Mp3Decoder(const char * filepath); + Mp3Decoder(const u8 * sound, int len); + virtual ~Mp3Decoder(); + int Rewind(); + int Read(u8 * buffer, int buffer_size, int pos); + protected: + void OpenFile(); + struct mad_stream Stream; + struct mad_frame Frame; + struct mad_synth Synth; + mad_timer_t Timer; + u8 * GuardPtr; + u8 * ReadBuffer; + u32 SynthPos; +}; diff --git a/src/sounds/OggDecoder.cpp b/src/sounds/OggDecoder.cpp new file mode 100644 index 0000000..abb64f4 --- /dev/null +++ b/src/sounds/OggDecoder.cpp @@ -0,0 +1,138 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include "dynamic_libs/os_functions.h" +#include "OggDecoder.hpp" + +static int ogg_read(void * punt, int bytes, int blocks, int *f) +{ + return ((CFile *) f)->read((u8 *) punt, bytes*blocks); +} + +static int ogg_seek(int *f, ogg_int64_t offset, int mode) +{ + return ((CFile *) f)->seek((u64) offset, mode); +} + +static int ogg_close(int *f) +{ + ((CFile *) f)->close(); + return 0; +} + +static long ogg_tell(int *f) +{ + return (long) ((CFile *) f)->tell(); +} + +static ov_callbacks callbacks = { + (size_t (*)(void *, size_t, size_t, void *)) ogg_read, + (int (*)(void *, ogg_int64_t, int)) ogg_seek, + (int (*)(void *)) ogg_close, + (long (*)(void *)) ogg_tell +}; + +OggDecoder::OggDecoder(const char * filepath) + : SoundDecoder(filepath) +{ + SoundType = SOUND_OGG; + + if(!file_fd) + return; + + OpenFile(); +} + +OggDecoder::OggDecoder(const u8 * snd, int len) + : SoundDecoder(snd, len) +{ + SoundType = SOUND_OGG; + + if(!file_fd) + return; + + OpenFile(); +} + +OggDecoder::~OggDecoder() +{ + ExitRequested = true; + while(Decoding) + usleep(100); + + if(file_fd) + ov_clear(&ogg_file); +} + +void OggDecoder::OpenFile() +{ + if (ov_open_callbacks(file_fd, &ogg_file, NULL, 0, callbacks) < 0) + { + delete file_fd; + file_fd = NULL; + return; + } + + ogg_info = ov_info(&ogg_file, -1); + if(!ogg_info) + { + ov_clear(&ogg_file); + delete file_fd; + file_fd = NULL; + return; + } + + Format = ((ogg_info->channels == 2) ? (FORMAT_PCM_16_BIT | CHANNELS_STEREO) : (FORMAT_PCM_16_BIT | CHANNELS_MONO)); + SampleRate = ogg_info->rate; +} + +int OggDecoder::Rewind() +{ + if(!file_fd) + return -1; + + int ret = ov_time_seek(&ogg_file, 0); + CurPos = 0; + EndOfFile = false; + + return ret; +} + +int OggDecoder::Read(u8 * buffer, int buffer_size, int pos) +{ + if(!file_fd) + return -1; + + int bitstream = 0; + + int read = ov_read(&ogg_file, (char *) buffer, buffer_size, &bitstream); + + if(read > 0) + CurPos += read; + + return read; +} diff --git a/src/sounds/OggDecoder.hpp b/src/sounds/OggDecoder.hpp new file mode 100644 index 0000000..8dc568e --- /dev/null +++ b/src/sounds/OggDecoder.hpp @@ -0,0 +1,43 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include + +#include "SoundDecoder.hpp" + +class OggDecoder : public SoundDecoder +{ + public: + OggDecoder(const char * filepath); + OggDecoder(const u8 * snd, int len); + virtual ~OggDecoder(); + int Rewind(); + int Read(u8 * buffer, int buffer_size, int pos); + protected: + void OpenFile(); + OggVorbis_File ogg_file; + vorbis_info *ogg_info; +}; diff --git a/src/sounds/SoundDecoder.cpp b/src/sounds/SoundDecoder.cpp new file mode 100644 index 0000000..e449170 --- /dev/null +++ b/src/sounds/SoundDecoder.cpp @@ -0,0 +1,225 @@ +/**************************************************************************** + * Copyright (C) 2009-2013 Dimok + * + * 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 . + ****************************************************************************/ +#include +#include +#include +#include +#include "dynamic_libs/os_functions.h" +#include "SoundDecoder.hpp" + +static const u32 FixedPointShift = 15; +static const u32 FixedPointScale = 1 << FixedPointShift; + +SoundDecoder::SoundDecoder() +{ + file_fd = NULL; + Init(); +} + +SoundDecoder::SoundDecoder(const std::string & filepath) +{ + file_fd = new CFile(filepath, CFile::ReadOnly); + Init(); +} + +SoundDecoder::SoundDecoder(const u8 * buffer, int size) +{ + file_fd = new CFile(buffer, size); + Init(); +} + +SoundDecoder::~SoundDecoder() +{ + ExitRequested = true; + while(Decoding) + usleep(1000); + + //! lock unlock once to make sure it's really not decoding + Lock(); + Unlock(); + + if(file_fd) + delete file_fd; + file_fd = NULL; + + if(ResampleBuffer) + free(ResampleBuffer); +} + +void SoundDecoder::Init() +{ + SoundType = SOUND_RAW; + SoundBlocks = 8; + SoundBlockSize = 0x4000; + ResampleTo48kHz = false; + CurPos = 0; + whichLoad = 0; + Loop = false; + EndOfFile = false; + Decoding = false; + ExitRequested = false; + SoundBuffer.SetBufferBlockSize(SoundBlockSize); + SoundBuffer.Resize(SoundBlocks); + ResampleBuffer = NULL; + ResampleRatio = 0; +} + +int SoundDecoder::Rewind() +{ + CurPos = 0; + EndOfFile = false; + file_fd->rewind(); + + return 0; +} + +int SoundDecoder::Read(u8 * buffer, int buffer_size, int pos) +{ + int ret = file_fd->read(buffer, buffer_size); + CurPos += ret; + + return ret; +} + +void SoundDecoder::EnableUpsample(void) +{ + if( (ResampleBuffer == NULL) + && IsStereo() && Is16Bit() + && SampleRate != 32000 + && SampleRate != 48000) + { + ResampleBuffer = (u8*)memalign(32, SoundBlockSize); + ResampleRatio = ( FixedPointScale * SampleRate ) / 48000; + SoundBlockSize = ( SoundBlockSize * ResampleRatio ) / FixedPointScale; + SoundBlockSize &= ~0x03; + // set new sample rate + SampleRate = 48000; + } +} + +void SoundDecoder::Upsample(s16 *src, s16 *dst, u32 nr_src_samples, u32 nr_dst_samples) +{ + int timer = 0; + + for(u32 i = 0, n = 0; i < nr_dst_samples; i += 2) + { + if((n+3) < nr_src_samples) { + // simple fixed point linear interpolation + dst[i] = src[n] + ( ((src[n+2] - src[n] ) * timer) >> FixedPointShift ); + dst[i+1] = src[n+1] + ( ((src[n+3] - src[n+1]) * timer) >> FixedPointShift ); + } + else { + dst[i] = src[n]; + dst[i+1] = src[n+1]; + } + + timer += ResampleRatio; + + if(timer >= (int)FixedPointScale) { + n += 2; + timer -= FixedPointScale; + } + } +} + +void SoundDecoder::Decode() +{ + if(!file_fd || ExitRequested || EndOfFile) + return; + + // check if we are not at the pre-last buffer (last buffer is playing) + u16 whichPlaying = SoundBuffer.Which(); + if( ((whichPlaying == 0) && (whichLoad == SoundBuffer.Size()-2)) + || ((whichPlaying == 1) && (whichLoad == SoundBuffer.Size()-1)) + || (whichLoad == (whichPlaying-2))) + { + return; + } + + Decoding = true; + + int done = 0; + u8 * write_buf = SoundBuffer.GetBuffer(whichLoad); + if(!write_buf) + { + ExitRequested = true; + Decoding = false; + return; + } + + if(ResampleTo48kHz && !ResampleBuffer) + EnableUpsample(); + + while(done < SoundBlockSize) + { + int ret = Read(&write_buf[done], SoundBlockSize-done, Tell()); + + if(ret <= 0) + { + if(Loop) + { + Rewind(); + continue; + } + else + { + EndOfFile = true; + break; + } + } + + done += ret; + } + + if(done > 0) + { + // check if we need to resample + if(ResampleBuffer && ResampleRatio) + { + memcpy(ResampleBuffer, write_buf, done); + + int src_samples = done >> 1; + int dest_samples = ( src_samples * FixedPointScale ) / ResampleRatio; + dest_samples &= ~0x01; + Upsample((s16*)ResampleBuffer, (s16*)write_buf, src_samples, dest_samples); + done = dest_samples << 1; + } + + //! TODO: remove this later and add STEREO support with two voices, for now we convert to MONO + if(IsStereo()) + { + s16* monoBuf = (s16*)write_buf; + done = done >> 1; + + for(int i = 0; i < done; i++) + monoBuf[i] = monoBuf[i << 1]; + } + + DCFlushRange(write_buf, done); + SoundBuffer.SetBufferSize(whichLoad, done); + SoundBuffer.SetBufferReady(whichLoad, true); + if(++whichLoad >= SoundBuffer.Size()) + whichLoad = 0; + } + + // check if next in queue needs to be filled as well and do so + if(!SoundBuffer.IsBufferReady(whichLoad)) + Decode(); + + Decoding = false; +} + diff --git a/src/sounds/SoundDecoder.hpp b/src/sounds/SoundDecoder.hpp new file mode 100644 index 0000000..c0c9da1 --- /dev/null +++ b/src/sounds/SoundDecoder.hpp @@ -0,0 +1,105 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef SOUND_DECODER_HPP +#define SOUND_DECODER_HPP + +#include "fs/CFile.hpp" +#include "system/CMutex.h" +#include "BufferCircle.hpp" + +class SoundDecoder +{ +public: + SoundDecoder(); + SoundDecoder(const std::string & filepath); + SoundDecoder(const u8 * buffer, int size); + virtual ~SoundDecoder(); + virtual void Lock() { mutex.lock(); } + virtual void Unlock() { mutex.unlock(); } + virtual int Read(u8 * buffer, int buffer_size, int pos); + virtual int Tell() { return CurPos; } + virtual int Seek(int pos) { CurPos = pos; return file_fd->seek(CurPos, SEEK_SET); } + virtual int Rewind(); + virtual u16 GetFormat() { return Format; } + virtual u16 GetSampleRate() { return SampleRate; } + virtual void Decode(); + virtual bool IsBufferReady() { return SoundBuffer.IsBufferReady(); } + virtual u8 * GetBuffer() { return SoundBuffer.GetBuffer(); } + virtual u32 GetBufferSize() { return SoundBuffer.GetBufferSize(); } + virtual void LoadNext() { SoundBuffer.LoadNext(); } + virtual bool IsEOF() { return EndOfFile; } + virtual void SetLoop(bool l) { Loop = l; EndOfFile = false; } + virtual u8 GetSoundType() { return SoundType; } + virtual void ClearBuffer() { SoundBuffer.ClearBuffer(); whichLoad = 0; } + virtual bool IsStereo() { return (GetFormat() & CHANNELS_STEREO) != 0; } + virtual bool Is16Bit() { return ((GetFormat() & 0xFF) == FORMAT_PCM_16_BIT); } + virtual bool IsDecoding() { return Decoding; } + + void EnableUpsample(void); + + enum SoundFormats + { + FORMAT_PCM_16_BIT = 0x0A, + FORMAT_PCM_8_BIT = 0x19, + }; + enum SoundChannels + { + CHANNELS_MONO = 0x100, + CHANNELS_STEREO = 0x200 + }; + + enum SoundType + { + SOUND_RAW = 0, + SOUND_MP3, + SOUND_OGG, + SOUND_WAV + }; +protected: + void Init(); + void Upsample(s16 *src, s16 *dst, u32 nr_src_samples, u32 nr_dst_samples); + + CFile * file_fd; + BufferCircle SoundBuffer; + u8 SoundType; + u16 whichLoad; + u16 SoundBlocks; + int SoundBlockSize; + int CurPos; + bool ResampleTo48kHz; + bool Loop; + bool EndOfFile; + bool Decoding; + bool ExitRequested; + u16 Format; + u16 SampleRate; + u8 *ResampleBuffer; + u32 ResampleRatio; + CMutex mutex; +}; + + +#endif diff --git a/src/sounds/SoundHandler.cpp b/src/sounds/SoundHandler.cpp new file mode 100644 index 0000000..68f9dd5 --- /dev/null +++ b/src/sounds/SoundHandler.cpp @@ -0,0 +1,351 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include "common/common.h" +#include "dynamic_libs/ax_functions.h" +#include "fs/CFile.hpp" +#include "SoundHandler.hpp" +#include "WavDecoder.hpp" +#include "Mp3Decoder.hpp" +#include "OggDecoder.hpp" + +SoundHandler * SoundHandler::handlerInstance = NULL; + +SoundHandler::SoundHandler() + : CThread(CThread::eAttributeAffCore1 | CThread::eAttributePinnedAff, 0, 0x8000) +{ + Decoding = false; + ExitRequested = false; + for(u32 i = 0; i < MAX_DECODERS; ++i) + { + DecoderList[i] = NULL; + voiceList[i] = NULL; + } + + resumeThread(); + + //! wait for initialization + while(!isThreadSuspended()) + usleep(1000); +} + +SoundHandler::~SoundHandler() +{ + ExitRequested = true; + ThreadSignal(); + + ClearDecoderList(); +} + +void SoundHandler::AddDecoder(int voice, const char * filepath) +{ + if(voice < 0 || voice >= MAX_DECODERS) + return; + + if(DecoderList[voice] != NULL) + RemoveDecoder(voice); + + DecoderList[voice] = GetSoundDecoder(filepath); +} + +void SoundHandler::AddDecoder(int voice, const u8 * snd, int len) +{ + if(voice < 0 || voice >= MAX_DECODERS) + return; + + if(DecoderList[voice] != NULL) + RemoveDecoder(voice); + + DecoderList[voice] = GetSoundDecoder(snd, len); +} + +void SoundHandler::RemoveDecoder(int voice) +{ + if(voice < 0 || voice >= MAX_DECODERS) + return; + + if(DecoderList[voice] != NULL) + { + if(voiceList[voice] && voiceList[voice]->getState() != Voice::STATE_STOPPED) + { + if(voiceList[voice]->getState() != Voice::STATE_STOP) + voiceList[voice]->setState(Voice::STATE_STOP); + + while(voiceList[voice]->getState() != Voice::STATE_STOPPED) + usleep(1000); + } + SoundDecoder *decoder = DecoderList[voice]; + decoder->Lock(); + DecoderList[voice] = NULL; + decoder->Unlock(); + delete decoder; + } +} + +void SoundHandler::ClearDecoderList() +{ + for(u32 i = 0; i < MAX_DECODERS; ++i) + RemoveDecoder(i); +} + +static inline bool CheckMP3Signature(const u8 * buffer) +{ + const char MP3_Magic[][3] = + { + {'I', 'D', '3'}, //'ID3' + {0xff, 0xfe}, //'MPEG ADTS, layer III, v1.0 [protected]', 'mp3', 'audio/mpeg'), + {0xff, 0xff}, //'MPEG ADTS, layer III, v1.0', 'mp3', 'audio/mpeg'), + {0xff, 0xfa}, //'MPEG ADTS, layer III, v1.0 [protected]', 'mp3', 'audio/mpeg'), + {0xff, 0xfb}, //'MPEG ADTS, layer III, v1.0', 'mp3', 'audio/mpeg'), + {0xff, 0xf2}, //'MPEG ADTS, layer III, v2.0 [protected]', 'mp3', 'audio/mpeg'), + {0xff, 0xf3}, //'MPEG ADTS, layer III, v2.0', 'mp3', 'audio/mpeg'), + {0xff, 0xf4}, //'MPEG ADTS, layer III, v2.0 [protected]', 'mp3', 'audio/mpeg'), + {0xff, 0xf5}, //'MPEG ADTS, layer III, v2.0', 'mp3', 'audio/mpeg'), + {0xff, 0xf6}, //'MPEG ADTS, layer III, v2.0 [protected]', 'mp3', 'audio/mpeg'), + {0xff, 0xf7}, //'MPEG ADTS, layer III, v2.0', 'mp3', 'audio/mpeg'), + {0xff, 0xe2}, //'MPEG ADTS, layer III, v2.5 [protected]', 'mp3', 'audio/mpeg'), + {0xff, 0xe3}, //'MPEG ADTS, layer III, v2.5', 'mp3', 'audio/mpeg'), + }; + + if(buffer[0] == MP3_Magic[0][0] && buffer[1] == MP3_Magic[0][1] && + buffer[2] == MP3_Magic[0][2]) + { + return true; + } + + for(int i = 1; i < 13; i++) + { + if(buffer[0] == MP3_Magic[i][0] && buffer[1] == MP3_Magic[i][1]) + return true; + } + + return false; +} + +SoundDecoder * SoundHandler::GetSoundDecoder(const char * filepath) +{ + u32 magic; + CFile f(filepath, CFile::ReadOnly); + if(f.size() == 0) + return NULL; + + do + { + f.read((u8 *) &magic, 1); + } + while(((u8 *) &magic)[0] == 0 && f.tell() < f.size()); + + if(f.tell() == f.size()) + return NULL; + + f.seek(f.tell()-1, SEEK_SET); + f.read((u8 *) &magic, 4); + f.close(); + + if(magic == 0x4f676753) // 'OggS' + { + return new OggDecoder(filepath); + } + else if(magic == 0x52494646) // 'RIFF' + { + return new WavDecoder(filepath); + } + else if(CheckMP3Signature((u8 *) &magic) == true) + { + return new Mp3Decoder(filepath); + } + + return new SoundDecoder(filepath); +} + +SoundDecoder * SoundHandler::GetSoundDecoder(const u8 * sound, int length) +{ + const u8 * check = sound; + int counter = 0; + + while(check[0] == 0 && counter < length) + { + check++; + counter++; + } + + if(counter >= length) + return NULL; + + u32 * magic = (u32 *) check; + + if(magic[0] == 0x4f676753) // 'OggS' + { + return new OggDecoder(sound, length); + } + else if(magic[0] == 0x52494646) // 'RIFF' + { + return new WavDecoder(sound, length); + } + else if(CheckMP3Signature(check) == true) + { + return new Mp3Decoder(sound, length); + } + + return new SoundDecoder(sound, length); +} + +void SoundHandler::executeThread() +{ + // v2 sound lib can not properly end transition audio on old firmwares + if (OS_FIRMWARE >= 400 && OS_FIRMWARE <= 410) + { + ProperlyEndTransitionAudio(); + } + + //! initialize 48 kHz renderer + u32 params[3] = { 1, 0, 0 }; + + if(AXInitWithParams != 0) + AXInitWithParams(params); + else + AXInit(); + + // The problem with last voice on 500 was caused by it having priority 0 + // We would need to change this priority distribution if for some reason + // we would need MAX_DECODERS > Voice::PRIO_MAX + for(u32 i = 0; i < MAX_DECODERS; ++i) + { + int priority = (MAX_DECODERS - i) * Voice::PRIO_MAX / MAX_DECODERS; + voiceList[i] = new Voice(priority); // allocate voice 0 with highest priority + } + + AXRegisterFrameCallback((void*)&axFrameCallback); + + + u16 i = 0; + while (!ExitRequested) + { + suspendThread(); + + for(i = 0; i < MAX_DECODERS; ++i) + { + if(DecoderList[i] == NULL) + continue; + + Decoding = true; + if(DecoderList[i]) + DecoderList[i]->Lock(); + if(DecoderList[i]) + DecoderList[i]->Decode(); + if(DecoderList[i]) + DecoderList[i]->Unlock(); + } + Decoding = false; + } + + for(u32 i = 0; i < MAX_DECODERS; ++i) + voiceList[i]->stop(); + + AXRegisterFrameCallback(NULL); + AXQuit(); + + for(u32 i = 0; i < MAX_DECODERS; ++i) + { + delete voiceList[i]; + voiceList[i] = NULL; + } +} + +void SoundHandler::axFrameCallback(void) +{ + for (u32 i = 0; i < MAX_DECODERS; i++) + { + Voice *voice = handlerInstance->getVoice(i); + + switch (voice->getState()) + { + default: + case Voice::STATE_STOPPED: + break; + + case Voice::STATE_START: { + SoundDecoder * decoder = handlerInstance->getDecoder(i); + decoder->Lock(); + if(decoder->IsBufferReady()) + { + const u8 *buffer = decoder->GetBuffer(); + const u32 bufferSize = decoder->GetBufferSize(); + decoder->LoadNext(); + + const u8 *nextBuffer = NULL; + u32 nextBufferSize = 0; + + if(decoder->IsBufferReady()) + { + nextBuffer = decoder->GetBuffer(); + nextBufferSize = decoder->GetBufferSize(); + decoder->LoadNext(); + } + + voice->play(buffer, bufferSize, nextBuffer, nextBufferSize, decoder->GetFormat() & 0xff, decoder->GetSampleRate()); + + handlerInstance->ThreadSignal(); + + voice->setState(Voice::STATE_PLAYING); + } + decoder->Unlock(); + break; + } + case Voice::STATE_PLAYING: + if(voice->getInternState() == 1) + { + if(voice->isBufferSwitched()) + { + SoundDecoder * decoder = handlerInstance->getDecoder(i); + decoder->Lock(); + if(decoder->IsBufferReady()) + { + voice->setNextBuffer(decoder->GetBuffer(), decoder->GetBufferSize()); + decoder->LoadNext(); + handlerInstance->ThreadSignal(); + } + else if(decoder->IsEOF()) + { + voice->setState(Voice::STATE_STOP); + } + decoder->Unlock(); + } + } + else + { + voice->setState(Voice::STATE_STOPPED); + } + break; + case Voice::STATE_STOP: + if(voice->getInternState() != 0) + voice->stop(); + voice->setState(Voice::STATE_STOPPED); + break; + } + } +} diff --git a/src/sounds/SoundHandler.hpp b/src/sounds/SoundHandler.hpp new file mode 100644 index 0000000..7b0beb6 --- /dev/null +++ b/src/sounds/SoundHandler.hpp @@ -0,0 +1,78 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef SOUNDHANDLER_H_ +#define SOUNDHANDLER_H_ + +#include +#include +#include "system/CThread.h" +#include "SoundDecoder.hpp" +#include "Voice.h" + +#define MAX_DECODERS 16 // can be increased up to 96 + +class SoundHandler : public CThread +{ +public: + static SoundHandler * instance() { + if (!handlerInstance) + handlerInstance = new SoundHandler(); + return handlerInstance; + } + + static void DestroyInstance() { delete handlerInstance; handlerInstance = NULL; } + + void AddDecoder(int voice, const char * filepath); + void AddDecoder(int voice, const u8 * snd, int len); + void RemoveDecoder(int voice); + + SoundDecoder * getDecoder(int i) { return ((i < 0 || i >= MAX_DECODERS) ? NULL : DecoderList[i]); }; + Voice * getVoice(int i) { return ((i < 0 || i >= MAX_DECODERS) ? NULL : voiceList[i]); }; + + void ThreadSignal() { resumeThread(); }; + bool IsDecoding() { return Decoding; }; +protected: + SoundHandler(); + ~SoundHandler(); + + static void axFrameCallback(void); + + void executeThread(void); + void ClearDecoderList(); + + SoundDecoder * GetSoundDecoder(const char * filepath); + SoundDecoder * GetSoundDecoder(const u8 * sound, int length); + + static SoundHandler * handlerInstance; + + bool Decoding; + bool ExitRequested; + + Voice * voiceList[MAX_DECODERS]; + SoundDecoder * DecoderList[MAX_DECODERS]; +}; + +#endif diff --git a/src/sounds/Voice.h b/src/sounds/Voice.h new file mode 100644 index 0000000..63fd94e --- /dev/null +++ b/src/sounds/Voice.h @@ -0,0 +1,170 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 _AXSOUND_H_ +#define _AXSOUND_H_ + +#include "dynamic_libs/os_functions.h" +#include "dynamic_libs/ax_functions.h" + +class Voice +{ +public: + + enum VoicePriorities + { + PRIO_MIN = 1, + PRIO_MAX = 31 + }; + + enum VoiceStates + { + STATE_STOPPED, + STATE_START, + STATE_PLAYING, + STATE_STOP, + }; + + Voice(int prio) + : state(STATE_STOPPED) + { + lastLoopCounter = 0; + nextBufferSize = 0; + + voice = AXAcquireVoice(prio, 0, 0); + if(voice) + { + AXVoiceBegin(voice); + AXSetVoiceType(voice, 0); + setVolume(0x80000000); + + u32 mix[24]; + memset(mix, 0, sizeof(mix)); + mix[0] = 0x80000000; + mix[4] = 0x80000000; + + AXSetVoiceDeviceMix(voice, 0, 0, mix); + AXSetVoiceDeviceMix(voice, 1, 0, mix); + + AXVoiceEnd(voice); + } + } + + ~Voice() + { + if(voice) + { + AXFreeVoice(voice); + } + } + + void play(const u8 *buffer, u32 bufferSize, const u8 *nextBuffer, u32 nextBufSize, u16 format, u32 sampleRate) + { + if(!voice) + return; + + memset(&voiceBuffer, 0, sizeof(voiceBuffer)); + + voiceBuffer.samples = buffer; + voiceBuffer.format = format; + voiceBuffer.loop = (nextBuffer == NULL) ? 0 : 1; + voiceBuffer.cur_pos = 0; + voiceBuffer.end_pos = bufferSize >> 1; + voiceBuffer.loop_offset = ((nextBuffer - buffer) >> 1); + nextBufferSize = nextBufSize; + + u32 samplesPerSec = (AXGetInputSamplesPerSec != 0) ? AXGetInputSamplesPerSec() : 32000; + + ratioBits[0] = (u32)(0x00010000 * ((f32)sampleRate / (f32)samplesPerSec)); + ratioBits[1] = 0; + ratioBits[2] = 0; + ratioBits[3] = 0; + + AXSetVoiceOffsets(voice, &voiceBuffer); + AXSetVoiceSrc(voice, ratioBits); + AXSetVoiceSrcType(voice, 1); + AXSetVoiceState(voice, 1); + } + + void stop() + { + if(voice) + AXSetVoiceState(voice, 0); + } + + void setVolume(u32 vol) + { + if(voice) + AXSetVoiceVe(voice, &vol); + } + + + void setNextBuffer(const u8 *buffer, u32 bufferSize) + { + voiceBuffer.loop_offset = ((buffer - voiceBuffer.samples) >> 1); + nextBufferSize = bufferSize; + + AXSetVoiceLoopOffset(voice, voiceBuffer.loop_offset); + } + + bool isBufferSwitched() + { + u32 loopCounter = AXGetVoiceLoopCount(voice); + if(lastLoopCounter != loopCounter) + { + lastLoopCounter = loopCounter; + AXSetVoiceEndOffset(voice, voiceBuffer.loop_offset + (nextBufferSize >> 1)); + return true; + } + return false; + } + + u32 getInternState() const { + if(voice) + return ((u32 *)voice)[1]; + return 0; + } + u32 getState() const { + return state; + } + void setState(u32 s) { + state = s; + } + + void * getVoice() const { + return voice; + } + +private: + void *voice; + u32 ratioBits[4]; + + typedef struct _ax_buffer_t { + u16 format; + u16 loop; + u32 loop_offset; + u32 end_pos; + u32 cur_pos; + const unsigned char *samples; + } ax_buffer_t; + + ax_buffer_t voiceBuffer; + u32 state; + u32 nextBufferSize; + u32 lastLoopCounter; +}; + +#endif // _AXSOUND_H_ diff --git a/src/sounds/WavDecoder.cpp b/src/sounds/WavDecoder.cpp new file mode 100644 index 0000000..f241df0 --- /dev/null +++ b/src/sounds/WavDecoder.cpp @@ -0,0 +1,154 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include "WavDecoder.hpp" +#include "utils/utils.h" + +WavDecoder::WavDecoder(const char * filepath) + : SoundDecoder(filepath) +{ + SoundType = SOUND_WAV; + SampleRate = 48000; + Format = CHANNELS_STEREO | FORMAT_PCM_16_BIT; + + if(!file_fd) + return; + + OpenFile(); +} + +WavDecoder::WavDecoder(const u8 * snd, int len) + : SoundDecoder(snd, len) +{ + SoundType = SOUND_WAV; + SampleRate = 48000; + Format = CHANNELS_STEREO | FORMAT_PCM_16_BIT; + + if(!file_fd) + return; + + OpenFile(); +} + +WavDecoder::~WavDecoder() +{ +} + + +void WavDecoder::OpenFile() +{ + SWaveHdr Header; + SWaveFmtChunk FmtChunk; + memset(&Header, 0, sizeof(SWaveHdr)); + memset(&FmtChunk, 0, sizeof(SWaveFmtChunk)); + + file_fd->read((u8 *) &Header, sizeof(SWaveHdr)); + file_fd->read((u8 *) &FmtChunk, sizeof(SWaveFmtChunk)); + + if (Header.magicRIFF != 0x52494646) // 'RIFF' + { + CloseFile(); + return; + } + else if(Header.magicWAVE != 0x57415645) // 'WAVE' + { + CloseFile(); + return; + } + else if(FmtChunk.magicFMT != 0x666d7420) // 'fmt ' + { + CloseFile(); + return; + } + + DataOffset = sizeof(SWaveHdr)+le32(FmtChunk.size)+8; + file_fd->seek(DataOffset, SEEK_SET); + SWaveChunk DataChunk; + file_fd->read((u8 *) &DataChunk, sizeof(SWaveChunk)); + + while(DataChunk.magicDATA != 0x64617461) // 'data' + { + DataOffset += 8+le32(DataChunk.size); + file_fd->seek(DataOffset, SEEK_SET); + int ret = file_fd->read((u8 *) &DataChunk, sizeof(SWaveChunk)); + if(ret <= 0) + { + CloseFile(); + return; + } + } + + DataOffset += 8; + DataSize = le32(DataChunk.size); + Is16Bit = (le16(FmtChunk.bps) == 16); + SampleRate = le32(FmtChunk.freq); + + if (le16(FmtChunk.channels) == 1 && le16(FmtChunk.bps) == 8 && le16(FmtChunk.alignment) <= 1) + Format = CHANNELS_MONO | FORMAT_PCM_8_BIT; + else if (le16(FmtChunk.channels) == 1 && le16(FmtChunk.bps) == 16 && le16(FmtChunk.alignment) <= 2) + Format = CHANNELS_MONO | FORMAT_PCM_16_BIT; + else if (le16(FmtChunk.channels) == 2 && le16(FmtChunk.bps) == 8 && le16(FmtChunk.alignment) <= 2) + Format = CHANNELS_STEREO | FORMAT_PCM_8_BIT; + else if (le16(FmtChunk.channels) == 2 && le16(FmtChunk.bps) == 16 && le16(FmtChunk.alignment) <= 4) + Format = CHANNELS_STEREO | FORMAT_PCM_16_BIT; +} + +void WavDecoder::CloseFile() +{ + if(file_fd) + delete file_fd; + + file_fd = NULL; +} + +int WavDecoder::Read(u8 * buffer, int buffer_size, int pos) +{ + if(!file_fd) + return -1; + + if(CurPos >= (int) DataSize) + return 0; + + file_fd->seek(DataOffset+CurPos, SEEK_SET); + + if(buffer_size > (int) DataSize-CurPos) + buffer_size = DataSize-CurPos; + + int read = file_fd->read(buffer, buffer_size); + if(read > 0) + { + if (Is16Bit) + { + read &= ~0x0001; + + for (u32 i = 0; i < (u32) (read / sizeof (u16)); ++i) + ((u16 *) buffer)[i] = le16(((u16 *) buffer)[i]); + } + CurPos += read; + } + + return read; +} diff --git a/src/sounds/WavDecoder.hpp b/src/sounds/WavDecoder.hpp new file mode 100644 index 0000000..5981883 --- /dev/null +++ b/src/sounds/WavDecoder.hpp @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef WAVDECODER_HPP_ +#define WAVDECODER_HPP_ + +#include "SoundDecoder.hpp" + +typedef struct +{ + u32 magicRIFF; + u32 size; + u32 magicWAVE; +} SWaveHdr; + +typedef struct +{ + u32 magicFMT; + u32 size; + u16 format; + u16 channels; + u32 freq; + u32 avgBps; + u16 alignment; + u16 bps; +} SWaveFmtChunk; + +typedef struct +{ + u32 magicDATA; + u32 size; +} SWaveChunk; + +class WavDecoder : public SoundDecoder +{ + public: + WavDecoder(const char * filepath); + WavDecoder(const u8 * snd, int len); + virtual ~WavDecoder(); + int Read(u8 * buffer, int buffer_size, int pos); + protected: + void OpenFile(); + void CloseFile(); + u32 DataOffset; + u32 DataSize; + bool Is16Bit; +}; + +#endif diff --git a/src/system/AsyncDeleter.cpp b/src/system/AsyncDeleter.cpp new file mode 100644 index 0000000..7b69751 --- /dev/null +++ b/src/system/AsyncDeleter.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include "AsyncDeleter.h" + +AsyncDeleter * AsyncDeleter::deleterInstance = NULL; + +AsyncDeleter::AsyncDeleter() + : CThread(CThread::eAttributeAffCore1 | CThread::eAttributePinnedAff) + , exitApplication(false) +{ +} + +AsyncDeleter::~AsyncDeleter() +{ + exitApplication = true; +} + +void AsyncDeleter::triggerDeleteProcess(void) +{ + if(!deleterInstance) + deleterInstance = new AsyncDeleter; + + //! to trigger the event after GUI process is finished execution + //! this function is used to swap elements from one to next array + if(!deleterInstance->deleteElements.empty()) + { + deleterInstance->deleteMutex.lock(); + while(!deleterInstance->deleteElements.empty()) + { + deleterInstance->realDeleteElements.push(deleterInstance->deleteElements.front()); + deleterInstance->deleteElements.pop(); + } + deleterInstance->deleteMutex.unlock(); + deleterInstance->resumeThread(); + } +} + +void AsyncDeleter::executeThread(void) +{ + while(!exitApplication) + { + suspendThread(); + log_printf("AsyncDeleter thread running\n"); + //! delete elements that require post process deleting + //! because otherwise they would block or do invalid access on GUI thread + while(!realDeleteElements.empty()) + { + deleteMutex.lock(); + AsyncDeleter::Element *element = realDeleteElements.front(); + realDeleteElements.pop(); + deleteMutex.unlock(); + + delete element; + } + } + +} diff --git a/src/system/AsyncDeleter.h b/src/system/AsyncDeleter.h new file mode 100644 index 0000000..6cce1fa --- /dev/null +++ b/src/system/AsyncDeleter.h @@ -0,0 +1,65 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 _ASYNC_DELETER_H +#define _ASYNC_DELETER_H + +#include +#include "CThread.h" +#include "CMutex.h" + +class AsyncDeleter : public CThread +{ +public: + static void destroyInstance() + { + if(deleterInstance != NULL){ + delete deleterInstance; + deleterInstance = NULL; + } + } + + class Element + { + public: + Element() {} + virtual ~Element() {} + }; + + static void pushForDelete(AsyncDeleter::Element *e) + { + if(!deleterInstance) + deleterInstance = new AsyncDeleter; + deleterInstance->deleteElements.push(e); + } + + static void triggerDeleteProcess(void); + +private: + AsyncDeleter(); + virtual ~AsyncDeleter(); + + static AsyncDeleter *deleterInstance; + + void executeThread(void); + + bool exitApplication; + std::queue deleteElements; + std::queue realDeleteElements; + CMutex deleteMutex; +}; + +#endif // _ASYNC_DELETER_H diff --git a/src/system/CMutex.h b/src/system/CMutex.h new file mode 100644 index 0000000..3e7cc1b --- /dev/null +++ b/src/system/CMutex.h @@ -0,0 +1,69 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 _CMUTEX_H_ +#define _CMUTEX_H_ + +#include +#include "dynamic_libs/os_functions.h" + +class CMutex +{ +public: + CMutex() { + pMutex = malloc(OS_MUTEX_SIZE); + if(!pMutex) + return; + + OSInitMutex(pMutex); + } + virtual ~CMutex() { + if(pMutex) + free(pMutex); + } + + void lock(void) { + if(pMutex) + OSLockMutex(pMutex); + } + void unlock(void) { + if(pMutex) + OSUnlockMutex(pMutex); + } + bool tryLock(void) { + if(!pMutex) + return false; + + return (OSTryLockMutex(pMutex) != 0); + } +private: + void *pMutex; +}; + +class CMutexLock +{ +public: + CMutexLock() { + mutex.lock(); + } + virtual ~CMutexLock() { + mutex.unlock(); + } +private: + CMutex mutex; +}; + +#endif // _CMUTEX_H_ diff --git a/src/system/CThread.h b/src/system/CThread.h new file mode 100644 index 0000000..3fade45 --- /dev/null +++ b/src/system/CThread.h @@ -0,0 +1,121 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 CTHREAD_H_ +#define CTHREAD_H_ + +#include +#include +#include +#include "dynamic_libs/os_functions.h" +#include "utils/logger.h" + +class CThread +{ +public: + typedef void (* Callback)(CThread *thread, void *arg); + + //! constructor + CThread(int iAttr, int iPriority = 16, int iStackSize = 0x8000, CThread::Callback callback = NULL, void *callbackArg = NULL) + : pThread(NULL) + , pThreadStack(NULL) + , pCallback(callback) + , pCallbackArg(callbackArg) + { + //! save attribute assignment + iAttributes = iAttr; + //! allocate the thread + pThread = memalign(8, 0x1000); + //! allocate the stack + pThreadStack = (u8 *) memalign(0x20, iStackSize); + //! create the thread + if(pThread && pThreadStack) + OSCreateThread(pThread, &CThread::threadCallback, 1, this, (u32)pThreadStack+iStackSize, iStackSize, iPriority, iAttributes); + } + + //! destructor + virtual ~CThread() { shutdownThread(); } + + static CThread *create(CThread::Callback callback, void *callbackArg, int iAttr = eAttributeNone, int iPriority = 16, int iStackSize = 0x8000) + { + return ( new CThread(iAttr, iPriority, iStackSize, callback, callbackArg) ); + } + + //! Get thread ID + virtual void* getThread() const { return pThread; } + //! Thread entry function + virtual void executeThread(void) + { + if(pCallback) + pCallback(this, pCallbackArg); + } + //! Suspend thread + virtual void suspendThread(void) { if(isThreadSuspended()) return; if(pThread) OSSuspendThread(pThread); } + //! Resume thread + virtual void resumeThread(void) { if(!isThreadSuspended()) return; if(pThread) OSResumeThread(pThread); } + //! Set thread priority + virtual void setThreadPriority(int prio) { if(pThread) OSSetThreadPriority(pThread, prio); } + //! Check if thread is suspended + virtual bool isThreadSuspended(void) const { if(pThread) return OSIsThreadSuspended(pThread); return false; } + //! Check if thread is terminated + virtual bool isThreadTerminated(void) const { if(pThread) return OSIsThreadTerminated(pThread); return false; } + //! Check if thread is running + virtual bool isThreadRunning(void) const { return !isThreadSuspended() && !isThreadRunning(); } + //! Shutdown thread + virtual void shutdownThread(void) + { + //! wait for thread to finish + if(pThread && !(iAttributes & eAttributeDetach)) + { + while(isThreadSuspended()){ + resumeThread(); + } + OSJoinThread(pThread, NULL); + } + //! free the thread stack buffer + if(pThreadStack){ + free(pThreadStack); + } + if(pThread) + free(pThread); + pThread = NULL; + pThreadStack = NULL; + } + //! Thread attributes + enum eCThreadAttributes + { + eAttributeNone = 0x07, + eAttributeAffCore0 = 0x01, + eAttributeAffCore1 = 0x02, + eAttributeAffCore2 = 0x04, + eAttributeDetach = 0x08, + eAttributePinnedAff = 0x10 + }; +private: + static int threadCallback(int argc, void *arg) + { + //! After call to start() continue with the internal function + ((CThread *) arg)->executeThread(); + return 0; + } + int iAttributes; + void *pThread; + u8 *pThreadStack; + Callback pCallback; + void *pCallbackArg; +}; + +#endif diff --git a/src/system/exception_handler.c b/src/system/exception_handler.c new file mode 100644 index 0000000..b642248 --- /dev/null +++ b/src/system/exception_handler.c @@ -0,0 +1,169 @@ +#include +#include "dynamic_libs/os_functions.h" +#include "utils/logger.h" +#include "exception_handler.h" + +#define OS_EXCEPTION_MODE_GLOBAL_ALL_CORES 4 + +#define OS_EXCEPTION_DSI 2 +#define OS_EXCEPTION_ISI 3 +#define OS_EXCEPTION_PROGRAM 6 + +/* Exceptions */ +typedef struct OSContext +{ + /* OSContext identifier */ + uint32_t tag1; + uint32_t tag2; + + /* GPRs */ + uint32_t gpr[32]; + + /* Special registers */ + uint32_t cr; + uint32_t lr; + uint32_t ctr; + uint32_t xer; + + /* Initial PC and MSR */ + uint32_t srr0; + uint32_t srr1; + + /* Only valid during DSI exception */ + uint32_t exception_specific0; + uint32_t exception_specific1; + + /* There is actually a lot more here but we don't need the rest*/ +} OSContext; + +#define CPU_STACK_TRACE_DEPTH 10 +#define __stringify(rn) #rn + +#define mfspr(_rn) \ +({ register uint32_t _rval = 0; \ + asm volatile("mfspr %0," __stringify(_rn) \ + : "=r" (_rval));\ + _rval; \ +}) + +typedef struct _framerec { + struct _framerec *up; + void *lr; +} frame_rec, *frame_rec_t; + +static const char *exception_names[] = { + "DSI", + "ISI", + "PROGRAM" +}; + +static const char exception_print_formats[18][45] = { + "Exception type %s occurred!\n", // 0 + "GPR00 %08X GPR08 %08X GPR16 %08X GPR24 %08X\n", // 1 + "GPR01 %08X GPR09 %08X GPR17 %08X GPR25 %08X\n", // 2 + "GPR02 %08X GPR10 %08X GPR18 %08X GPR26 %08X\n", // 3 + "GPR03 %08X GPR11 %08X GPR19 %08X GPR27 %08X\n", // 4 + "GPR04 %08X GPR12 %08X GPR20 %08X GPR28 %08X\n", // 5 + "GPR05 %08X GPR13 %08X GPR21 %08X GPR29 %08X\n", // 6 + "GPR06 %08X GPR14 %08X GPR22 %08X GPR30 %08X\n", // 7 + "GPR07 %08X GPR15 %08X GPR23 %08X GPR31 %08X\n", // 8 + "LR %08X SRR0 %08x SRR1 %08x\n", // 9 + "DAR %08X DSISR %08X\n", // 10 + "\nSTACK DUMP:", // 11 + " --> ", // 12 + " -->\n", // 13 + "\n", // 14 + "%p", // 15 + "\nCODE DUMP:\n", // 16 + "%p: %08X %08X %08X %08X\n", // 17 +}; + +static unsigned char exception_cb(void * c, unsigned char exception_type) { + char buf[850]; + int pos = 0; + + OSContext *context = (OSContext *) c; + /* + * This part is mostly from libogc. Thanks to the devs over there. + */ + pos += sprintf(buf + pos, exception_print_formats[0], exception_names[exception_type]); + pos += sprintf(buf + pos, exception_print_formats[1], context->gpr[0], context->gpr[8], context->gpr[16], context->gpr[24]); + pos += sprintf(buf + pos, exception_print_formats[2], context->gpr[1], context->gpr[9], context->gpr[17], context->gpr[25]); + pos += sprintf(buf + pos, exception_print_formats[3], context->gpr[2], context->gpr[10], context->gpr[18], context->gpr[26]); + pos += sprintf(buf + pos, exception_print_formats[4], context->gpr[3], context->gpr[11], context->gpr[19], context->gpr[27]); + pos += sprintf(buf + pos, exception_print_formats[5], context->gpr[4], context->gpr[12], context->gpr[20], context->gpr[28]); + pos += sprintf(buf + pos, exception_print_formats[6], context->gpr[5], context->gpr[13], context->gpr[21], context->gpr[29]); + pos += sprintf(buf + pos, exception_print_formats[7], context->gpr[6], context->gpr[14], context->gpr[22], context->gpr[30]); + pos += sprintf(buf + pos, exception_print_formats[8], context->gpr[7], context->gpr[15], context->gpr[23], context->gpr[31]); + pos += sprintf(buf + pos, exception_print_formats[9], context->lr, context->srr0, context->srr1); + + //if(exception_type == OS_EXCEPTION_DSI) { + pos += sprintf(buf + pos, exception_print_formats[10], context->exception_specific1, context->exception_specific0); // this freezes + //} + + void *pc = (void*)context->srr0; + void *lr = (void*)context->lr; + void *r1 = (void*)context->gpr[1]; + register uint32_t i = 0; + register frame_rec_t l,p = (frame_rec_t)lr; + + l = p; + p = r1; + if(!p) + asm volatile("mr %0,%%r1" : "=r"(p)); + + pos += sprintf(buf + pos, exception_print_formats[11]); + + for(i = 0; i < CPU_STACK_TRACE_DEPTH-1 && p->up; p = p->up, i++) { + if(i % 4) + pos += sprintf(buf + pos, exception_print_formats[12]); + else { + if(i > 0) + pos += sprintf(buf + pos, exception_print_formats[13]); + else + pos += sprintf(buf + pos, exception_print_formats[14]); + } + + switch(i) { + case 0: + if(pc) + pos += sprintf(buf + pos, exception_print_formats[15],pc); + break; + case 1: + if(!l) + l = (frame_rec_t)mfspr(8); + pos += sprintf(buf + pos, exception_print_formats[15],(void*)l); + break; + default: + pos += sprintf(buf + pos, exception_print_formats[15],(void*)(p->up->lr)); + break; + } + } + + //if(exception_type == OS_EXCEPTION_DSI) { + uint32_t *pAdd = (uint32_t*)context->srr0; + pos += sprintf(buf + pos, exception_print_formats[16]); + // TODO by Dimok: this was actually be 3 instead of 2 lines in libogc .... but there is just no more space anymore on the screen + for (i = 0; i < 8; i += 4) + pos += sprintf(buf + pos, exception_print_formats[17], &(pAdd[i]),pAdd[i], pAdd[i+1], pAdd[i+2], pAdd[i+3]); + //} + log_print(buf); + OSFatal(buf); + return 1; +} + +static unsigned char dsi_exception_cb(void * context) { + return exception_cb(context, 0); +} +static unsigned char isi_exception_cb(void * context) { + return exception_cb(context, 1); +} +static unsigned char program_exception_cb(void * context) { + return exception_cb(context, 2); +} + +void setup_os_exceptions(void) { + OSSetExceptionCallback(OS_EXCEPTION_DSI, &dsi_exception_cb); + OSSetExceptionCallback(OS_EXCEPTION_ISI, &isi_exception_cb); + OSSetExceptionCallback(OS_EXCEPTION_PROGRAM, &program_exception_cb); +} diff --git a/src/system/exception_handler.h b/src/system/exception_handler.h new file mode 100644 index 0000000..7626f92 --- /dev/null +++ b/src/system/exception_handler.h @@ -0,0 +1,14 @@ +#ifndef __EXCEPTION_HANDLER_H_ +#define __EXCEPTION_HANDLER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void setup_os_exceptions(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/system/memory.c b/src/system/memory.c new file mode 100644 index 0000000..91f5392 --- /dev/null +++ b/src/system/memory.c @@ -0,0 +1,198 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include +#include +#include "dynamic_libs/os_functions.h" +#include "common/common.h" +#include "memory.h" + +#define MEMORY_ARENA_1 0 +#define MEMORY_ARENA_2 1 +#define MEMORY_ARENA_3 2 +#define MEMORY_ARENA_4 3 +#define MEMORY_ARENA_5 4 +#define MEMORY_ARENA_6 5 +#define MEMORY_ARENA_7 6 +#define MEMORY_ARENA_8 7 +#define MEMORY_ARENA_FG_BUCKET 8 + +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! Memory functions +//! This is the only place where those are needed so lets keep them more or less private +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +extern unsigned int * pMEMAllocFromDefaultHeapEx; +extern unsigned int * pMEMAllocFromDefaultHeap; +extern unsigned int * pMEMFreeToDefaultHeap; + +extern int (* MEMGetBaseHeapHandle)(int mem_arena); +extern unsigned int (* MEMGetAllocatableSizeForFrmHeapEx)(int heap, int align); +extern void *(* MEMAllocFromFrmHeapEx)(int heap, unsigned int size, int align); +extern void (* MEMFreeToFrmHeap)(int heap, int mode); +extern void *(* MEMAllocFromExpHeapEx)(int heap, unsigned int size, int align); +extern int (* MEMCreateExpHeapEx)(void* address, unsigned int size, unsigned short flags); +extern void *(* MEMDestroyExpHeap)(int heap); +extern void (* MEMFreeToExpHeap)(int heap, void* ptr); + +static int mem1_heap = -1; +static int bucket_heap = -1; + +void memoryInitialize(void) +{ + int mem1_heap_handle = MEMGetBaseHeapHandle(MEMORY_ARENA_1); + unsigned int mem1_allocatable_size = MEMGetAllocatableSizeForFrmHeapEx(mem1_heap_handle, 4); + void *mem1_memory = MEMAllocFromFrmHeapEx(mem1_heap_handle, mem1_allocatable_size, 4); + if(mem1_memory) + mem1_heap = MEMCreateExpHeapEx(mem1_memory, mem1_allocatable_size, 0); + + int bucket_heap_handle = MEMGetBaseHeapHandle(MEMORY_ARENA_FG_BUCKET); + unsigned int bucket_allocatable_size = MEMGetAllocatableSizeForFrmHeapEx(bucket_heap_handle, 4); + void *bucket_memory = MEMAllocFromFrmHeapEx(bucket_heap_handle, bucket_allocatable_size, 4); + if(bucket_memory) + bucket_heap = MEMCreateExpHeapEx(bucket_memory, bucket_allocatable_size, 0); +} + +void memoryRelease(void) +{ + MEMDestroyExpHeap(mem1_heap); + MEMFreeToFrmHeap(MEMGetBaseHeapHandle(MEMORY_ARENA_1), 3); + mem1_heap = -1; + + MEMDestroyExpHeap(bucket_heap); + MEMFreeToFrmHeap(MEMGetBaseHeapHandle(MEMORY_ARENA_FG_BUCKET), 3); + bucket_heap = -1; +} + +//!------------------------------------------------------------------------------------------- +//! wraps +//!------------------------------------------------------------------------------------------- +void *__wrap_malloc(size_t size) +{ + // pointer to a function resolve + return ((void * (*)(size_t))(*pMEMAllocFromDefaultHeap))(size); +} + +void *__wrap_memalign(size_t align, size_t size) +{ + if (align < 4) + align = 4; + + // pointer to a function resolve + return ((void * (*)(size_t, size_t))(*pMEMAllocFromDefaultHeapEx))(size, align); +} + +void __wrap_free(void *p) +{ + // pointer to a function resolve + if(p != 0) + ((void (*)(void *))(*pMEMFreeToDefaultHeap))(p); +} + +void *__wrap_calloc(size_t n, size_t size) +{ + void *p = __wrap_malloc(n * size); + if (p != 0) { + memset(p, 0, n * size); + } + return p; +} + +size_t __wrap_malloc_usable_size(void *p) +{ + //! TODO: this is totally wrong and needs to be addressed + return 0x7FFFFFFF; +} + +void *__wrap_realloc(void *p, size_t size) +{ + void *new_ptr = __wrap_malloc(size); + if (new_ptr != 0) + { + memcpy(new_ptr, p, __wrap_malloc_usable_size(p) < size ? __wrap_malloc_usable_size(p) : size); + __wrap_free(p); + } + return new_ptr; +} + +//!------------------------------------------------------------------------------------------- +//! reent versions +//!------------------------------------------------------------------------------------------- +void *__wrap__malloc_r(struct _reent *r, size_t size) +{ + return __wrap_malloc(size); +} + +void *__wrap__calloc_r(struct _reent *r, size_t n, size_t size) +{ + return __wrap_calloc(n, size); +} + +void *__wrap__memalign_r(struct _reent *r, size_t align, size_t size) +{ + return __wrap_memalign(align, size); +} + +void __wrap__free_r(struct _reent *r, void *p) +{ + __wrap_free(p); +} + +size_t __wrap__malloc_usable_size_r(struct _reent *r, void *p) +{ + return __wrap_malloc_usable_size(p); +} + +void *__wrap__realloc_r(struct _reent *r, void *p, size_t size) +{ + return __wrap_realloc(p, size); +} + +//!------------------------------------------------------------------------------------------- +//! some wrappers +//!------------------------------------------------------------------------------------------- +void * MEM2_alloc(unsigned int size, unsigned int align) +{ + return __wrap_memalign(align, size); +} + +void MEM2_free(void *ptr) +{ + __wrap_free(ptr); +} + +void * MEM1_alloc(unsigned int size, unsigned int align) +{ + if (align < 4) + align = 4; + return MEMAllocFromExpHeapEx(mem1_heap, size, align); +} + +void MEM1_free(void *ptr) +{ + MEMFreeToExpHeap(mem1_heap, ptr); +} + +void * MEMBucket_alloc(unsigned int size, unsigned int align) +{ + if (align < 4) + align = 4; + return MEMAllocFromExpHeapEx(bucket_heap, size, align); +} + +void MEMBucket_free(void *ptr) +{ + MEMFreeToExpHeap(bucket_heap, ptr); +} diff --git a/src/system/memory.h b/src/system/memory.h new file mode 100644 index 0000000..59764d0 --- /dev/null +++ b/src/system/memory.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 __MEMORY_H_ +#define __MEMORY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +void memoryInitialize(void); +void memoryRelease(void); + +void * MEM2_alloc(unsigned int size, unsigned int align); +void MEM2_free(void *ptr); + +void * MEM1_alloc(unsigned int size, unsigned int align); +void MEM1_free(void *ptr); + +void * MEMBucket_alloc(unsigned int size, unsigned int align); +void MEMBucket_free(void *ptr); + +#ifdef __cplusplus +} +#endif + +#endif // __MEMORY_H_ diff --git a/src/utils/StringTools.cpp b/src/utils/StringTools.cpp new file mode 100644 index 0000000..debb6c7 --- /dev/null +++ b/src/utils/StringTools.cpp @@ -0,0 +1,207 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + +const char * fmt(const char * format, ...) +{ + static char strChar[512]; + strChar[0] = 0; + char * tmp = NULL; + + va_list va; + va_start(va, format); + if((vasprintf(&tmp, format, va) >= 0) && tmp) + { + snprintf(strChar, sizeof(strChar), tmp); + free(tmp); + va_end(va); + return (const char *) strChar; + } + va_end(va); + + if(tmp) + free(tmp); + + return NULL; +} + +const wchar_t * wfmt(const char * format, ...) +{ + static wchar_t strWChar[512]; + strWChar[0] = 0; + + if(!format) + return (const wchar_t *) strWChar; + + if(strcmp(format, "") == 0) + return (const wchar_t *) strWChar; + + char * tmp = NULL; + + va_list va; + va_start(va, format); + if((vasprintf(&tmp, format, va) >= 0) && tmp) + { + int bt; + int strlength = strlen(tmp); + bt = mbstowcs(strWChar, tmp, (strlength < 512) ? strlength : 512 ); + free(tmp); + tmp = 0; + + if(bt > 0) + { + strWChar[bt] = 0; + return (const wchar_t *) strWChar; + } + } + va_end(va); + + if(tmp) + free(tmp); + + return NULL; +} + +int strprintf(std::string &str, const char * format, ...) +{ + int result = 0; + char * tmp = NULL; + + va_list va; + va_start(va, format); + if((vasprintf(&tmp, format, va) >= 0) && tmp) + { + str = tmp; + result = str.size(); + } + va_end(va); + + if(tmp) + free(tmp); + + return result; +} + +std::string strfmt(const char * format, ...) +{ + std::string str; + char * tmp = NULL; + + va_list va; + va_start(va, format); + if((vasprintf(&tmp, format, va) >= 0) && tmp) + { + str = tmp; + } + va_end(va); + + if(tmp) + free(tmp); + + return str; +} + +bool char2wchar_t(const char * strChar, wchar_t * dest) +{ + if(!strChar || !dest) + return false; + + int bt; + bt = mbstowcs(dest, strChar, strlen(strChar)); + if (bt > 0) { + dest[bt] = 0; + return true; + } + + return false; +} + +int strtokcmp(const char * string, const char * compare, const char * separator) +{ + if(!string || !compare) + return -1; + + char TokCopy[512]; + strncpy(TokCopy, compare, sizeof(TokCopy)); + TokCopy[511] = '\0'; + + char * strTok = strtok(TokCopy, separator); + + while (strTok != NULL) + { + if (strcasecmp(string, strTok) == 0) + { + return 0; + } + strTok = strtok(NULL,separator); + } + + return -1; +} + +int strextcmp(const char * string, const char * extension, char seperator) +{ + if(!string || !extension) + return -1; + + char *ptr = strrchr(string, seperator); + if(!ptr) + return -1; + + return strcasecmp(ptr + 1, extension); +} + + +std::vector stringSplit(const std::string & inValue, const std::string & splitter) +{ + std::string value = inValue; + std::vector result; + while (true) { + unsigned int index = value.find(splitter); + if (index == std::string::npos) { + result.push_back(value); + break; + } + std::string first = value.substr(0, index); + result.push_back(first); + if (index + splitter.size() == value.length()) { + result.push_back(""); + break; + } + if(index + splitter.size() > value.length()) { + break; + } + value = value.substr(index + splitter.size(), value.length()); + } + return result; +} diff --git a/src/utils/StringTools.h b/src/utils/StringTools.h new file mode 100644 index 0000000..bcf89c4 --- /dev/null +++ b/src/utils/StringTools.h @@ -0,0 +1,78 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef __STRING_TOOLS_H +#define __STRING_TOOLS_H + +#include +#include +#include + +const char * fmt(const char * format, ...); +const wchar_t * wfmt(const char * format, ...); +int strprintf(std::string &str, const char * format, ...); +std::string strfmt(const char * format, ...); +bool char2wchar_t(const char * src, wchar_t * dest); +int strtokcmp(const char * string, const char * compare, const char * separator); +int strextcmp(const char * string, const char * extension, char seperator); + +inline const char * FullpathToFilename(const char *path) +{ + if(!path) return path; + + const char * ptr = path; + const char * Filename = ptr; + + while(*ptr != '\0') + { + if(ptr[0] == '/' && ptr[1] != '\0') + Filename = ptr+1; + + ++ptr; + } + + return Filename; +} + +inline void RemoveDoubleSlashs(std::string &str) +{ + u32 length = str.size(); + + //! clear path of double slashes + for(u32 i = 1; i < length; ++i) + { + if(str[i-1] == '/' && str[i] == '/') + { + str.erase(i, 1); + i--; + length--; + } + } +} + +std::vector stringSplit(const std::string & value, const std::string & splitter); + +#endif /* __STRING_TOOLS_H */ + diff --git a/src/utils/logger.c b/src/utils/logger.c new file mode 100644 index 0000000..e1e411f --- /dev/null +++ b/src/utils/logger.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include +#include "dynamic_libs/os_functions.h" +#include "dynamic_libs/socket_functions.h" +#include "logger.h" + +#ifdef DEBUG_LOGGER +static int log_socket = -1; +static volatile int log_lock = 0; + + +void log_init(const char * ipString) +{ + log_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (log_socket < 0) + return; + + struct sockaddr_in connect_addr; + memset(&connect_addr, 0, sizeof(connect_addr)); + connect_addr.sin_family = AF_INET; + connect_addr.sin_port = 4405; + inet_aton(ipString, &connect_addr.sin_addr); + + if(connect(log_socket, (struct sockaddr*)&connect_addr, sizeof(connect_addr)) < 0) + { + socketclose(log_socket); + log_socket = -1; + } +} + +void log_deinit(void) +{ + if(log_socket >= 0) + { + socketclose(log_socket); + log_socket = -1; + } +} + +void log_print(const char *str) +{ + // socket is always 0 initially as it is in the BSS + if(log_socket < 0) { + return; + } + + while(log_lock) + usleep(1000); + log_lock = 1; + + int len = strlen(str); + int ret; + while (len > 0) { + int block = len < 1400 ? len : 1400; // take max 1400 bytes per UDP packet + ret = send(log_socket, str, block, 0); + if(ret < 0) + break; + + len -= ret; + str += ret; + } + + log_lock = 0; +} + +void log_printf(const char *format, ...) +{ + if(log_socket < 0) { + return; + } + + char * tmp = NULL; + + va_list va; + va_start(va, format); + if((vasprintf(&tmp, format, va) >= 0) && tmp) + { + log_print(tmp); + } + va_end(va); + + if(tmp) + free(tmp); +} +#endif diff --git a/src/utils/logger.h b/src/utils/logger.h new file mode 100644 index 0000000..dd7cc71 --- /dev/null +++ b/src/utils/logger.h @@ -0,0 +1,26 @@ +#ifndef __LOGGER_H_ +#define __LOGGER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define DEBUG_LOGGER 1 + +#ifdef DEBUG_LOGGER +void log_init(const char * ip); +void log_deinit(void); +void log_print(const char *str); +void log_printf(const char *format, ...); +#else +#define log_init(x) +#define log_deinit() +#define log_print(x) +#define log_printf(x, ...) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/utils/utils.h b/src/utils/utils.h new file mode 100644 index 0000000..c460fa2 --- /dev/null +++ b/src/utils/utils.h @@ -0,0 +1,47 @@ +#ifndef __UTILS_H_ +#define __UTILS_H_ + +#include +#include "../common/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FlushBlock(addr) asm volatile("dcbf %0, %1\n" \ + "icbi %0, %1\n" \ + "sync\n" \ + "eieio\n" \ + "isync\n" \ + : \ + :"r"(0), "r"(((addr) & ~31)) \ + :"memory", "ctr", "lr", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12" \ + ); + +#define LIMIT(x, min, max) \ + ({ \ + typeof( x ) _x = x; \ + typeof( min ) _min = min; \ + typeof( max ) _max = max; \ + ( ( ( _x ) < ( _min ) ) ? ( _min ) : ( ( _x ) > ( _max ) ) ? ( _max) : ( _x ) ); \ + }) + +#define DegToRad(a) ( (a) * 0.01745329252f ) +#define RadToDeg(a) ( (a) * 57.29577951f ) + +#define ALIGN4(x) (((x) + 3) & ~3) +#define ALIGN32(x) (((x) + 31) & ~31) + +// those work only in powers of 2 +#define ROUNDDOWN(val, align) ((val) & ~(align-1)) +#define ROUNDUP(val, align) ROUNDDOWN(((val) + (align-1)), align) + +#define le16(i) ((((u16) ((i) & 0xFF)) << 8) | ((u16) (((i) & 0xFF00) >> 8))) +#define le32(i) ((((u32)le16((i) & 0xFFFF)) << 16) | ((u32)le16(((i) & 0xFFFF0000) >> 16))) +#define le64(i) ((((u64)le32((i) & 0xFFFFFFFFLL)) << 32) | ((u64)le32(((i) & 0xFFFFFFFF00000000LL) >> 32))) + +#ifdef __cplusplus +} +#endif + +#endif // __UTILS_H_ diff --git a/src/video/CVideo.cpp b/src/video/CVideo.cpp new file mode 100644 index 0000000..63d134b --- /dev/null +++ b/src/video/CVideo.cpp @@ -0,0 +1,290 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include +#include +#include "CVideo.h" +#include "system/memory.h" +#include "shaders/Texture2DShader.h" +#include "shaders/ColorShader.h" +#include "shaders/Shader3D.h" +#include "shaders/ShaderFractalColor.h" +#include "shaders/FXAAShader.h" +#include "dynamic_libs/os_functions.h" + +CVideo::CVideo(s32 forceTvScanMode, s32 forceDrcScanMode) +{ + tvEnabled = false; + drcEnabled = false; + + //! allocate MEM2 command buffer memory + gx2CommandBuffer = MEM2_alloc(GX2_COMMAND_BUFFER_SIZE, 0x40); + + //! initialize GX2 command buffer + u32 gx2_init_attributes[9]; + gx2_init_attributes[0] = GX2_INIT_ATTRIB_CB_BASE; + gx2_init_attributes[1] = (u32)gx2CommandBuffer; + gx2_init_attributes[2] = GX2_INIT_ATTRIB_CB_SIZE; + gx2_init_attributes[3] = GX2_COMMAND_BUFFER_SIZE; + gx2_init_attributes[4] = GX2_INIT_ATTRIB_ARGC; + gx2_init_attributes[5] = 0; + gx2_init_attributes[6] = GX2_INIT_ATTRIB_ARGV; + gx2_init_attributes[7] = 0; + gx2_init_attributes[8] = GX2_INIT_ATTRIB_NULL; + GX2Init(gx2_init_attributes); + + //! GX2 resources are not used in this application but if needed, the allocator is setup + GX2RSetAllocator(&CVideo::GX2RAlloc, &CVideo::GX2RFree); + + u32 scanBufferSize = 0; + s32 scaleNeeded = 0; + + s32 tvScanMode = (forceTvScanMode >= 0) ? forceTvScanMode : GX2GetSystemTVScanMode(); + s32 drcScanMode = (forceDrcScanMode >= 0) ? forceDrcScanMode : GX2GetSystemDRCScanMode(); + + s32 tvRenderMode; + u32 tvWidth = 0; + u32 tvHeight = 0; + + switch(tvScanMode) + { + case GX2_TV_SCAN_MODE_480I: + case GX2_TV_SCAN_MODE_480P: + tvWidth = 854; + tvHeight = 480; + tvRenderMode = GX2_TV_RENDER_480_WIDE; + break; + case GX2_TV_SCAN_MODE_1080I: + case GX2_TV_SCAN_MODE_1080P: + tvWidth = 1920; + tvHeight = 1080; + tvRenderMode = GX2_TV_RENDER_1080; + break; + case GX2_TV_SCAN_MODE_720P: + default: + tvWidth = 1280; + tvHeight = 720; + tvRenderMode = GX2_TV_RENDER_720; + break; + } + + s32 tvAAMode = GX2_AA_MODE_1X; + s32 drcAAMode = GX2_AA_MODE_4X; + + //! calculate the scale factor for later texture resize + widthScaleFactor = 1.0f / (f32)tvWidth; + heightScaleFactor = 1.0f / (f32)tvHeight; + depthScaleFactor = widthScaleFactor; + + //! calculate the size needed for the TV scan buffer and allocate the buffer from bucket memory + GX2CalcTVSize(tvRenderMode, GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM, GX2_BUFFERING_DOUBLE, &scanBufferSize, &scaleNeeded); + tvScanBuffer = MEMBucket_alloc(scanBufferSize, GX2_SCAN_BUFFER_ALIGNMENT); + GX2Invalidate(GX2_INVALIDATE_CPU, tvScanBuffer, scanBufferSize); + GX2SetTVBuffer(tvScanBuffer, scanBufferSize, tvRenderMode, GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM, GX2_BUFFERING_DOUBLE); + + //! calculate the size needed for the DRC scan buffer and allocate the buffer from bucket memory + GX2CalcDRCSize(drcScanMode, GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM, GX2_BUFFERING_DOUBLE, &scanBufferSize, &scaleNeeded); + drcScanBuffer = MEMBucket_alloc(scanBufferSize, GX2_SCAN_BUFFER_ALIGNMENT); + GX2Invalidate(GX2_INVALIDATE_CPU, drcScanBuffer, scanBufferSize); + GX2SetDRCBuffer(drcScanBuffer, scanBufferSize, drcScanMode, GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM, GX2_BUFFERING_DOUBLE); + + //! Setup color buffer for TV rendering + GX2InitColorBuffer(&tvColorBuffer, GX2_SURFACE_DIM_2D, tvWidth, tvHeight, 1, GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM, tvAAMode); + tvColorBuffer.surface.image_data = MEM1_alloc(tvColorBuffer.surface.image_size, tvColorBuffer.surface.align); + GX2Invalidate(GX2_INVALIDATE_CPU, tvColorBuffer.surface.image_data, tvColorBuffer.surface.image_size); + + //! due to AA we can only use 16 bit depth buffer in MEM1 otherwise we would have to switch to mem2 for depth buffer + //! this should be ok for our purpose i guess + + //! Setup TV depth buffer (can be the same for both if rendered one after another) + u32 size, align; + GX2InitDepthBuffer(&tvDepthBuffer, GX2_SURFACE_DIM_2D, tvColorBuffer.surface.width, tvColorBuffer.surface.height, 1, GX2_SURFACE_FORMAT_TCD_R32_FLOAT, tvAAMode); + tvDepthBuffer.surface.image_data = MEM1_alloc(tvDepthBuffer.surface.image_size, tvDepthBuffer.surface.align); + GX2Invalidate(GX2_INVALIDATE_CPU, tvDepthBuffer.surface.image_data, tvDepthBuffer.surface.image_size); + + //! Setup TV HiZ buffer + GX2CalcDepthBufferHiZInfo(&tvDepthBuffer, &size, &align); + tvDepthBuffer.hiZ_data = MEM1_alloc(size, align); + GX2Invalidate(GX2_INVALIDATE_CPU, tvDepthBuffer.hiZ_data, size); + GX2InitDepthBufferHiZEnable(&tvDepthBuffer, GX2_ENABLE); + + //! Setup color buffer for DRC rendering + GX2InitColorBuffer(&drcColorBuffer, GX2_SURFACE_DIM_2D, 854, 480, 1, GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM, drcAAMode); + drcColorBuffer.surface.image_data = MEM1_alloc(drcColorBuffer.surface.image_size, drcColorBuffer.surface.align); + GX2Invalidate(GX2_INVALIDATE_CPU, drcColorBuffer.surface.image_data, drcColorBuffer.surface.image_size); + + //! Setup DRC depth buffer (can be the same for both if rendered one after another) + GX2InitDepthBuffer(&drcDepthBuffer, GX2_SURFACE_DIM_2D, drcColorBuffer.surface.width, drcColorBuffer.surface.height, 1, GX2_SURFACE_FORMAT_TCD_R32_FLOAT, drcAAMode); + drcDepthBuffer.surface.image_data = MEM1_alloc(drcDepthBuffer.surface.image_size, drcDepthBuffer.surface.align); + GX2Invalidate(GX2_INVALIDATE_CPU, drcDepthBuffer.surface.image_data, drcDepthBuffer.surface.image_size); + + //! Setup DRC HiZ buffer + GX2CalcDepthBufferHiZInfo(&drcDepthBuffer, &size, &align); + drcDepthBuffer.hiZ_data = MEM1_alloc(size, align); + GX2Invalidate(GX2_INVALIDATE_CPU, drcDepthBuffer.hiZ_data, size); + GX2InitDepthBufferHiZEnable(&drcDepthBuffer, GX2_ENABLE); + + + //! allocate auxilary buffer last as there might not be enough MEM1 left for other stuff after that + if (tvColorBuffer.surface.aa) + { + u32 auxSize, auxAlign; + GX2CalcColorBufferAuxInfo(&tvColorBuffer, &auxSize, &auxAlign); + tvColorBuffer.aux_data = MEM1_alloc(auxSize, auxAlign); + if(!tvColorBuffer.aux_data) + tvColorBuffer.aux_data = MEM2_alloc(auxSize, auxAlign); + + tvColorBuffer.aux_size = auxSize; + memset(tvColorBuffer.aux_data, GX2_AUX_BUFFER_CLEAR_VALUE, auxSize); + GX2Invalidate(GX2_INVALIDATE_CPU, tvColorBuffer.aux_data, auxSize); + } + + if (drcColorBuffer.surface.aa) + { + u32 auxSize, auxAlign; + GX2CalcColorBufferAuxInfo(&drcColorBuffer, &auxSize, &auxAlign); + drcColorBuffer.aux_data = MEM1_alloc(auxSize, auxAlign); + if(!drcColorBuffer.aux_data) + drcColorBuffer.aux_data = MEM2_alloc(auxSize, auxAlign); + drcColorBuffer.aux_size = auxSize; + memset(drcColorBuffer.aux_data, GX2_AUX_BUFFER_CLEAR_VALUE, auxSize); + GX2Invalidate(GX2_INVALIDATE_CPU, drcColorBuffer.aux_data, auxSize ); + } + + //! allocate memory and setup context state TV + tvContextState = (GX2ContextState*)MEM2_alloc(sizeof(GX2ContextState), GX2_CONTEXT_STATE_ALIGNMENT); + GX2SetupContextStateEx(tvContextState, GX2_TRUE); + + //! allocate memory and setup context state DRC + drcContextState = (GX2ContextState*)MEM2_alloc(sizeof(GX2ContextState), GX2_CONTEXT_STATE_ALIGNMENT); + GX2SetupContextStateEx(drcContextState, GX2_TRUE); + + //! set initial context state and render buffers + GX2SetContextState(tvContextState); + GX2SetColorBuffer(&tvColorBuffer, GX2_RENDER_TARGET_0); + GX2SetDepthBuffer(&tvDepthBuffer); + + GX2SetContextState(drcContextState); + GX2SetColorBuffer(&drcColorBuffer, GX2_RENDER_TARGET_0); + GX2SetDepthBuffer(&drcDepthBuffer); + + //! set initial viewport + GX2SetViewport(0.0f, 0.0f, tvColorBuffer.surface.width, tvColorBuffer.surface.height, 0.0f, 1.0f); + GX2SetScissor(0, 0, tvColorBuffer.surface.width, tvColorBuffer.surface.height); + + //! this is not necessary but can be used for swap counting and vsyncs + GX2SetSwapInterval(1); + + //GX2SetTVGamma(0.8f); + //GX2SetDRCGamma(0.8f); + + //! initialize perspective matrix + const float cam_X_rot = 25.0f; + + projectionMtx = glm::perspective(45.0f, 1.0f, 0.1f, 100.0f); + + viewMtx = glm::mat4(1.0f); + viewMtx = glm::translate(viewMtx, glm::vec3(0.0f, 0.0f, -2.5f)); + viewMtx = glm::rotate(viewMtx, DegToRad(cam_X_rot), glm::vec3(1.0f, 0.0f, 0.0f)); + + GX2InitSampler(&aaSampler, GX2_TEX_CLAMP_CLAMP, GX2_TEX_XY_FILTER_BILINEAR); + GX2InitTexture(&tvAaTexture, tvColorBuffer.surface.width, tvColorBuffer.surface.height, 1, 0, GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM, GX2_SURFACE_DIM_2D, GX2_TILE_MODE_DEFAULT); + tvAaTexture.surface.image_data = tvColorBuffer.surface.image_data; + tvAaTexture.surface.image_size = tvColorBuffer.surface.image_size; + tvAaTexture.surface.mip_data = tvColorBuffer.surface.mip_data; +} + +CVideo::~CVideo() +{ + //! flush buffers + GX2Flush(); + GX2DrawDone(); + //! shutdown + GX2Shutdown(); + //! free command buffer memory + MEM2_free(gx2CommandBuffer); + //! free scan buffers + MEMBucket_free(tvScanBuffer); + MEMBucket_free(drcScanBuffer); + //! free color buffers + MEM1_free(tvColorBuffer.surface.image_data); + MEM1_free(drcColorBuffer.surface.image_data); + //! free depth buffers + MEM1_free(tvDepthBuffer.surface.image_data); + MEM1_free(tvDepthBuffer.hiZ_data); + MEM1_free(drcDepthBuffer.surface.image_data); + MEM1_free(drcDepthBuffer.hiZ_data); + //! free context buffers + MEM2_free(tvContextState); + MEM2_free(drcContextState); + //! free aux buffer + if(tvColorBuffer.aux_data) + { + if(((u32)tvColorBuffer.aux_data & 0xF0000000) == 0xF0000000) + MEM1_free(tvColorBuffer.aux_data); + else + MEM2_free(tvColorBuffer.aux_data); + } + if(drcColorBuffer.aux_data) + { + if(((u32)drcColorBuffer.aux_data & 0xF0000000) == 0xF0000000) + MEM1_free(drcColorBuffer.aux_data); + else + MEM2_free(drcColorBuffer.aux_data); + } + //! destroy shaders + ColorShader::destroyInstance(); + FXAAShader::destroyInstance(); + Shader3D::destroyInstance(); + ShaderFractalColor::destroyInstance(); + Texture2DShader::destroyInstance(); +} + +void CVideo::renderFXAA(const GX2Texture * texture, const GX2Sampler *sampler) +{ + resolution[0] = texture->surface.width; + resolution[1] = texture->surface.height; + + GX2Invalidate(GX2_INVALIDATE_COLOR_BUFFER | GX2_INVALIDATE_TEXTURE, texture->surface.image_data, texture->surface.image_size); + + GX2SetDepthOnlyControl(GX2_ENABLE, GX2_ENABLE, GX2_COMPARE_ALWAYS); + FXAAShader::instance()->setShaders(); + FXAAShader::instance()->setAttributeBuffer(); + FXAAShader::instance()->setResolution(resolution); + FXAAShader::instance()->setTextureAndSampler(texture, sampler); + FXAAShader::instance()->draw(); + GX2SetDepthOnlyControl(GX2_ENABLE, GX2_ENABLE, GX2_COMPARE_LEQUAL); +} + +void* CVideo::GX2RAlloc(u32 flags, u32 size, u32 align) +{ + //! min. alignment + if (align < 4) + align = 4; + + if ((flags & 0x2040E) && !(flags & 0x40000)) + return MEM1_alloc(size, align); + else + return MEM2_alloc(size, align); +} + +void CVideo::GX2RFree(u32 flags, void* p) +{ + if ((flags & 0x2040E) && !(flags & 0x40000)) + MEM1_free(p); + else + MEM2_free(p); +} diff --git a/src/video/CVideo.h b/src/video/CVideo.h new file mode 100644 index 0000000..e9b457e --- /dev/null +++ b/src/video/CVideo.h @@ -0,0 +1,202 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 __CVIDEO_H_ +#define __CVIDEO_H_ + +#include "dynamic_libs/gx2_functions.h" +#include "shaders/Shader.h" + +class CVideo +{ +public: + CVideo(s32 forceTvScanMode = -1, s32 forceDrcScanMode = -1); + virtual ~CVideo(); + + void prepareTvRendering(void) { + currContextState = tvContextState; + currColorBuffer = &tvColorBuffer; + currDepthBuffer = &tvDepthBuffer; + prepareRendering(); + } + + void prepareDrcRendering(void) { + currContextState = drcContextState; + currColorBuffer = &drcColorBuffer; + currDepthBuffer = &drcDepthBuffer; + prepareRendering(); + } + + void prepareRendering(void) { + GX2ClearColor(currColorBuffer, 0.0f, 0.0f, 0.0f, 1.0f); + GX2ClearDepthStencilEx(currDepthBuffer, currDepthBuffer->clear_depth, currDepthBuffer->clear_stencil, GX2_CLEAR_BOTH); + + GX2SetContextState(currContextState); + GX2SetViewport(0.0f, 0.0f, currColorBuffer->surface.width, currColorBuffer->surface.height, 0.0f, 1.0f); + GX2SetScissor(0, 0, currColorBuffer->surface.width, currColorBuffer->surface.height); + + GX2SetDepthOnlyControl(GX2_ENABLE, GX2_ENABLE, GX2_COMPARE_LEQUAL); + GX2SetColorControl(GX2_LOGIC_OP_COPY, 1, GX2_DISABLE, GX2_ENABLE); + GX2SetBlendControl(GX2_RENDER_TARGET_0, GX2_BLEND_SRC_ALPHA, GX2_BLEND_ONE_MINUS_SRC_ALPHA, GX2_BLEND_COMBINE_ADD, GX2_ENABLE, GX2_BLEND_SRC_ALPHA, GX2_BLEND_ONE_MINUS_SRC_ALPHA, GX2_BLEND_COMBINE_ADD); + GX2SetCullOnlyControl(GX2_FRONT_FACE_CCW, GX2_DISABLE, GX2_ENABLE); + } + + void setStencilRender(bool bEnable) + { + if(bEnable) + { + GX2SetStencilMask(0xff, 0xff, 0x01, 0xff, 0xff, 0x01); + GX2SetDepthStencilControl(GX2_DISABLE, GX2_DISABLE, GX2_COMPARE_LEQUAL, GX2_ENABLE, GX2_ENABLE, GX2_COMPARE_ALWAYS, GX2_STENCIL_KEEP, GX2_STENCIL_KEEP, GX2_STENCIL_REPLACE, + GX2_COMPARE_ALWAYS, GX2_STENCIL_KEEP, GX2_STENCIL_KEEP, GX2_STENCIL_REPLACE); + } + else + { + GX2SetStencilMask(0xff, 0xff, 0xff, 0xff, 0xff, 0xff); + GX2SetDepthStencilControl(GX2_ENABLE, GX2_ENABLE, GX2_COMPARE_LEQUAL, GX2_DISABLE, GX2_DISABLE, GX2_COMPARE_NEVER, GX2_STENCIL_KEEP, GX2_STENCIL_KEEP, GX2_STENCIL_KEEP, + GX2_COMPARE_NEVER, GX2_STENCIL_KEEP, GX2_STENCIL_KEEP, GX2_STENCIL_KEEP); + } + } + + void drcDrawDone(void) { + //! on DRC we do a hardware AA because FXAA does not look good + //renderFXAA(&drcAaTexture, &aaSampler); + GX2CopyColorBufferToScanBuffer(&drcColorBuffer, GX2_SCAN_TARGET_DRC_FIRST); + } + + void tvDrawDone(void) { + renderFXAA(&tvAaTexture, &aaSampler); + GX2CopyColorBufferToScanBuffer(&tvColorBuffer, GX2_SCAN_TARGET_TV); + GX2SwapScanBuffers(); + GX2Flush(); + } + + void waitForVSync(void) { + GX2WaitForVsync(); + frameCount++; + } + + void tvEnable(bool bEnable) { + if(tvEnabled != bEnable) + { + GX2SetTVEnable(bEnable ? GX2_ENABLE : GX2_DISABLE); + tvEnabled = bEnable; + } + } + void drcEnable(bool bEnable) { + if(drcEnabled != bEnable) + { + GX2SetDRCEnable(bEnable ? GX2_ENABLE : GX2_DISABLE); + drcEnabled = bEnable; + } + } + + u32 getFrameCount(void) const { + return frameCount; + } + + u32 getTvWidth(void) const { + return tvColorBuffer.surface.width; + } + u32 getTvHeight(void) const { + return tvColorBuffer.surface.height; + } + + u32 getDrcWidth(void) const { + return drcColorBuffer.surface.width; + } + u32 getDrcHeight(void) const { + return drcColorBuffer.surface.height; + } + + const glm::mat4 & getProjectionMtx(void) const { + return projectionMtx; + } + const glm::mat4 & getViewMtx(void) const { + return viewMtx; + } + + f32 getWidthScaleFactor(void) const { + return widthScaleFactor; + } + f32 getHeightScaleFactor(void) const { + return heightScaleFactor; + } + f32 getDepthScaleFactor(void) const { + return depthScaleFactor; + } + + void screenPosToWorldRay(f32 posX, f32 posY, glm::vec3 & rayOrigin, glm::vec3 & rayDirection) + { + //! normalize positions + posX = 2.0f * posX * getWidthScaleFactor(); + posY = 2.0f * posY * getHeightScaleFactor(); + + glm::vec4 rayStart(posX, posY, 0.0f, 1.0f); + glm::vec4 rayEnd(posX, posY, 1.0f, 1.0f); + + glm::mat4 IMV = glm::inverse(projectionMtx * viewMtx); + glm::vec4 rayStartWorld = IMV * rayStart; + rayStartWorld /= rayStartWorld.w; + + glm::vec4 rayEndWorld = IMV * rayEnd; + rayEndWorld /= rayEndWorld.w; + + glm::vec3 rayDirectionWorld(rayEndWorld - rayStartWorld); + rayDirectionWorld = glm::normalize(rayDirectionWorld); + + rayOrigin = glm::vec3(rayStartWorld); + rayDirection = glm::normalize(rayDirectionWorld); + } +private: + static void *GX2RAlloc(u32 flags, u32 size, u32 align); + static void GX2RFree(u32 flags, void* p); + + void renderFXAA(const GX2Texture * texture, const GX2Sampler *sampler); + + void *gx2CommandBuffer; + + void *tvScanBuffer; + void *drcScanBuffer; + + u32 frameCount; + f32 widthScaleFactor; + f32 heightScaleFactor; + f32 depthScaleFactor; + + bool tvEnabled; + bool drcEnabled; + + GX2ColorBuffer tvColorBuffer; + GX2DepthBuffer tvDepthBuffer; + GX2ColorBuffer drcColorBuffer; + GX2DepthBuffer drcDepthBuffer; + + GX2ContextState *tvContextState; + GX2ContextState *drcContextState; + + GX2ContextState *currContextState; + GX2ColorBuffer *currColorBuffer; + GX2DepthBuffer *currDepthBuffer; + + GX2Texture tvAaTexture; + GX2Sampler aaSampler; + + glm::mat4 projectionMtx; + glm::mat4 viewMtx; + glm::vec2 resolution; +}; + +#endif // __GX2_VIDEO_H_ diff --git a/src/video/shaders/ColorShader.cpp b/src/video/shaders/ColorShader.cpp new file mode 100644 index 0000000..d8e963e --- /dev/null +++ b/src/video/shaders/ColorShader.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include +#include +#include "ColorShader.h" + +static const u32 cpVertexShaderProgram[] = +{ + 0x00000000,0x00008009,0x20000000,0x000078a0, + 0x3c200000,0x88060094,0x00c00000,0x88062014, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00a11f00,0xfc00620f,0x02490001,0x80000040, + 0xfd041f80,0x900c0060,0x83f9223e,0x0000803f, + 0xfe282001,0x10000040,0xfe001f80,0x00080060, + 0xfeac9f80,0xfd00624f,0xdb0f49c0,0xdb0fc940, + 0xfea81f80,0x9000e02f,0x83f9223e,0x00000000, + 0xfe041f80,0x00370000,0xffa01f00,0x80000000, + 0xff101f00,0x800c0020,0x7f041f80,0x80370000, + 0x0000103f,0x00000000,0x02c51f00,0x80000000, + 0xfea41f00,0x80000020,0xffa09f00,0x80000040, + 0xff001f80,0x800c0060,0x398ee33f,0x0000103f, + 0x02c41f00,0x9000e00f,0x02c59f01,0x80000020, + 0xfea81f00,0x80000040,0x02c19f80,0x9000e06f, + 0x398ee33f,0x00000000,0x02c11f01,0x80000000, + 0x02c49f80,0x80000060,0x02e08f01,0xfe0c620f, + 0x02c01f80,0x7f00622f,0xfe242000,0x10000000, + 0xfe20a080,0x10000020,0xf2178647,0x49c0e9fb, + 0xfbbdb2ab,0x768ac733 +}; + +static const u32 cpVertexShaderRegs[] = { + 0x00000103,0x00000000,0x00000000,0x00000001, + 0xffffff00,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0x00000000,0xfffffffc, + 0x00000002,0x00000001,0x00000000,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x00000000,0x0000000e,0x00000010 +}; + +static const u32 cpPixelShaderProgram[] = +{ + 0x20000000,0x00000ca0,0x00000000,0x88062094, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00002000,0x90000000,0x0004a000,0x90000020, + 0x00082001,0x90000040,0x000ca081,0x90000060, + 0xbb7dd898,0x9746c59c,0xc69b00e7,0x03c36218 +}; +static const u32 cpPixelShaderRegs[] = { + 0x00000001,0x00000002,0x14000001,0x00000000, + 0x00000001,0x00000100,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x0000000f,0x00000001,0x00000010, + 0x00000000 +}; + +ColorShader * ColorShader::shaderInstance = NULL; + +ColorShader::ColorShader() + : vertexShader(cuAttributeCount) +{ + //! create pixel shader + pixelShader.setProgram(cpPixelShaderProgram, sizeof(cpPixelShaderProgram), cpPixelShaderRegs, sizeof(cpPixelShaderRegs)); + + colorIntensityLocation = 0; + pixelShader.addUniformVar((GX2UniformVar){ "unf_color_intensity", GX2_VAR_TYPE_VEC4, 1, colorIntensityLocation, 0xffffffff }); + + //! create vertex shader + vertexShader.setProgram(cpVertexShaderProgram, sizeof(cpVertexShaderProgram), cpVertexShaderRegs, sizeof(cpVertexShaderRegs)); + + angleLocation = 0; + offsetLocation = 4; + scaleLocation = 8; + vertexShader.addUniformVar((GX2UniformVar){ "unf_angle", GX2_VAR_TYPE_FLOAT, 1, angleLocation, 0xffffffff }); + vertexShader.addUniformVar((GX2UniformVar){ "unf_offset", GX2_VAR_TYPE_VEC3, 1, offsetLocation, 0xffffffff }); + vertexShader.addUniformVar((GX2UniformVar){ "unf_scale", GX2_VAR_TYPE_VEC3, 1, scaleLocation, 0xffffffff }); + + colorLocation = 1; + positionLocation = 0; + vertexShader.addAttribVar((GX2AttribVar){ "attr_color", GX2_VAR_TYPE_VEC4, 0, colorLocation }); + vertexShader.addAttribVar((GX2AttribVar){ "attr_position", GX2_VAR_TYPE_VEC3, 0, positionLocation }); + + //! setup attribute streams + GX2InitAttribStream(vertexShader.getAttributeBuffer(0), positionLocation, 0, 0, GX2_ATTRIB_FORMAT_32_32_32_FLOAT); + GX2InitAttribStream(vertexShader.getAttributeBuffer(1), colorLocation, 1, 0, GX2_ATTRIB_FORMAT_8_8_8_8_UNORM); + + //! create fetch shader + fetchShader = new FetchShader(vertexShader.getAttributeBuffer(), vertexShader.getAttributesCount()); + + //! model vertex has to be align and cannot be in unknown regions for GX2 like 0xBCAE1000 + positionVtxs = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, cuPositionVtxsSize); + if(positionVtxs) + { + //! position vertex structure + int i = 0; + positionVtxs[i++] = -1.0f; positionVtxs[i++] = -1.0f; positionVtxs[i++] = 0.0f; + positionVtxs[i++] = 1.0f; positionVtxs[i++] = -1.0f; positionVtxs[i++] = 0.0f; + positionVtxs[i++] = 1.0f; positionVtxs[i++] = 1.0f; positionVtxs[i++] = 0.0f; + positionVtxs[i++] = -1.0f; positionVtxs[i++] = 1.0f; positionVtxs[i++] = 0.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, positionVtxs, cuPositionVtxsSize); + } +} + +ColorShader::~ColorShader() +{ + if(positionVtxs) + { + free(positionVtxs); + positionVtxs = NULL; + } + + delete fetchShader; + fetchShader = NULL; +} diff --git a/src/video/shaders/ColorShader.h b/src/video/shaders/ColorShader.h new file mode 100644 index 0000000..35c13b6 --- /dev/null +++ b/src/video/shaders/ColorShader.h @@ -0,0 +1,100 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 __COLOR_SHADER_H_ +#define __COLOR_SHADER_H_ + +#include "VertexShader.h" +#include "PixelShader.h" +#include "FetchShader.h" + +class ColorShader : public Shader +{ +private: + ColorShader(); + virtual ~ColorShader(); + + static const u32 cuAttributeCount = 2; + static const u32 cuPositionVtxsSize = 4 * cuVertexAttrSize; + + static ColorShader *shaderInstance; + + FetchShader *fetchShader; + VertexShader vertexShader; + PixelShader pixelShader; + + f32 *positionVtxs; + + u32 angleLocation; + u32 offsetLocation; + u32 scaleLocation; + u32 colorLocation; + u32 colorIntensityLocation; + u32 positionLocation; +public: + static const u32 cuColorVtxsSize = 4 * cuColorAttrSize; + + static ColorShader *instance() { + if(!shaderInstance) { + shaderInstance = new ColorShader(); + } + return shaderInstance; + } + static void destroyInstance() { + if(shaderInstance) { + delete shaderInstance; + shaderInstance = NULL; + } + } + + void setShaders(void) const + { + fetchShader->setShader(); + vertexShader.setShader(); + pixelShader.setShader(); + } + + void setAttributeBuffer(const u8 * colorAttr, const f32 * posVtxs_in = NULL, const u32 & vtxCount = 0) const + { + if(posVtxs_in && vtxCount) { + VertexShader::setAttributeBuffer(0, vtxCount * cuVertexAttrSize, cuVertexAttrSize, posVtxs_in); + VertexShader::setAttributeBuffer(1, vtxCount * cuColorAttrSize, cuColorAttrSize, colorAttr); + } + else { + VertexShader::setAttributeBuffer(0, cuPositionVtxsSize, cuVertexAttrSize, positionVtxs); + VertexShader::setAttributeBuffer(1, cuColorVtxsSize, cuColorAttrSize, colorAttr); + } + } + + void setAngle(const float & val) + { + VertexShader::setUniformReg(angleLocation, 4, &val); + } + void setOffset(const glm::vec3 & vec) + { + VertexShader::setUniformReg(offsetLocation, 4, &vec[0]); + } + void setScale(const glm::vec3 & vec) + { + VertexShader::setUniformReg(scaleLocation, 4, &vec[0]); + } + void setColorIntensity(const glm::vec4 & vec) + { + PixelShader::setUniformReg(colorIntensityLocation, 4, &vec[0]); + } +}; + +#endif // __COLOR_SHADER_H_ diff --git a/src/video/shaders/FXAAShader.cpp b/src/video/shaders/FXAAShader.cpp new file mode 100644 index 0000000..f86087b --- /dev/null +++ b/src/video/shaders/FXAAShader.cpp @@ -0,0 +1,230 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include +#include +#include "FXAAShader.h" + +static const u32 cpVertexShaderProgram[] = +{ + 0x00000000,0x00008009,0x20000000,0x000004a0, + 0x3ca00000,0x88060094,0x00400000,0xff0f2094, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0xfd001f80,0x900c2060,0x0000803f,0x00000000, + 0xc1a229f5,0xd0eddc33,0x426618fd,0x8509cfe7 +}; + +static const u32 cpVertexShaderRegs[] = { + 0x00000102,0x00000000,0x00000000,0x00000001, + 0xffffffff,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0x00000000,0xfffffffe, + 0x00000001,0x00000000,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x00000000,0x0000000e,0x00000010 +}; + +static const u32 cpPixelShaderProgram[] = +{ + 0x20000000,0x00003ca0,0xa0000000,0x000c8080, + 0x30000000,0x000010a1,0xa8000000,0x0010c080, + 0x75000000,0x000088a0,0x00800100,0x88062094, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00241f02,0x1000e00f,0x00241f00,0x1000e02f, + 0x00201f02,0x00000040,0x00201f00,0x00000060, + 0x00011f80,0x10332060,0xff000000,0xff102200, + 0xfd001f00,0x900cc020,0xffc09f01,0x90004040, + 0xffc01f01,0x90000060,0x00051f80,0x1033a040, + 0x0000803f,0x00000000,0xffe00f00,0x90004000, + 0xff008000,0xff102220,0xffe08f00,0x90000440, + 0x010c0000,0x010c4660,0xff008080,0xff004220, + 0x01a01f00,0x00280000,0x01a49f00,0x00280020, + 0x01a81f01,0x00280040,0xfd0c1f00,0x1028e06f, + 0x00208081,0x90002000,0x8716993e,0xa245163f, + 0xd578e93d,0x00000080,0x03a01f00,0x00280000, + 0x03a49f00,0x00280020,0x03a81f01,0x1028e04f, + 0xfd0c1f00,0x00280060,0x00a40081,0x90002020, + 0x8716993e,0xa245163f,0xd578e93d,0x00000080, + 0x04a01f00,0x00280000,0x04a49f00,0x1028a02f, + 0x04a81f01,0x00280040,0xfd0c1f00,0x00280060, + 0x7fcc1f80,0x1000c02f,0x8716993e,0xa245163f, + 0xd578e93d,0x00000080,0x02a01f00,0x1028e00f, + 0x02a49f00,0x00280020,0x02a81f01,0x00280040, + 0xfd0c1f00,0x00280060,0x7fcc1f80,0x1000e02f, + 0x8716993e,0xa245163f,0xd578e93d,0x00000080, + 0x7dc41f00,0x00020000,0x7fec0f01,0x00020020, + 0x7fc81f00,0x00000040,0x7dc41f00,0x00000060, + 0x7fec0f81,0x9001802f,0xfef88f00,0x1000e00f, + 0xfedc8f00,0x00000420,0x7de40f00,0x80010040, + 0x7ec49f01,0x00001060,0xfec41f80,0x10024060, + 0xfed49f00,0x80020000,0xfe141f00,0x900c802f, + 0xfeac1f00,0x80000040,0xfec01f02,0x80020060, + 0x7cc41f81,0x90010060,0x0000003d,0x00000000, + 0xfd001f00,0x900c6000,0xfea89f00,0x80010020, + 0xfec09f81,0x00020040,0x0000803f,0x0000003e, + 0xfec41f81,0x00000020,0xfe041f80,0x00330000, + 0x7fe01f00,0x80000040,0x7ce41f80,0x80000060, + 0xfea81f00,0x80010000,0xfeac1f80,0x80010020, + 0x000000c1,0x00000000,0xfea01f00,0x00020040, + 0xfea41f80,0x00020060,0x00000041,0x00000000, + 0x05c81f01,0x9000e00f,0x01cc9f81,0x9000e06f, + 0xfeac1f00,0x01004200,0xfea01f00,0x01044220, + 0xfeac9f00,0x01002240,0xfea09f00,0x01042260, + 0xfe8c1f80,0x01008600,0xacaa2a3e,0xaaaa2abe, + 0x7f9c1f00,0x0100a200,0x7f801f00,0x01048220, + 0x7f901f80,0x0104a240,0x02080001,0x7000a00f, + 0x02000000,0x7000c04f,0x02048000,0x7000e06f, + 0x01a81f80,0x9000e00f,0xd578e93d,0x00000000, + 0x04a80001,0x1000c00f,0x04a48000,0x00000020, + 0x04a00000,0x00000040,0xfe081f00,0xe00c0060, + 0xfe0c1f80,0xe00c0000,0x01a41f00,0x7f00620f, + 0xfea89f00,0xfe0c822f,0xfea49f00,0xff00a24f, + 0x7d001f80,0xe00c0060,0xa245163f,0x0000803e, + 0x7ea01f00,0xfe0ce20f,0x01a09f80,0xfe006a4f, + 0x0000803e,0x8716993e,0xfe088001,0x9001c00f, + 0xfe488001,0x1002e44f,0xfea01f80,0x80000000, + 0xd578e93d,0x00000000,0x7ca41f00,0x00280000, + 0x7da89f00,0x00280020,0xff201f00,0x00280040, + 0xfd081f80,0x00280060,0x8716993e,0xa245163f, + 0x00000080,0x00000000,0x7fc81f00,0x80060000, + 0xfec00f80,0x80060060,0xfec09f81,0xfb80634f, + 0xfe888f00,0x7e886300,0xfea80f01,0x7f8c6320, + 0xfee80f00,0x7d806340,0xfe680080,0x06846f60, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x10000100,0x01101df0,0x00008010,0xecdfea0d, + 0x10000200,0x03101df0,0x00002050,0xecdfea0d, + 0x10000000,0x04101df0,0x00003071,0xecdfea0d, + 0x10000200,0x02101df0,0x0000b070,0xecdfea0d, + 0x10000200,0x02101df0,0x00008010,0xecdfea0d, + 0x10000100,0x00101df0,0x0000a051,0xecdfea0d, + 0x10000400,0x04101df0,0x00008010,0xecdfea0d, + 0x10000500,0x05101df0,0x00000011,0xecdfea0d, + 0x10000100,0x01101df0,0x00008010,0xecdfea0d, + 0xfe2e963a,0x0269a9a3,0x38f88096,0x400cf48b +}; +static const u32 cpPixelShaderRegs[] = { + 0x00000007,0x00000002,0x04000101,0x00000000, + 0x00000001,0x00000100,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x0000000f,0x00000001,0x00000010, + 0x00000000 +}; + +FXAAShader * FXAAShader::shaderInstance = NULL; + +FXAAShader::FXAAShader() + : vertexShader(cuAttributeCount) +{ + //! create pixel shader + pixelShader.setProgram(cpPixelShaderProgram, sizeof(cpPixelShaderProgram), cpPixelShaderRegs, sizeof(cpPixelShaderRegs)); + + resolutionLocation = 0; + pixelShader.addUniformVar((GX2UniformVar){ "unf_resolution", GX2_VAR_TYPE_VEC2, 1, resolutionLocation, 0xffffffff }); + + samplerLocation = 0; + pixelShader.addSamplerVar((GX2SamplerVar){ "sampl_texture", GX2_SAMPLER_TYPE_2D, samplerLocation }); + + //! create vertex shader + vertexShader.setProgram(cpVertexShaderProgram, sizeof(cpVertexShaderProgram), cpVertexShaderRegs, sizeof(cpVertexShaderRegs)); + + positionLocation = 0; + texCoordLocation = 1; + vertexShader.addAttribVar((GX2AttribVar){ "attr_position", GX2_VAR_TYPE_VEC3, 0, positionLocation }); + vertexShader.addAttribVar((GX2AttribVar){ "attr_texture_coord", GX2_VAR_TYPE_VEC2, 0, texCoordLocation }); + + //! setup attribute streams + GX2InitAttribStream(vertexShader.getAttributeBuffer(0), positionLocation, 0, 0, GX2_ATTRIB_FORMAT_32_32_32_FLOAT); + GX2InitAttribStream(vertexShader.getAttributeBuffer(1), texCoordLocation, 1, 0, GX2_ATTRIB_FORMAT_32_32_FLOAT); + + //! create fetch shader + fetchShader = new FetchShader(vertexShader.getAttributeBuffer(), vertexShader.getAttributesCount()); + + //! model vertex has to be align and cannot be in unknown regions for GX2 like 0xBCAE1000 + posVtxs = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciPositionVtxsSize); + texCoords = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciTexCoordsVtxsSize); + + //! position vertex structure and texture coordinate vertex structure + int i = 0; + posVtxs[i++] = -1.0f; posVtxs[i++] = -1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = 1.0f; posVtxs[i++] = -1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = 1.0f; posVtxs[i++] = 1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = -1.0f; posVtxs[i++] = 1.0f; posVtxs[i++] = 0.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, posVtxs, ciPositionVtxsSize); + + i = 0; + texCoords[i++] = 0.0f; texCoords[i++] = 1.0f; + texCoords[i++] = 1.0f; texCoords[i++] = 1.0f; + texCoords[i++] = 1.0f; texCoords[i++] = 0.0f; + texCoords[i++] = 0.0f; texCoords[i++] = 0.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, texCoords, ciTexCoordsVtxsSize); +} + +FXAAShader::~FXAAShader() +{ + if(posVtxs) + { + free(posVtxs); + posVtxs = NULL; + } + if(texCoords) + { + free(texCoords); + texCoords = NULL; + } + + delete fetchShader; + fetchShader = NULL; +} diff --git a/src/video/shaders/FXAAShader.h b/src/video/shaders/FXAAShader.h new file mode 100644 index 0000000..b7604bc --- /dev/null +++ b/src/video/shaders/FXAAShader.h @@ -0,0 +1,86 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 __FXAA_SHADER_H_ +#define __FXAA_SHADER_H_ + +#include "VertexShader.h" +#include "PixelShader.h" +#include "FetchShader.h" + +class FXAAShader : public Shader +{ +public: + static FXAAShader *instance() { + if(!shaderInstance) { + shaderInstance = new FXAAShader(); + } + return shaderInstance; + } + static void destroyInstance() { + if(shaderInstance) { + delete shaderInstance; + shaderInstance = NULL; + } + } + + void setShaders(void) const + { + fetchShader->setShader(); + vertexShader.setShader(); + pixelShader.setShader(); + } + + void setAttributeBuffer() const + { + VertexShader::setAttributeBuffer(0, ciPositionVtxsSize, cuVertexAttrSize, posVtxs); + VertexShader::setAttributeBuffer(1, ciTexCoordsVtxsSize, cuTexCoordAttrSize, texCoords); + } + + void setResolution(const glm::vec2 & vec) + { + PixelShader::setUniformReg(resolutionLocation, 4, &vec[0]); + } + + void setTextureAndSampler(const GX2Texture *texture, const GX2Sampler *sampler) const { + GX2SetPixelTexture(texture, samplerLocation); + GX2SetPixelSampler(sampler, samplerLocation); + } + +private: + FXAAShader(); + virtual ~FXAAShader(); + + static const u32 cuAttributeCount = 2; + static const u32 ciPositionVtxsSize = 4 * cuVertexAttrSize; + static const u32 ciTexCoordsVtxsSize = 4 * cuTexCoordAttrSize; + + static FXAAShader *shaderInstance; + + FetchShader *fetchShader; + VertexShader vertexShader; + PixelShader pixelShader; + + f32 *posVtxs; + f32 *texCoords; + + u32 samplerLocation; + u32 positionLocation; + u32 texCoordLocation; + u32 resolutionLocation; +}; + +#endif // __FXAA_SHADER_H_ diff --git a/src/video/shaders/FetchShader.h b/src/video/shaders/FetchShader.h new file mode 100644 index 0000000..292052f --- /dev/null +++ b/src/video/shaders/FetchShader.h @@ -0,0 +1,58 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 FETCH_SHADER_H +#define FETCH_SHADER_H + +#include "Shader.h" + +class FetchShader : public Shader +{ +public: + FetchShader(GX2AttribStream * attributes, u32 attrCount, s32 type = GX2_FETCH_SHADER_TESSELATION_NONE, s32 tess = GX2_TESSELLATION_MODE_DISCRETE) + : fetchShader(NULL) + , fetchShaderProgramm(NULL) + { + u32 shaderSize = GX2CalcFetchShaderSizeEx(attrCount, type, tess); + fetchShaderProgramm = memalign(GX2_SHADER_ALIGNMENT, shaderSize); + if(fetchShaderProgramm) + { + fetchShader = new GX2FetchShader; + GX2InitFetchShaderEx(fetchShader, fetchShaderProgramm, attrCount, attributes, type, tess); + GX2Invalidate(GX2_INVALIDATE_CPU_SHADER, fetchShaderProgramm, shaderSize); + } + } + virtual ~FetchShader() { + if(fetchShaderProgramm) + free(fetchShaderProgramm); + if(fetchShader) + delete fetchShader; + } + + GX2FetchShader *getFetchShader() const { + return fetchShader; + } + + void setShader(void) const { + GX2SetFetchShader(fetchShader); + } + +protected: + GX2FetchShader *fetchShader; + void *fetchShaderProgramm; +}; + +#endif // FETCH_SHADER_H diff --git a/src/video/shaders/PixelShader.h b/src/video/shaders/PixelShader.h new file mode 100644 index 0000000..a1fa76b --- /dev/null +++ b/src/video/shaders/PixelShader.h @@ -0,0 +1,150 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 PIXEL_SHADER_H +#define PIXEL_SHADER_H + +#include "Shader.h" + +class PixelShader : public Shader +{ +public: + PixelShader() + : pixelShader((GX2PixelShader*) memalign(0x40, sizeof(GX2PixelShader))) + { + if(pixelShader) + { + memset(pixelShader, 0, sizeof(GX2PixelShader)); + pixelShader->shader_mode = GX2_SHADER_MODE_UNIFORM_REGISTER; + } + } + virtual ~PixelShader() + { + if(pixelShader) + { + if(pixelShader->shader_data) + free(pixelShader->shader_data); + + for(u32 i = 0; i < pixelShader->uniform_blocks_count; i++) + free((void*)pixelShader->uniform_block[i].name); + + if(pixelShader->uniform_block) + free((void*)pixelShader->uniform_block); + + for(u32 i = 0; i < pixelShader->uniform_vars_count; i++) + free((void*)pixelShader->uniform_var[i].name); + + if(pixelShader->uniform_var) + free((void*)pixelShader->uniform_var); + + if(pixelShader->initial_value) + free((void*)pixelShader->initial_value); + + for(u32 i = 0; i < pixelShader->sampler_vars_count; i++) + free((void*)pixelShader->sampler_var[i].name); + + if(pixelShader->sampler_var) + free((void*)pixelShader->sampler_var); + + if(pixelShader->loops_data) + free((void*)pixelShader->loops_data); + + free(pixelShader); + } + } + + void setProgram(const u32 * program, const u32 & programSize, const u32 * regs, const u32 & regsSize) + { + if(!pixelShader) + return; + + //! this must be moved into an area where the graphic engine has access to and must be aligned to 0x100 + pixelShader->shader_size = programSize; + pixelShader->shader_data = memalign(GX2_SHADER_ALIGNMENT, pixelShader->shader_size); + if(pixelShader->shader_data) + { + memcpy(pixelShader->shader_data, program, pixelShader->shader_size); + GX2Invalidate(GX2_INVALIDATE_CPU_SHADER, pixelShader->shader_data, pixelShader->shader_size); + } + + memcpy(pixelShader->regs, regs, regsSize); + } + + void addUniformVar(const GX2UniformVar & var) + { + if(!pixelShader) + return; + + u32 idx = pixelShader->uniform_vars_count; + + GX2UniformVar* newVar = (GX2UniformVar*) malloc((pixelShader->uniform_vars_count + 1) * sizeof(GX2UniformVar)); + if(newVar) + { + if(pixelShader->uniform_var) + { + memcpy(newVar, pixelShader->uniform_var, pixelShader->uniform_vars_count * sizeof(GX2UniformVar)); + free(pixelShader->uniform_var); + } + pixelShader->uniform_var = newVar; + + memcpy(pixelShader->uniform_var + idx, &var, sizeof(GX2UniformVar)); + pixelShader->uniform_var[idx].name = (char*) malloc(strlen(var.name) + 1); + strcpy((char*)pixelShader->uniform_var[idx].name, var.name); + + pixelShader->uniform_vars_count++; + } + } + + void addSamplerVar(const GX2SamplerVar & var) + { + if(!pixelShader) + return; + + u32 idx = pixelShader->sampler_vars_count; + + GX2SamplerVar* newVar = (GX2SamplerVar*) malloc((pixelShader->sampler_vars_count + 1) * sizeof(GX2SamplerVar)); + if(newVar) + { + if(pixelShader->sampler_var) + { + memcpy(newVar, pixelShader->sampler_var, pixelShader->sampler_vars_count * sizeof(GX2SamplerVar)); + free(pixelShader->sampler_var); + } + pixelShader->sampler_var = newVar; + + memcpy(pixelShader->sampler_var + idx, &var, sizeof(GX2SamplerVar)); + pixelShader->sampler_var[idx].name = (char*) malloc(strlen(var.name) + 1); + strcpy((char*)pixelShader->sampler_var[idx].name, var.name); + + pixelShader->sampler_vars_count++; + } + } + GX2PixelShader * getPixelShader() const { + return pixelShader; + } + + void setShader(void) const { + GX2SetPixelShader(pixelShader); + } + + static inline void setUniformReg(u32 location, u32 size, const void * reg) { + GX2SetPixelUniformReg(location, size, reg); + } +protected: + GX2PixelShader *pixelShader; +}; + +#endif // PIXEL_SHADER_H diff --git a/src/video/shaders/Shader.h b/src/video/shaders/Shader.h new file mode 100644 index 0000000..93741d5 --- /dev/null +++ b/src/video/shaders/Shader.h @@ -0,0 +1,74 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 SHADER_H_ +#define SHADER_H_ + +#include "glm/glm.hpp" +#include "glm/gtc/matrix_transform.hpp" +#include "dynamic_libs/gx2_functions.h" +#include "utils/utils.h" + +class Shader +{ +protected: + Shader() {} + virtual ~Shader() {} +public: + static const u16 cuVertexAttrSize = sizeof(f32) * 3; + static const u16 cuTexCoordAttrSize = sizeof(f32) * 2; + static const u16 cuColorAttrSize = sizeof(u8) * 4; + + static void setLineWidth(const f32 & width) { + GX2SetLineWidth(width); + } + + static void draw(s32 primitive = GX2_PRIMITIVE_QUADS, u32 vtxCount = 4) + { + switch(primitive) + { + default: + case GX2_PRIMITIVE_QUADS: + { + GX2DrawEx(GX2_PRIMITIVE_QUADS, vtxCount, 0, 1); + break; + } + case GX2_PRIMITIVE_TRIANGLES: + { + GX2DrawEx(GX2_PRIMITIVE_TRIANGLES, vtxCount, 0, 1); + break; + } + case GX2_PRIMITIVE_TRIANGLE_FAN: + { + GX2DrawEx(GX2_PRIMITIVE_TRIANGLE_FAN, vtxCount, 0, 1); + break; + } + case GX2_PRIMITIVE_LINES: + { + GX2DrawEx(GX2_PRIMITIVE_LINES, vtxCount, 0, 1); + break; + } + case GX2_PRIMITIVE_LINE_STRIP: + { + GX2DrawEx(GX2_PRIMITIVE_LINE_STRIP, vtxCount, 0, 1); + break; + } + //! TODO: add other primitives later + }; + } +}; + +#endif // SHADER_H_ diff --git a/src/video/shaders/Shader3D.cpp b/src/video/shaders/Shader3D.cpp new file mode 100644 index 0000000..6857cd1 --- /dev/null +++ b/src/video/shaders/Shader3D.cpp @@ -0,0 +1,266 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include +#include +#include "Shader3D.h" + +static const u32 cpVertexShaderProgram[] = +{ + 0x00000000,0x00008009,0x20000000,0x0000e4a1, + 0x00c00100,0x88048093,0x01c00300,0x98060014, + 0x9a000000,0x000058a0,0x3c200200,0x88062094, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x0765a101,0x9000e00f,0x0761a101,0x9000e02f, + 0x01081f00,0x900ce040,0x01041f00,0x900ce060, + 0x01001f80,0x900ce000,0x02001f00,0x900c6000, + 0x02041f00,0x900c6020,0x076da101,0x9000e04f, + 0x0769a181,0x9000e06f,0x0745a101,0x9000c00f, + 0x0741a181,0x9000c02f,0x074da101,0x9000c04f, + 0x0749a181,0x9000c06f,0x0bc9a000,0x7f00e20f, + 0x0bc92080,0x7f04e22f,0x0bc9a001,0x7f08e24f, + 0x0bc92081,0x7f0ce26f,0x0725a101,0x9000a00f, + 0x0721a181,0x9000a02f,0x072da101,0x9000a04f, + 0x0729a181,0x9000a06f,0x0ac9a000,0x7e00c20f, + 0x0ac92080,0x7e04c22f,0x0ac9a001,0x7e08c24f, + 0x0ac92081,0x7e0cc26f,0x0ba5a000,0x7f00e20f, + 0x0ba52080,0x7f04e22f,0x0ba5a001,0x7f08e24f, + 0x0ba52081,0x7f0ce26f,0x08eda000,0x9000800f, + 0x08ed2080,0x9000802f,0x08eda001,0x9000804f, + 0x08ed2081,0x9000806f,0x09c9a000,0x7d00a20f, + 0x09c92080,0x7d04a22f,0x09c9a001,0x7d08a24f, + 0x09c92081,0x7d0ca26f,0x0aa5a000,0x7e00c20f, + 0x0aa52080,0x7e04c22f,0x0aa5a001,0x7e08c24f, + 0x0aa52081,0x7e0cc26f,0x0b81a000,0x7f004200, + 0x0b812080,0x7f044220,0x0b81a001,0x7f082240, + 0x0b812081,0x7f0c0260,0x08c9a000,0x7c00820f, + 0x08c92080,0x7c04822f,0x08c9a001,0x7c08824f, + 0x08c92081,0x7c0c826f,0x09a5a000,0x7d00a20f, + 0x09a52080,0x7d04a22f,0x09a5a001,0x7d08a24f, + 0x09a52081,0x7d0ca26f,0x0a81a000,0x7e000200, + 0x0a812080,0x7e040220,0x0a81a001,0x7e080240, + 0x0a812081,0x7e0c2260,0x0240a001,0x9000c00f, + 0x0244a001,0x9000c02f,0x0148a001,0x9000c04f, + 0x004ca001,0x9000c06f,0x0264a081,0x9000e02f, + 0x0260a001,0x9000e00f,0x0224a001,0x90002020, + 0x0168a001,0x9000e04f,0x006ca001,0x9000e06f, + 0x0220a081,0x90002000,0x08a5a000,0x7c00820f, + 0x08a52080,0x7c04822f,0x08a5a001,0x7c08824f, + 0x08a52081,0x7c0c826f,0x0981a000,0x7d008200, + 0x09812080,0x7d048220,0x0981a001,0x7d084240, + 0x09812081,0x7d0c4260,0x02090000,0x7e00c20f, + 0x02098000,0x7e04c22f,0x0128a001,0x9000a04f, + 0x002ca001,0x9000c06f,0x02298081,0x7e0caa6f, + 0x03090000,0x7f00e20f,0x03098000,0x7f04e22f, + 0x02090001,0x7e08f64f,0x03298001,0x7f0ce26f, + 0x03090081,0x7f08ca4f,0x0881a000,0x7c00c200, + 0x08812080,0x7c04e220,0x0881a001,0x7c08a240, + 0x08812081,0x7c0c8260,0x0200a001,0x9000800f, + 0x0204a001,0x9000802f,0x0108a001,0x9000804f, + 0x000ca001,0x9000806f,0x01098080,0x0104aa2f, + 0x01090000,0x0100a20f,0x02858000,0x7e04c22f, + 0x01090001,0x7d08a24f,0x01298081,0x7e0cc26f, + 0x02850000,0x7e00f60f,0x03858000,0x7f04622f, + 0x02450001,0x7f08e24f,0x02458001,0x7d0ca26f, + 0x03850080,0x7f00ca0f,0x00090000,0x7c004200, + 0x00098000,0x7c04b220,0x03450001,0x7e08c24f, + 0x03458001,0x7f0ce26f,0x03e18080,0xfe042620, + 0x01850000,0x7d00a200,0x01858000,0x7d04622f, + 0x00090001,0x7c086240,0x00298081,0x7c0c0260, + 0x02c10000,0x7f000200,0x02e18000,0x7e040620, + 0x01450001,0x7d088240,0x01458001,0x7e0c6260, + 0x01e18080,0xfe04c620,0x03c10000,0x7e002200, + 0x03818001,0x7f0c4220,0x02a10001,0x7f081640, + 0x02818001,0x7d0c3660,0x03a10081,0x7e082a40, + 0x07080000,0x0100c20f,0x07088000,0x0104622f, + 0x00458001,0x000cea4f,0x07288081,0x0204f66f, + 0x00850000,0x0200620f,0x00858000,0x05046a2f, + 0x07080001,0x0108c24f,0x01818001,0x030c726f, + 0x07cc8080,0xfe04c22f,0x01c10000,0x0500660f, + 0x00e18000,0xfe04622f,0x00450001,0x0308624f, + 0x07cc9f01,0x7f0ce26f,0x00c10080,0xfe00e60f, + 0x07cc1f00,0x7e00660f,0x00a10001,0xfe08c22f, + 0x01a10001,0x0408624f,0x00818001,0x7f086a6f, + 0x07c09f80,0x7e048200,0x07e00f00,0xfe008220, + 0x07cc1f01,0x7e086a4f,0x07c09f81,0x7f0c8240, + 0x07c08f80,0xfe088260,0x2c34800d,0xe3b4f15e, + 0x7642ed30,0x7408600d +}; + +static const u32 cpVertexShaderRegs[] = { + 0x00000108,0x00000000,0x00000002,0x00000001, + 0xffff0001,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0x00000000,0xfffffffc, + 0x00000002,0x00000000,0x00000001,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x00000000,0x0000000e,0x00000010 +}; + +static const u32 cPixelShaderProgram[] = +{ + 0x20000000,0x000008a4,0x03000000,0x01004085, + 0x23000000,0x000044a8,0x35000000,0x000000a4, + 0x06000000,0x01004085,0x36000000,0x00002ca8, + 0x50000000,0x0000c080,0x42000000,0x00001ca0, + 0x00800000,0x88062094,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0xfd001f80,0x900c0060,0x0000803f,0x00000000, + 0x02011f80,0x8c110000,0xf8402000,0x9006a00f, + 0x02552001,0x00000020,0x01248082,0x80020060, + 0xfe3c1f00,0x1000e04f,0xfe041f80,0x1033c00f, + 0xfe482081,0x80060020,0xfee40f81,0x0289e30f, + 0x02c51f80,0x80060060,0xfeec0f80,0x0285634f, + 0xfec80f80,0x80000060,0xfe4ca081,0x9000e04f, + 0xfe281f00,0x80060000,0xf8c01f81,0x9006e02f, + 0xfee00f81,0xfd80636f,0x0000803f,0x00000000, + 0x7fc49f81,0xf880e34f,0xfe381f80,0x00000000, + 0x7de00f81,0xfe800360,0x01011f80,0x8c100000, + 0x00a81f00,0x9000e02f,0x00000082,0x80020060, + 0x00002040,0x00000000,0xfeac9f80,0xfd00624f, + 0x3333333f,0x00002040,0xfee88f80,0x0101620f, + 0x00cc1f80,0x9000e06f,0xf8c09f01,0x80060020, + 0xfe2c1f80,0x9006e04f,0xfee48f81,0xf880630f, + 0x7fc81f80,0xfd800360,0x0000803f,0x00000000, + 0x000ca001,0x80000000,0x00091f00,0x800c0020, + 0x00051f00,0x800c0040,0x00011f80,0x800c0060, + 0xfe2c0000,0x90002000,0xfe288000,0x90002020, + 0xfe240001,0x90002040,0xfe208081,0x90002060, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x10000100,0x01100df0,0x00008010,0xecdfea0d, + 0x99720984,0x041cab0d,0xa28a9ccd,0x95d199a5 +}; +static const u32 cPixelShaderRegs[] = { + 0x00000102,0x00000002,0x14000002,0x00000000, + 0x00000002,0x00000100,0x00000101,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x0000000f,0x00000001,0x00000010, + 0x00000000 +}; + +Shader3D * Shader3D::shaderInstance = NULL; + +Shader3D::Shader3D() + : vertexShader(cuAttributeCount) +{ + //! create pixel shader + pixelShader.setProgram(cPixelShaderProgram, sizeof(cPixelShaderProgram), cPixelShaderRegs, sizeof(cPixelShaderRegs)); + + colorIntensityLocation = 0; + fadeDistanceLocation = 4; + fadeOutLocation = 8; + pixelShader.addUniformVar((GX2UniformVar){ "unf_color_intensity", GX2_VAR_TYPE_VEC4, 1, colorIntensityLocation, 0xffffffff }); + pixelShader.addUniformVar((GX2UniformVar){ "unf_fade_distance", GX2_VAR_TYPE_FLOAT, 1, fadeDistanceLocation, 0xffffffff }); + pixelShader.addUniformVar((GX2UniformVar){ "unf_fade_out_alpha", GX2_VAR_TYPE_VEC4, 1, fadeOutLocation, 0xffffffff }); + + samplerLocation = 0; + pixelShader.addSamplerVar((GX2SamplerVar){ "sampl_texture", GX2_SAMPLER_TYPE_2D, samplerLocation }); + + //! create vertex shader + vertexShader.setProgram(cpVertexShaderProgram, sizeof(cpVertexShaderProgram), cpVertexShaderRegs, sizeof(cpVertexShaderRegs)); + + modelMatrixLocation = 0; + projectionMatrixLocation = 16; + viewMatrixLocation = 32; + vertexShader.addUniformVar((GX2UniformVar){ "modelMatrix", GX2_VAR_TYPE_MAT4, 1, modelMatrixLocation, 0xffffffff }); + vertexShader.addUniformVar((GX2UniformVar){ "viewMatrix", GX2_VAR_TYPE_MAT4, 1, projectionMatrixLocation, 0xffffffff }); + vertexShader.addUniformVar((GX2UniformVar){ "projectionMatrix", GX2_VAR_TYPE_MAT4, 1, viewMatrixLocation, 0xffffffff }); + + positionLocation = 0; + texCoordLocation = 1; + vertexShader.addAttribVar((GX2AttribVar){ "attr_position", GX2_VAR_TYPE_VEC3, 0, positionLocation }); + vertexShader.addAttribVar((GX2AttribVar){ "attr_texture_coord", GX2_VAR_TYPE_VEC2, 0, texCoordLocation }); + + //! setup attribute streams + GX2InitAttribStream(vertexShader.getAttributeBuffer(0), positionLocation, 0, 0, GX2_ATTRIB_FORMAT_32_32_32_FLOAT); + GX2InitAttribStream(vertexShader.getAttributeBuffer(1), texCoordLocation, 1, 0, GX2_ATTRIB_FORMAT_32_32_FLOAT); + + //! create fetch shader + fetchShader = new FetchShader(vertexShader.getAttributeBuffer(), vertexShader.getAttributesCount()); + + //! initialize default quad texture vertexes as those are very commonly used + //! model vertex has to be align and cannot be in unknown regions for GX2 like 0xBCAE1000 + posVtxs = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciPositionVtxsSize); + texCoords = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciTexCoordsVtxsSize); + + //! position vertex structure and texture coordinate vertex structure + int i = 0; + posVtxs[i++] = -1.0f; posVtxs[i++] = -1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = 1.0f; posVtxs[i++] = -1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = 1.0f; posVtxs[i++] = 1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = -1.0f; posVtxs[i++] = 1.0f; posVtxs[i++] = 0.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, posVtxs, ciPositionVtxsSize); + + i = 0; + texCoords[i++] = 0.0f; texCoords[i++] = 1.0f; + texCoords[i++] = 1.0f; texCoords[i++] = 1.0f; + texCoords[i++] = 1.0f; texCoords[i++] = 0.0f; + texCoords[i++] = 0.0f; texCoords[i++] = 0.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, texCoords, ciTexCoordsVtxsSize); +} + +Shader3D::~Shader3D() +{ + if(posVtxs) + { + free(posVtxs); + posVtxs = NULL; + } + if(texCoords) + { + free(texCoords); + texCoords = NULL; + } + + delete fetchShader; + fetchShader = NULL; +} diff --git a/src/video/shaders/Shader3D.h b/src/video/shaders/Shader3D.h new file mode 100644 index 0000000..7289152 --- /dev/null +++ b/src/video/shaders/Shader3D.h @@ -0,0 +1,119 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 SHADER_3D_H_ +#define SHADER_3D_H_ + +#include "VertexShader.h" +#include "PixelShader.h" +#include "FetchShader.h" + +class Shader3D : public Shader +{ +private: + Shader3D(); + virtual ~Shader3D(); + + static Shader3D * shaderInstance; + + static const unsigned char cuAttributeCount = 2; + static const u32 ciPositionVtxsSize = 4 * cuVertexAttrSize; + static const u32 ciTexCoordsVtxsSize = 4 * cuTexCoordAttrSize; + + FetchShader *fetchShader; + VertexShader vertexShader; + PixelShader pixelShader; + + f32 *posVtxs; + f32 *texCoords; + + u32 modelMatrixLocation; + u32 viewMatrixLocation; + u32 projectionMatrixLocation; + u32 positionLocation; + u32 texCoordLocation; + + u32 colorIntensityLocation; + u32 fadeDistanceLocation; + u32 fadeOutLocation; + u32 samplerLocation; +public: + static Shader3D *instance() { + if(!shaderInstance) { + shaderInstance = new Shader3D(); + } + return shaderInstance; + } + static void destroyInstance() { + if(shaderInstance) { + delete shaderInstance; + shaderInstance = NULL; + } + } + + void setShaders(void) const + { + fetchShader->setShader(); + vertexShader.setShader(); + pixelShader.setShader(); + } + + void setAttributeBuffer(const u32 & vtxCount = 0, const f32 * posVtxs_in = NULL, const f32 * texCoords_in = NULL) const + { + if(posVtxs_in && texCoords_in && vtxCount) + { + VertexShader::setAttributeBuffer(0, vtxCount * cuVertexAttrSize, cuVertexAttrSize, posVtxs_in); + VertexShader::setAttributeBuffer(1, vtxCount * cuTexCoordAttrSize, cuTexCoordAttrSize, texCoords_in); + } + else { + //! use default quad vertex and texture coordinates if nothing is passed + VertexShader::setAttributeBuffer(0, ciPositionVtxsSize, cuVertexAttrSize, posVtxs); + VertexShader::setAttributeBuffer(1, ciTexCoordsVtxsSize, cuTexCoordAttrSize, texCoords); + } + } + + void setProjectionMtx(const glm::mat4 & mtx) + { + VertexShader::setUniformReg(projectionMatrixLocation, 16, &mtx[0][0]); + } + void setViewMtx(const glm::mat4 & mtx) + { + VertexShader::setUniformReg(viewMatrixLocation, 16, &mtx[0][0]); + } + void setModelViewMtx(const glm::mat4 & mtx) + { + VertexShader::setUniformReg(modelMatrixLocation, 16, &mtx[0][0]); + } + void setColorIntensity(const glm::vec4 & vec) + { + PixelShader::setUniformReg(colorIntensityLocation, 4, &vec[0]); + } + void setAlphaFadeOut(const glm::vec4 & vec) + { + PixelShader::setUniformReg(fadeOutLocation, 4, &vec[0]); + } + void setDistanceFadeOut(const float & value) + { + PixelShader::setUniformReg(fadeDistanceLocation, 4, &value); + } + + void setTextureAndSampler(const GX2Texture *texture, const GX2Sampler *sampler) const { + GX2SetPixelTexture(texture, samplerLocation); + GX2SetPixelSampler(sampler, samplerLocation); + } +}; + +#endif // SHADER_3D_H_ diff --git a/src/video/shaders/ShaderFractalColor.cpp b/src/video/shaders/ShaderFractalColor.cpp new file mode 100644 index 0000000..7e8624c --- /dev/null +++ b/src/video/shaders/ShaderFractalColor.cpp @@ -0,0 +1,373 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include +#include +#include "ShaderFractalColor.h" + +static const u32 cpVertexShaderProgram[] = +{ + 0x00000000,0x00008009,0x20000000,0x0000eca1, + 0x00c00000,0x88068093,0x01400200,0x9a048013, + 0x9c000000,0x000044a0,0x3c200000,0x88060094, + 0x02400000,0x88062014,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x0765a101,0x9000e00f,0x0761a101,0x9000e02f, + 0x03001f00,0x900c8040,0x03041f80,0x900c8060, + 0x076da101,0x9000e04f,0x0769a181,0x9000e06f, + 0x0745a101,0x9000c00f,0x0741a181,0x9000c02f, + 0x074da101,0x9000c04f,0x0749a181,0x9000c06f, + 0x0bc9a000,0x7f00e20f,0x0bc92080,0x7f04e22f, + 0x0bc9a001,0x7f08e24f,0x0bc92081,0x7f0ce26f, + 0x0725a101,0x9000a00f,0x0721a181,0x9000a02f, + 0x072da101,0x9000a04f,0x0729a181,0x9000a06f, + 0x0ac9a000,0x7e00c20f,0x0ac92080,0x7e04c22f, + 0x0ac9a001,0x7e08c24f,0x0ac92081,0x7e0cc26f, + 0x0ba5a000,0x7f00e20f,0x0ba52080,0x7f04e22f, + 0x0ba5a001,0x7f08e24f,0x0ba52081,0x7f0ce26f, + 0x08eda000,0x9000800f,0x08ed2080,0x9000802f, + 0x08eda001,0x9000804f,0x08ed2081,0x9000806f, + 0x09c9a000,0x7d00a20f,0x09c92080,0x7d04a22f, + 0x09c9a001,0x7d08a24f,0x09c92081,0x7d0ca26f, + 0x0aa5a000,0x7e00c20f,0x0aa52080,0x7e04c22f, + 0x0aa5a001,0x7e08c24f,0x0aa52081,0x7e0cc26f, + 0x0b81a000,0x7f006200,0x0b812080,0x7f046220, + 0x0b81a001,0x7f080240,0x0b812081,0x7f0c0260, + 0x08c9a000,0x7c00820f,0x08c92080,0x7c04822f, + 0x08c9a001,0x7c08824f,0x08c92081,0x7c0c826f, + 0x09a5a000,0x7d00a20f,0x09a52080,0x7d04a22f, + 0x09a5a001,0x7d08a24f,0x09a52081,0x7d0ca26f, + 0x0a81a000,0x7e008200,0x0a812080,0x7e048220, + 0x0a81a001,0x7e086240,0x0a812081,0x7e0c4260, + 0x0340a001,0x9000c00f,0x0344a001,0x9000c02f, + 0x0048a001,0x9000c04f,0x004ca001,0x9000c06f, + 0x0364a081,0x9000e02f,0x0360a001,0x9000e00f, + 0x0324a001,0x90000020,0x0068a001,0x9000e04f, + 0x006ca001,0x9000e06f,0x0320a081,0x90000000, + 0x08a5a000,0x7c00820f,0x08a52080,0x7c04822f, + 0x08a5a001,0x7c08824f,0x08a52081,0x7c0c826f, + 0x0981a000,0x7d00a200,0x09812080,0x7d04a220, + 0x0981a001,0x7d08a240,0x09812081,0x7d0c6260, + 0x02890000,0x7e00c20f,0x02898000,0x7e04c22f, + 0x0028a001,0x9000a04f,0x002ca001,0x9000c06f, + 0x02498081,0x7e0caa6f,0x03890000,0x7f00e20f, + 0x03898000,0x7f04e22f,0x02690001,0x7e08f64f, + 0x03498001,0x7f0ce26f,0x03690081,0x7f08ca4f, + 0x0881a000,0x7c00c200,0x08812080,0x7c04c220, + 0x0881a001,0x7c08e240,0x08812081,0x7c0ca260, + 0x0300a001,0x9000800f,0x0304a001,0x9000802f, + 0x0008a001,0x9000804f,0x000ca001,0x9000806f, + 0x01898080,0x0004aa2f,0x01890000,0x0000a20f, + 0x02a58000,0x7e04c22f,0x01690001,0x7d08a24f, + 0x01498081,0x7e0cc26f,0x02a50000,0x7e00f60f, + 0x03a58000,0x7f04622f,0x02a50001,0x7f08e24f, + 0x02658001,0x7d0ca26f,0x03a50080,0x7f00ca0f, + 0x00890000,0x7c00820f,0x00898000,0x7c049220, + 0x03a50001,0x7e08c24f,0x03658001,0x7f0ce26f, + 0x03c18080,0xfe04862f,0x01a50000,0x7d008200, + 0x01a58000,0x7d04622f,0x00690001,0x7c086240, + 0x00498081,0x7c0c4260,0x02c10000,0x7f00e20f, + 0x02c18000,0x7e04c62f,0x01a50001,0x7d080240, + 0x01658001,0x7e0c0260,0x01c18080,0xfe040620, + 0x03c10000,0x7e00620f,0x03a18001,0x7f0c622f, + 0x02e10001,0x7f08764f,0x02a18001,0x7d0c766f, + 0x03e10081,0x7e084a0f,0x02e80f00,0xfe000e00, + 0x02c88f00,0x7c046220,0x02c81f01,0xff00c240, + 0x02c89f01,0xfe04c260,0x00a50080,0x7c00aa00, + 0x01c10000,0x0400760f,0x00a58000,0x0404622f, + 0x00a50001,0x0308e24f,0x00658001,0x020c626f, + 0x00c10080,0x0500ea0f,0x02c41f00,0x0000620f, + 0x00c18000,0xfe04c22f,0x01e10001,0x0008624f, + 0x01a18001,0x000c666f,0x00a18081,0xfe0ce66f, + 0x00e10001,0x7f08620f,0x02048000,0x03046a2f, + 0x02c41f01,0x06086a4f,0x02c49f01,0x060c6a6f, + 0x02e00f80,0xfe000220,0x02c08f00,0xfe040200, + 0x02e08f01,0xfe0c0240,0x02c01f80,0xfe080260, + 0x8aa480ad,0x2bfc5ca6,0xb5e05b5b,0xd48dc71c +}; + +static const u32 cpVertexShaderRegs[] = { + 0x00000108,0x00000000,0x00000004,0x00000001, + 0xff000201,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0x00000000,0xfffffff8, + 0x00000003,0x00000001,0x00000000,0x00000002, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x00000000,0x0000000e,0x00000010 +}; + +static const u32 cpPixelShaderProgram[] = +{ + 0x20000000,0x000008a4,0x04000000,0x01004085, + 0x23000000,0x0000eca1,0x9f000000,0x0000e0a8, + 0xd8000000,0x000000a4,0x07000000,0x01004085, + 0xd9000000,0x000048a8,0xec000000,0x000000a4, + 0x0a000000,0x01004085,0xed000000,0x000050a8, + 0x02010000,0x000030a0,0x00000000,0x88062094, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0xfd001f80,0x900c0060,0x0000803f,0x00000000, + 0x03011f80,0x8c210000,0xfd001f00,0x900c0000, + 0xfd001f00,0x900ca02f,0x00000002,0x80020040, + 0x00048002,0x80020060,0xf8001f80,0x900cc04f, + 0x0000803f,0x00000000,0xfea81f00,0x9000e00f, + 0xfeac1f00,0x9000e02f,0xf8001f00,0x900c804f, + 0xf8001f80,0x900ca06f,0x00000040,0x00000000, + 0xfea01f00,0x00280000,0xfea41f00,0x00280020, + 0xfe041f00,0x00280040,0xfd041f80,0x00280060, + 0xaf67bb3e,0x00000080,0x7fc41f00,0x00000000, + 0x7fc01f80,0x00000020,0xfe041f00,0x100ac00f, + 0xfe001f80,0x100ac02f,0xfea01f00,0x00280000, + 0xfea41f00,0x00280020,0xfe041f00,0x00280040, + 0xfd041f00,0x1028e06f,0x7fc01f82,0x00000000, + 0x8c65583e,0x00000080,0x7ea41f00,0x80000000, + 0x7ea01f00,0x80000020,0xfee01f00,0x10006040, + 0x7fc48f82,0x00000860,0xa7c4623b,0x00000000, + 0xfea81f00,0x1000e00f,0x7fcc9f01,0x10006020, + 0xfe001f00,0x000a0040,0xfe041f00,0x000a0060, + 0xfea89f80,0x10008040,0x8c65583e,0x3acd13bf, + 0xfeb81f00,0x7e04c20f,0xfebc1f00,0x7e00822f, + 0x03c89f00,0x80060040,0xfea49f00,0x1000e06f, + 0xfea41f81,0x10006060,0x00809043,0x8c65583e, + 0x3acd13bf,0x00000000,0xfea81f00,0xf880a30f, + 0xfe001f00,0x900ca02f,0x7dc41f00,0x1000e04f, + 0xfe081f00,0xfd80636f,0x04081f80,0x900c800f, + 0x0000803f,0x00000000,0xfea81f00,0xf900620f, + 0xfea41f00,0xf900622f,0xfe0c1f00,0x900ca04f, + 0xfec00f00,0x1000c46f,0xfefc0f80,0x10006000, + 0x00000842,0x00000000,0xfeac1f00,0xf900620f, + 0x7fc81f00,0x9000c02f,0x7dc49f00,0x9000e04f, + 0x7df08f01,0x10008060,0x030c1f80,0x900ca02f, + 0x00000842,0x00000000,0xfea41f00,0x80000000, + 0x7ecc1f00,0x9000e02f,0x7e688000,0x80000040, + 0xfea81f00,0x80000060,0x7d6c8081,0x80000000, + 0xa7c4623b,0x00000000,0xfe001f00,0x000a0000, + 0xfe0c1f00,0x000a0020,0xfea41f00,0x80000040, + 0x03648000,0xfe08626f,0x7d648081,0xff00420f, + 0xa7c4623b,0x00000000,0xfeb01f00,0x7e04620f, + 0xfeb41f00,0x7f08662f,0x7c800001,0xff006e4f, + 0xfe081f00,0x000a0060,0x03680081,0xfe0c4e0f, + 0x00809043,0x00000000,0xfebc1f00,0x7f04620f, + 0x7cc41f00,0x00000020,0x7cc49f00,0x1000e04f, + 0xff901f00,0x00000060,0xfe981f80,0x00000000, + 0x00809043,0x00000000,0xfea81f00,0xf900620f, + 0x7cc41f00,0x00000020,0x00c09f00,0x1000c04f, + 0xfe0c1f00,0x80010060,0xff001f80,0x80010000, + 0x00000842,0x00000000,0xfea81f00,0xf900620f, + 0xfecc9f01,0x80000020,0x7fc81f00,0x9000e04f, + 0x7dc89f00,0x1000c86f,0xffe01f80,0x80000000, + 0x00000842,0x00000000,0xfeac1f00,0xf900620f, + 0x7ec81f00,0x9000802f,0xfec49f00,0x9000a040, + 0xfea89f00,0x80000060,0xffe01f80,0x9000a060, + 0x00000842,0xa7c4623b,0xfea41f00,0x80000000, + 0x7ecc1f00,0x9000e02f,0xfe0c1f00,0x000a0040, + 0x7c888081,0x80000000,0xa7c4623b,0x00000000, + 0xfe001f00,0x000a0000,0xfeb81f00,0x7f08622f, + 0xfea49f00,0x80000040,0x048c8081,0xff00420f, + 0x00809043,0xa7c4623b,0xfeb01f00,0x7c04620f, + 0x03600000,0xff00622f,0xfea49f00,0x80000040, + 0xfe081f80,0x000a0060,0x00809043,0x0ccec73c, + 0xfebc1f00,0x7f040200,0xfea09f00,0x90000020, + 0xfe941f00,0x10000040,0xfe081f80,0x30080060, + 0x00809043,0x0ccec73c,0x00041f00,0x20080000, + 0x00a01f00,0x80000020,0x002c1f02,0x1000e04f, + 0x00081f80,0x80010060,0x0ccec73c,0x00000000, + 0xfe201f02,0x1000800f,0xfec81f03,0x80020020, + 0xfe041f00,0x20080040,0xfe881f00,0x00000060, + 0xfecc9f81,0x9000a06f,0xfe0c1f00,0x000a0000, + 0xfe801f00,0x00000020,0xfec01f02,0x80020040, + 0xfe281f02,0x1000c06f,0xfe841f82,0x1000804f, + 0xfe041f00,0x000a0000,0x7fc81f02,0x00000020, + 0xfe8c1f00,0x00000040,0xfecc9f03,0x80020060, + 0xfe881f82,0x1000a00f,0x7cc01f02,0x00000000, + 0xfe8c1f02,0x1000e02f,0xfec49f00,0x80000040, + 0xfe081f00,0x000a0060,0x03c89f80,0x9000e04f, + 0x7ecc9f03,0x00000000,0xfec01f00,0x80000020, + 0x04c81f00,0x80000040,0x7c880f01,0xfe086a6f, + 0x7dac8f81,0x9000800f,0x7da00f00,0xfe04620f, + 0xfec01f00,0x80000020,0x03c01f00,0x80000840, + 0x03ac0f00,0xfe08c66f,0xfebc9f80,0xfd00420f, + 0xe07be53f,0x5c8e5a3f,0xfeb09f00,0xfd00620f, + 0x05e81f00,0x9000f02f,0x7fe48f00,0xfe04624f, + 0x04ec8f00,0xfe08626f,0x03840f81,0x7f08a20f, + 0xe07be53f,0x5c8e5a3f,0x7e0c1f00,0x900ce00f, + 0xfe0c1f00,0x900c802f,0x05cc1f00,0x9000e84f, + 0xfeb89f80,0xfd00626f,0xe07be53f,0x5c8e5a3f, + 0x7cc09f81,0x80000020,0x7fa40f00,0x00280000, + 0xfe848f00,0x00280020,0x7fe80f00,0x00280440, + 0xfd001f80,0x00280060,0x00000080,0x00000000, + 0xfdc01f80,0xf800620f,0x00000243,0x00000000, + 0xfea01f80,0x90000060,0x5555d53f,0x00000000, + 0x02011f80,0x8c110000,0x02448002,0x80020000, + 0xf8402000,0x9006a02f,0x02552081,0x00000040, + 0xfe301f00,0x1000e06f,0xfe081f80,0x1033c02f, + 0xfe4c2081,0x80060040,0xfee88f81,0x0289e32f, + 0x02c59f80,0x80060000,0xfee08f80,0x0285636f, + 0xfecc8f80,0x80000000,0xfe40a081,0x80000060, + 0x00cc9f81,0x9000e04f,0xfe281f00,0x80060000, + 0xf8c01f81,0x9006c02f,0xfee00f81,0xfd80636f, + 0x0000803f,0x00000000,0x7ec49f81,0xf880e34f, + 0xfe381f80,0x00000000,0x7de40f81,0xfe800360, + 0x00011f80,0x8c100000,0xf8001f00,0x900ce00f, + 0x00311f00,0x1000e02f,0x02a41f00,0xf910624f, + 0x02a01f00,0xf910626f,0x00011f80,0x1033e04f, + 0x00000040,0x00000000,0xfecc9f03,0x80020000, + 0xfec81f83,0x80020060,0x7fd49f01,0x00000020, + 0x7fd41f80,0x00000040,0xfe081f00,0x80010000, + 0xfe041f80,0x80010060,0xfee00f01,0x80000000, + 0xfeec0f81,0x80000020,0xfec01f00,0x00280000, + 0xfec49f00,0x00280020,0x7fe00f00,0x00280040, + 0xfd001f80,0x00280060,0x00000080,0x00000000, + 0xfe001f80,0x00350000,0x00ec1f82,0x000c0260, + 0x01011f00,0x800c0000,0x01051f00,0x800c0020, + 0x002c1f00,0x80060040,0xf8008001,0x9006e06f, + 0x01091f80,0x800c0000,0x01c01f00,0x90000000, + 0xfe088001,0xfd80632f,0x01e81f00,0x90000040, + 0x01c49f80,0x90000020,0x0000803f,0x00000000, + 0x7fcc9f80,0xf880630f,0xfe20a081,0x80000000, + 0x01cc1f80,0x90000060,0xc21e82a7,0x62ccc547, + 0x1708607c,0x73ea57a6 +}; +static const u32 cpPixelShaderRegs[] = { + 0x00000106,0x00000002,0x14000003,0x00000000, + 0x00000003,0x00000100,0x00000101,0x00000102, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x0000000f,0x00000001,0x00000010, + 0x00000000 +}; + +ShaderFractalColor * ShaderFractalColor::shaderInstance = NULL; + +ShaderFractalColor::ShaderFractalColor() + : vertexShader(cuAttributeCount) +{ + //! create pixel shader + pixelShader.setProgram(cpPixelShaderProgram, sizeof(cpPixelShaderProgram), cpPixelShaderRegs, sizeof(cpPixelShaderRegs)); + + blurLocation = 0; + colorIntensityLocation = 4; + fadeOutLocation = 8; + fractalLocation = 12; + pixelShader.addUniformVar((GX2UniformVar){ "unf_blur_border", GX2_VAR_TYPE_FLOAT, 1, blurLocation, 0xffffffff }); + pixelShader.addUniformVar((GX2UniformVar){ "unf_color_intensity", GX2_VAR_TYPE_VEC4, 1, colorIntensityLocation, 0xffffffff }); + pixelShader.addUniformVar((GX2UniformVar){ "unf_fade_out_alpha", GX2_VAR_TYPE_VEC4, 1, fadeOutLocation, 0xffffffff }); + pixelShader.addUniformVar((GX2UniformVar){ "unf_fract_alpha", GX2_VAR_TYPE_INT, 1, fractalLocation, 0xffffffff }); + + //! create vertex shader + vertexShader.setProgram(cpVertexShaderProgram, sizeof(cpVertexShaderProgram), cpVertexShaderRegs, sizeof(cpVertexShaderRegs)); + + modelMatrixLocation = 0; + projectionMatrixLocation = 16; + viewMatrixLocation = 32; + vertexShader.addUniformVar((GX2UniformVar){ "modelMatrix", GX2_VAR_TYPE_MAT4, 1, modelMatrixLocation, 0xffffffff }); + vertexShader.addUniformVar((GX2UniformVar){ "projectionMatrix", GX2_VAR_TYPE_MAT4, 1, projectionMatrixLocation, 0xffffffff }); + vertexShader.addUniformVar((GX2UniformVar){ "viewMatrix", GX2_VAR_TYPE_MAT4, 1, viewMatrixLocation, 0xffffffff }); + + positionLocation = 0; + colorLocation = 1; + texCoordLocation = 2; + vertexShader.addAttribVar((GX2AttribVar){ "attr_colors", GX2_VAR_TYPE_VEC4, 0, colorLocation }); + vertexShader.addAttribVar((GX2AttribVar){ "attr_position", GX2_VAR_TYPE_VEC3, 0, positionLocation }); + vertexShader.addAttribVar((GX2AttribVar){ "attr_texture_coord", GX2_VAR_TYPE_VEC2, 0, texCoordLocation }); + + //! setup attribute streams + GX2InitAttribStream(vertexShader.getAttributeBuffer(0), positionLocation, 0, 0, GX2_ATTRIB_FORMAT_32_32_32_FLOAT); + GX2InitAttribStream(vertexShader.getAttributeBuffer(1), texCoordLocation, 1, 0, GX2_ATTRIB_FORMAT_32_32_FLOAT); + GX2InitAttribStream(vertexShader.getAttributeBuffer(2), colorLocation, 2, 0, GX2_ATTRIB_FORMAT_8_8_8_8_UNORM); + + //! create fetch shader + fetchShader = new FetchShader(vertexShader.getAttributeBuffer(), vertexShader.getAttributesCount()); + + //! initialize default quad texture vertexes as those are very commonly used + //! model vertex has to be align and cannot be in unknown regions for GX2 like 0xBCAE1000 + posVtxs = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciPositionVtxsSize); + texCoords = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciTexCoordsVtxsSize); + colorVtxs = (u8*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciColorVtxsSize); + + //! position vertex structure and texture coordinate vertex structure + int i = 0; + posVtxs[i++] = -1.0f; posVtxs[i++] = -1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = 1.0f; posVtxs[i++] = -1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = 1.0f; posVtxs[i++] = 1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = -1.0f; posVtxs[i++] = 1.0f; posVtxs[i++] = 0.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, posVtxs, ciPositionVtxsSize); + + i = 0; + texCoords[i++] = 0.0f; texCoords[i++] = 1.0f; + texCoords[i++] = 1.0f; texCoords[i++] = 1.0f; + texCoords[i++] = 1.0f; texCoords[i++] = 0.0f; + texCoords[i++] = 0.0f; texCoords[i++] = 0.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, texCoords, ciTexCoordsVtxsSize); + + + for(i = 0; i < (int)ciColorVtxsSize; i++) + colorVtxs[i] = 0xff; + + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, colorVtxs, ciColorVtxsSize); +} + +ShaderFractalColor::~ShaderFractalColor() +{ + if(posVtxs) + { + free(posVtxs); + posVtxs = NULL; + } + if(texCoords) + { + free(texCoords); + texCoords = NULL; + } + if(colorVtxs) + { + free(colorVtxs); + colorVtxs = NULL; + } + + delete fetchShader; + fetchShader = NULL; +} diff --git a/src/video/shaders/ShaderFractalColor.h b/src/video/shaders/ShaderFractalColor.h new file mode 100644 index 0000000..d3d8355 --- /dev/null +++ b/src/video/shaders/ShaderFractalColor.h @@ -0,0 +1,124 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 SHADER_FRACTAL_COLOR_H_ +#define SHADER_FRACTAL_COLOR_H_ + +#include "VertexShader.h" +#include "PixelShader.h" +#include "FetchShader.h" + +class ShaderFractalColor : public Shader +{ +private: + ShaderFractalColor(); + virtual ~ShaderFractalColor(); + + static ShaderFractalColor * shaderInstance; + + static const unsigned char cuAttributeCount = 3; + static const u32 ciPositionVtxsSize = 4 * cuVertexAttrSize; + static const u32 ciTexCoordsVtxsSize = 4 * cuTexCoordAttrSize; + static const u32 ciColorVtxsSize = 4 * cuColorAttrSize; + + FetchShader *fetchShader; + VertexShader vertexShader; + PixelShader pixelShader; + + f32 *posVtxs; + f32 *texCoords; + u8 *colorVtxs; + + u32 modelMatrixLocation; + u32 viewMatrixLocation; + u32 projectionMatrixLocation; + u32 positionLocation; + u32 colorLocation; + u32 texCoordLocation; + + u32 blurLocation; + u32 colorIntensityLocation; + u32 fadeOutLocation; + u32 fractalLocation; +public: + static ShaderFractalColor *instance() { + if(!shaderInstance) { + shaderInstance = new ShaderFractalColor(); + } + return shaderInstance; + } + static void destroyInstance() { + if(shaderInstance) { + delete shaderInstance; + shaderInstance = NULL; + } + } + + void setShaders(void) const + { + fetchShader->setShader(); + vertexShader.setShader(); + pixelShader.setShader(); + } + + void setAttributeBuffer(const u32 & vtxCount = 0, const f32 * posVtxs_in = NULL, const f32 * texCoords_in = NULL, const u8 * colorVtxs_in = NULL) const + { + if(posVtxs_in && texCoords_in && vtxCount) + { + VertexShader::setAttributeBuffer(0, vtxCount * cuVertexAttrSize, cuVertexAttrSize, posVtxs_in); + VertexShader::setAttributeBuffer(1, vtxCount * cuTexCoordAttrSize, cuTexCoordAttrSize, texCoords_in); + VertexShader::setAttributeBuffer(2, vtxCount * cuColorAttrSize, cuColorAttrSize, colorVtxs_in); + } + else { + //! use default quad vertex and texture coordinates if nothing is passed + VertexShader::setAttributeBuffer(0, ciPositionVtxsSize, cuVertexAttrSize, posVtxs); + VertexShader::setAttributeBuffer(1, ciTexCoordsVtxsSize, cuTexCoordAttrSize, texCoords); + VertexShader::setAttributeBuffer(2, ciColorVtxsSize, cuColorAttrSize, colorVtxs); + } + } + + void setProjectionMtx(const glm::mat4 & mtx) + { + VertexShader::setUniformReg(projectionMatrixLocation, 16, &mtx[0][0]); + } + void setViewMtx(const glm::mat4 & mtx) + { + VertexShader::setUniformReg(viewMatrixLocation, 16, &mtx[0][0]); + } + void setModelViewMtx(const glm::mat4 & mtx) + { + VertexShader::setUniformReg(modelMatrixLocation, 16, &mtx[0][0]); + } + + void setBlurBorder(const float & blurBorderSize) + { + PixelShader::setUniformReg(blurLocation, 4, &blurBorderSize); + } + void setColorIntensity(const glm::vec4 & vec) + { + PixelShader::setUniformReg(colorIntensityLocation, 4, &vec[0]); + } + void setAlphaFadeOut(const glm::vec4 & vec) + { + PixelShader::setUniformReg(fadeOutLocation, 4, &vec[0]); + } + void setFractalColor(const int & fractalColorEnable) + { + PixelShader::setUniformReg(fractalLocation, 4, &fractalColorEnable); + } +}; + +#endif // SHADER_FRACTAL_COLOR_H_ diff --git a/src/video/shaders/Texture2DShader.cpp b/src/video/shaders/Texture2DShader.cpp new file mode 100644 index 0000000..ad7ac52 --- /dev/null +++ b/src/video/shaders/Texture2DShader.cpp @@ -0,0 +1,271 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 . + ****************************************************************************/ +#include +#include +#include "Texture2DShader.h" + +static const u32 cpVertexShaderProgram[] = +{ + 0x00000000,0x00008009,0x20000000,0x000080a0, + 0x3c200100,0x88060094,0x00400000,0x88042014, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x02290001,0x80000000,0x02041f00,0x900c0020, + 0x00a11f00,0xfc00624f,0xfd041f00,0x900c4060, + 0x02001f80,0x900c0000,0x83f9223e,0x0000803f, + 0xfe081f00,0x00080020,0xfe202081,0x10004040, + 0xfea49f80,0xfd00620f,0xdb0f49c0,0xdb0fc940, + 0xfea01f80,0x9000e06f,0x83f9223e,0x00000000, + 0xfe0c1f80,0x00370000,0xffa01f00,0x80000040, + 0xff101f00,0x800c0060,0x7f0c1f80,0x80370040, + 0x0000103f,0x00000000,0xffa01f00,0x80000000, + 0xff001f00,0x800c0020,0x02c51f01,0x80000040, + 0xfeac9f80,0x80000060,0x0000103f,0x398ee33f, + 0xfea01f00,0x80000000,0x02c19f01,0x9000e02f, + 0x01c41f01,0x9000e04f,0x02c59f80,0x80000060, + 0x398ee33f,0x00000000,0x01c49f01,0x80000020, + 0x02c11f80,0x80000040,0x01e08f00,0xfe04624f, + 0x01c01f81,0x7f08626f,0xfe2c2000,0x10004000, + 0xfe28a080,0x10004020,0xeb825790,0xb6f711be, + 0x7c0e2df2,0x81173cfa +}; + +static const u32 cpVertexShaderRegs[] = { + 0x00000103,0x00000000,0x00000000,0x00000001, + 0xffffff00,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0x00000000,0xfffffffc, + 0x00000002,0x00000000,0x00000001,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x00000000,0x0000000e,0x00000010 +}; + +static const u32 cPixelShaderProgram[] = +{ + 0x20000000,0x00000ca4,0x0b000000,0x00000085, + 0x24000000,0x000050a0,0xb0000000,0x000cc080, + 0x39000000,0x00005ca0,0xb8000000,0x000cc080, + 0x51000000,0x000078a0,0xc0000000,0x000cc080, + 0x70000000,0x000064a0,0xc8000000,0x0008c080, + 0x8a000000,0x00005ca0,0x0e000000,0x01008086, + 0xce000000,0x0000c080,0xa2000000,0x00000ca8, + 0x00800000,0x88062094,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00051f00,0x80060000,0x00011f80,0x80060040, + 0xfec81f80,0xfb802320,0x01041f80,0x8c220000, + 0x00a41f00,0xfc10620f,0x010d1f00,0x900c0021, + 0x00091f00,0x80060040,0x00a01f80,0xfc10626f, + 0x00000040,0x00000000,0xfe080000,0xfe8cc300, + 0xfe088080,0xfe80c320,0x00a11f00,0xfe000200, + 0x00a51f00,0xfe040220,0x00a19f00,0xfe000240, + 0x00a59f00,0xfe040260,0x00a11f81,0xfe002600, + 0x4260e5bc,0xa69bc4bc,0x0ad7a3bc,0x00000000, + 0x00a11f00,0x06004200,0x00a59f00,0x06042220, + 0x00a51f00,0x06044240,0x00a11f01,0x06008260, + 0x00a51f81,0x06048620,0x6f1283bc,0x0ad7a3bc, + 0xa69b44bc,0x00000000,0x00a41f00,0x80000000, + 0x00a01f00,0x80000020,0x00ac1f00,0x80000040, + 0x00a81f00,0x80000060,0x00a19f80,0x06000600, + 0xcac3123c,0x6f1203bc,0x03a41f00,0xfe00620f, + 0x03a01f00,0xfe04622f,0x03ac1f00,0xfe08624f, + 0x03a81f00,0xfe0c626f,0x00a59f80,0x06040620, + 0xcc28913b,0x6f1203bc,0x01a41f00,0xfe00620f, + 0x01a01f00,0xfe04622f,0x01ac1f00,0xfe08624f, + 0x01a81f00,0xfe0c626f,0x00a19f80,0x06002600, + 0xe8eab03c,0x6f1283bb,0x02ac1f00,0xfe084200, + 0x02a81f00,0xfe0c4220,0x02a41f00,0xfe004240, + 0x02a01f00,0xfe044260,0x00a59f80,0x06042620, + 0x92bb353d,0x6f1283bb,0x04a81f00,0x0204620f, + 0x04ac1f00,0x0200662f,0x04a41f00,0x0208624f, + 0x04a01f00,0x020c626f,0x00a19f80,0x06004600, + 0xc4139f3d,0x6f12833b,0x00a41f00,0xfe08620f, + 0x00a01f00,0xfe0c622f,0x00ac1f00,0xfe04624f, + 0x00a81f00,0xfe00626f,0x00a59f80,0x06044620, + 0xb950ed3d,0x6f12833b,0x01a41f00,0xfe00620f, + 0x01a01f00,0xfe04622f,0x01ac1f00,0xfe08624f, + 0x01a81f00,0xfe0c626f,0x00a19f80,0x06002600, + 0xecd7163e,0x6f12033c,0x03a41f00,0xfe000200, + 0x03a01f00,0xfe040220,0x03ac1f00,0xfe082240, + 0x03a81f00,0xfe0c2260,0x00a59f80,0x06042620, + 0x2168233e,0x6f12033c,0x00a11f00,0x06006200, + 0x00a51f00,0x06046220,0x00a19f00,0x06006240, + 0x00a59f00,0x06046260,0x00a11f81,0x0600e600, + 0xa69b443c,0x6f12833c,0x0ad7a33c,0x00000000, + 0x02ac1f00,0x0108620f,0x02a81f00,0x010c622f, + 0x02a41f00,0x0000624f,0x02a01f00,0x0004666f, + 0x00a59f80,0x0604e620,0xecd7163e,0x0ad7a33c, + 0x04a81f00,0xfe04620f,0x04ac1f00,0xfe00622f, + 0x04a41f00,0xfe08624f,0x04a01f00,0xfe0c626f, + 0x00a19f80,0x06008600,0xb950ed3d,0xa69bc43c, + 0x05a41f00,0xfe08620f,0x05a01f00,0xfe0c622f, + 0x05ac1f00,0xfe04624f,0x05a81f00,0xfe00626f, + 0x00a59f80,0x06048620,0xc4139f3d,0xa69bc43c, + 0x03a41f00,0xfe00a200,0x03a01f00,0xfe04a220, + 0x03ac1f00,0xfe086240,0x03a81f00,0xfe0c6260, + 0x00a19f80,0x06006600,0x92bb353d,0x4260e53c, + 0x00a51f80,0x06046220,0x4260e53c,0x00000000, + 0x07ac1f00,0x0308620f,0x07a81f00,0x030c622f, + 0x07a41f00,0x0500624f,0x07a01f80,0x0504626f, + 0xe8eab03c,0x00000000,0x04a81f00,0xfe04620f, + 0x04ac1f00,0xfe00622f,0x04a41f00,0xfe08624f, + 0x04a01f80,0xfe0c626f,0xcac3123c,0x00000000, + 0x06a41f00,0xfe08620f,0x06a01f00,0xfe0c622f, + 0x06ac1f00,0xfe04624f,0x06a81f80,0xfe00626f, + 0xcc28913b,0x00000000,0xfe20a000,0x9000e00f, + 0xfe242000,0x9000e02f,0xfe28a001,0x9000e04f, + 0xfe2c2081,0x9000e06f,0xfe28a081,0x80060020, + 0xfee48f00,0x7f842300,0xfee40f00,0x7f802320, + 0xfee48f01,0x7f8c2340,0xfee40f81,0x08842b60, + 0x00202000,0x90002000,0x0024a000,0x90002020, + 0x00282001,0x90002040,0x002ca081,0x90002060, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x10000000,0x03100df0,0x00008010,0xecdfea0d, + 0x10000000,0x00100df0,0x0000a051,0xecdfea0d, + 0x10000100,0x01100df0,0x00008010,0xecdfea0d, + 0x10000200,0x02100df0,0x00000011,0xecdfea0d, + 0x10000400,0x04100df0,0x0000b070,0xecdfea0d, + 0x10000000,0x00100df0,0x00008010,0xecdfea0d, + 0x10000100,0x01100df0,0x00008010,0xecdfea0d, + 0x10000600,0x03100df0,0x00008010,0xecdfea0d, + 0x10000200,0x02100df0,0x00008010,0xecdfea0d, + 0x10000100,0x04100df0,0x00008010,0xecdfea0d, + 0x10000300,0x05100df0,0x00008010,0xecdfea0d, + 0x10000300,0x03100df0,0x0000a051,0xecdfea0d, + 0x10000700,0x07100df0,0x00008010,0xecdfea0d, + 0x10000400,0x04100df0,0x00008010,0xecdfea0d, + 0x10000300,0x06100df0,0x00008010,0xecdfea0d, + 0x10000000,0x00100df0,0x00008010,0xecdfea0d, + 0xc8581837,0x22740275,0x281eddcc,0xfa8b9b65 +}; +static const u32 cPixelShaderRegs[] = { + 0x00000109,0x00000002,0x14000001,0x00000000, + 0x00000001,0x00000100,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x0000000f,0x00000001,0x00000010, + 0x00000000 +}; + +Texture2DShader * Texture2DShader::shaderInstance = NULL; + +Texture2DShader::Texture2DShader() + : vertexShader(cuAttributeCount) +{ + //! create pixel shader + pixelShader.setProgram(cPixelShaderProgram, sizeof(cPixelShaderProgram), cPixelShaderRegs, sizeof(cPixelShaderRegs)); + + blurLocation = 0; + colorIntensityLocation = 4; + pixelShader.addUniformVar((GX2UniformVar){ "unf_blur_texture_direction", GX2_VAR_TYPE_VEC3, 1, blurLocation, 0xffffffff }); + pixelShader.addUniformVar((GX2UniformVar){ "unf_color_intensity", GX2_VAR_TYPE_VEC4, 1, colorIntensityLocation, 0xffffffff }); + + samplerLocation = 0; + pixelShader.addSamplerVar((GX2SamplerVar){ "sampl_texture", GX2_SAMPLER_TYPE_2D, samplerLocation }); + + //! create vertex shader + vertexShader.setProgram(cpVertexShaderProgram, sizeof(cpVertexShaderProgram), cpVertexShaderRegs, sizeof(cpVertexShaderRegs)); + + angleLocation = 0; + offsetLocation = 4; + scaleLocation = 8; + vertexShader.addUniformVar((GX2UniformVar){ "unf_angle", GX2_VAR_TYPE_FLOAT, 1, angleLocation, 0xffffffff }); + vertexShader.addUniformVar((GX2UniformVar){ "unf_offset", GX2_VAR_TYPE_VEC3, 1, offsetLocation, 0xffffffff }); + vertexShader.addUniformVar((GX2UniformVar){ "unf_scale", GX2_VAR_TYPE_VEC3, 1, scaleLocation, 0xffffffff }); + + positionLocation = 0; + texCoordLocation = 1; + vertexShader.addAttribVar((GX2AttribVar){ "attr_position", GX2_VAR_TYPE_VEC3, 0, positionLocation }); + vertexShader.addAttribVar((GX2AttribVar){ "attr_texture_coord", GX2_VAR_TYPE_VEC2, 0, texCoordLocation }); + + //! setup attribute streams + GX2InitAttribStream(vertexShader.getAttributeBuffer(0), positionLocation, 0, 0, GX2_ATTRIB_FORMAT_32_32_32_FLOAT); + GX2InitAttribStream(vertexShader.getAttributeBuffer(1), texCoordLocation, 1, 0, GX2_ATTRIB_FORMAT_32_32_FLOAT); + + //! create fetch shader + fetchShader = new FetchShader(vertexShader.getAttributeBuffer(), vertexShader.getAttributesCount()); + + //! model vertex has to be align and cannot be in unknown regions for GX2 like 0xBCAE1000 + posVtxs = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciPositionVtxsSize); + texCoords = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciTexCoordsVtxsSize); + + //! defaults for normal square + //! position vertex structure and texture coordinate vertex structure + int i = 0; + posVtxs[i++] = -1.0f; posVtxs[i++] = -1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = 1.0f; posVtxs[i++] = -1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = 1.0f; posVtxs[i++] = 1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = -1.0f; posVtxs[i++] = 1.0f; posVtxs[i++] = 0.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, posVtxs, ciPositionVtxsSize); + + i = 0; + texCoords[i++] = 0.0f; texCoords[i++] = 1.0f; + texCoords[i++] = 1.0f; texCoords[i++] = 1.0f; + texCoords[i++] = 1.0f; texCoords[i++] = 0.0f; + texCoords[i++] = 0.0f; texCoords[i++] = 0.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, texCoords, ciTexCoordsVtxsSize); +} + +Texture2DShader::~Texture2DShader() +{ + if(posVtxs) + { + free(posVtxs); + posVtxs = NULL; + } + if(texCoords) + { + free(texCoords); + texCoords = NULL; + } + + delete fetchShader; + fetchShader = NULL; +} diff --git a/src/video/shaders/Texture2DShader.h b/src/video/shaders/Texture2DShader.h new file mode 100644 index 0000000..cddeee0 --- /dev/null +++ b/src/video/shaders/Texture2DShader.h @@ -0,0 +1,112 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 __TEXTURE_2D_SHADER_H_ +#define __TEXTURE_2D_SHADER_H_ + +#include "VertexShader.h" +#include "PixelShader.h" +#include "FetchShader.h" + +class Texture2DShader : public Shader +{ +private: + Texture2DShader(); + virtual ~Texture2DShader(); + + static const u32 cuAttributeCount = 2; + static const u32 ciPositionVtxsSize = 4 * cuVertexAttrSize; + static const u32 ciTexCoordsVtxsSize = 4 * cuTexCoordAttrSize; + + static Texture2DShader *shaderInstance; + + FetchShader *fetchShader; + VertexShader vertexShader; + PixelShader pixelShader; + + f32 *posVtxs; + f32 *texCoords; + + u32 angleLocation; + u32 offsetLocation; + u32 scaleLocation; + u32 colorIntensityLocation; + u32 blurLocation; + u32 samplerLocation; + u32 positionLocation; + u32 texCoordLocation; +public: + static Texture2DShader *instance() { + if(!shaderInstance) { + shaderInstance = new Texture2DShader(); + } + return shaderInstance; + } + static void destroyInstance() { + if(shaderInstance) { + delete shaderInstance; + shaderInstance = NULL; + } + } + + void setShaders(void) const + { + fetchShader->setShader(); + vertexShader.setShader(); + pixelShader.setShader(); + } + + void setAttributeBuffer(const f32 * texCoords_in = NULL, const f32 * posVtxs_in = NULL, const u32 & vtxCount = 0) const + { + if(posVtxs_in && texCoords_in && vtxCount) + { + VertexShader::setAttributeBuffer(0, vtxCount * cuVertexAttrSize, cuVertexAttrSize, posVtxs_in); + VertexShader::setAttributeBuffer(1, vtxCount * cuTexCoordAttrSize, cuTexCoordAttrSize, texCoords_in); + } + else { + VertexShader::setAttributeBuffer(0, ciPositionVtxsSize, cuVertexAttrSize, posVtxs); + VertexShader::setAttributeBuffer(1, ciTexCoordsVtxsSize, cuTexCoordAttrSize, texCoords); + } + } + + void setAngle(const float & val) + { + VertexShader::setUniformReg(angleLocation, 4, &val); + } + void setOffset(const glm::vec3 & vec) + { + VertexShader::setUniformReg(offsetLocation, 4, &vec[0]); + } + void setScale(const glm::vec3 & vec) + { + VertexShader::setUniformReg(scaleLocation, 4, &vec[0]); + } + void setColorIntensity(const glm::vec4 & vec) + { + PixelShader::setUniformReg(colorIntensityLocation, 4, &vec[0]); + } + void setBlurring(const glm::vec3 & vec) + { + PixelShader::setUniformReg(blurLocation, 4, &vec[0]); + } + + void setTextureAndSampler(const GX2Texture *texture, const GX2Sampler *sampler) const { + GX2SetPixelTexture(texture, samplerLocation); + GX2SetPixelSampler(sampler, samplerLocation); + } +}; + +#endif // __TEXTURE_2D_SHADER_H_ diff --git a/src/video/shaders/VertexShader.h b/src/video/shaders/VertexShader.h new file mode 100644 index 0000000..18dc0fe --- /dev/null +++ b/src/video/shaders/VertexShader.h @@ -0,0 +1,178 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * 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 VERTEX_SHADER_H +#define VERTEX_SHADER_H + +#include +#include "Shader.h" + +class VertexShader : public Shader +{ +public: + VertexShader(u32 numAttr) + : attributesCount( numAttr ) + , attributes( new GX2AttribStream[attributesCount] ) + , vertexShader( (GX2VertexShader*) memalign(0x40, sizeof(GX2VertexShader)) ) + { + if(vertexShader) + { + memset(vertexShader, 0, sizeof(GX2VertexShader)); + vertexShader->shader_mode = GX2_SHADER_MODE_UNIFORM_REGISTER; + } + } + + virtual ~VertexShader() { + delete [] attributes; + + if(vertexShader) + { + if(vertexShader->shader_data) + free(vertexShader->shader_data); + + for(u32 i = 0; i < vertexShader->uniform_blocks_count; i++) + free((void*)vertexShader->uniform_block[i].name); + + if(vertexShader->uniform_block) + free((void*)vertexShader->uniform_block); + + for(u32 i = 0; i < vertexShader->uniform_vars_count; i++) + free((void*)vertexShader->uniform_var[i].name); + + if(vertexShader->uniform_var) + free((void*)vertexShader->uniform_var); + + if(vertexShader->initial_value) + free((void*)vertexShader->initial_value); + + for(u32 i = 0; i < vertexShader->sampler_vars_count; i++) + free((void*)vertexShader->sampler_var[i].name); + + if(vertexShader->sampler_var) + free((void*)vertexShader->sampler_var); + + for(u32 i = 0; i < vertexShader->attribute_vars_count; i++) + free((void*)vertexShader->attribute_var[i].name); + + if(vertexShader->attribute_var) + free((void*)vertexShader->attribute_var); + + if(vertexShader->loops_data) + free((void*)vertexShader->loops_data); + + free(vertexShader); + } + } + + void setProgram(const u32 * program, const u32 & programSize, const u32 * regs, const u32 & regsSize) + { + if(!vertexShader) + return; + + //! this must be moved into an area where the graphic engine has access to and must be aligned to 0x100 + vertexShader->shader_size = programSize; + vertexShader->shader_data = memalign(GX2_SHADER_ALIGNMENT, vertexShader->shader_size); + if(vertexShader->shader_data) + { + memcpy(vertexShader->shader_data, program, vertexShader->shader_size); + GX2Invalidate(GX2_INVALIDATE_CPU_SHADER, vertexShader->shader_data, vertexShader->shader_size); + } + + memcpy(vertexShader->regs, regs, regsSize); + } + + void addUniformVar(const GX2UniformVar & var) + { + if(!vertexShader) + return; + + u32 idx = vertexShader->uniform_vars_count; + + GX2UniformVar* newVar = (GX2UniformVar*) malloc((vertexShader->uniform_vars_count + 1) * sizeof(GX2UniformVar)); + if(newVar) + { + if(vertexShader->uniform_vars_count > 0) + { + memcpy(newVar, vertexShader->uniform_var, vertexShader->uniform_vars_count * sizeof(GX2UniformVar)); + free(vertexShader->uniform_var); + } + vertexShader->uniform_var = newVar; + + memcpy(vertexShader->uniform_var + idx, &var, sizeof(GX2UniformVar)); + vertexShader->uniform_var[idx].name = (char*) malloc(strlen(var.name) + 1); + strcpy((char*)vertexShader->uniform_var[idx].name, var.name); + + vertexShader->uniform_vars_count++; + } + } + + void addAttribVar(const GX2AttribVar & var) + { + if(!vertexShader) + return; + + u32 idx = vertexShader->attribute_vars_count; + + GX2AttribVar* newVar = (GX2AttribVar*) malloc((vertexShader->attribute_vars_count + 1) * sizeof(GX2AttribVar)); + if(newVar) + { + if(vertexShader->attribute_vars_count > 0) + { + memcpy(newVar, vertexShader->attribute_var, vertexShader->attribute_vars_count * sizeof(GX2AttribVar)); + free(vertexShader->attribute_var); + } + vertexShader->attribute_var = newVar; + + memcpy(vertexShader->attribute_var + idx, &var, sizeof(GX2AttribVar)); + vertexShader->attribute_var[idx].name = (char*) malloc(strlen(var.name) + 1); + strcpy((char*)vertexShader->attribute_var[idx].name, var.name); + + vertexShader->attribute_vars_count++; + } + } + + static inline void setAttributeBuffer(u32 bufferIdx, u32 bufferSize, u32 stride, const void * buffer) { + GX2SetAttribBuffer(bufferIdx, bufferSize, stride, buffer); + } + + GX2VertexShader *getVertexShader() const { + return vertexShader; + } + + void setShader(void) const { + GX2SetVertexShader(vertexShader); + } + + GX2AttribStream * getAttributeBuffer(u32 idx = 0) const { + if(idx >= attributesCount) { + return NULL; + } + return &attributes[idx]; + } + u32 getAttributesCount() const { + return attributesCount; + } + + static void setUniformReg(u32 location, u32 size, const void * reg) { + GX2SetVertexUniformReg(location, size, reg); + } +protected: + u32 attributesCount; + GX2AttribStream *attributes; + GX2VertexShader *vertexShader; +}; + +#endif // VERTEX_SHADER_H