[
  {
    "path": ".github/workflows/Linux-build-archive.yml",
    "content": "name: Linux archive build\n\non:\n  push:\n    branches: [ main ]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - name: Get repo archive\n      run: |\n        wget https://github.com/ABelliqueux/nolibgs_hello_worlds/releases/download/v0.11/nolibgs_hello_worlds.zip\n        7z x nolibgs_hello_worlds.zip -o${{github.workspace}}\n    - name: Install mipsel toolchain\n      run: |\n        sudo apt-get update\n        sudo apt-get install gcc-mipsel-linux-gnu g++-mipsel-linux-gnu binutils-mipsel-linux-gnu p7zip  cmake build-essential libtinyxml2-10 libtinyxml2-dev\n    - name: Clone mkpsxiso\n      uses: GuillaumeFalourd/clone-github-repo-action@v1\n      with:\n        owner: 'Lameguy64'\n        repository: 'mkpsxiso'\n    - name: Build mkpsxiso\n      run: |\n        sudo chown -R runner:docker ${{github.workspace}}/mkpsxiso/\n        mkdir ${{github.workspace}}/mkpsxiso/build\n        cmake -DCMAKE_BUILD_TYPE=Release -S ${{github.workspace}}/mkpsxiso/ -B ${{github.workspace}}/mkpsxiso/build\n        cmake --build ${{github.workspace}}/mkpsxiso/build\n        echo \"${{github.workspace}}/mkpsxiso/build\" >> $GITHUB_PATH\n    - name: Get converted libs\n      run: |\n        wget http://psx.arthus.net/sdk/Psy-Q/psyq-4.7-converted-full.7z\n        7z x psyq-4.7-converted-full.7z -o${{github.workspace}}/nolibgs_hello_worlds/psyq\n    - name: Make all\n      run: |\n        cd ${{github.workspace}}/nolibgs_hello_worlds\n        make all\n"
  },
  {
    "path": ".github/workflows/linux-build.yml",
    "content": "name: Linux build\n\non:\n  push:\n    branches: [ main ]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v2\n    - name: Install mipsel toolchain\n      run: |\n        sudo apt-get update\n        sudo apt-get install gcc-mipsel-linux-gnu g++-mipsel-linux-gnu binutils-mipsel-linux-gnu p7zip  cmake build-essential libtinyxml2-10 libtinyxml2-dev\n    - name: Fetch submodules\n      run: git submodule update --init --recursive\n    - name: Clone mkpsxiso\n      uses: GuillaumeFalourd/clone-github-repo-action@v1\n      with:\n        owner: 'Lameguy64'\n        repository: 'mkpsxiso'\n    - name: Build mkpsxiso\n      run: |\n        sudo chown -R runner:docker ${{github.workspace}}/mkpsxiso/\n        git -C ${{github.workspace}}/mkpsxiso/ submodule update --init --recursive\n        mkdir ${{github.workspace}}/mkpsxiso/build\n        cmake -DCMAKE_BUILD_TYPE=Release -S ${{github.workspace}}/mkpsxiso/ -B ${{github.workspace}}/mkpsxiso/build\n        cmake --build ${{github.workspace}}/mkpsxiso/build\n        echo \"${{github.workspace}}/mkpsxiso/build\" >> $GITHUB_PATH\n    - name: Get converted libs\n      run: |\n        wget http://psx.arthus.net/sdk/Psy-Q/psyq-4.7-converted-full.7z\n        7z x psyq-4.7-converted-full.7z -o./psyq\n    - name: Make all\n      run: make all\n"
  },
  {
    "path": ".github/workflows/macos-build.yml",
    "content": "name: macOS build\n\non:\n  push:\n    branches: [ main ]\n\njobs:\n  build:\n    runs-on: macOS-latest\n\n    steps:\n      - uses: actions/checkout@v2\n      - name: Fetch submodules\n        run: git submodule update --init --recursive \n      - name: Install tinyxml2\n        run : |\n          brew update --verbose\n          brew install tinyxml2\n      - name: Install mipsel binutils\n        run: |\n          wget https://raw.githubusercontent.com/grumpycoders/pcsx-redux/a899d09d81cf602ef48e51cda09a6c62638fa5c5/tools/macos-mips/mipsel-none-elf-binutils.rb -O ${{github.workspace}}/mipsel-none-elf-binutils.rb\n          brew install ${{github.workspace}}/mipsel-none-elf-binutils.rb --debug\n      - name: Upload mipsel-binutils\n        uses: actions/upload-artifact@v2\n        with: \n          name: mipsel-none-elf-binutils-macos\n          path: /usr/local/Cellar/mipsel-none-elf-binutils/\n      - name: Install mipsel gcc\n        run: |\n          wget https://raw.githubusercontent.com/grumpycoders/pcsx-redux/a899d09d81cf602ef48e51cda09a6c62638fa5c5/tools/macos-mips/mipsel-none-elf-gcc.rb -O ${{github.workspace}}/mipsel-none-elf-gcc.rb\n          brew install ${{github.workspace}}/mipsel-none-elf-gcc.rb --debug\n      - name: Upload mipsel-gcc\n        uses: actions/upload-artifact@v2\n        with: \n          name: mipsel-none-elf-gcc-macos\n          path: /usr/local/Cellar/mipsel-none-elf-gcc/\n      - name: Build mkpsxiso\n        run: |\n          wget https://github.com/Lameguy64/mkpsxiso/archive/refs/heads/master.zip -O ${{github.workspace}}/master.zip\n          7z x ${{github.workspace}}/master.zip -o${{github.workspace}}\n          awk 'n>=4 { print a[n%7] } { a[n%7]=$0; n=n+1 }' ${{github.workspace}}/mkpsxiso-master/CMakeLists.txt >> ${{github.workspace}}/mkpsxiso-master/CMakeLists.txt.tmp\n          mv -f ${{github.workspace}}/mkpsxiso-master/CMakeLists.txt.tmp ${{github.workspace}}/mkpsxiso-master/CMakeLists.txt\n          mkdir ${{github.workspace}}/mkpsxiso-master/build\n          cmake -DCMAKE_BUILD_TYPE=Release -S ${{github.workspace}}/mkpsxiso-master -B ${{github.workspace}}/mkpsxiso-master/build\n          cmake --build ${{github.workspace}}/mkpsxiso-master/build\n          echo \"${{github.workspace}}/mkpsxiso-master/build\" >> $GITHUB_PATH\n      - name: Upload mkpsxiso-macos\n        uses: actions/upload-artifact@v2\n        with: \n          name: mkpsxiso-macos\n          path: ${{github.workspace}}/mkpsxiso-master/build\n      - name: Get converted libs\n        run: |\n          wget http://psx.arthus.net/sdk/Psy-Q/psyq-4.7-converted-full.7z\n          7z x psyq-4.7-converted-full.7z -o./psyq\n      - name: Make all\n        run: make all\n"
  },
  {
    "path": ".github/workflows/windows-build.yml",
    "content": "name: Windows build\non:\n  push:\n    branches: [ main ]\n\njobs:\n  build:\n\n    runs-on: windows-latest\n\n    steps:\n    - uses: actions/checkout@v2\n    - name: Fetch submodules\n      run: git submodule update --init --recursive\n    - name: Get prebuilt stuff\n      run: |\n        C:\\msys64\\usr\\bin\\wget.exe http://static.grumpycoder.net/pixel/mips/g++-mipsel-none-elf-11.2.0.zip\n        C:\\msys64\\usr\\bin\\wget.exe http://lameguy64.github.io/mkpsxiso/mkpsxiso-1.20.zip\n        C:\\msys64\\usr\\bin\\wget.exe http://psx.arthus.net/sdk/Psy-Q/psyq-4.7-converted-full.7z\n        7z.exe x g++-mipsel-none-elf-11.2.0.zip -o\"$GITHUB_WORKSPACE\\mipsel\"\n        7z.exe x mkpsxiso-1.20.zip -o\"$GITHUB_WORKSPACE\\mkpsxiso\"\n        7z.exe x psyq-4.7-converted-full.7z -o\"D:\\a\\nolibgs_hello_worlds\\nolibgs_hello_worlds\\psyq\"\n        echo \"$GITHUB_WORKSPACE/mipsel/bin\" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append\n        echo \"$GITHUB_WORKSPACE/mkpsxiso\" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append\n        echo $GITHUB_PATH\n    - name: Make all\n      run: make all\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"thirdparty/nugget\"]\n\tpath = thirdparty/nugget\n\turl = https://github.com/pcsx-redux/nugget.git\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<https://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<https://www.gnu.org/licenses/why-not-lgpl.html>.\n"
  },
  {
    "path": "Makefile",
    "content": "hello_2pads:\n\t$(MAKE) -C hello_2pads\nhello_bs:\n\t$(MAKE) -C hello_bs\nhello_cd:\n\t$(MAKE) -C hello_cd\nhello_cdda:\n\t$(MAKE) -C hello_cdda\nhello_cd_exec:\n\t$(MAKE) -C hello_cd_exec\nhello_cube:\n\t$(MAKE) -C hello_cube\nhello_cubetex:\n\t$(MAKE) -C hello_cubetex\nhello_cubetex_stp:\n\t$(MAKE) -C hello_cubetex_stp\nhello_font:\n\t$(MAKE) -C hello_font\nhello_fx:\n\t$(MAKE) -C hello_fx\nhello_gte_opti:\n\t$(MAKE) -C hello_gte_opti\nhello_light:\n\t$(MAKE) -C hello_light\nhello_mod:\n\t$(MAKE) -C hello_mod\nhello_multi_vag:\n\t$(MAKE) -C hello_multi_vag\nhello_multi_xa:\n\t$(MAKE) -C hello_multi_xa\nhello_ovl_exec:\n\t$(MAKE) -C hello_ovl_exec\nhello_pad:\n\t$(MAKE) -C hello_pad\nhello_poly:\n\t$(MAKE) -C hello_poly\nhello_poly_ft:\n\t$(MAKE) -C hello_poly_ft\nhello_poly_fun:\n\t$(MAKE) -C hello_poly_fun\nhello_poly_gt:\n\t$(MAKE) -C hello_poly_gt\nhello_poly_gt_tw:\n\t$(MAKE) -C hello_poly_gt_tw\nhello_poly_inline:\n\t$(MAKE) -C hello_poly_inline\nhello_poly_stp:\n\t$(MAKE) -C hello_poly_stp\nhello_sio:\n\t$(MAKE) -C hello_sio\nhello_sprt:\n\t$(MAKE) -C hello_sprt\nhello_spu_readback:\n\t$(MAKE) -C hello_spu_readback\nhello_str:\n\t$(MAKE) -C hello_str\nhello_strplay:\n\t$(MAKE) -C hello_strplay\nhello_tile:\n\t$(MAKE) -C hello_tile\nhello_vag:\n\t$(MAKE) -C hello_vag\nhello_world:\n\t$(MAKE) -C hello_world\nhello_xa:\n\t$(MAKE) -C hello_xa\nhello_xa_streaming:\n\t$(MAKE) -C hello_xa_streaming\n\nclean:\n\t$(MAKE) -C hello_2pads clean\n\t$(MAKE) -C hello_cube clean\n\t$(MAKE) -C hello_cubetex clean\n\t$(MAKE) -C hello_cubetex_stp clean\n\t$(MAKE) -C hello_poly_fun clean\n\t$(MAKE) -C hello_gte_opti clean\n\t$(MAKE) -C hello_light clean\n\t$(MAKE) -C hello_mod clean\n\t$(MAKE) -C hello_multi_vag clean\n\t$(MAKE) -C hello_multi_xa clean\n\t$(MAKE) -C hello_ovl_exec cleansub\n\t$(MAKE) -C hello_pad clean\n\t$(MAKE) -C hello_poly clean\n\t$(MAKE) -C hello_poly_ft clean\n\t$(MAKE) -C hello_poly_stp clean\n\t$(MAKE) -C hello_poly_gt clean\n\t$(MAKE) -C hello_poly_gt_tw clean\n\t$(MAKE) -C hello_poly_inline clean\n\t$(MAKE) -C hello_sio clean\n\t$(MAKE) -C hello_sprt clean\n\t$(MAKE) -C hello_spu_readback cleansub\n\t$(MAKE) -C hello_tile clean\n\t$(MAKE) -C hello_vag clean\n\t$(MAKE) -C hello_world clean\n\t$(MAKE) -C hello_cdda cleansub\n\t$(MAKE) -C hello_cd cleansub\n\t$(MAKE) -C hello_xa cleansub\n\t$(MAKE) -C hello_bs cleansub\n\t$(MAKE) -C hello_str cleansub\n\t$(MAKE) -C hello_strplay cleansub\n\nall:\n\t$(MAKE) -C hello_2pads \n\t$(MAKE) -C hello_cube \n\t$(MAKE) -C hello_cubetex \n\t$(MAKE) -C hello_cubetex_stp \n\t$(MAKE) -C hello_poly_fun \n\t$(MAKE) -C hello_gte_opti \n\t$(MAKE) -C hello_light \n\t$(MAKE) -C hello_mod\n\t$(MAKE) -C hello_multi_vag \n\t$(MAKE) -C hello_multi_xa \n\t$(MAKE) -C hello_ovl_exec\n\t$(MAKE) -C hello_pad \n\t$(MAKE) -C hello_poly \n\t$(MAKE) -C hello_poly_ft \n\t$(MAKE) -C hello_poly_gt \n\t$(MAKE) -C hello_poly_gt_tw \n\t$(MAKE) -C hello_poly_inline \n\t$(MAKE) -C hello_sio \n\t$(MAKE) -C hello_sprt \n\t$(MAKE) -C hello_spu_readback\n\t$(MAKE) -C hello_tile \n\t$(MAKE) -C hello_vag \n\t$(MAKE) -C hello_world \n\t$(MAKE) -C hello_cd all\n\t$(MAKE) -C hello_cdda all\n\t$(MAKE) -C hello_xa all\n\t$(MAKE) -C hello_bs all\n\t$(MAKE) -C hello_str all\n\t$(MAKE) -C hello_strplay all\n\t\n# declare phony rules\n.PHONY: hello_2pads hello_bs hello_cd hello_cdda hello_cd_exec hello_cube hello_cubetex hello_cubetex_stp hello_font hello_fx hello_gte_opti hello_light hello_mod hello_multi_vag hello_multi_xa hello_ovl_exec hello_pad hello_poly hello_poly_ft hello_poly_fun hello_poly_gt hello_poly_gt_tw hello_poly_inline hello_poly_stp hello_sio hello_sprt hello_spu_readback hello_str hello_strplay hello_tile hello_vag hello_world hello_xa hello_xa_streaming \\\n\t\tclean all\n"
  },
  {
    "path": "README.md",
    "content": "# Nolibgs Hello Worlds !\n\n<p align=\"center\">\n\n<img height=\"240px\" src=\"http://wiki.arthus.net/assets/cube.gif\" alt=\"3D power !\">\n\n<img height=\"240px\" src=\"http://wiki.arthus.net/assets/polyfun.jpg\" alt=\"3D power !\">\n\n<img height=\"240px\" src=\"http://wiki.arthus.net/assets/hello_gt.jpg\" alt=\"3D power !\">\n\n</p>\n\nSo you want to begin developping on the original PSX but don't know where to start ?  \n\nThis repo is destined to host a bunch of simple examples, each describing how to do one thing.  \n\nThe code here will be using **Nugget + PsyQ**, the \"Official\" Sony SDK but with a modern MIPS toolchain.  \n\nWe will not be using libGS, the Extended Graphics Library for the graphic stuff...  \n\nInstead we'll try to devise methods to reproduce libgs functions. This will not necessarly be more efficient, but we'll learn\na lot more stuff !  \n\n## Installation\n\nWe'll keep things simple for now. If you want to read about more methods to get things up and running, see the wiki's [Installation methods](https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/Installation-methods) section. \n\n### Windows\n\n#### MIPS toolchain setup\n\nYou can setup a pre-built MIPS toolchain by copy-pasting the following into a command prompt:\n```\npowershell -c \"& { iwr https://raw.githubusercontent.com/grumpycoders/pcsx-redux/main/mips.ps1 | iex }\"\n```\nThen, open a new command prompt, and type the following:\n```\nmips install 11.2.0\n```\n\n#### Nugget + PsyQ setup\n1. Download the PsyQ converted libraries here : [http://psx.arthus.net/sdk/Psy-Q/psyq-4.7-converted-full.7z](http://psx.arthus.net/sdk/Psy-Q/psyq-4.7-converted-full.7z)  \n2. Clone the 'nolibgs_hello_worlds' repo with  \n`git clone https://github.com/ABelliqueux/nolibgs_hello_worlds.git --recursive`  \nor download this [repository's release](https://github.com/ABelliqueux/nolibgs_hello_worlds/releases/download/v0.11/nolibgs_hello_worlds.zip) and extract **`nolibgs_hello_worlds.zip`**'s content to `C:\\no_libgs_hello_worlds\\` .\n3. Extract the content of `psyq-4.7-converted-full.7z` in `C:\\no_libgs_hello_worlds\\psyq`. You should now have `C:\\no_libgs_hello_worlds\\psyq\\include` and `C:\\no_libgs_hello_worlds\\psyq\\lib` ;\n```\nno_libgs_hello_worlds\n├── common.mk\n├── hello_world\n|       ├── hello_world.c\n|       ├── Makefile\n├── hello_...\n└── psyq\n    ├── lib\n    |    └── *.a \n    └── include\n         └── *.h  \n```\n4. Test everything is working by [launching a command prompt](https://www.lifewire.com/how-to-open-command-prompt-2618089), change to the `C:\\no_libgs_hello_worlds\\` directory with the following command: `cd C:\\no_libgs_hello_worlds\\`, then type `make` and hit enter.  \nBy default, this should build the `hello_world` example, and you should now have a `hello_world.ps-exe` file in `C:\\no_libgs_hello_worlds\\hello_world`. This a PSX executable that can be run in an emulator like [pcsx-redux](https://github.com/grumpycoders/pcsx-redux/).\n\n### Linux \n\n#### Install your distribution's MIPS toolchain\n\nIn a terminal :\n\nOn Debian derivatives (Ubuntu, Mint...) :\n```bash\nsudo apt-get install make gcc-mipsel-linux-gnu g++-mipsel-linux-gnu binutils-mipsel-linux-gnu\n```\nOn Arch derivatives (Manjaro), the mipsel environment can be installed from [AUR](https://wiki.archlinux.org/index.php/Aur) : [mipsel-linux-gnu-binutils](https://aur.archlinux.org/packages/mipsel-linux-gnu-binutils/) and [mipsel-linux-gnu-gcc](https://aur.archlinux.org/packages/mipsel-linux-gnu-gcc/) using your [AURhelper](https://wiki.archlinux.org/index.php/AUR_helpers) of choice:\n```bash\nyay -S make mipsel-linux-gnu-binutils mipsel-linux-gnu-gcc\n```\n\n#### Nugget + PsyQ setup\n\nLet's do it all on the [CLI](https://en.wikipedia.org/wiki/Command-line_interface) !\n\n 1. Install the git client :\n```bash\nsudo apt-get install git\n```\n 2. Clone this repository :\n```bash\ngit clone https://github.com/ABelliqueux/nolibgs_hello_worlds.git --recursive\n```\n 3. Change to the repo's directory and get the PsyQ converted libraries:\n```bash\ncd nolibgs_hello_worlds\nwget http://psx.schnappy.xyz/sdk/Psy-Q/psyq-4.7-converted-full.7z\n7z x psyq-4.7-converted-full.7z -o./psyq\n```\n 4. Try your setup :\n```bash\nmake\n```\nBy default, this should build the `hello_world` example, and you should now have a `hello_world.ps-exe` file in `./hello_world/`. This a PSX executable that can be run in an emulator like [pcsx-redux](https://github.com/grumpycoders/pcsx-redux/).\n\n### MacOS\n\nA [brew](https://brew.sh/) installation script can be found [here.](https://github.com/grumpycoders/pcsx-redux#macos).  \n\n## Compilation\n\nIn a terminal, `cd` to your psxdev setup directory and type `make all` to build all examples in their respective directories.  \n\nAlternatively, you can use `make example_name` to only build that example, i.e : `make hello_poly`.  \n\nIf you want to remove all the files generated by the compilation process, type `make clean`.  \n\n## Upcoming examples\n\n  * hello_poly_subdiv (polygon subdivision)\n  * hello_rsd (rsd format)\n\n# Links and Doc\n  \n  * [Getting started with PSX dev](https://psx.arthus.net/starting.html)\n  * [Ps1 dev ressource center](https://ps1.consoledev.net/)\n  * [PsyQ docs](https://psx.arthus.net/sdk/Psy-Q/DOCS/)\n  * [psxdev.net](http://psxdev.net/)\n  * [psxdev Discord](https://discord.com/invite/N2mmwp)\n\n# Credits, thanks, hugs\n\nEverything here was learnt from some more talented persons, mainly but not excluding others that hang around on the [psxdev discord](https://discord.com/channels/642647820683444236/642848627823345684)\nNicolas Noble, Lameguy64, NDR008, Jaby smoll seamonstah, danhans42, rama, sickle, paul, squaresoft74, and lot mores !\n"
  },
  {
    "path": "TIM/README.md",
    "content": "See here for more informations about the TIM fileformat and tools :  \n\nhttps://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/TIM\n"
  },
  {
    "path": "VAG/README.md",
    "content": "See here for more informations about the VAG fileformat and tools :  \n\nhttps://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/VAG\n"
  },
  {
    "path": "common.mk",
    "content": "# If you change this to exe, you'll have to rename the file ./thirdparty/nugget/ps-exe.ld too.\nTYPE = ps-exe\n\nTHISDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))\n\nSRCS += $(THISDIR)thirdparty/nugget/common/crt0/crt0.s\nSRCS += $(THISDIR)thirdparty/nugget/common/syscalls/printf.s \n\nCPPFLAGS += -I$(THISDIR)thirdparty/nugget/psyq/include -I$(THISDIR)psyq-4_7-converted/include -I$(THISDIR)psyq-4.7-converted-full/include -I$(THISDIR)psyq/include \nLDFLAGS += -L$(THISDIR)thirdparty/nugget/psyq/lib -L$(THISDIR)psyq-4_7-converted/lib -L$(THISDIR)psyq-4.7-converted-full/lib -L$(THISDIR)psyq/lib\n# add support for NDR008's VScode setup\nCPPFLAGS += -I$(THISDIR)../third_party/psyq/include\nLDFLAGS += -L$(THISDIR)../third_party/psyq/lib\nLDFLAGS += -Wl,--start-group\nLDFLAGS += -lapi\nLDFLAGS += -lc\nLDFLAGS += -lc2\nLDFLAGS += -lcard\nLDFLAGS += -lcomb\nLDFLAGS += -lds\nLDFLAGS += -letc\nLDFLAGS += -lgpu\nLDFLAGS += -lgs\nLDFLAGS += -lgte\nLDFLAGS += -lgun\nLDFLAGS += -lhmd\nLDFLAGS += -lmath\nLDFLAGS += -lmcrd\nLDFLAGS += -lmcx\nLDFLAGS += -lpad\nLDFLAGS += -lpress\nLDFLAGS += -lsio\nLDFLAGS += -lsnd\nLDFLAGS += -lspu\nLDFLAGS += -ltap\nLDFLAGS += -lcd\nLDFLAGS += -Wl,--end-group\n\n\ninclude $(THISDIR)thirdparty/nugget/common.mk\n\ndefine OBJCOPYME\n$(PREFIX)-objcopy -I binary --set-section-alignment .data=4 --rename-section .data=.rodata,alloc,load,readonly,data,contents -O $(FORMAT) -B mips $< $@\nendef\n\n# convert TIM file to bin\n%.o: %.tim\n\t$(call OBJCOPYME)\n\n# convert VAG files to bin\n%.o: %.vag\n\t$(call OBJCOPYME)\n\t\n# convert HIT to bin\n%.o: %.HIT\n\t$(call OBJCOPYME)"
  },
  {
    "path": "hello_2pads/Makefile",
    "content": "TARGET = hello_2pads\n\nSRCS = hello_2pads.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_2pads/hello_2pads.c",
    "content": "// hello_libpad example\n//\n// We're using libpad this time.\n// You can use the classic controller, analog, wheel, gun buttons or mouse\n//\n// Schnappy - 12/2020\n//\n// Based on :  ../psyq/addons/scea/CNTRL/PAD.C\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n#include <libapi.h>\n#define VMODE 0                  // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320\n#define SCREENYRES 240\n#define CENTERX SCREENXRES/2\n#define CENTERY SCREENYRES/2\n#define MARGINX 32               // margins for text display\n#define MARGINY 32\n#define FONTSIZE 8 * 7           // Text Field Height\n#define OTLEN 8                  // Ordering Table Length \nDISPENV disp[2];                 // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nu_long ot[2][OTLEN];             // double ordering table of length 8 * 32 = 256 bits / 32 bytes\nchar primbuff[2][32768];   // double primitive buffer of length 32768 * 8 =  262.144 bits / 32,768 Kbytes\nchar *nextpri = primbuff[0];     // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]\nshort db = 0;                    // index of which buffer is used, values 0, 1\n// Pad stuff\n// Structure for RAW hardware-based light gun position values\ntypedef struct\n{\n    unsigned short    v_count;      // Y-axis (vertical scan counter)\n    unsigned short    h_count;      // H-axis (horizontal pixel clock value)\n} Gun_Position;\n// Structure for storing processed controller data\ntypedef struct\n{\n    int             xpos, ypos;     // Stored position for sprite(s)\n    int             xpos2, ypos2;   // controlled by this controller.\n    unsigned char   status;         // These 8 values are obtained\n    unsigned char   type;           // directly from the controller\n    unsigned char   button1;        // buffer we installed with InitPAD.\n    unsigned char   button2;\n    unsigned char   analog0;\n    unsigned char   analog1;\n    unsigned char   analog2;\n    unsigned char   analog3;\n} Controller_Data;\n// All-purpose controller data buffer\ntypedef struct\n{\n    unsigned char pad[34];          // 8-bytes w/o Multi-Tap, 34-bytes w/Multi-Tap\n} Controller_Buffer;\nController_Buffer controllers[2];   // Buffers for reading controllers\nController_Data theControllers[8];  // Processed controller data\nvoid init(void)\n{\n    ResetGraph(0);\n    SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\n    if (VMODE)\n    {\n        SetVideoMode(MODE_PAL);\n        disp[0].screen.y += 8;\n        disp[1].screen.y += 8;\n        }\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 50, 50, 50);\n    setRGB0(&draw[1], 50, 50, 50);\n    draw[0].isbg = 1;\n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );\n}\nvoid display(void)\n{\n    DrawSync(0);\n    VSync(0);\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    DrawOTag(&ot[db][OTLEN - 1]);\n    db = !db;\n    nextpri = primbuff[db];\n}\nvoid get_digital_direction( Controller_Data *c, int buttondata ) // get analog stick values\n{\nint i;\n    i = ~(buttondata);\n    if( i & 0x80 )\n        c->xpos -= 1;\n    if( i & 0x20 )\n        c->xpos += 1;\n    if( i & 0x40 )\n        c->ypos += 1;\n    if( i & 0x10 )\n        c->ypos -= 1;\n}\nvoid read_controller( Controller_Data *c, unsigned char *buf, int port )  // get the raw values from controller\n{\n    register int mouse_x, mouse_y, x;\n    register Gun_Position *g;\n    c->status =  buf[0];    // Copy over raw controller data\n    c->type =    buf[1];\n    c->button1 = buf[2];\n    c->button2 = buf[3];\n    c->analog0 = buf[4];\n    c->analog1 = buf[5];\n    c->analog2 = buf[6];\n    c->analog3 = buf[7];\n    if( buf[0] == 0xff )    // If controller returns BAD status then bail on it.\n    {\n        c->type = 0;\n        return;\n    }\n    // Look at the controller type code & process controller data as indicated\n    switch( c->type )\n    {\n        case 0x12:      // Sony Mouse\n            mouse_x = buf[4];\n            mouse_y = buf[5];\n            if( mouse_x & 0x80 )\n                mouse_x |= 0xffffff80;\n            if( mouse_y & 0x80 )\n                mouse_y |= 0xffffff80;\n            c->xpos += mouse_x;\n            c->ypos += mouse_y;\n            break;\n        case 0x23:      // Namco negCon\n                        // Steering wheel\n                        // Sankyo Pachinko controler\n            get_digital_direction( c, buf[2] );\n            break;\n        case 0x53:      // Analog 2-stick\n            get_digital_direction( c, buf[2] );\n            break;\n        case 0x41:      // Standard Sony PAD controller\n            get_digital_direction( c, buf[2] );\n            break;\n        default:        // If don't know what it is, treat it like standard controller\n            get_digital_direction( c, buf[2] );\n            break;\n    }\n}\nint main(void)\n{\n    TILE * PADL;                    // Tile primitives\n    TILE * TRIGGERL;\n    TILE * PADR;\n    TILE * TRIGGERR;\n    TILE * START, * SELECT;\n    init();\n    InitPAD(controllers[0].pad, 34, controllers[1].pad, 34);\n    StartPAD();\n    while (1)\n    {\n        read_controller( &theControllers[0], &controllers[0].pad[0], 0 );  // Read controllers\n        read_controller( &theControllers[1], &controllers[1].pad[0], 1 );\n        ClearOTagR(ot[db], OTLEN);\n        // D-cross\n        PADL = (TILE *)nextpri;\n        setTile(PADL);\n        setRGB0(PADL, 80, 180, 255);        \n        setXY0(PADL, CENTERX - 80, CENTERY);\n        setWH(PADL, 24, 24);\n        addPrim(ot[db], PADL);\n        nextpri += sizeof(TILE);\n        // L1+L2\n        TRIGGERL = (TILE *)nextpri;\n        setTile(TRIGGERL);\n        setRGB0(TRIGGERL, 255, 0, 0);        \n        setXY0(TRIGGERL, CENTERX - 80, CENTERY - 80);\n        setWH(TRIGGERL, 24, 24);\n        addPrim(ot[db], TRIGGERL);\n        nextpri += sizeof(TILE);\n        // /\\, X, O, [] \n        PADR = (TILE *)nextpri;\n        setTile(PADR);\n        setRGB0(PADR, 0, 255, 0);        \n        setXY0(PADR, CENTERX + 50, CENTERY);\n        setWH(PADR, 24, 24);\n        addPrim(ot[db], PADR);\n        nextpri += sizeof(TILE);\n        // R1+R2\n        TRIGGERR = (TILE *)nextpri;\n        setTile(TRIGGERR);\n        setRGB0(TRIGGERR, 255, 0, 255);        \n        setXY0(TRIGGERR, CENTERX + 50, CENTERY -80);\n        setWH(TRIGGERR, 24, 24);\n        addPrim(ot[db], TRIGGERR);\n        nextpri += sizeof(TILE);\n        // START + SELECT\n        START = (TILE *)nextpri;\n        setTile(START);\n        setRGB0(START, 240, 240, 240);        \n        setXY0(START, CENTERX - 16, CENTERY - 36);\n        setWH(START, 24, 24);\n        addPrim(ot[db], START);\n        nextpri += sizeof(TILE);\n        // D-pad\n        switch(theControllers[0].button1){\n            case 0xDF:                      // Right \n                PADL->x0 = CENTERX - 64;\n                break;\n            case 0x7F:                      // Left  \n                PADL->x0 = CENTERX - 96;\n                break;\n            case 0xEF:                      // Up    \n                PADL->y0 = CENTERY - 16;\n                break;\n            case 0xBF:                      // Down  \n                PADL->y0 = CENTERY + 16;\n                break;\n            // Start & Select\n            case 0xF7:\n                START->w = 32; START->h = 32;START->x0 -= 4;START->y0 -= 4; // START\n                break;\n            case 0xFE:                                                      // SELECT\n                START->r0 = 0;\n                break;\n            // Dualshock L3 + R3\n            case 0xFD:                      // L3\n                TRIGGERL->w += 10;\n                TRIGGERL->h += 10;\n                break;\n            case 0xFB:                      //R3\n                TRIGGERR->w += 10;\n                TRIGGERR->h += 10;\n                break;\n        }\n        // Buttons\n        switch(theControllers[0].button2){\n            case 0xDF:                      // ⭘\n                PADR->x0 = CENTERX + 66;\n                break;\n            case 0x7F:                      // ⬜\n                PADR->x0 = CENTERX + 34;\n                break;\n            case 0xEF:                      // △\n                PADR->y0 = CENTERY - 16;\n                break;\n            case 0xBF:                      // ╳\n                PADR->y0 = CENTERY + 16;\n                break;\n        // Shoulder buttons             \n            case 0xFB:                       // L1\n                TRIGGERL->y0 = CENTERY - 64;\n                break;\n            case 0xFE:                       // L2\n                TRIGGERL->y0 = CENTERY - 96;\n                break;\n            case 0xF7:                       // R1\n                TRIGGERR->y0 = CENTERY - 96;\n                break;\n            case 0xFD:                       // R2\n                TRIGGERR->y0 = CENTERY - 64;\n                break;\n        // Mouse buttons \n            case 0xF4:                      // Mouse Left click\n                PADL->w += 10;\n                PADL->h += 10;\n                break;\n            case 0xF8:                      // Mouse Right click\n                PADL->w -= 10; \n                PADL->h -= 10; \n                break;\n        }\n        FntPrint(\"Hello 2 pads!\\n\\n\");\n        FntPrint( \"Pad 1 : %02x\\nButtons:%02x %02x, Stick:%02x %02x %02x %02x\\n\",\n                    theControllers[0].type,             // Controller type : 00 == none,  41 == standard, 73 == analog/dualshock, 12 == mouse, 23 == steering wheel, 63 == gun, 53 == analog joystick\n                    theControllers[0].button1,          // \n                    theControllers[0].button2,\n                    theControllers[0].analog0,\n                    theControllers[0].analog1,\n                    theControllers[0].analog2,\n                    theControllers[0].analog3 );\n        FntPrint( \"Pad 2 : %02x\\nButtons:%02x %02x, Stick:%02x %02x %02x %02x\\n\",\n                    theControllers[1].type,             // Controller type : 00 == none,  41 == standard, 73 == analog/dualshock, 12 == mouse, 23 == steering wheel, 63 == gun, 53 == analog joystick\n                    theControllers[1].button1,          // \n                    theControllers[1].button2,\n                    theControllers[1].analog0,          // R3 horizontal\n                    theControllers[1].analog1,          // R3 vertical\n                    theControllers[1].analog2,          // L3 horizontal\n                    theControllers[1].analog3 );        // L3 vertical\n        FntFlush(-1);\n        display();\n        }\n    return 0;\n    }\n"
  },
  {
    "path": "hello_bs/Makefile",
    "content": ".PHONY: all cleansub\nall:\n\tmkpsxiso -y ./isoconfig.xml\ncleansub:\n\t$(MAKE) clean\n\trm -f hello_bs.cue hello_bs.bin\n\t\nTARGET = hello_bs\n\nSRCS = hello_bs.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_bs/README.md",
    "content": "# Loading a BS still image\n\nYou need [mkpsxiso](https://github.com/Lameguy64/mkpsxiso) in your $PATH to generate a PSX disk image.\n\n## Compile\n\n```bash\nmake all\n```\n\n## Clean directory\n\n```bash\nmake cleansub\n```\n\n## Converting a still image to BS\n\n`MC32` can convert these formats to BS : TIM, RGB, YUV.\n\n### Image > TIM with img2tim\n\nConvert your image to a 24bpp TIM with [`img2tim`](https://github.com/Lameguy64/img2tim):\n\n```bash\nimg2tim -bpp 24 -o output.tim input.png\n```\n\nThen use `MC32` as instructed below.\n\nResult :  \n\n```bash\nidentify bace.tim \nbace.tim TIM 320x240 320x240+0+0 8-bit sRGB 230420B 0.000u 0:00.000\n```\n\n### Image > RGB with imagemagick\n\nYou can convert your image to RGB with:\n\n```bash\nconvert input.png RGB:output.rgb\n```\nResult :  \n```bash\nidentify -size 320x240 -depth 8 RGB:bace.rgb\nRGB:bace.rgb=>bace.rgb RGB 320x240 320x240+0+0 8-bit sRGB 230400B 0.000u 0:00.003\n```\n\n\n### Image > YUV422 UYVY with imagemagick\n\nYou can convert your image to YUV with:\n\n```bash\nconvert input.png UYVY:output.yuv\n```\nResult :  \n```bash\ndentify -size 320x240 UYVY:bace.yuv \nUYVY:bace.yuv=>bace.yuv UYVY 320x240 320x240+0+0 8-bit YCbCr 153600B 0.000u 0:00.005\n```\n\n\n### TIM/RGB/UYVY > BS conversion\n\nUse the [`MC32` tool](http://psx.arthus.net/tools/pimp-psx.zip) conversion tool to import the image, specifying the right dimensions, and convert to `bs` with those settings :\n\n**Note that a BS image must have a width and height that is a multiple of 16**\n\n```\nInput: RGB, Output: bs\nMDEC version : 2\nCustom: Size in sectors or (2048 * sector number) bytes, Variable frame size\n```\n\n![MC32 bs conversion](https://wiki.arthus.net/assets/mc32-bs-conv.png)\n\n## Sources & Refs\n\nimg2tim : https://github.com/Lameguy64/img2tim  \nMC32 : http://psx.arthus.net/tools/pimp-psx.zip  \n\nmdecnote : http://psx.arthus.net/sdk/Psy-Q/DOCS/TECHNOTE/mdecnote.pdf  \nPSX RGB and YUV format : http://psx.arthus.net/sdk/Psy-Q/DOCS/Devrefs/Dataconv.pdf , p.68\n\nYUV pixel format : https://www.fourcc.org/pixel-format/yuv-uyvy/\nRGB pixelformat : https://www.fourcc.org/pixel-format/rgb-bi_rgb/\n\nRGB<>YUV conversion formulas : https://www.fourcc.org/fccyvrgb.php\n"
  },
  {
    "path": "hello_bs/hello_bs.c",
    "content": "// Load a BS file from CD, decompress and display it.\n// Schnappy 07-2021\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n// CD library\n#include <libcd.h>\n// CODEC library\n#include <libpress.h>\n#include <malloc.h>\n\n\n#define VMODE 0                 // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320          // Screen width\n#define SCREENYRES 240 + (VMODE << 4)          // Screen height : If VMODE is 0 = 240, if VMODE is 1 = 256 \n#define CENTERX SCREENXRES/2    // Center of screen on x \n#define CENTERY SCREENYRES/2    // Center of screen on y\n#define MARGINX 8                // margins for text display\n#define MARGINY 16\n#define FONTSIZE 8 * 7           // Text Field Height\nDISPENV disp[2];                 // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nshort db = 0;                      // index of which buffer is used, values 0, 1\n\n// CD specifics\n#define CD_SECTOR_SIZE 2048\n// Converting bytes to sectors SECTOR_SIZE is defined in words, aka int\n#define BtoS(len) ( ( len + CD_SECTOR_SIZE - 1 ) / CD_SECTOR_SIZE ) \n// Name of file to load\nstatic char * loadFile;\n// libcd's CD file structure contains size, location and filename\nCdlFILE filePos = {0};\n//~ struct EXEC * exeStruct;\n// Define start address of allocated memory\n// Let's use an array so we don't have to worry about using a memory segment that's already in use.\nstatic unsigned char ramAddr[0x40000]; // https://discord.com/channels/642647820683444236/663664210525290507/864936962199781387\n// We could also set a memory address manually, but we have to make sure this won't get in the way of other routines.\n// void * ramAddr = (void *)0x80030D40; \n// Load data to this buffer\nu_long * dataBuffer;              \n// Those are not strictly needed, but we'll use them to see the commands results.\n// They could be replaced by a 0 in the various functions they're used with.\nu_char CtrlResult[8];\n// Value returned by CDread() - 1 is good, 0 is bad\nint CDreadOK = 0;\n// Value returned by CDsync() - Returns remaining sectors to load. 0 is good.\nint CDreadResult = 0;\n// BS decompression\n// Store size of uncompressed data\nlong bsBufferSize;\n// Allocated memory address\nvoid * bsWorkBuffer;\n// Define image draw area\nRECT bsDrawArea = { 0, 0, 16, SCREENYRES};\n// Used to store a 16x240 image strip\nu_long bsStrip[16*240];\n\nvoid init(void)\n{\n    ResetGraph(0);                 // Initialize drawing engine with a complete reset (0)\n    SetDefDispEnv(&disp[0], 0, 0         , SCREENXRES, SCREENYRES);     // Set display area for both &disp[0] and &disp[1]\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // &disp[0] is on top  of &disp[1]\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // Set draw for both &draw[0] and &draw[1]\n    SetDefDrawEnv(&draw[1], 0, 0         , SCREENXRES, SCREENYRES);     // &draw[0] is below &draw[1]\n    // Set video mode\n    if (VMODE){ SetVideoMode(MODE_PAL);}\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 155, 0, 150); // set color for first draw area\n    setRGB0(&draw[1], 155, 0, 150); // set color for second draw area\n    draw[0].isbg = 0;               // set mask for draw areas. 1 means repainting the area with the RGB color each frame \n    draw[1].isbg = 0;\n    PutDispEnv(&disp[db]);          // set the disp and draw environnments\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);                // Load font to vram at 960,0(+128)\n    FntOpen(MARGINX, MARGINY, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 ); // FntOpen(x, y, width, height,  black_bg, max. nbr. chars\n}\nvoid display(void)\n{\n    DrawSync(0);                    // Wait for all drawing to terminate\n    VSync(0);                       // Wait for the next vertical blank\n    PutDispEnv(&disp[db]);          // set alternate disp and draw environnments\n    PutDrawEnv(&draw[db]);  \n    db = !db;                       // flip db value (0 or 1)\n}\nint main(void)\n{   \n    // Init display\n    init();\n    // Init CD system\n    CdInit();\n    // Init heap\n    InitHeap((u_long *)ramAddr, sizeof(ramAddr));\n    // If the other method was chosen at l.39\n    // InitHeap((void *)0x80030D40, 0x40000);\n    // Set name of file to load\n    loadFile = \"\\\\BACE.BS;1\";\n    // Get file position from filename\n    CdSearchFile( &filePos, loadFile);\n    // Allocate memory\n    dataBuffer = malloc( BtoS(filePos.size) * CD_SECTOR_SIZE );\n    // Issue  CdlSetloc CDROM command : Set the seek target position\n    // Beware of a misnomed 'sector' member in the CdlLOC struct that should really be named 'frame'.\n    // https://discord.com/channels/642647820683444236/663664210525290507/864912470996942910\n    CdControl(CdlSetloc, (u_char *)&filePos.pos, CtrlResult);\n    // Read data and load it to dataBuffer\n    CDreadOK = CdRead( (int)BtoS(filePos.size), (u_long *)dataBuffer, CdlModeSpeed );\n    // Wait for operation to complete\n    CDreadResult = CdReadSync(0, 0);\n\n    // Image Decompression\n    // Initialize image processing subsystem\n    DecDCTReset(0);\n    // Find the needed buffer size\n    bsBufferSize = DecDCTBufSize(dataBuffer);\n    // Allocate buffer size at &bsWorkBuffer\n    bsWorkBuffer = malloc( bsBufferSize );\n    // Decode Huffman (also called VLC: variable length coding ) compressed image \n    DecDCTvlc( dataBuffer, (u_long *) bsWorkBuffer );\n    // Send decoded data to MDEC for RLE decoding.\n    DecDCTin( (u_long*) bsWorkBuffer, 0);\n    // Fetch decoded image in 16x240 strips\n    for( bsDrawArea.x = 0; bsDrawArea.x < SCREENXRES; bsDrawArea.x += 16 ){\n        // Request decoded data from MDEC\n        // Request 16 * 240 pixel high lines.\n        // But size is in long words (4B), so divide by 2 to get words (2B) ?\n        DecDCTout( bsStrip,  (16*SCREENYRES)/2);\n        // Wait for transfer to complete \n        DecDCToutSync(0);\n        // Load image data to fb\n        LoadImage( &bsDrawArea, bsStrip );\n    }\n    free( bsWorkBuffer );\n    while (1)  // infinite loop\n    {   \n        // Copy BS image to the other buffer\n        MoveImage2(&disp[db].disp, 0, disp[!db].disp.y );\n        DrawSync(0);\n        FntPrint(\"Hello BS! \\n\");\n        // Print filesize in bytes/sectors\n        FntPrint(\"Bs Size: %dB sectors: %d\\n\", filePos.size, BtoS(filePos.size));\n        // Print heap and buffer addresses\n        FntPrint(\"Heap: %x - Buf: %x\\n\", ramAddr, dataBuffer);\n        FntPrint(\"bsWork: %x\\nbsBufSize: %dB\\n\", bsWorkBuffer, bsBufferSize);        \n        \n        FntFlush(-1);               // Draw print stream\n        display();                  // Execute display()\n    }\n    return 0;\n    }\n"
  },
  {
    "path": "hello_bs/isoconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!-- MKPSXISO example XML script -->\n\n<!-- <iso_project>\n        Starts an ISO image project to build. Multiple <iso_project> elements may be\n        specified within the same xml script which useful for multi-disc projects.\n    \n        <iso_project> elements must contain at least one <track> element.\n    \n    Attributes:\n        image_name  - File name of the ISO image file to generate.\n        cue_sheet   - Optional, file name of the cue sheet for the image file\n                      (required if more than one track is specified).\n-->\n<iso_project image_name=\"hello_bs.bin\" cue_sheet=\"hello_bs.cue\">\n\n    <!-- <track>\n            Specifies a track to the ISO project. This example element creates a data\n            track for storing data files and CD-XA/STR streams.\n        \n            Only one data track is allowed and data tracks must only be specified as the\n            first track in the ISO image and cannot be specified after an audio track.\n        \n        Attributes:\n            type        - Track type (either data or audio).\n            source      - For audio tracks only, specifies the file name of a wav audio\n                          file to use for the audio track.\n            \n    -->\n    <track type=\"data\">\n    \n        <!-- <identifiers>\n                Optional, Specifies the identifier strings to use for the data track.\n                \n            Attributes:\n                system          - Optional, specifies the system identifier (PLAYSTATION if unspecified).\n                application     - Optional, specifies the application identifier (PLAYSTATION if unspecified).\n                volume          - Optional, specifies the volume identifier.\n                volume_set      - Optional, specifies the volume set identifier.\n                publisher       - Optional, specifies the publisher identifier.\n                data_preparer   - Optional, specifies the data preparer identifier. If unspecified, MKPSXISO\n                                  will fill it with lengthy text telling that the image file was generated\n                                  using MKPSXISO.\n        -->\n        <identifiers\n            system          =\"PLAYSTATION\"\n            application     =\"PLAYSTATION\"\n            volume          =\"HELOCD\"\n            volume_set      =\"HELOCD\"\n            publisher       =\"SCHNAPPY\"\n            data_preparer       =\"MKPSXISO\"\n        />\n        \n        <!-- <license>\n                Optional, specifies the license file to use, the format of the license file must be in\n                raw 2336 byte sector format, like the ones included with the PsyQ SDK in psyq\\cdgen\\LCNSFILE.\n                \n                License data is not included within the MKPSXISO program to avoid possible legal problems\n                in the open source environment... Better be safe than sorry.\n                \n            Attributes:\n                file    - Specifies the license file to inject into the ISO image.\n        -->\n        <!--\n        <license file=\"LICENSEA.DAT\"/>\n        -->\n        \n        <!-- <directory_tree>\n                Specifies and contains the directory structure for the data track.\n            \n            Attributes:\n                None.\n        -->\n        <directory_tree>\n        \n            <!-- <file>\n                    Specifies a file in the directory tree.\n                    \n                Attributes:\n                    name    - File name to use in the directory tree (can be used for renaming).\n                    type    - Optional, type of file (data for regular files and is the default, xa for\n                              XA audio and str for MDEC video).\n                    source  - File name of the source file.\n            -->\n            <!-- Stores system.txt as system.cnf -->\n            <file name=\"system.cnf\" type=\"data\" source=\"system.cnf\"/>\n            <file name=\"SCES_313.37\"   type=\"data\" source=\"hello_bs.ps-exe\"/>\n            <file name=\"BACE.BS\"   type=\"data\" source=\"bs/bace.bs\"/>\n            <dummy sectors=\"1024\"/>\n            \n            <!-- <dir>\n                    Specifies a directory in the directory tree. <file> and <dir> elements inside the element\n                    will be inside the specified directory.\n            -->\n        </directory_tree>\n        \n    </track>\n    \n</iso_project>\n"
  },
  {
    "path": "hello_bs/system.cnf",
    "content": "BOOT=cdrom:\\SCES_313.37;1\nTCB=4\nEVENT=10\nSTACK=801FFFF0\n"
  },
  {
    "path": "hello_cd/Makefile",
    "content": ".PHONY: all cleansub\nall:\n\tmkpsxiso -y ./isoconfig.xml\ncleansub:\n\t$(MAKE) clean\n\trm -f hello_cd.cue hello_cd.bin\n\t\nTARGET = hello_cd\n\nSRCS = hello_cd.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_cd/README.md",
    "content": "##  Loading a file from CD\n\nYou need [mkpsxiso](https://github.com/Lameguy64/mkpsxiso) in your $PATH to generate a PSX disk image.\n\n### Compile\n\n```bash\nmake all\n```\n\n### Clean directory\n\n```bash\nmake cleansub\n```\n\n### Adding data to the CD\n\nIn `isoconfig.xml`, in the data track's `directory_tree` section, use this syntax :\n\n```xml\n<file name=\"HELO.DAT\"   type=\"data\" source=\"theFile.dat\"/>\n```\n\nSee https://github.com/Lameguy64/mkpsxiso/blob/master/examples/example.xml for more details.\n"
  },
  {
    "path": "hello_cd/hello_cd.c",
    "content": "// Load files from CD and execute them\n// Schnappy 07-2021\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n#include <libapi.h>\n// CD library\n#include <libcd.h>\n#include <malloc.h>\n\n\n#define VMODE 0                 // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320          // Screen width\n#define SCREENYRES 240 + (VMODE << 4)          // Screen height : If VMODE is 0 = 240, if VMODE is 1 = 256 \n#define CENTERX SCREENXRES/2    // Center of screen on x \n#define CENTERY SCREENYRES/2    // Center of screen on y\n#define MARGINX 0                // margins for text display\n#define MARGINY 32\n#define FONTSIZE 8 * 7           // Text Field Height\nDISPENV disp[2];                 // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nshort db = 0;                      // index of which buffer is used, values 0, 1\n\n// CD specifics\n#define CD_SECTOR_SIZE 2048\n// Converting bytes to sectors SECTOR_SIZE is defined in words, aka int\n#define BtoS(len) ( ( len + CD_SECTOR_SIZE - 1 ) / CD_SECTOR_SIZE ) \n// Name of file to load\nstatic char * loadFile;\n// libcd's CD file structure contains size, location and filename\nCdlFILE filePos = {0};\n//~ struct EXEC * exeStruct;\n// Define start address of allocated memory\n// Let's use an array so we don't have to worry about using a memory segment that's already in use.\nstatic unsigned char ramAddr[0x40000]; // https://discord.com/channels/642647820683444236/663664210525290507/864936962199781387\n// We could also set a memory address manually, but we have to make sure this won't get in the way of other routines.\n// void * ramAddr = (void *)0x80030D40; \n// Load data to this buffer\nu_long * dataBuffer;              \n// Those are not strictly needed, but we'll use them to see the commands results.\n// They could be replaced by a 0 in the various functions they're used with.\nu_char CtrlResult[8];\n// Value returned by CDread() - 1 is good, 0 is bad\nint CDreadOK = 0;\n// Value returned by CDsync() - Returns remaining sectors to load. 0 is good.\nint CDreadResult = 0;\n\nvoid init(void)\n{\n    ResetGraph(0);                 // Initialize drawing engine with a complete reset (0)\n    SetDefDispEnv(&disp[0], 0, 0         , SCREENXRES, SCREENYRES);     // Set display area for both &disp[0] and &disp[1]\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // &disp[0] is on top  of &disp[1]\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // Set draw for both &draw[0] and &draw[1]\n    SetDefDrawEnv(&draw[1], 0, 0         , SCREENXRES, SCREENYRES);     // &draw[0] is below &draw[1]\n    // Set video mode\n    if (VMODE){ SetVideoMode(MODE_PAL);}\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 255, 50, 50); // set color for first draw area\n    setRGB0(&draw[1], 255, 50, 50); // set color for second draw area\n    draw[0].isbg = 1;               // set mask for draw areas. 1 means repainting the area with the RGB color each frame \n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);          // set the disp and draw environnments\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);                // Load font to vram at 960,0(+128)\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 ); // FntOpen(x, y, width, height,  black_bg, max. nbr. chars\n}\nvoid display(void)\n{\n    DrawSync(0);                    // Wait for all drawing to terminate\n    VSync(0);                       // Wait for the next vertical blank\n    PutDispEnv(&disp[db]);          // set alternate disp and draw environnments\n    PutDrawEnv(&draw[db]);  \n    db = !db;                       // flip db value (0 or 1)\n}\nint main(void)\n{   \n    // Init display\n    init();          \n    // Init CD system\n    CdInit();\n    // Init heap\n    InitHeap((u_long *)ramAddr, sizeof(ramAddr));\n    // If the other method was chosen at l.39\n    // InitHeap((void *)0x80030D40, 0x40000);\n    // Set name of file to load\n    loadFile = \"\\\\HELO.DAT;1\";\n    // Get file position from filename\n    CdSearchFile( &filePos, loadFile);\n    // Allocate memory\n    dataBuffer = malloc( BtoS(filePos.size) * CD_SECTOR_SIZE );\n    // Issue  CdlSetloc CDROM command : Set the seek target position\n    // Beware of a misnomed 'sector' member in the CdlLOC struct that should really be named 'frame'.\n    // https://discord.com/channels/642647820683444236/663664210525290507/864912470996942910\n    CdControl(CdlSetloc, (u_char *)&filePos.pos, CtrlResult);\n    // Read data and load it to dataBuffer\n    CDreadOK = CdRead( (int)BtoS(filePos.size), (u_long *)dataBuffer, CdlModeSpeed );\n    // Wait for operation to complete\n    CDreadResult = CdReadSync(0, 0);\n\n    while (1)  // infinite loop\n    {   \n        // Print the content of the loaded file - See HELO.DAT\n        FntPrint(\"%s%d\\n\", (char *)dataBuffer, VSync(-1));\n        // Print heap and buffer addresses\n        FntPrint(\"Heap: %x - Buf: %x\\n\", ramAddr, dataBuffer);\n        // Print returned values\n        FntPrint(\"CdCtrl: %d\\nRead  : %d %d\\n\", CtrlResult[0], CDreadOK, CDreadResult);\n        // Print filesize in bytes/sectors\n        FntPrint(\"Size: %dB sectors: %d\", filePos.size, BtoS(filePos.size));\n        \n        FntFlush(-1);               // Draw print stream\n        display();                  // Execute display()\n    }\n    return 0;\n    }\n"
  },
  {
    "path": "hello_cd/isoconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!-- MKPSXISO example XML script -->\n\n<!-- <iso_project>\n        Starts an ISO image project to build. Multiple <iso_project> elements may be\n        specified within the same xml script which useful for multi-disc projects.\n    \n        <iso_project> elements must contain at least one <track> element.\n    \n    Attributes:\n        image_name  - File name of the ISO image file to generate.\n        cue_sheet   - Optional, file name of the cue sheet for the image file\n                      (required if more than one track is specified).\n-->\n<iso_project image_name=\"hello_cd.bin\" cue_sheet=\"hello_cd.cue\">\n\n    <!-- <track>\n            Specifies a track to the ISO project. This example element creates a data\n            track for storing data files and CD-XA/STR streams.\n        \n            Only one data track is allowed and data tracks must only be specified as the\n            first track in the ISO image and cannot be specified after an audio track.\n        \n        Attributes:\n            type        - Track type (either data or audio).\n            source      - For audio tracks only, specifies the file name of a wav audio\n                          file to use for the audio track.\n            \n    -->\n    <track type=\"data\">\n    \n        <!-- <identifiers>\n                Optional, Specifies the identifier strings to use for the data track.\n                \n            Attributes:\n                system          - Optional, specifies the system identifier (PLAYSTATION if unspecified).\n                application     - Optional, specifies the application identifier (PLAYSTATION if unspecified).\n                volume          - Optional, specifies the volume identifier.\n                volume_set      - Optional, specifies the volume set identifier.\n                publisher       - Optional, specifies the publisher identifier.\n                data_preparer   - Optional, specifies the data preparer identifier. If unspecified, MKPSXISO\n                                  will fill it with lengthy text telling that the image file was generated\n                                  using MKPSXISO.\n        -->\n        <identifiers\n            system          =\"PLAYSTATION\"\n            application     =\"PLAYSTATION\"\n            volume          =\"HELOCD\"\n            volume_set      =\"HELOCD\"\n            publisher       =\"SCHNAPPY\"\n            data_preparer       =\"MKPSXISO\"\n        />\n        \n        <!-- <license>\n                Optional, specifies the license file to use, the format of the license file must be in\n                raw 2336 byte sector format, like the ones included with the PsyQ SDK in psyq\\cdgen\\LCNSFILE.\n                \n                License data is not included within the MKPSXISO program to avoid possible legal problems\n                in the open source environment... Better be safe than sorry.\n                \n            Attributes:\n                file    - Specifies the license file to inject into the ISO image.\n        -->\n        <!--\n        <license file=\"LICENSEA.DAT\"/>\n        -->\n        \n        <!-- <directory_tree>\n                Specifies and contains the directory structure for the data track.\n            \n            Attributes:\n                None.\n        -->\n        <directory_tree>\n        \n            <!-- <file>\n                    Specifies a file in the directory tree.\n                    \n                Attributes:\n                    name    - File name to use in the directory tree (can be used for renaming).\n                    type    - Optional, type of file (data for regular files and is the default, xa for\n                              XA audio and str for MDEC video).\n                    source  - File name of the source file.\n            -->\n            <!-- Stores system.txt as system.cnf -->\n            <file name=\"system.cnf\" type=\"data\" source=\"system.cnf\"/>\n            <file name=\"SCES_313.37\"   type=\"data\" source=\"hello_cd.ps-exe\"/>\n            <file name=\"HELO.DAT\"   type=\"data\" source=\"HELO.DAT\"/>\n            <dummy sectors=\"1024\"/>\n            \n            <!-- <dir>\n                    Specifies a directory in the directory tree. <file> and <dir> elements inside the element\n                    will be inside the specified directory.\n            -->\n        </directory_tree>\n        \n    </track>\n    \n</iso_project>\n"
  },
  {
    "path": "hello_cd/system.cnf",
    "content": "BOOT=cdrom:\\SCES_313.37;1\nTCB=4\nEVENT=10\nSTACK=801FFFF0\n"
  },
  {
    "path": "hello_cdda/Makefile",
    "content": ".PHONY: all cleansub\nall:\n\tmkpsxiso -y ./isoconfig.xml\ncleansub:\n\t$(MAKE) clean\n\trm -f hello_cdda.cue hello_cdda.bin\n\nTARGET = hello_cdda\n\nSRCS = hello_cdda.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_cdda/README.md",
    "content": "## Compiling\n\nYou need [mkpsxiso](https://github.com/Lameguy64/mkpsxiso) in your $PATH to generate a PSX disk image.\nTyping \n```bash\nmake\n```\nin a terminal will compile and generate the bin/cue files.  \n\nTyping\n```bash\nmake cleansub\n``` \nwill clean the current directory\n\n##  Creating the disk image\n\n```bash\nmkpsxiso -y isoconfig.xml\n```\n\n## Using ffmpeg to generate a CDDA compliant Wav file\n\nNeeded Specification : `RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, stereo 44100 Hz`\n\n### Conversion\n\n```bash\nffmpeg -i input.mp3 -acodec pcm_s16le -ac 2 -ar 44100 output.wav\n```\n\n### Merging two mono audio channels into one stereo channel \n\n```bash\nffmpeg -i herb.wav.new -filter_complex \"[0:a][0:a]amerge=inputs=2[a]\" -map \"[a]\" herbi.wav\n```\n\n### Adding the audio track to the CD\n\nAdd a track section **after** your data track in `isoconfig.xml` :  \n\n```xml\n<track type=\"audio\" source=\"file.wav\"/>\n```\n\n## Music credits\n\nTrack 1 :\nBeach Party by Kevin MacLeod\nLink: https://incompetech.filmmusic.io/song/3429-beach-party\nLicense: https://filmmusic.io/standard-license  \n\nTrack 2:\nFunk Game Loop by Kevin MacLeod\nLink: https://incompetech.filmmusic.io/song/3787-funk-game-loop\nLicense: https://filmmusic.io/standard-license\n"
  },
  {
    "path": "hello_cdda/hello_cdda.c",
    "content": "// CDDA track playback example\n// Schnappy 07-2021\n#include <sys/types.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n// CD library\n#include <libcd.h>\n// SPU library\n#include <libspu.h>\n\n#define VMODE 0                 // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320          // Screen width\n#define SCREENYRES 240 + (VMODE << 4)          // Screen height : If VMODE is 0 = 240, if VMODE is 1 = 256 \n#define CENTERX SCREENXRES/2    // Center of screen on x \n#define CENTERY SCREENYRES/2    // Center of screen on y\n#define MARGINX 0                // margins for text display\n#define MARGINY 32\n#define FONTSIZE 8 * 7           // Text Field Height\nDISPENV disp[2];                 // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nshort db = 0;                      // index of which buffer is used, values 0, 1\n// SPU attributes\nSpuCommonAttr spuSettings;\n// CD tracks \nint playing = -1;\nint tracks[] = {2, 0};  // Track to play , 1 is data, 2 is beach.wav, 3 is funk.wav. See isoconfig.xml\n\nvoid init(void)\n{\n    ResetGraph(0);                 // Initialize drawing engine with a complete reset (0)\n    SetDefDispEnv(&disp[0], 0, 0         , SCREENXRES, SCREENYRES);     // Set display area for both &disp[0] and &disp[1]\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // &disp[0] is on top  of &disp[1]\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // Set draw for both &draw[0] and &draw[1]\n    SetDefDrawEnv(&draw[1], 0, 0         , SCREENXRES, SCREENYRES);     // &draw[0] is below &draw[1]\n    // Set video mode\n    if (VMODE){ SetVideoMode(MODE_PAL);}\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 50, 50, 50); // set color for first draw area\n    setRGB0(&draw[1], 50, 50, 50); // set color for second draw area\n    draw[0].isbg = 1;               // set mask for draw areas. 1 means repainting the area with the RGB color each frame \n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);          // set the disp and draw environnments\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);                // Load font to vram at 960,0(+128)\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 ); // FntOpen(x, y, width, height,  black_bg, max. nbr. chars\n}\nvoid display(void)\n{\n    DrawSync(0);                    // Wait for all drawing to terminate\n    VSync(0);                       // Wait for the next vertical blank\n    PutDispEnv(&disp[db]);          // set alternate disp and draw environnments\n    PutDrawEnv(&draw[db]);  \n    db = !db;                       // flip db value (0 or 1)\n}\nint main(void)\n{   \n    int count = 0;\n    int flip = 1;\n    CdlLOC loc[100];\n    int ntoc;\n    // Init display\n    init();                       \n    // Init extended CD system\n    CdInit();\n    // Init Spu\n    SpuInit();\n    // Set master & CD volume to max\n    spuSettings.mask = (SPU_COMMON_MVOLL | SPU_COMMON_MVOLR | SPU_COMMON_CDVOLL | SPU_COMMON_CDVOLR | SPU_COMMON_CDMIX);\n    // Master volume should be in range 0x0000 - 0x3fff\n    spuSettings.mvol.left  = 0x3fff;\n    spuSettings.mvol.right = 0x3fff;\n    // Cd volume should be in range 0x0000 - 0x7fff\n    spuSettings.cd.volume.left = 0x7fff;\n    spuSettings.cd.volume.right = 0x7fff;\n    // Enable CD input ON\n    spuSettings.cd.mix = SPU_ON;\n    // Apply settings\n    SpuSetCommonAttr(&spuSettings);\n    // Set transfer mode \n    SpuSetTransferMode(SPU_TRANSFER_BY_DMA);\n    // CD Playback setup\n    // Play second audio track\n    // Get CD TOC\n    while ((ntoc = CdGetToc(loc)) == 0) { \t\t/* Read TOC */\n        FntPrint(\"No TOC found: please use CD-DA disc...\\n\");\n    }\n    // Prevent out of bound pos\n    for (int i = 1; i < ntoc; i++) {\n        CdIntToPos(CdPosToInt(&loc[i]) - 74, &loc[i]);\n    }\n    // Those array will hold the return values of the CD commands\n    u_char param[4], result[8];\n    // Set CD parameters ; Report Mode ON, CD-DA ON. See LibeOver47.pdf, p.188\n    param[0] = CdlModeRept|CdlModeDA;\t\n    CdControlB (CdlSetmode, param, 0);\t/* set mode */\n    VSync (3);\t\t\t\t/* wait three vsync times */\n    // Play second track in toc array\n    CdControlB (CdlPlay, (u_char *)&loc[3], 0);\t/* play */\n\n\n    while (1)  // infinite loop\n    {           \n        count ++;\n        // Get current track number ~ every second\n        // See LibeOver47.pdf, p.188\n        if (count%50 == 0){\n            CdReady(1, &result[0]);\n            // current track number can also be obtained with \n            // CdControlB (CdlGetlocP, 0, &result[0]);\n        }\n        // Switch track after ~ 20 seconds\n        if (count%(50*20) == 0){\n            // Flip can have a value of 1 or -1\n            flip *= -1;\n            uint8_t nextTrackIndex = result[1] + flip;\n            // Send CD command to switch track\n            CdControlB (CdlPlay, (u_char *)&loc[ nextTrackIndex ], 0);\n        }\n\n        FntPrint(\"Hello CDDA !\\n\");  // Send string to print stream\n        FntPrint(\"Playback status: %d\", result[1]);  // Send string to print stream\n        \n        FntFlush(-1);               // Draw printe stream\n        display();                  // Execute display()\n    }\n    return 0;\n    }\n"
  },
  {
    "path": "hello_cdda/isoconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!-- MKPSXISO example XML script -->\n\n<!-- <iso_project>\n        Starts an ISO image project to build. Multiple <iso_project> elements may be\n        specified within the same xml script which useful for multi-disc projects.\n    \n        <iso_project> elements must contain at least one <track> element.\n    \n    Attributes:\n        image_name  - File name of the ISO image file to generate.\n        cue_sheet   - Optional, file name of the cue sheet for the image file\n                      (required if more than one track is specified).\n-->\n<iso_project image_name=\"hello_cdda.bin\" cue_sheet=\"hello_cdda.cue\">\n\n    <!-- <track>\n            Specifies a track to the ISO project. This example element creates a data\n            track for storing data files and CD-XA/STR streams.\n        \n            Only one data track is allowed and data tracks must only be specified as the\n            first track in the ISO image and cannot be specified after an audio track.\n        \n        Attributes:\n            type        - Track type (either data or audio).\n            source      - For audio tracks only, specifies the file name of a wav audio\n                          file to use for the audio track.\n            \n    -->\n    <track type=\"data\">\n    \n        <!-- <identifiers>\n                Optional, Specifies the identifier strings to use for the data track.\n                \n            Attributes:\n                system          - Optional, specifies the system identifier (PLAYSTATION if unspecified).\n                application     - Optional, specifies the application identifier (PLAYSTATION if unspecified).\n                volume          - Optional, specifies the volume identifier.\n                volume_set      - Optional, specifies the volume set identifier.\n                publisher       - Optional, specifies the publisher identifier.\n                data_preparer   - Optional, specifies the data preparer identifier. If unspecified, MKPSXISO\n                                  will fill it with lengthy text telling that the image file was generated\n                                  using MKPSXISO.\n        -->\n        <identifiers\n            system          =\"PLAYSTATION\"\n            application     =\"PLAYSTATION\"\n            volume          =\"HELOCD\"\n            volume_set      =\"HELOCD\"\n            publisher       =\"SCHNAPPY\"\n            data_preparer       =\"MKPSXISO\"\n        />\n        \n        <!-- <license>\n                Optional, specifies the license file to use, the format of the license file must be in\n                raw 2336 byte sector format, like the ones included with the PsyQ SDK in psyq\\cdgen\\LCNSFILE.\n                \n                License data is not included within the MKPSXISO program to avoid possible legal problems\n                in the open source environment... Better be safe than sorry.\n                \n            Attributes:\n                file    - Specifies the license file to inject into the ISO image.\n        -->\n        <!--\n        <license file=\"LICENSEA.DAT\"/>\n        -->\n        \n        <!-- <directory_tree>\n                Specifies and contains the directory structure for the data track.\n            \n            Attributes:\n                None.\n        -->\n        <directory_tree>\n        \n            <!-- <file>\n                    Specifies a file in the directory tree.\n                    \n                Attributes:\n                    name    - File name to use in the directory tree (can be used for renaming).\n                    type    - Optional, type of file (data for regular files and is the default, xa for\n                              XA audio and str for MDEC video).\n                    source  - File name of the source file.\n            -->\n            <!-- Stores system.txt as system.cnf -->\n            <file name=\"system.cnf\" type=\"data\" source=\"system.cnf\"/>\n            <file name=\"SCES_313.37\"   type=\"data\" source=\"hello_cdda.ps-exe\"/>\n            <dummy sectors=\"1024\"/>\n            \n            <!-- <dir>\n                    Specifies a directory in the directory tree. <file> and <dir> elements inside the element\n                    will be inside the specified directory.\n            -->\n        </directory_tree>\n        \n    </track>\n    <!--  \n    Track 1 :\n    Beach Party by Kevin MacLeod\n    Link: https://incompetech.filmmusic.io/song/3429-beach-party\n    License: https://filmmusic.io/standard-license  \n    Track 2:\n    Funk Game Loop by Kevin MacLeod\n    Link: https://incompetech.filmmusic.io/song/3787-funk-game-loop\n    License: https://filmmusic.io/standard-license\n    -->\n    <track type=\"audio\" source=\"audio/beach.wav\"/>\n    <track type=\"audio\" source=\"audio/funk.wav\"/>\n    \n</iso_project>\n"
  },
  {
    "path": "hello_cdda/system.cnf",
    "content": "BOOT=cdrom:\\SCES_313.37;1\nTCB=4\nEVENT=10\nSTACK=801FFFF0\n"
  },
  {
    "path": "hello_cube/Makefile",
    "content": "TARGET = hello_cube\n\nSRCS = hello_cube.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_cube/cube.c",
    "content": "SVECTOR modelCube_mesh[] = {\n    { -128,128,128 },\n    { 128,128,128 },\n    { 128,128,-128 },\n    { -128,128,-128 },\n    { -128,-128,128 },\n    { 128,-128,128 },\n    { 128,-128,-128 },\n    { -128,-128,-128 }\n};\n\nSVECTOR modelCube_normal[] = {\n    2365,-2365,-2365, 0,\n    -2365,-2365,-2365, 0,\n    -2365,-2365,2365, 0,\n    2365,-2365,2365, 0,\n    2365,2365,-2365, 0,\n    -2365,2365,-2365, 0,\n    -2365,2365,2365, 0,\n    2365,2365,2365, 0\n};\n\nCVECTOR modelCube_color[] = {\n    255,237,0, 0,\n    255,235,0, 0,\n    255,236,0, 0,\n    255,2,0, 0,\n    254,3,0, 0,\n    255,8,0, 0,\n    229,0,255, 0,\n    229,0,255, 0,\n    229,0,255, 0,\n    5,16,250, 0,\n    0,12,255, 0,\n    0,12,255, 0,\n    4,251,25, 0,\n    0,255,26, 0,\n    0,255,26, 0,\n    0,248,255, 0,\n    0,248,255, 0,\n    0,248,255, 0,\n    255,237,0, 0,\n    255,237,0, 0,\n    255,235,0, 0,\n    255,2,0, 0,\n    255,6,2, 0,\n    254,3,0, 0,\n    229,0,255, 0,\n    232,21,232, 0,\n    229,0,255, 0,\n    5,16,250, 0,\n    2,13,253, 0,\n    0,12,255, 0,\n    4,251,25, 0,\n    0,255,26, 0,\n    0,255,26, 0,\n    0,248,255, 0,\n    0,248,255, 0,\n    0,248,255, 0\n};\n\nint modelCube_index[] = {\n    0,2,3,\n    7,5,4,\n    4,1,0,\n    5,2,1,\n    2,7,3,\n    0,7,4,\n    0,1,2,\n    7,6,5,\n    4,5,1,\n    5,6,2,\n    2,6,7,\n    0,3,7\n};\n\nTMESH modelCube = {\n    modelCube_mesh,\n    modelCube_normal,\n    0,\n    modelCube_color,\n    12\n};\n\nSVECTOR modelCube1_mesh[] = {\n    { -128,128,128 },\n    { 128,128,128 },\n    { 128,128,-128 },\n    { -128,128,-128 },\n    { -128,-128,128 },\n    { 128,-128,128 },\n    { 128,-128,-128 },\n    { -128,-128,-128 }\n};\n\nSVECTOR modelCube1_normal[] = {\n    2365,-2365,-2365, 0,\n    -2365,-2365,-2365, 0,\n    -2365,-2365,2365, 0,\n    2365,-2365,2365, 0,\n    2365,2365,-2365, 0,\n    -2365,2365,-2365, 0,\n    -2365,2365,2365, 0,\n    2365,2365,2365, 0\n};\n\nCVECTOR modelCube1_color[] = {\n    255,237,0, 0,\n    255,235,0, 0,\n    255,236,0, 0,\n    255,2,0, 0,\n    254,3,0, 0,\n    255,8,0, 0,\n    229,0,255, 0,\n    229,0,255, 0,\n    229,0,255, 0,\n    5,16,250, 0,\n    0,12,255, 0,\n    0,12,255, 0,\n    4,251,25, 0,\n    0,255,26, 0,\n    0,255,26, 0,\n    0,248,255, 0,\n    0,248,255, 0,\n    0,248,255, 0,\n    255,237,0, 0,\n    255,237,0, 0,\n    255,235,0, 0,\n    255,2,0, 0,\n    255,6,2, 0,\n    254,3,0, 0,\n    229,0,255, 0,\n    232,21,232, 0,\n    229,0,255, 0,\n    5,16,250, 0,\n    2,13,253, 0,\n    0,12,255, 0,\n    4,251,25, 0,\n    0,255,26, 0,\n    0,255,26, 0,\n    0,248,255, 0,\n    0,248,255, 0,\n    0,248,255, 0\n};\n\nint modelCube1_index[] = {\n    0,2,3,\n    7,5,4,\n    4,1,0,\n    5,2,1,\n    2,7,3,\n    0,7,4,\n    0,1,2,\n    7,6,5,\n    4,5,1,\n    5,6,2,\n    2,6,7,\n    0,3,7\n};\n\nTMESH modelCube1 = {\n    modelCube1_mesh,\n    modelCube1_normal,\n    0,\n    modelCube1_color,\n    12\n};\n"
  },
  {
    "path": "hello_cube/hello_cube.c",
    "content": "/*  primdrawG.c, by Schnappy, 12-2020\r\n    - Draw a gouraud shaded mesh exported as a TMESH by the blender <= 2.79b plugin io_export_psx_tmesh.py\r\n    based on primdraw.c by Lameguy64 (http://www.psxdev.net/forum/viewtopic.php?f=64&t=537)\r\n    2014 Meido-Tek Productions.\r\n    Controls:\r\n        Start                           - Toggle interactive/non-interactive mode.\r\n        Select                          - Reset object's position and angles.\r\n        L1/L2                           - Move object closer/farther.\r\n        L2/R2                           - Rotate object (XY).\r\n        Up/Down/Left/Right              - Rotate object (XZ/YZ).\r\n        Triangle/Cross/Square/Circle    - Move object up/down/left/right.\r\n*/\r\n#include <sys/types.h>\r\n#include <libgte.h>\r\n#include <libgpu.h>\r\n#include <libetc.h>\r\n#include <stdio.h>\r\n// Sample vector model\r\n#include \"cube.c\"\r\n#define VMODE       0\r\n#define SCREENXRES 320\r\n#define SCREENYRES 240\r\n#define CENTERX     SCREENXRES/2\r\n#define CENTERY     SCREENYRES/2\r\n#define OTLEN       2048        // Maximum number of OT entries\r\n#define PRIMBUFFLEN 32768       // Maximum number of POLY_GT3 primitives\r\n// Display and draw environments, double buffered\r\nDISPENV disp[2];\r\nDRAWENV draw[2];\r\nu_long      ot[2][OTLEN];                   // Ordering table (contains addresses to primitives)\r\nchar        primbuff[2][PRIMBUFFLEN]; // Primitive list // That's our prim buffer\r\nchar * nextpri = primbuff[0];                       // Primitive counter\r\nshort           db  = 0;                        // Current buffer counter\r\n// Prototypes\r\nvoid init(void);\r\nvoid display(void);\r\n//~ void LoadTexture(u_long * tim, TIM_IMAGE * tparam);\r\nvoid init(){\r\n    // Reset the GPU before doing anything and the controller\r\n    PadInit(0);\r\n    ResetGraph(0);\r\n    // Initialize and setup the GTE\r\n    InitGeom();\r\n    SetGeomOffset(CENTERX, CENTERY);        // x, y offset\r\n    SetGeomScreen(CENTERX);                 // Distance between eye and screen  \r\n        // Set the display and draw environments\r\n    SetDefDispEnv(&disp[0], 0, 0         , SCREENXRES, SCREENYRES);\r\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\r\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\r\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\r\n    if (VMODE)\r\n    {\r\n        SetVideoMode(MODE_PAL);\r\n        disp[0].screen.y += 8;\r\n        disp[1].screen.y += 8;\r\n    }\r\n    SetDispMask(1);                 // Display on screen        \r\n    setRGB0(&draw[0], 0, 128, 255);\r\n    setRGB0(&draw[1], 0, 128, 255);\r\n    draw[0].isbg = 1;\r\n    draw[1].isbg = 1;\r\n    PutDispEnv(&disp[db]);\r\n    PutDrawEnv(&draw[db]);\r\n    // Init font system\r\n    FntLoad(960, 0);\r\n    FntOpen(16, 16, 196, 64, 0, 256);\r\n    }\r\nvoid display(void){\r\n    DrawSync(0);\r\n    VSync(0);\r\n    PutDispEnv(&disp[db]);\r\n    PutDrawEnv(&draw[db]);\r\n    DrawOTag(&ot[db][OTLEN - 1]);\r\n    db = !db;\r\n    nextpri = primbuff[db];\r\n    }\r\nint main() {\r\n    int     i;\r\n    int     PadStatus;\r\n    int     TPressed=0;\r\n    int     AutoRotate=1;\r\n    long    t, p, OTz, Flag;                // t == vertex count, p == depth cueing interpolation value, OTz ==  value to create Z-ordered OT, Flag == see LibOver47.pdf, p.143\r\n    POLY_G3 *poly = {0};                           // pointer to a POLY_G4 \r\n    SVECTOR Rotate={ 232, 232, 0, 0 };                   // Rotation coordinates\r\n    VECTOR  Trans={ 0, 0, CENTERX * 3, 0 };     // Translation coordinates\r\n                                            // Scaling coordinates\r\n    VECTOR  Scale={ ONE/2, ONE/2, ONE/2, 0 };     // ONE == 4096\r\n    MATRIX  Matrix={0};                     // Matrix data for the GTE\r\n    init();\r\n    // Main loop\r\n    while (1) {\r\n        // Read pad status\r\n        PadStatus = PadRead(0);\r\n        if (AutoRotate == 0) {\r\n            if (PadStatus & PADL1) Trans.vz -= 4;\r\n            if (PadStatus & PADR1) Trans.vz += 4;\r\n            if (PadStatus & PADL2) Rotate.vz -= 8;\r\n            if (PadStatus & PADR2) Rotate.vz += 8;\r\n            if (PadStatus & PADLup)     Rotate.vx -= 8;\r\n            if (PadStatus & PADLdown)   Rotate.vx += 8;\r\n            if (PadStatus & PADLleft)   Rotate.vy -= 8;\r\n            if (PadStatus & PADLright)  Rotate.vy += 8;\r\n            if (PadStatus & PADRup)     Trans.vy -= 2;\r\n            if (PadStatus & PADRdown)   Trans.vy += 2;\r\n            if (PadStatus & PADRleft)   Trans.vx -= 2;\r\n            if (PadStatus & PADRright)  Trans.vx += 2;\r\n            if (PadStatus & PADselect) {\r\n                Rotate.vx = Rotate.vy = Rotate.vz = 0;\r\n                Scale.vx = Scale.vy = Scale.vz = ONE/2;\r\n                Trans.vx = Trans.vy = 0;\r\n                Trans.vz = CENTERX * 3;\r\n            }\r\n        }\r\n        if (PadStatus & PADstart) {\r\n            if (TPressed == 0) {\r\n                AutoRotate = (AutoRotate + 1) & 1;\r\n                Rotate.vx = Rotate.vy = Rotate.vz = 0;\r\n                Scale.vx = Scale.vy = Scale.vz = ONE/2;\r\n                Trans.vx = Trans.vy = 0;\r\n                Trans.vz = CENTERX * 3;\r\n            }\r\n            TPressed = 1;\r\n        } else {\r\n            TPressed = 0;\r\n        }\r\n        if (AutoRotate) {\r\n            Rotate.vy += 28; // Pan\r\n            Rotate.vx += 28; // Tilt\r\n            //~ Rotate.vz += 8; // Roll\r\n        }\r\n        // Clear the current OT\r\n        ClearOTagR(ot[db], OTLEN);\r\n        // Convert and set the matrixes\r\n        RotMatrix(&Rotate, &Matrix);\r\n        TransMatrix(&Matrix, &Trans);\r\n        ScaleMatrix(&Matrix, &Scale);\r\n        SetRotMatrix(&Matrix);\r\n        SetTransMatrix(&Matrix);\r\n        // Render the sample vector model\r\n        t=0;\r\n        // modelCube is a TMESH, len member == # vertices, but here it's # of triangle... So, for each tri * 3 vertices ...\r\n        for (i = 0; i < (modelCube.len*3); i += 3) {               \r\n            poly = (POLY_G3 *)nextpri;\r\n            // Initialize the primitive and set its color values\r\n            SetPolyG3(poly);\r\n            setRGB0(poly, modelCube.c[i].r , modelCube.c[i].g   , modelCube.c[i].b);\r\n            setRGB1(poly, modelCube.c[i+2].r, modelCube.c[i+2].g, modelCube.c[i+2].b);\r\n            setRGB2(poly, modelCube.c[i+1].r, modelCube.c[i+1].g, modelCube.c[i+1].b);\r\n            // Rotate, translate, and project the vectors and output the results into a primitive\r\n            OTz  = RotTransPers(&modelCube_mesh[modelCube_index[t]]  , (long*)&poly->x0, &p, &Flag);\r\n            OTz += RotTransPers(&modelCube_mesh[modelCube_index[t+2]], (long*)&poly->x1, &p, &Flag);\r\n            OTz += RotTransPers(&modelCube_mesh[modelCube_index[t+1]], (long*)&poly->x2, &p, &Flag);\r\n            // Sort the primitive into the OT\r\n            OTz /= 3;\r\n            if ((OTz > 0) && (OTz < OTLEN))\r\n                AddPrim(&ot[db][OTz-2], poly);\r\n            nextpri += sizeof(POLY_G3);\r\n            t+=3;\r\n        }\r\n        FntPrint(\"Hello gouraud shaded cube!\\n\");\r\n        FntFlush(-1);\r\n        display();\r\n    }\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "hello_cubetex/Makefile",
    "content": "TARGET = hello_cubetex\n\nSRCS = hello_cubetex.c \\\n../TIM/cubetex.tim \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_cubetex/cubetex.c",
    "content": "SVECTOR modelCube_mesh[] = {\n    {32,32,-32.0},\n    {32,-32,-32},\n    {-32,-32,-32},\n    {-32,32,-32},\n    {32,32,32},\n    {32,-32,32},\n    {-32,-32,32},\n    {-32,32,32}\n};\n\nSVECTOR modelCube_normal[] = {\n    0,-0,-1,0,\n    0,0,1,0,\n    1,0,-2,0,\n    -9,-1,-3,0,\n    -1,2,-1,0,\n    3,1,2,0,\n    0,0,-1,0,\n    0,-0,1,0,\n    1,-6,3,0,\n    -5,-1,9,0,\n    -1,2,-1,0,\n    2,1,2,0\n};\n\nSVECTOR modelCube_uv[] = {\n    84,84, 0, 0,\n    125,42, 0, 0,\n    84,42, 0, 0,\n    125,84, 0, 0,\n    84,125, 0, 0,\n    125,125, 0, 0,\n    1,84, 0, 0,\n    42,125, 0, 0,\n    42,84, 0, 0,\n    42,125, 0, 0,\n    84,84, 0, 0,\n    42,84, 0, 0,\n    42,1, 0, 0,\n    1,42, 0, 0,\n    42,42, 0, 0,\n    42,84, 0, 0,\n    1,42, 0, 0,\n    1,84, 0, 0,\n    84,84, 0, 0,\n    125,84, 0, 0,\n    125,42, 0, 0,\n    125,84, 0, 0,\n    84,84, 0, 0,\n    84,125, 0, 0,\n    1,84, 0, 0,\n    1,125, 0, 0,\n    42,125, 0, 0,\n    42,125, 0, 0,\n    84,125, 0, 0,\n    84,84, 0, 0,\n    42,1, 0, 0,\n    1,1, 0, 0,\n    1,42, 0, 0,\n    42,84, 0, 0,\n    42,42, 0, 0,\n    1,42, 0, 0\n};\n\nCVECTOR modelCube_color[] = {\n    255,255,255, 0,\n    255,255,255, 0,\n    255,0,251, 0,\n    255,255,255, 0,\n    255,5,7, 0,\n    255,255,255, 0,\n    255,255,255, 0,\n    255,255,255, 0,\n    4,18,255, 0,\n    255,5,7, 0,\n    255,255,255, 0,\n    255,255,255, 0,\n    254,255,23, 0,\n    122,255,107, 0,\n    255,255,255, 0,\n    255,255,255, 0,\n    255,255,255, 0,\n    254,255,94, 0,\n    255,255,255, 0,\n    35,255,11, 0,\n    255,255,255, 0,\n    255,255,255, 0,\n    255,255,255, 0,\n    255,5,7, 0,\n    255,255,255, 0,\n    255,5,7, 0,\n    255,255,255, 0,\n    255,5,7, 0,\n    255,255,255, 0,\n    255,255,255, 0,\n    254,255,23, 0,\n    255,255,255, 0,\n    122,255,107, 0,\n    255,255,255, 0,\n    54,65,255, 0,\n    255,255,255, 0\n};\n\nint modelCube_index[] = {\n    0,2,3,\n    7,5,4,\n    4,1,0,\n    5,2,1,\n    2,7,3,\n    0,7,4,\n    0,1,2,\n    7,6,5,\n    4,5,1,\n    5,6,2,\n    2,6,7,\n    0,3,7\n};\n\nTMESH modelCube = {\n    modelCube_mesh,\n    modelCube_normal,\n    modelCube_uv,\n    modelCube_color,\n    12\n};\n\nextern unsigned long _binary____TIM_cubetex_tim_start[];\nextern unsigned long _binary____TIM_cubetex_tim_end[];\nextern unsigned long _binary____TIM_cubetex_tim_length;\n\nTIM_IMAGE tim_cube;\n"
  },
  {
    "path": "hello_cubetex/hello_cubetex.c",
    "content": "/*  primdrawG.c, by Schnappy, 12-2020\r\n    \r\n    - Draw a gouraud shaded textured mesh exported as a TMESH by the blender <= 2.79b plugin io_export_psx_tmesh.py\r\n    \r\n    based on primdraw.c by Lameguy64 (http://www.psxdev.net/forum/viewtopic.php?f=64&t=537)\r\n    2014 Meido-Tek Productions.\r\n    \r\n    Demonstrates:\r\n        - Using a primitive OT to draw triangles without libgs.\r\n        - Using the GTE to rotate, translate, and project 3D primitives.\r\n    \r\n    Controls:\r\n        Start                           - Toggle interactive/non-interactive mode.\r\n        Select                          - Reset object's position and angles.\r\n        L1/L2                           - Move object closer/farther.\r\n        L2/R2                           - Rotate object (XY).\r\n        Up/Down/Left/Right              - Rotate object (XZ/YZ).\r\n        Triangle/Cross/Square/Circle    - Move object up/down/left/right.\r\n        \r\n*/\r\n#include <sys/types.h>\r\n#include <libgte.h>\r\n#include <libgpu.h>\r\n#include <libetc.h>\r\n#include <stdio.h>\r\n\r\n// Sample vector model\r\n#include \"cubetex.c\"\r\n\r\n#define VMODE       0\r\n\r\n#define SCREENXRES 320\r\n#define SCREENYRES 240\r\n\r\n#define CENTERX     SCREENXRES/2\r\n#define CENTERY     SCREENYRES/2\r\n\r\n#define OTLEN       2048        // Maximum number of OT entries\r\n#define PRIMBUFFLEN 32768       // Maximum number of POLY_GT3 primitives\r\n\r\n// Display and draw environments, double buffered\r\nDISPENV disp[2];\r\nDRAWENV draw[2];\r\n\r\nu_long      ot[2][OTLEN];                   // Ordering table (contains addresses to primitives)\r\nchar    primbuff[2][PRIMBUFFLEN] = {0}; // Primitive list // That's our prim buffer\r\n\r\n//~ int         primcnt=0;                      // Primitive counter\r\n\r\nchar * nextpri = primbuff[0];                       // Primitive counter\r\n\r\nshort           db  = 0;                        // Current buffer counter\r\n\r\n// Prototypes\r\nvoid init(void);\r\nvoid display(void);\r\nvoid LoadTexture(u_long * tim, TIM_IMAGE * tparam);\r\n\r\nvoid init(){\r\n    // Reset the GPU before doing anything and the controller\r\n    PadInit(0);\r\n    ResetGraph(0);\r\n    \r\n    // Initialize and setup the GTE\r\n    InitGeom();\r\n    SetGeomOffset(CENTERX, CENTERY);        // x, y offset\r\n    SetGeomScreen(CENTERX);                 // Distance between eye and screen  \r\n    \r\n        // Set the display and draw environments\r\n    SetDefDispEnv(&disp[0], 0, 0         , SCREENXRES, SCREENYRES);\r\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\r\n    \r\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\r\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\r\n    \r\n    if (VMODE)\r\n    {\r\n        SetVideoMode(MODE_PAL);\r\n        disp[0].screen.y += 8;\r\n        disp[1].screen.y += 8;\r\n    }\r\n    \r\n    SetDispMask(1);\r\n\r\n    setRGB0(&draw[0], 0, 0, 255);\r\n    setRGB0(&draw[1], 0, 0, 255);\r\n\r\n    draw[0].isbg = 1;\r\n    draw[1].isbg = 1;\r\n\r\n    PutDispEnv(&disp[db]);\r\n    PutDrawEnv(&draw[db]);\r\n        \r\n    // Init font system\r\n    FntLoad(960, 0);\r\n    FntOpen(16, 16, 196, 64, 0, 256);\r\n    \r\n    }\r\n\r\nvoid display(void){\r\n    \r\n    DrawSync(0);\r\n    VSync(0);\r\n\r\n    PutDispEnv(&disp[db]);\r\n    PutDrawEnv(&draw[db]);\r\n\r\n    DrawOTag(&ot[db][OTLEN - 1]);\r\n    \r\n    db = !db;\r\n\r\n    nextpri = primbuff[db];\r\n    \r\n        \r\n    }\r\n\r\nvoid LoadTexture(u_long * tim, TIM_IMAGE * tparam){     // This part is from Lameguy64's tutorial series : lameguy64.net/svn/pstutorials/chapter1/3-textures.html login/pw: annoyingmous\r\n        OpenTIM(tim);                                   // Open the tim binary data, feed it the address of the data in memory\r\n        ReadTIM(tparam);                                // This read the header of the TIM data and sets the corresponding members of the TIM_IMAGE structure\r\n        \r\n        LoadImage(tparam->prect, tparam->paddr);        // Transfer the data from memory to VRAM at position prect.x, prect.y\r\n        DrawSync(0);                                    // Wait for the drawing to end\r\n        \r\n        if (tparam->mode & 0x8){ // check 4th bit       // If 4th bit == 1, TIM has a CLUT\r\n            LoadImage(tparam->crect, tparam->caddr);    // Load it to VRAM at position crect.x, crect.y\r\n            DrawSync(0);                                // Wait for drawing to end\r\n    }\r\n\r\n}\r\n\r\nint main() {\r\n        \r\n    int     i;\r\n    int     PadStatus;\r\n    int     TPressed=0;\r\n    int     AutoRotate=1;\r\n    \r\n    long    t, p, OTz, Flag;                // t == vertex count, p == depth cueing interpolation value, OTz ==  value to create Z-ordered OT, Flag == see LibOver47.pdf, p.143\r\n    \r\n    POLY_GT3 *poly = {0};                           // pointer to a POLY_G4 \r\n\r\n    \r\n    SVECTOR Rotate={ 0 };                   // Rotation coordinates\r\n    VECTOR  Trans={ 0, 0, CENTERX, 0 };     // Translation coordinates\r\n                                            // Scaling coordinates\r\n    VECTOR  Scale={ ONE, ONE, ONE, 0 };     // ONE == 4096\r\n    MATRIX  Matrix={0};                     // Matrix data for the GTE\r\n    \r\n    // Texture window\r\n    \r\n    DR_MODE * dr_mode;                        // Pointer to dr_mode prim\r\n    \r\n    RECT tws = {0, 0, 32, 32};            // Texture window coordinates : x, y, w, h\r\n                \r\n    init();\r\n    \r\n    LoadTexture(_binary____TIM_cubetex_tim_start, &tim_cube);\r\n    \r\n    // Main loop\r\n    while (1) {\r\n    \r\n        // Read pad status\r\n        PadStatus = PadRead(0);\r\n        \r\n        if (AutoRotate == 0) {\r\n        \r\n            if (PadStatus & PADL1) Trans.vz -= 4;\r\n            if (PadStatus & PADR1) Trans.vz += 4;\r\n            if (PadStatus & PADL2) Rotate.vz -= 8;\r\n            if (PadStatus & PADR2) Rotate.vz += 8;\r\n\r\n            if (PadStatus & PADLup)     Rotate.vx -= 8;\r\n            if (PadStatus & PADLdown)   Rotate.vx += 8;\r\n            if (PadStatus & PADLleft)   Rotate.vy -= 8;\r\n            if (PadStatus & PADLright)  Rotate.vy += 8;\r\n            \r\n            if (PadStatus & PADRup)     Trans.vy -= 2;\r\n            if (PadStatus & PADRdown)   Trans.vy += 2;\r\n            if (PadStatus & PADRleft)   Trans.vx -= 2;\r\n            if (PadStatus & PADRright)  Trans.vx += 2;\r\n                    \r\n            if (PadStatus & PADselect) {\r\n                Rotate.vx = Rotate.vy = Rotate.vz = 0;\r\n                Scale.vx = Scale.vy = Scale.vz = ONE;\r\n                Trans.vx = Trans.vy = 0;\r\n                Trans.vz = CENTERX;\r\n            }\r\n            \r\n        }\r\n        \r\n        if (PadStatus & PADstart) {\r\n            if (TPressed == 0) {\r\n                AutoRotate = (AutoRotate + 1) & 1;\r\n                Rotate.vx = Rotate.vy = Rotate.vz = 0;\r\n                Scale.vx = Scale.vy = Scale.vz = ONE;\r\n                Trans.vx = Trans.vy = 0;\r\n                Trans.vz = CENTERX;\r\n            }\r\n            TPressed = 1;\r\n        } else {\r\n            TPressed = 0;\r\n        }\r\n\r\n        if (AutoRotate) {\r\n            Rotate.vy += 8; // Pan\r\n            Rotate.vx += 8; // Tilt\r\n            //~ Rotate.vz += 8; // Roll\r\n        }\r\n        \r\n        \r\n        // Clear the current OT\r\n        ClearOTagR(ot[db], OTLEN);\r\n        \r\n        // Convert and set the matrixes\r\n        RotMatrix(&Rotate, &Matrix);\r\n        TransMatrix(&Matrix, &Trans);\r\n        ScaleMatrix(&Matrix, &Scale);\r\n        \r\n        SetRotMatrix(&Matrix);\r\n        SetTransMatrix(&Matrix);\r\n        \r\n        \r\n        // Render the sample vector model\r\n        t=0;\r\n        \r\n        // modelCube is a TMESH, len member == # vertices, but here it's # of triangle... So, for each tri * 3 vertices ...\r\n        for (i = 0; i < (modelCube.len*3); i += 3) {               \r\n            \r\n            poly = (POLY_GT3 *)nextpri;\r\n            \r\n            // Initialize the primitive and set its color values\r\n            \r\n            SetPolyGT3(poly);\r\n\r\n            ((POLY_GT3 *)poly)->tpage = getTPage(tim_cube.mode&0x3, 0,\r\n                                                 tim_cube.prect->x,\r\n                                                 tim_cube.prect->y\r\n                                                );\r\n\r\n            setRGB0(poly, modelCube.c[i].r , modelCube.c[i].g   , modelCube.c[i].b);\r\n            setRGB1(poly, modelCube.c[i+2].r, modelCube.c[i+2].g, modelCube.c[i+2].b);\r\n            setRGB2(poly, modelCube.c[i+1].r, modelCube.c[i+1].g, modelCube.c[i+1].b);\r\n\r\n            setUV3(poly, modelCube.u[i].vx, modelCube.u[i].vy,\r\n                         modelCube.u[i+2].vx, modelCube.u[i+2].vy,\r\n                         modelCube.u[i+1].vx, modelCube.u[i+1].vy);\r\n                         \r\n            // Rotate, translate, and project the vectors and output the results into a primitive\r\n\r\n            OTz  = RotTransPers(&modelCube_mesh[modelCube_index[t]]  , (long*)&poly->x0, &p, &Flag);\r\n            OTz += RotTransPers(&modelCube_mesh[modelCube_index[t+2]], (long*)&poly->x1, &p, &Flag);\r\n            OTz += RotTransPers(&modelCube_mesh[modelCube_index[t+1]], (long*)&poly->x2, &p, &Flag);\r\n            \r\n            // Sort the primitive into the OT\r\n            OTz /= 3;\r\n            if ((OTz > 0) && (OTz < OTLEN))\r\n                AddPrim(&ot[db][OTz-2], poly);\r\n            \r\n            nextpri += sizeof(POLY_GT3);\r\n            \r\n            t+=3;\r\n            \r\n        }\r\n        \r\n            dr_mode = (DR_MODE *)nextpri;\r\n            \r\n            setDrawMode(dr_mode,1,0, getTPage(tim_cube.mode&0x3, 0,\r\n                                              tim_cube.prect->x,\r\n                                              tim_cube.prect->y), &tws);  //set texture window\r\n        \r\n            AddPrim(&ot[db], dr_mode);\r\n            \r\n            nextpri += sizeof(DR_MODE);\r\n        \r\n\r\n        FntPrint(\"Hello textured cube!\\n\");\r\n    \r\n        \r\n        FntFlush(-1);\r\n        \r\n        display();\r\n\r\n    }\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "hello_cubetex_stp/Makefile",
    "content": "TARGET = hello_cubetex_stp\n\nSRCS = hello_cubetex_stp.c \\\nTIM/stpOnBlack.tim \\\nTIM/stpOnNonBlack.tim \\\nTIM/stpOn8bpp.tim \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_cubetex_stp/README.md",
    "content": "![Hello_stp](https://wiki.arthus.net/assets/hello_cubetex_stp.png)\n\n# STP : Semi-Transparency usage\n\nThis example shows the effect of activating Semi-Transparency on a textured primitive.\n\nUse the `SELECT` button to switch primitive semi-transparency on and off.  \nUse the `START` button to cycle throught the 4 transparency rates.\n\nIt also features a few C struct to facilitate access to the TIM file / pixel data.\n\nSee [https://github.com/ABelliqueux/nolibgs_hello_worlds/tree/main/hello_poly_stp](https://github.com/ABelliqueux/nolibgs_hello_worlds/tree/main/hello_poly_stp) for more information on how to convert your images to TIM while preserving transparency.\n\nSee [https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/TIM#transparency](https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/TIM#transparency) for mor details on transparency.  \n\n## Documentation \n\nhttp://psx.arthus.net/sdk/Psy-Q/DOCS/LibOver47.pdf, p.107  \nhttp://psx.arthus.net/sdk/Psy-Q/DOCS/FileFormat47.pdf, p.181  \nhttp://psx.arthus.net/sdk/Psy-Q/DOCS/LibRef47.pdf, p.306, 345, 365  \n"
  },
  {
    "path": "hello_cubetex_stp/cubetex.c",
    "content": "SVECTOR modelCube_mesh[] = {\n    {48,48,-48.0},\n    {48,-48,-48},\n    {-48,-48,-48},\n    {-48,48,-48},\n    {48,48,48},\n    {48,-48,48},\n    {-48,-48,48},\n    {-48,48,48}\n};\n\nSVECTOR modelCube_normal[] = {\n    0,-0,-1,0,\n    0,0,1,0,\n    1,0,-2,0,\n    -9,-1,-3,0,\n    -1,2,-1,0,\n    3,1,2,0,\n    0,0,-1,0,\n    0,-0,1,0,\n    1,-6,3,0,\n    -5,-1,9,0,\n    -1,2,-1,0,\n    2,1,2,0\n};\n\nSVECTOR modelCube_uv[] = {\n    84,84, 0, 0,\n    125,42, 0, 0,\n    84,42, 0, 0,\n    125,84, 0, 0,\n    84,125, 0, 0,\n    125,125, 0, 0,\n    1,84, 0, 0,\n    42,125, 0, 0,\n    42,84, 0, 0,\n    42,125, 0, 0,\n    84,84, 0, 0,\n    42,84, 0, 0,\n    42,1, 0, 0,\n    1,42, 0, 0,\n    42,42, 0, 0,\n    42,84, 0, 0,\n    1,42, 0, 0,\n    1,84, 0, 0,\n    84,84, 0, 0,\n    125,84, 0, 0,\n    125,42, 0, 0,\n    125,84, 0, 0,\n    84,84, 0, 0,\n    84,125, 0, 0,\n    1,84, 0, 0,\n    1,125, 0, 0,\n    42,125, 0, 0,\n    42,125, 0, 0,\n    84,125, 0, 0,\n    84,84, 0, 0,\n    42,1, 0, 0,\n    1,1, 0, 0,\n    1,42, 0, 0,\n    42,84, 0, 0,\n    42,42, 0, 0,\n    1,42, 0, 0\n};\n\nCVECTOR modelCube_color[] = {\n    255,255,255, 0,\n    255,255,255, 0,\n    255,0,251, 0,\n    255,255,255, 0,\n    255,5,7, 0,\n    255,255,255, 0,\n    255,255,255, 0,\n    255,255,255, 0,\n    4,18,255, 0,\n    255,5,7, 0,\n    255,255,255, 0,\n    255,255,255, 0,\n    254,255,23, 0,\n    122,255,107, 0,\n    255,255,255, 0,\n    255,255,255, 0,\n    255,255,255, 0,\n    254,255,94, 0,\n    255,255,255, 0,\n    35,255,11, 0,\n    255,255,255, 0,\n    255,255,255, 0,\n    255,255,255, 0,\n    255,5,7, 0,\n    255,255,255, 0,\n    255,5,7, 0,\n    255,255,255, 0,\n    255,5,7, 0,\n    255,255,255, 0,\n    255,255,255, 0,\n    254,255,23, 0,\n    255,255,255, 0,\n    122,255,107, 0,\n    255,255,255, 0,\n    54,65,255, 0,\n    255,255,255, 0\n};\n\nint modelCube_index[] = {\n    0,2,3,\n    7,5,4,\n    4,1,0,\n    5,2,1,\n    2,7,3,\n    0,7,4,\n    0,1,2,\n    7,6,5,\n    4,5,1,\n    5,6,2,\n    2,6,7,\n    0,3,7\n};\n\nTMESH modelCube = {\n    modelCube_mesh,\n    modelCube_normal,\n    modelCube_uv,\n    modelCube_color,\n    12\n};\n\ntypedef struct RGB_PIX {\n    u_int  R:5, G:5, B:5, STP:1;\n    } RGB_PIX;\n    \n// Some structures to handle TIM files \ntypedef struct PIXEL {\n    u_long bnum;\n    u_short DX, DY;\n    u_short W, H;\n    RGB_PIX data[]; \n} PIXEL;\n\ntypedef struct CLUT {\n    u_long bnum;\n    u_short DX, DY;\n    u_short W, H;\n    u_short clut[]; \n} CLUT;\n\ntypedef struct TIM_FILE_CLUT{\n    u_long ID;\n    u_long flag;\n    u_long clut;\n    PIXEL pixel[];\n} TIM_FILE_CLUT;\n\ntypedef struct TIM_FILE{\n    u_long ID;\n    u_long flag;\n    PIXEL pixel[];\n} TIM_FILE;\n\nextern TIM_FILE _binary_TIM_stpOnBlack_tim_start;\nextern TIM_FILE _binary_TIM_stpOnNonBlack_tim_start;\nextern TIM_FILE _binary_TIM_stpOn8bpp_tim_start;\n"
  },
  {
    "path": "hello_cubetex_stp/hello_cubetex_stp.c",
    "content": "// Demo the different settings and rates for pixel and primitive semi-transparency on a cube\r\n// Controls :\r\n//             SELECT : Switch semi-transparency on/off on primitives\r\n//             START : Cycle semi-transparency rates on/off on primitives\r\n// Schnappy 07-2021\r\n#include <sys/types.h>\r\n#include <libgte.h>\r\n#include <libgpu.h>\r\n#include <libetc.h>\r\n#include <libapi.h>\r\n//~ #include <stdio.h>\r\n// Sample vector model\r\n#include \"cubetex.c\"\r\n#define VMODE       0\r\n// Number of primitives to draw\r\n#define NUM_PRIM 3\r\n#define SCREENXRES 320\r\n#define SCREENYRES 240\r\n#define CENTERX     SCREENXRES/2\r\n#define CENTERY     SCREENYRES/2\r\n#define MARGINX 16               // margins for text display\r\n#define MARGINY 16\r\n#define OTLEN       2048        // Maximum number of OT entries\r\n#define PRIMBUFFLEN 32768       // Maximum number of POLY_GT3 primitives\r\n// Display and draw environments, double buffered\r\nDISPENV disp[2];\r\nDRAWENV draw[2];\r\nu_long ot[2][OTLEN];                   // Ordering table (contains addresses to primitives)\r\nchar primbuff[2][PRIMBUFFLEN]; // Primitive list // That's our prim buffer\r\nchar * nextpri = primbuff[0];                       // Primitive counter\r\nshort db  = 0;                        // Current buffer counter\r\n// Store TIM files in an array so we can iterate over them - see 'cubetex.c' for TIM_FILE struct and declaration\r\nTIM_FILE * timFiles[3];\r\nTIM_IMAGE timImages[3];\r\n// Prototypes\r\nvoid init(void);\r\nvoid display(void);\r\nvoid LoadTexture(TIM_FILE * tim, TIM_IMAGE * tparam);\r\nvoid init(){\r\n    // Reset the GPU before doing anything and the controller\r\n    PadInit(0);\r\n    ResetGraph(0);\r\n    // Initialize and setup the GTE\r\n    InitGeom();\r\n    SetGeomOffset(CENTERX, CENTERY);        // x, y offset\r\n    SetGeomScreen(CENTERX);                 // Distance between eye and screen  \r\n    // Set the display and draw environments\r\n    SetDefDispEnv(&disp[0], 0, 0         , SCREENXRES, SCREENYRES);\r\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\r\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\r\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\r\n    if (VMODE)\r\n    {\r\n        SetVideoMode(MODE_PAL);\r\n        disp[0].screen.y += 8;\r\n        disp[1].screen.y += 8;\r\n    }\r\n    SetDispMask(1);\r\n    setRGB0(&draw[0], 0, 0, 255);\r\n    setRGB0(&draw[1], 0, 0, 255);\r\n    draw[0].isbg = 1;\r\n    draw[1].isbg = 1;\r\n    PutDispEnv(&disp[db]);\r\n    PutDrawEnv(&draw[db]);\r\n    // Init font system\r\n    FntLoad(960, 0);\r\n    FntOpen(MARGINX, MARGINY, SCREENXRES - MARGINX * 2, SCREENXRES - MARGINY * 2, 0, 512 );\r\n}\r\nvoid display(void){\r\n    DrawSync(0);\r\n    VSync(0);\r\n    PutDispEnv(&disp[db]);\r\n    PutDrawEnv(&draw[db]);\r\n    DrawOTag(&ot[db][OTLEN - 1]);\r\n    db = !db;\r\n    nextpri = primbuff[db];\r\n    }\r\nvoid LoadTexture(TIM_FILE * tim, TIM_IMAGE * tparam){     // This part is from Lameguy64's tutorial series : lameguy64.net/svn/pstutorials/chapter1/3-textures.html login/pw: annoyingmous\r\n        OpenTIM((u_long*)tim);                                   // Open the tim binary data, feed it the address of the data in memory\r\n        ReadTIM(tparam);                                // This read the header of the TIM data and sets the corresponding members of the TIM_IMAGE structure\r\n        LoadImage(tparam->prect, tparam->paddr);        // Transfer the data from memory to VRAM at position prect.x, prect.y\r\n        DrawSync(0);                                    // Wait for the drawing to end\r\n        if (tparam->mode & 0x8){ // check 4th bit       // If 4th bit == 1, TIM has a CLUT\r\n            LoadImage(tparam->crect, tparam->caddr);    // Load it to VRAM at position crect.x, crect.y\r\n            DrawSync(0);                                // Wait for drawing to end\r\n    }\r\n}\r\nint main() {\r\n    // Populate array with pointers to TIM data\r\n    timFiles[0] = &_binary_TIM_stpOnBlack_tim_start;\r\n    timFiles[1] = &_binary_TIM_stpOnNonBlack_tim_start;\r\n    timFiles[2] = &_binary_TIM_stpOn8bpp_tim_start;\r\n    // Pad values\r\n    int pad, oldPad;\r\n    // Set semi-transparency on (1) and off (0)\r\n    int stpFlag = 0;\r\n    // Set primitive semi-transparency rate - See LibOver47.pdf, p.107\r\n    int stpRate = 0;\r\n    // If set, rotate cube\r\n    int rotateCube = 1;\r\n    // Array of pointers to a POLY_G4 we iterate over\r\n    POLY_GT3 * poly[NUM_PRIM];                           \r\n     // Rotation vector\r\n    SVECTOR rotVector={ 496, 0, 0, 0 };\r\n    // Translation vector\r\n    VECTOR transVector= { -SCREENXRES/NUM_PRIM, -SCREENYRES/NUM_PRIM, SCREENXRES, 0};\r\n    // Init Disp/Drawenv, Font, etc.\r\n    init();\r\n    // Load textures to VRAM\r\n    for (char tim = 0; tim < NUM_PRIM; tim++){\r\n        LoadTexture(timFiles[tim], &timImages[tim]);\r\n    }\r\n    // Main loop\r\n    while (1) {\r\n        // Work matrix\r\n        MATRIX  Work= {0} ;\r\n        // Triangle counters array - one for each cube\r\n        long curTriangle[3] = {0,0,0}; \r\n        // Clear the current OT\r\n        ClearOTagR(ot[db], OTLEN);\r\n        // Rotate cube\r\n        if(rotateCube) rotVector.vy += 10;\r\n        // Apply Transl, Rot, then matrix\r\n        RotMatrix(&rotVector, &Work);\r\n        TransMatrix(&Work, &transVector);\r\n        SetRotMatrix(&Work);\r\n        SetTransMatrix(&Work);\r\n        \r\n        // Draw NUM_PRIM primitives\r\n        for (int prim = 0; prim < NUM_PRIM; prim++){\r\n            // Draw prims with an offset based on iteration number\r\n            // A bit messy but the cubes are drawn where we want them :)\r\n            transVector.vx = ( SCREENXRES/NUM_PRIM + ( prim * (SCREENXRES/NUM_PRIM + 48) )) - SCREENXRES + 56 ;\r\n            transVector.vy = SCREENYRES/NUM_PRIM - SCREENYRES + 86;\r\n            // Add vertical offset to second cube\r\n            if ( prim == 1) { \r\n                transVector.vy = SCREENYRES/NUM_PRIM + 48;\r\n            } \r\n            // Apply transl matrix\r\n            TransMatrix(&Work, &transVector);         \r\n            SetTransMatrix(&Work);\r\n            \r\n            // modelCube is a TMESH, len member == # vertices, but here it's # of triangle... So, for each tri * 3 vertices ...\r\n            for (int i = 0; i < (modelCube.len * 3); i += 3) {\r\n                // t == vertex count, p == depth cueing interpolation value, OTz ==  value to create Z-ordered OT, Flag == see LibOver47.pdf, p.143 \r\n                long p, OTz, Flag;\r\n                // cast nextpri as POLY_GT3\r\n                poly[prim] = (POLY_GT3 *)nextpri;\r\n                // Initialize the primitive and set its color values\r\n                SetPolyGT3(poly[prim]);\r\n                // Get TPAGE\r\n                poly[prim]->tpage = getTPage( timImages[prim].mode&0x3, stpRate,\r\n                                              timImages[prim].prect->x,\r\n                                              timImages[prim].prect->y\r\n                                              );\r\n                // Set RGB colors for each vertex\r\n                setRGB0(poly[prim] , modelCube.c[i].r , modelCube.c[i].g   , modelCube.c[i].b);\r\n                setRGB1(poly[prim], modelCube.c[i+2].r, modelCube.c[i+2].g, modelCube.c[i+2].b);\r\n                setRGB2(poly[prim], modelCube.c[i+1].r, modelCube.c[i+1].g, modelCube.c[i+1].b);\r\n                // If 8/4bpp, load CLUT to vram\r\n                if ( (timImages[prim].mode & 0x3) < 2 ) {\r\n                    setClut( poly[prim],          \r\n                             timImages[prim].crect->x,\r\n                             timImages[prim].crect->y\r\n                    );\r\n                }\r\n                // Set stpFlag\r\n                SetSemiTrans(poly[prim], stpFlag);\r\n                // Set UV coordinates\r\n                setUV3(poly[prim], modelCube.u[i].vx, modelCube.u[i].vy,\r\n                                   modelCube.u[i+2].vx, modelCube.u[i+2].vy,\r\n                                   modelCube.u[i+1].vx, modelCube.u[i+1].vy);\r\n                // Rotate, translate, and project the vectors and output the results into a primitive\r\n                // curTriangle, +1, +2 point to the vertices index of the triangle we're drawing.\r\n                OTz  = RotTransPers(&modelCube_mesh[ modelCube_index[ curTriangle[prim] ] ]  , ( long * ) &poly[prim]->x0, &p, &Flag);\r\n                OTz += RotTransPers(&modelCube_mesh[ modelCube_index[ curTriangle[prim] + 2] ], ( long*) &poly[prim]->x1, &p, &Flag);\r\n                OTz += RotTransPers(&modelCube_mesh[ modelCube_index[ curTriangle[prim] + 1] ], ( long * ) &poly[prim]->x2, &p, &Flag);\r\n                // Average OTz value for 3 vertices\r\n                // OTz is 1/4 of screen to vertex length\r\n                OTz /= 3;\r\n                // If OTz is in range (not to close) \r\n                if ((OTz > 0) && (OTz < OTLEN))\r\n                    // Add to ordering table, at index OTz-2 \r\n                    AddPrim(&ot[ db ][ OTz-2 ], poly[prim]);\r\n                // Increment next primitive address\r\n                nextpri += sizeof(POLY_GT3);\r\n                // Increment to next triangle\r\n                curTriangle[prim] += 3;\r\n            }\r\n        }\r\n        // Get pad input\r\n        pad = PadRead(0); \r\n        // If select button is used\r\n        if ( pad & PADselect && !(oldPad & PADselect) ){\r\n            // Flip STP flag\r\n            stpFlag = !stpFlag;\r\n            // Set flag to avoir misfire\r\n            oldPad = pad;\r\n        } \r\n        // Reset flag when button released\r\n        if ( !(pad & PADselect) && oldPad & PADselect) {\r\n            oldPad = pad;\r\n        }\r\n        // If start button is used\r\n        if ( pad & PADstart && !( oldPad & PADstart ) ){\r\n            // Switch STP rates \r\n            stpRate > 2 ? stpRate = 0 : stpRate++;\r\n            // Set flag to avoir misfire\r\n            oldPad = pad;\r\n        } \r\n        // Reset flag when button released\r\n        if (!(pad & PADstart) && oldPad & PADstart) {\r\n            oldPad = pad;\r\n        }\r\n        FntPrint(\"Hello semi-transparency  !\\nPrim STP (push Select) : %d\\nSTP rate (push start): %d\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\", stpFlag, stpRate);                   \r\n        FntPrint(\"    stp on black    stp on col index\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\");                   \r\n        FntPrint(\"          stp on non-black\");   \r\n        FntFlush(-1);\r\n        display();\r\n    }\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "hello_font/Makefile",
    "content": "TARGET = hello_font\n\nSRCS = hello_font.c \\\nfnt.tim \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_font/README.md",
    "content": "See the **wiki** for more details : [https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/FONT](https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/FONT)  "
  },
  {
    "path": "hello_font/hello_font.c",
    "content": "// Change the debug font face and colors !\n// Schnappy 2020\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n#define VMODE 0                 // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320          // Screen width\n#define SCREENYRES 240          // Screen height\n#define CENTERX SCREENXRES/2    // Center of screen on x \n#define CENTERY SCREENYRES/2    // Center of screen on y\n#define MARGINX 96                // margins for text display\n#define MARGINY 64\n#define FONTSIZE 8 * 7           // Text Field Height\nDISPENV disp[2];                 // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nshort db = 0;                      // index of which buffer is used, values 0, 1\n#define FONTX   960\n#define FONTY   0\n// Two color vectors R,G,B\nCVECTOR fntColor = { 255, 0, 0 };\nCVECTOR fntColorBG = { 0, 0, 0 };\n\nextern unsigned long _binary_fnt_tim_start[];\nextern unsigned long _binary_fnt_tim_end[];\nextern unsigned long _binary_fnt_tim_length;\n\n// Loading an image to vram. See https://github.com/ABelliqueux/nolibgs_hello_worlds/blob/main/hello_sprt/hello_sprt.c#L42\nTIM_IMAGE fontface;\nvoid LoadTexture(u_long * tim, TIM_IMAGE * tparam){     \n        OpenTIM(tim);                                   \n        ReadTIM(tparam);                                \n        LoadImage(tparam->prect, tparam->paddr);        \n        DrawSync(0);                                    \n        if (tparam->mode & 0x8){ // check 4th bit       \n            LoadImage(tparam->crect, tparam->caddr);    \n            DrawSync(0);                                \n    }\n}\n\nvoid FntColor(CVECTOR fgcol, CVECTOR bgcol )\n{\n    // The debug font clut is at tx, ty + 128\n    // tx = bg color\n    // tx + 1 = fg color\n    // We can override the color by drawing a rect at these coordinates\n    // \n    // Define 1 pixel at 960,128 (background color) and 1 pixel at 961, 128 (foreground color)\n    RECT fg = { FONTX+1, FONTY + 128, 1, 1 };\n    RECT bg = { FONTX, FONTY + 128, 1, 1 };\n    // Set colors\n    ClearImage(&fg, fgcol.r, fgcol.g, fgcol.b);\n    ClearImage(&bg, bgcol.r, bgcol.g, bgcol.b);\n}\n\nvoid init(void)\n{\n    ResetGraph(0);                 // Initialize drawing engine with a complete reset (0)\n    SetDefDispEnv(&disp[0], 0, 0         , SCREENXRES, SCREENYRES);     // Set display area for both &disp[0] and &disp[1]\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // &disp[0] is on top  of &disp[1]\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // Set draw for both &draw[0] and &draw[1]\n    SetDefDrawEnv(&draw[1], 0, 0         , SCREENXRES, SCREENYRES);     // &draw[0] is below &draw[1]\n    if (VMODE)                  // PAL\n    {\n        SetVideoMode(MODE_PAL);\n        disp[0].screen.y += 8;  // add offset : 240 + 8 + 8 = 256\n        disp[1].screen.y += 8;\n        }\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 50, 50, 50); // set color for first draw area\n    setRGB0(&draw[1], 50, 50, 50); // set color for second draw area\n    draw[0].isbg = 1;               // set mask for draw areas. 1 means repainting the area with the RGB color each frame \n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);          // set the disp and draw environnments\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);                // Load font to vram at 960,0(+128)\n    FntOpen(MARGINX, MARGINY, SCREENXRES, SCREENXRES, 0, 280 ); // FntOpen(x, y, width, height,  black_bg, max. nbr. chars\n\n}\nvoid display(void)\n{\n    DrawSync(0);                    // Wait for all drawing to terminate\n    VSync(0);                       // Wait for the next vertical blank\n    PutDispEnv(&disp[db]);          // set alternate disp and draw environnments\n    PutDrawEnv(&draw[db]);  \n    db = !db;                       // flip db value (0 or 1)\n}\nint main(void)\n{\n    u_int t = 0;\n    u_short step = 10;\n    u_char * channel, * prevChannel;\n    channel = &fntColor.r;\n    prevChannel = &fntColor.b;\n    init();                         // execute init()\n    LoadTexture(_binary_fnt_tim_start, &fontface);\n    FntColor(fntColor, fntColorBG);\n    while (1)                       // infinite loop\n    {   \n        \n        t++;\n                \n        if (fntColor.r >= 254 - step ){channel = &fntColor.g; prevChannel = &fntColor.r;}\n        if (fntColor.g >= 254 - step ){channel = &fntColor.b; prevChannel = &fntColor.g;}\n        if (fntColor.b >= 254 - step ){channel = &fntColor.r; prevChannel = &fntColor.b;}\n            \n        *channel += step;\n        \n        if (*prevChannel){\n            *prevChannel -= step;\n        }\n        //~ fntColorBG.g = 255 - color ;\n        FntColor(fntColor, fntColorBG);\n        // 4lines, 16 glyphs on each line\n        // Glyphs are 5x7 pixels wide in 16bpp, \n        FntPrint(\"!\\\"#$%%&'()*+,-./\\n\");\n        FntPrint(\"0123456789:;<=^?\\n\");\n        FntPrint(\"@ABCDEFGHIJKLMNO\\n\");\n        FntPrint(\"PQRSTUVWXYZ[\\\\]>\");\n\n        FntPrint(\"\\n\\nHELLO DEBUG FONT! %d\", t);\n                                             \n        FntFlush(-1);               // Draw print stream\n        display();                  // Execute display()\n    }\n    return 0;\n    }\n"
  },
  {
    "path": "hello_fx/Makefile",
    "content": "TARGET = hello_fx\n\nSRCS = hello_fx.c \\\nTIM/cube.tim \\\nTIM/sky.tim \\\nTIM/bg.tim \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_fx/cubetex.c",
    "content": "SVECTOR modelCube_mesh[] = {\n    {48,48,-48.0},\n    {48,-48,-48},\n    {-48,-48,-48},\n    {-48,48,-48},\n    {48,48,48},\n    {48,-48,48},\n    {-48,-48,48},\n    {-48,48,48}\n};\n\nSVECTOR modelCube_normal[] = {\n    0,-0,-1,0,\n    0,0,1,0,\n    1,0,-2,0,\n    -9,-1,-3,0,\n    -1,2,-1,0,\n    3,1,2,0,\n    0,0,-1,0,\n    0,-0,1,0,\n    1,-6,3,0,\n    -5,-1,9,0,\n    -1,2,-1,0,\n    2,1,2,0\n};\n\nSVECTOR modelCube_uv[] = {\n    84,84, 0, 0,\n    125,42, 0, 0,\n    84,42, 0, 0,\n    125,84, 0, 0,\n    84,125, 0, 0,\n    125,125, 0, 0,\n    1,84, 0, 0,\n    42,125, 0, 0,\n    42,84, 0, 0,\n    42,125, 0, 0,\n    84,84, 0, 0,\n    42,84, 0, 0,\n    42,1, 0, 0,\n    1,42, 0, 0,\n    42,42, 0, 0,\n    42,84, 0, 0,\n    1,42, 0, 0,\n    1,84, 0, 0,\n    84,84, 0, 0,\n    125,84, 0, 0,\n    125,42, 0, 0,\n    125,84, 0, 0,\n    84,84, 0, 0,\n    84,125, 0, 0,\n    1,84, 0, 0,\n    1,125, 0, 0,\n    42,125, 0, 0,\n    42,125, 0, 0,\n    84,125, 0, 0,\n    84,84, 0, 0,\n    42,1, 0, 0,\n    1,1, 0, 0,\n    1,42, 0, 0,\n    42,84, 0, 0,\n    42,42, 0, 0,\n    1,42, 0, 0\n};\n\nCVECTOR modelCube_color[] = {\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0,\n    128,128,128, 0\n};\n\nint modelCube_index[] = {\n    0,2,3,\n    7,5,4,\n    4,1,0,\n    5,2,1,\n    2,7,3,\n    0,7,4,\n    0,1,2,\n    7,6,5,\n    4,5,1,\n    5,6,2,\n    2,6,7,\n    0,3,7\n};\n\nTMESH modelCube = {\n    modelCube_mesh,\n    modelCube_normal,\n    modelCube_uv,\n    modelCube_color,\n    12\n};\n\ntypedef struct RGB_PIX {\n    u_int  R:5, G:5, B:5, STP:1;\n    } RGB_PIX;\n    \n// Some structures to handle TIM files \ntypedef struct PIXEL {\n    u_long bnum;\n    u_short DX, DY;\n    u_short W, H;\n    RGB_PIX data[]; \n} PIXEL;\n\ntypedef struct CLUT {\n    u_long bnum;\n    u_short DX, DY;\n    u_short W, H;\n    u_short clut[]; \n} CLUT;\n\ntypedef struct TIM_FILE_CLUT{\n    u_long ID;\n    u_long flag;\n    u_long clut;\n    PIXEL pixel[];\n} TIM_FILE_CLUT;\n\ntypedef struct TIM_FILE{\n    u_long ID;\n    u_long flag;\n    PIXEL pixel[];\n} TIM_FILE;\n"
  },
  {
    "path": "hello_fx/hello_fx.c",
    "content": "// Controls :\r\n//             SELECT : Switch semi-transparency on/off on primitives\r\n//             START : Cycle semi-transparency rates on/off on primitives\r\n//             LEFT/RIGHT: Move forward cube\r\n//             X : Reset Cube position\r\n// Schnappy 11-2021\r\n#include <sys/types.h>\r\n#include <libgte.h>\r\n#include <libgpu.h>\r\n#include <libetc.h>\r\n#include <libapi.h>\r\n#include <inline_n.h>\r\n#include <gtemac.h>\r\n// Sample vector model\r\n#include \"cubetex.c\"\r\n#define VMODE       0\r\n// Number of primitives to draw\r\n#define NUM_PRIM 2\r\n// Number of textures to load\r\n#define NUM_TEX 3\r\n#define SCREENXRES 320\r\n#define SCREENYRES 240\r\n#define CENTERX     SCREENXRES/2\r\n#define CENTERY     SCREENYRES/2\r\n#define MARGINX 16               // margins for text display\r\n#define MARGINY 16\r\n#define OTLEN       2048        // Maximum number of OT entries\r\n#define PRIMBUFFLEN 32768       // Maximum number of POLY_GT3 primitives\r\n// Display and draw environments, double buffered\r\nDISPENV disp[2];\r\nDRAWENV draw[2];\r\nu_long ot[2][OTLEN];                   // Ordering table (contains addresses to primitives)\r\nchar primbuff[2][PRIMBUFFLEN]; // Primitive list // That's our prim buffer\r\nchar * nextpri = primbuff[0];                       // Primitive counter\r\nshort db  = 0;                        // Current buffer counter\r\n// Store TIM files in an array so we can iterate over them - see 'cubetex.c' for TIM_FILE struct and declaration\r\nTIM_FILE * timFiles[3];\r\nTIM_IMAGE timImages[3];\r\n// Get included tim files address\r\nextern TIM_FILE _binary_TIM_cube_tim_start;\r\nextern TIM_FILE _binary_TIM_sky_tim_start;\r\nextern TIM_FILE _binary_TIM_bg_tim_start;\r\n// Light\r\nCVECTOR BGc = {130, 200, 255, 0};  \r\n// Back color  \r\nVECTOR  BKc = {128, 128, 128, 0};\r\n// Light rotation angle\r\nSVECTOR lgtang = {0, 0, 0}; \r\n// These will be used to store the light rotation matrix, cube rotation matrix, and composite light matrix.\r\nMATRIX  rotlgt, rotcube, light;\r\n// Local Light Matrix : Direction and reach of each light source. \r\nMATRIX lgtmat = {\r\n//      X      Y      Z\r\n        0,  -ONE,   0, // Lightsource 1 : here, the light source is at the Bottom-Left of the screen, and points into the screen.\r\n        0,     0,     0, // Lightsource 2\r\n        0,     0,     0, // Lightsource 3\r\n    };\r\n// Local Color Matrix\r\nMATRIX cmat = {\r\n//   L1    L2   L3\r\n    4096,   0,   0, // R\r\n    4096,   0,   0, // G\r\n    4096,   0,   0  // B\r\n    };\r\n\r\n// Prototypes\r\nvoid init(void);\r\nvoid display(void);\r\nvoid LoadTexture(TIM_FILE * tim, TIM_IMAGE * tparam);\r\nvoid init(){\r\n    // Reset the GPU before doing anything and the controller\r\n    PadInit(0);\r\n    ResetGraph(0);\r\n    // Initialize and setup the GTE\r\n    InitGeom();\r\n    SetGeomOffset(CENTERX, CENTERY);        // x, y offset\r\n    SetGeomScreen(CENTERX);                 // Distance between eye and screen  \r\n    // Set the display and draw environments\r\n    SetDefDispEnv(&disp[0], 0, 0         , SCREENXRES, SCREENYRES);\r\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\r\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\r\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\r\n    if (VMODE)\r\n    {\r\n        SetVideoMode(MODE_PAL);\r\n        disp[0].screen.y += 8;\r\n        disp[1].screen.y += 8;\r\n    }\r\n    SetDispMask(1);\r\n    // Set far color\r\n    SetFarColor( BGc.r, BGc.g, BGc.b );\r\n    // Set Ambient color\r\n    SetBackColor( BKc.vx, BKc.vy, BKc.vz );\r\n    // Set Color matrix\r\n    SetColorMatrix(&cmat);\r\n    // Set Fog settings\r\n    SetFogNearFar( 128, 1024, CENTERX );\r\n    setRGB0(&draw[0], 0, 0, 0);\r\n    setRGB0(&draw[1], 0, 0, 0);\r\n    draw[0].isbg = 1;\r\n    draw[1].isbg = 1;\r\n    PutDispEnv(&disp[db]);\r\n    PutDrawEnv(&draw[db]);\r\n    // Init font system\r\n    FntLoad(960, 0);\r\n    FntOpen(MARGINX, MARGINY, SCREENXRES - MARGINX * 2, SCREENXRES - MARGINY * 2, 0, 512 );\r\n}\r\nvoid display(void){\r\n    DrawSync(0);\r\n    VSync(0);\r\n    PutDispEnv(&disp[db]);\r\n    PutDrawEnv(&draw[db]);\r\n    DrawOTag(&ot[db][OTLEN - 1]);\r\n    db = !db;\r\n    nextpri = primbuff[db];\r\n    }\r\nvoid LoadTexture(TIM_FILE * tim, TIM_IMAGE * tparam){     // This part is from Lameguy64's tutorial series : lameguy64.net/svn/pstutorials/chapter1/3-textures.html login/pw: annoyingmous\r\n        OpenTIM((u_long*)tim);                                   // Open the tim binary data, feed it the address of the data in memory\r\n        ReadTIM(tparam);                                // This read the header of the TIM data and sets the corresponding members of the TIM_IMAGE structure\r\n        LoadImage(tparam->prect, tparam->paddr);        // Transfer the data from memory to VRAM at position prect.x, prect.y\r\n        DrawSync(0);                                    // Wait for the drawing to end\r\n        if (tparam->mode & 0x8){ // check 4th bit       // If 4th bit == 1, TIM has a CLUT\r\n            LoadImage(tparam->crect, tparam->caddr);    // Load it to VRAM at position crect.x, crect.y\r\n            DrawSync(0);                                // Wait for drawing to end\r\n    }\r\n}\r\nint main() {\r\n    // Populate array with pointers to TIM data\r\n    timFiles[0] = &_binary_TIM_cube_tim_start;\r\n    timFiles[1] = &_binary_TIM_sky_tim_start;\r\n    timFiles[2] = &_binary_TIM_bg_tim_start;\r\n    // Pad values\r\n    int pad, oldPad;\r\n    // Set semi-transparency on (1) and off (0)\r\n    int stpFlag = 1;\r\n    // Set primitive semi-transparency rate - See LibOver47.pdf, p.107\r\n    int stpRate = 0;\r\n    // If set, rotate cube\r\n    int rotateCube = 1;\r\n    int offsetCube = 0;\r\n    // Array of pointers to a POLY_G4 we iterate over\r\n    POLY_GT3 * poly[NUM_PRIM];                           \r\n     // Rotation vector\r\n    SVECTOR rotVector={ 384, 0, 128, 0 };\r\n    // Translation vector\r\n    VECTOR transVector= { 0, 0, 256, 0};\r\n    // BG sprt\r\n    POLY_FT4 * bg;\r\n    // Normalized UV coordinates for the X axis\r\n    long normH = ((255 << 12) / SCREENXRES);\r\n    \r\n    // Init Disp/Drawenv, Font, etc.\r\n    init();\r\n    // Load textures to VRAM\r\n    for (char tex = 0; tex < NUM_TEX; tex++){\r\n        LoadTexture(timFiles[tex], &timImages[tex]);\r\n    }\r\n    \r\n    // Main loop\r\n    while (1) {\r\n        // Work matrix\r\n        MATRIX  Work= {0} ;\r\n        // Triangle counters array - one for each cube\r\n        long curTriangle[3] = {0,0,0}; \r\n        // Clear the current OT\r\n        ClearOTagR(ot[db], OTLEN);\r\n        // Draw BG\r\n        bg = (POLY_FT4 * )nextpri;\r\n        SetPolyFT4(bg);\r\n        bg->tpage = getTPage( timImages[2].mode&0x3, 0,\r\n                                    timImages[2].prect->x,\r\n                                    timImages[2].prect->y\r\n                                   );\r\n        if ( (timImages[2].mode & 0x3) < 2 ) {\r\n            setClut( bg,          \r\n                     timImages[2].crect->x,\r\n                     timImages[2].crect->y\r\n            );\r\n        }\r\n        setRGB0(bg, 127,127,127);\r\n        setUV4(bg, 0, 0, \r\n                   SCREENYRES, 0,\r\n                   0, SCREENYRES,\r\n                   SCREENYRES, SCREENYRES\r\n              );\r\n        setXY4(bg, 0 , 0,\r\n                   SCREENXRES, 0,\r\n                   0 , SCREENYRES,\r\n                   SCREENXRES, SCREENYRES);\r\n        addPrim(ot[db][OTLEN-1], bg);\r\n        nextpri += sizeof(POLY_FT4);        \r\n        // Rotate cube\r\n        if(rotateCube) rotVector.vy += 10;\r\n        // Find and apply light rotation matrix\r\n        // Find rotmat from light angles\r\n        RotMatrix_gte(&lgtang, &rotlgt);\r\n        // Find rotmat from cube angles\r\n        RotMatrix_gte(&rotVector, &rotcube);  \r\n        // RotMatrix cube * RotMatrix light\r\n        MulMatrix0(&rotcube, &rotlgt, &rotlgt);\r\n        // Light Matrix * RotMatrix light \r\n        MulMatrix0(&lgtmat, &rotlgt, &light);\r\n        // Set new light matrix \r\n        SetLightMatrix(&light);\r\n        // Apply Transl, Rot, then matrix\r\n        RotMatrix(&rotVector, &Work);\r\n        TransMatrix(&Work, &transVector);\r\n        SetRotMatrix(&Work);\r\n        SetTransMatrix(&Work);\r\n        long p, OTz, Flag;\r\n        // Draw NUM_PRIM primitives\r\n        for (int i = 0; i < (modelCube.len * 3); i += 3) {\r\n            // Set projection matrices\r\n            transVector.vx = 0;\r\n            TransMatrix(&Work, &transVector);\r\n            SetRotMatrix(&Work);\r\n            SetTransMatrix(&Work);\r\n            // Cast nextpri as POLY_GT3\r\n            poly[0] = (POLY_GT3 *)nextpri;\r\n            poly[1] = (POLY_GT3 *)nextpri+sizeof(POLY_GT3);\r\n            // Initialize the primitives\r\n            SetPolyGT3(poly[0]);\r\n            SetPolyGT3(poly[1]);\r\n\r\n            // Reflection Cube\r\n            // This cube has its UVs mapped directly to VRAM coordinates\r\n            // We're using the framebuffers as a texture (0,0 and 0,256)\r\n            // Get 256x256 texture page that's at x0, y0\r\n            poly[1]->tpage = getTPage( 2, stpRate,\r\n                                      0,\r\n                                      !(db) << 8 // Here, we're using db's value that can be either 0 or 1 to determine the texture page Y coordinate.\r\n                                      );\r\n            // Set STP\r\n            SetSemiTrans(poly[1], stpFlag); \r\n            // Map coordinates from drawarea (320x240) to texture size (128x128) in fixed point math\r\n            // x = x * (256 / 320) => ( x * ( 128 * 4096 ) / 320 ) / 4096\r\n            // y = y * (240 / 240) => ( y * ( 240 * 4096 ) / 240 ) / 4096 => y * 2184 >> 12 -> y\r\n            setUV3( poly[1],  \r\n                (poly[1]->x0 * normH) >> 12,\r\n                poly[1]->y0 - (!(db) << 4) , // We're using db's value again to add a 16 pixels offset to the Y's coordinates of the UVs\r\n                (poly[1]->x1 * normH) >> 12,\r\n                poly[1]->y1 - (!(db) << 4),  // We have to do that because the buffer is 240 high, whereas our texture page is 256, hence 256 - 240 == 16\r\n                (poly[1]->x2 * normH) >> 12,\r\n                poly[1]->y2 - (!(db) << 4)\r\n            );\r\n            \r\n            // Draw \"container\" cube\r\n            // This cube has a texture with transparent areas. \r\n            // STP bit is set on PNG's alpha channel : img2tim -usealpha -org 320 0 -o cube.tim cube.png\r\n            poly[0]->tpage = getTPage( timImages[0].mode&0x3, stpRate,\r\n                                          timImages[0].prect->x,\r\n                                          timImages[0].prect->y\r\n                                          );\r\n            // If 8/4bpp, load CLUT to vram\r\n            if ( (timImages[0].mode & 0x3) < 2 ) {\r\n                setClut( poly[0],          \r\n                         timImages[0].crect->x,\r\n                         timImages[0].crect->y\r\n                );\r\n            }\r\n            // Set UV coordinates\r\n            setUV3(poly[0], modelCube.u[i].vx, modelCube.u[i].vy,\r\n                            modelCube.u[i+2].vx, modelCube.u[i+2].vy,\r\n                            modelCube.u[i+1].vx, modelCube.u[i+1].vy\r\n                    );\r\n            // Rotate, translate, and project the vectors and output the results into a primitive\r\n            // curTriangle, +1, +2 point to the vertices index of the triangle we're drawing.\r\n            OTz  = RotTransPers(&modelCube_mesh[ modelCube_index[ curTriangle[0] ] ]  , ( long * ) &poly[1]->x0, &p, &Flag);\r\n            OTz += RotTransPers(&modelCube_mesh[ modelCube_index[ curTriangle[0] + 2] ], ( long*) &poly[1]->x1, &p, &Flag);\r\n            OTz += RotTransPers(&modelCube_mesh[ modelCube_index[ curTriangle[0] + 1] ], ( long * ) &poly[1]->x2, &p, &Flag);\r\n            \r\n            // Here we're only messing with the matrices so that the foreground cube can be moved independantly from the backgound one.\r\n            // In real code, you don't want to do the same calculation twice !            \r\n            transVector.vx = offsetCube;\r\n            TransMatrix(&Work, &transVector);\r\n            SetRotMatrix(&Work);\r\n            SetTransMatrix(&Work);\r\n            \r\n            OTz  = RotTransPers(&modelCube_mesh[ modelCube_index[ curTriangle[0] ] ]  , ( long * ) &poly[0]->x0, &p, &Flag);\r\n            OTz += RotTransPers(&modelCube_mesh[ modelCube_index[ curTriangle[0] + 2] ], ( long*)  &poly[0]->x1, &p, &Flag);\r\n            OTz += RotTransPers(&modelCube_mesh[ modelCube_index[ curTriangle[0] + 1] ], ( long * ) &poly[0]->x2, &p, &Flag);\r\n            \r\n            // The right way to do it is re-using the results from the first RotTransPer() batch\r\n            // i.e commenting lines 273 to 280 and uncommenting lines 284 to 289\r\n            //~ poly[0]->x0 = poly[1]->x0;\r\n            //~ poly[0]->y0 = poly[1]->y0;\r\n            //~ poly[0]->x1 = poly[1]->x1;\r\n            //~ poly[0]->y1 = poly[1]->y1;\r\n            //~ poly[0]->x2 = poly[1]->x2;\r\n            //~ poly[0]->y2 = poly[1]->y2;\r\n            \r\n            // Average OTz value for 3 vertices\r\n            // OTz is 1/4 of screen to vertex length\r\n            OTz /= 3;\r\n            // Work color vectors\r\n            // This is the hue of the transparent cube\r\n            CVECTOR prismCol = {0xff,0xff,0x0,0x0};\r\n            // This will store the result of the depth cueing.\r\n            CVECTOR outCol, outCol1, outCol2  = { 0,0,0,0 };\r\n            // Find local color from three normal vectors and perform depth cueing.\r\n            gte_NormalColorDpq3( &modelCube.n[i+0],\r\n                                 &modelCube.n[i+2],\r\n                                 &modelCube.n[i+3],\r\n                                 &prismCol, p, &outCol, &outCol1, &outCol2);\r\n            // Set vertex colors on transparent/background cube                 \r\n            setRGB0(poly[1], outCol.r, outCol.g  , outCol.b);\r\n            setRGB1(poly[1], outCol1.r, outCol1.g, outCol1.b);\r\n            setRGB2(poly[1], outCol2.r, outCol2.g, outCol2.b);\r\n            // Non-transparent/foreground cube color\r\n            // Find local color from three normal vectors and perform depth cueing.\r\n            gte_NormalColorDpq( &modelCube.n[i+0], &modelCube.c[i+0], p, &outCol);\r\n            gte_NormalColorDpq( &modelCube.n[i+2], &modelCube.c[i+2], p, &outCol2);\r\n            gte_NormalColorDpq( &modelCube.n[i+1], &modelCube.c[i+1], p, &outCol1);\r\n            // Set vertex colors                 \r\n            setRGB0(poly[0], outCol.r, outCol.g  , outCol.b);\r\n            setRGB1(poly[0], outCol1.r, outCol1.g, outCol1.b);\r\n            setRGB2(poly[0], outCol2.r, outCol2.g, outCol2.b);\r\n            // If OTz is in range (not too close) \r\n            if ((OTz > 0) && (OTz < OTLEN))\r\n                // Add to ordering table, at index OTz-2 \r\n                AddPrim(&ot[ db ][ OTz-2 ], poly[0]);\r\n                AddPrim(&ot[ db ][ OTz-2 ], poly[1]);\r\n            // Increment next primitive address\r\n            nextpri += sizeof(POLY_GT3)*2;\r\n            // Increment to next triangle\r\n            curTriangle[0] += 3;\r\n            curTriangle[1] += 3;\r\n        }\r\n        // Get pad input\r\n        pad = PadRead(0); \r\n        // If select button is used\r\n        if ( pad & PADselect && !(oldPad & PADselect) ){\r\n            // Flip STP flag\r\n            stpFlag = !stpFlag;\r\n            // Set flag to avoir misfire\r\n            oldPad = pad;\r\n        } \r\n        // Reset flag when button released\r\n        if ( !(pad & PADselect) && oldPad & PADselect) {\r\n            oldPad = pad;\r\n        }\r\n        // If start button is used\r\n        if ( pad & PADstart && !( oldPad & PADstart ) ){\r\n            // Switch STP rates \r\n            stpRate > 2 ? stpRate = 0 : stpRate++;\r\n            // Set flag to avoir misfire\r\n            oldPad = pad;\r\n        } \r\n        // Reset flag when button released\r\n        if (!(pad & PADstart) && oldPad & PADstart) {\r\n            oldPad = pad;\r\n        }\r\n        if ( pad & PADRdown && !( oldPad & PADRdown ) ){\r\n            // Switch STP rates \r\n            offsetCube = 0;\r\n            // Set flag to avoir misfire\r\n            oldPad = pad;\r\n        } \r\n        // Reset flag when button released\r\n        if (!(pad & PADRdown) && oldPad & PADRdown) {\r\n            oldPad = pad;\r\n        }\r\n        if ( pad & PADLright && !( oldPad & PADLright ) ){\r\n            offsetCube += 6;\r\n        } \r\n        if ( pad & PADLleft && !( oldPad & PADLleft ) ){\r\n            offsetCube -= 6;\r\n        } \r\n        FntPrint(\"Hello fx  !\\n\");\r\n        FntPrint(\"Select: STP on/off\\nStart: Cycle STP rates\\nLeft/Right: Move FG cube.\\nX: Reset cube pos\\n\");\r\n        FntPrint(\"STP : %d\\n\", stpFlag);\r\n        FntPrint(\"STP rate : %d\\n\", stpRate);\r\n        FntFlush(-1);\r\n        display();\r\n    }\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "hello_gte_opti/Makefile",
    "content": "TARGET = hello_gte_opti\n\nSRCS = hello_gte_opti.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_gte_opti/hello_gte_opti.c",
    "content": "// Hello free cycles !\n//\n// Ref :     /psyq/DOCS/Devrefs/Inlinref.pdf, p.18\n//           /psyq/psx/sample/scea/GTE\n//           https://psx-spx.consoledev.net/geometrytransformationenginegte/\n// PSX                    / Z+\n//  screen               / \n//coordinate         +-----X+\n//system           / | \n//              eye  | Y+      \n//\n// Credits, thanks : Nicolas Noble, Sickle, Lameguy64 @ psxdev discord : https://discord.com/invite/N2mmwp\n// https://discord.com/channels/642647820683444236/663664210525290507/834831466100949002\n// Schnappy 2021\n#include <sys/types.h>\n#include <stdio.h>\n#include <libetc.h>\n#include <libgte.h>\n#include <libgpu.h>\n// OldWorld PsyQ has a inline_c.h file for inline GTE functions. We have to use the one at https://github.com/grumpycoders/pcsx-redux/blob/07f9b02d1dbb68f57a9f5b9773041813c55a4913/src/mips/psyq/include/inline_n.h\n// because the real GTE commands are needed in nugget : https://psx-spx.consoledev.net/geometrytransformationenginegte/#gte-coordinate-calculation-commands \n#include <inline_n.h>\n// RAM -> CPU and CPU -> GTE macros : \n#include \"../includes/CPUMAC.H\"\n\n#define VMODE 0                         // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320                  // Screen width\n#define SCREENYRES 240 + (VMODE << 4)     // Screen height : If VMODE is 0 = 240, if VMODE is 1 = 256 \n#define CENTERX ( SCREENXRES >> 1 )       // Center of screen on x \n#define CENTERY ( SCREENYRES >> 1 )       // Center of screen on y\n#define MARGINX 0                       // margins for text display\n#define MARGINY 32\n#define FONTSIZE 8 * 7                  // Text Field Height\n#define OTLEN 10                        // Ordering Table Length \n\nDISPENV disp[2];                        // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nu_long ot[2][OTLEN];               // double ordering table of length 8 * 32 = 256 bits / 32 bytes\nchar primbuff[2][32768] = {1};     // double primitive buffer of length 32768 * 8 =  262.144 bits / 32,768 Kbytes\nchar *nextpri = primbuff[0];       // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]\nshort db = 0;                      // index of which buffer is used, values 0, 1\n\n// DCache setup\n#define  dc_camdirp ((sshort*)  getScratchAddr(0))\n#define  dc_ip      ((uchar*)   getScratchAddr(1))\n#define  dc_opzp    ((slong*)   getScratchAddr(2))\n#define  dc_wmatp   ((MATRIX*)  getScratchAddr(3))\n#define  dc_cmatp   ((MATRIX*)  getScratchAddr(9))\n#define  dc_sxytbl  ((DVECTOR*) getScratchAddr(15))\n\nvoid init(void)\n{\n    ResetGraph(0);\n    // Initialize and setup the GTE\n    InitGeom();\n    //~ SetGeomOffset(CENTERX,CENTERY);\n    gte_SetGeomOffset(CENTERX,CENTERY);\n    gte_SetGeomScreen(CENTERX);\n    // Set display environment\n    SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    // Set draw environment\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\n    if (VMODE){ SetVideoMode(MODE_PAL);}\n    SetDispMask(1);\n    // Set background color\n    setRGB0(&draw[0], 50, 50, 50);\n    setRGB0(&draw[1], 50, 50, 50);\n    draw[0].isbg = 1;\n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );    \n}\n\nvoid display(void)\n{\n    // Wait for drawing\n    DrawSync(0);\n    // Wait for vsync\n    VSync(1);\n    // Flip DISP and DRAW env\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    DrawOTag(&ot[db][OTLEN - 1]);\n    // Flip db index\n    db = !db;\n    // Get next primitive in buffer\n    nextpri = primbuff[db];\n}\n\nint main(void)\n{\n    long p, flag, OTz;\n    SVECTOR rotVector = {0};                    \n    SVECTOR rotVector4 = {0};                  // Initialize rotation vector {x, y, z} - ALWAYS !\n    VECTOR  transVector = {0, 0, CENTERX, 0};         // Initialize translation vector {x, y, z}\n    SVECTOR vertPos[4] = {\n        { 0, -32, 0, 0 },           // Vert 1 \n        { 32,  0, 0, 0 },           // Vert 2\n        { -32, 0, 0, 0 },\n        { 0,  32, 0, 0 }\n    };           // Vert 3\n    MATRIX workMatrix = {0};                       \n    POLY_F3 * poly  = {0};                            // pointer to a POLY_F4 \n    POLY_F4 * poly4 = {0};                            // pointer to a POLY_F4 \n    init();\n    \n    // Declare registers\n    register ulong   ur0     asm(\"$16\");\n    register ulong   ur1     asm(\"$17\");\n    register ulong   ur2     asm(\"$18\");\n    register ulong   ur3     asm(\"$19\");\n    register ulong   ur4     asm(\"$20\");\n    register ulong   ur5     asm(\"$21\");\n    \n    while (1)\n    {\n        // Set Ordering table\n        ClearOTagR(ot[db], OTLEN);\n        // Cast next primitives in buffer as a POLY_F3 and a POLY_F4 (see display() )\n        poly = (POLY_F3 *)nextpri;  \n        nextpri += sizeof(POLY_F3);\n        poly4 = (POLY_F4 *)nextpri;    \n        // Set matrices - Move to left of screen\n        // Draw on the left part of the screen\n        transVector.vx = -CENTERX/2;\n        // Increment rotation angle on Y axis\n        rotVector.vy += 1;\n        // Find rotation matrix from vector, store in \n        RotMatrix_gte(&rotVector, &workMatrix);\n        // Ditto for translation        \n        TransMatrix(&workMatrix, &transVector);\n        // Set the matrices we just found\n        gte_SetRotMatrix(&workMatrix);\n        gte_SetTransMatrix(&workMatrix);\n        // Draw a Tri and a Quad\n        // Copy Tri vertices from ram to cpu registers casting as ulong so that ur0 (len 32bits) contains vx and vy (2 * 8bits) \n        // Hence the use of vx, vz members\n        cpu_ldr(ur0,(ulong*)&vertPos[0].vx); // Put vx, vy value in ur0\n        cpu_ldr(ur1,(ulong*)&vertPos[0].vz); // Put vz, pad value in ur1\n        cpu_ldr(ur2,(ulong*)&vertPos[1].vx);\n        cpu_ldr(ur3,(ulong*)&vertPos[1].vz);\n        cpu_ldr(ur4,(ulong*)&vertPos[2].vx);\n        cpu_ldr(ur5,(ulong*)&vertPos[2].vz);\n        // Load the gte registers from the cpu registers (gte-cpu move 1 cycle) - mtc2 %0, $0;\n        cpu_gted0(ur0);\n        cpu_gted1(ur1);\n        cpu_gted2(ur2);\n        cpu_gted3(ur3);\n        cpu_gted4(ur4);\n        cpu_gted5(ur5);\n        // Tri RotTransPers3\n        // The two last cpu->gte copy will happen during the 2 nops in gte_rtpt() \n        gte_rtpt();\n        // Fill the cpu registers with the Quad vertices \n        cpu_ldr(ur0,(ulong*)&vertPos[0].vx);\n        cpu_ldr(ur1,(ulong*)&vertPos[0].vz);\n        cpu_ldr(ur2,(ulong*)&vertPos[1].vx);\n        cpu_ldr(ur3,(ulong*)&vertPos[1].vz);\n        cpu_ldr(ur4,(ulong*)&vertPos[2].vx);\n        cpu_ldr(ur5,(ulong*)&vertPos[2].vz);\n        // Get nclip value, and win two cycles\n        gte_nclip();\n         // Copy Tri 's screen coordinates from gte registers to d-cache.\n        gte_stsxy3c(&dc_sxytbl[0]);\n        // Set matrices - Move to right of screen\n        transVector.vx = CENTERX/2;\n        // Increment rot on X/Y axis\n        rotVector4.vy -= 1 ;\n        rotVector4.vx -= 1 ;\n        // Set matrices\n        RotMatrix_gte(&rotVector4, &workMatrix);\n        TransMatrix(&workMatrix, &transVector);\n        gte_SetRotMatrix(&workMatrix);\n        gte_SetTransMatrix(&workMatrix);\n        // Load the gte registers from the cpu registers (gte-cpu move 1 cycle) - mtc2 %0, $0;\n        cpu_gted0(ur0);\n        cpu_gted1(ur1);\n        cpu_gted2(ur2);\n        cpu_gted3(ur3);\n        cpu_gted4(ur4);\n        cpu_gted5(ur5);\n        // Quad RotTransPers3\n        // Getting 2 cycles back thanks to nops\n        gte_rtpt();\n        // gte_nclip() has 2 nops, lets use them to load the remaining vertex data from ram->cpu register\n        cpu_ldr(ur0,(ulong*)&vertPos[3].vx);\n        cpu_ldr(ur1,(ulong*)&vertPos[3].vz);\n        // Calculate nclip (outer product)\n        gte_nclip();\n        // Copy result to d-cache + 3\n        gte_stsxy3c(&dc_sxytbl[3]);\n        // Copy from cpu-gte\n        cpu_gted0(ur0);\n        cpu_gted1(ur1);\n        // Quad last vertex RotTransPers\n        // These two last cpu->gte load are free :p\n        gte_rtps();\n        gte_nclip();\n        // Copy last vertex value to d-cache\n        gte_stsxy(&dc_sxytbl[6]);\n        // Get p, flag, OTz\n        gte_stdp(&p);\n        gte_stflg(&flag);\n        gte_stszotz(&OTz);\n        // That's 10 cycles we won back ?\n        // Copy vertices data from d-cache to ram \n        // Tri \n        *(unsigned long long*)&poly->x0 = *(unsigned long long*)&dc_sxytbl[0];\n        *(ulong*)&poly->x2 = *(ulong*)&dc_sxytbl[2];\n        // Quad\n        *(unsigned long long*)&poly4->x0 = *(unsigned long long*)&dc_sxytbl[3];\n        *(unsigned long long*)&poly4->x2 = *(unsigned long long*)&dc_sxytbl[5];\n        // Initialize polygons\n        setPolyF3(poly);                \n        setRGB0(poly, 255, 0, 255);                   \n        setPolyF4(poly4);                \n        setRGB0(poly4, 0, 255, 255);                   \n        // Add to OT\n        addPrim(ot[db], poly);\n        addPrim(ot[db], poly4);\n        // Display text\n        FntPrint(\"Hello Free cycles !\\n\");                            \n        FntFlush(-1);\n        \n        display();\n        }\n    return 0;\n    }\n"
  },
  {
    "path": "hello_light/Makefile",
    "content": "TARGET = hello_light\n\nSRCS = hello_light.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_light/cube.c",
    "content": "SVECTOR modelCube_mesh[] = {\n    { -128,128,128 },\n    { 128,128,128 },\n    { 128,128,-128 },\n    { -128,128,-128 },\n    { -128,-128,128 },\n    { 128,-128,128 },\n    { 128,-128,-128 },\n    { -128,-128,-128 }\n};\n\nSVECTOR modelCube_normal[] = {\n    2365,-2365,-2365, 0,\n    -2365,-2365,-2365, 0,\n    -2365,-2365,2365, 0,\n    2365,-2365,2365, 0,\n    2365,2365,-2365, 0,\n    -2365,2365,-2365, 0,\n    -2365,2365,2365, 0,\n    2365,2365,2365, 0\n};\n\nCVECTOR modelCube_color[] = {\n    255,237,0, 0,\n    255,235,0, 0,\n    255,236,0, 0,\n    255,2,0, 0,\n    254,3,0, 0,\n    255,8,0, 0,\n    229,0,255, 0,\n    229,0,255, 0,\n    229,0,255, 0,\n    5,16,250, 0,\n    0,12,255, 0,\n    0,12,255, 0,\n    4,251,25, 0,\n    0,255,26, 0,\n    0,255,26, 0,\n    0,248,255, 0,\n    0,248,255, 0,\n    0,248,255, 0,\n    255,237,0, 0,\n    255,237,0, 0,\n    255,235,0, 0,\n    255,2,0, 0,\n    255,6,2, 0,\n    254,3,0, 0,\n    229,0,255, 0,\n    232,21,232, 0,\n    229,0,255, 0,\n    5,16,250, 0,\n    2,13,253, 0,\n    0,12,255, 0,\n    4,251,25, 0,\n    0,255,26, 0,\n    0,255,26, 0,\n    0,248,255, 0,\n    0,248,255, 0,\n    0,248,255, 0\n};\n\nint modelCube_index[] = {\n    0,2,3,\n    7,5,4,\n    4,1,0,\n    5,2,1,\n    2,7,3,\n    0,7,4,\n    0,1,2,\n    7,6,5,\n    4,5,1,\n    5,6,2,\n    2,6,7,\n    0,3,7\n};\n\nTMESH modelCube = {\n    modelCube_mesh,\n    modelCube_normal,\n    0,\n    modelCube_color,\n    12\n};\n\nSVECTOR modelCube1_mesh[] = {\n    { -128,128,128 },\n    { 128,128,128 },\n    { 128,128,-128 },\n    { -128,128,-128 },\n    { -128,-128,128 },\n    { 128,-128,128 },\n    { 128,-128,-128 },\n    { -128,-128,-128 }\n};\n\nSVECTOR modelCube1_normal[] = {\n    2365,-2365,-2365, 0,\n    -2365,-2365,-2365, 0,\n    -2365,-2365,2365, 0,\n    2365,-2365,2365, 0,\n    2365,2365,-2365, 0,\n    -2365,2365,-2365, 0,\n    -2365,2365,2365, 0,\n    2365,2365,2365, 0\n};\n\nCVECTOR modelCube1_color[] = {\n    255,237,0, 0,\n    255,235,0, 0,\n    255,236,0, 0,\n    255,2,0, 0,\n    254,3,0, 0,\n    255,8,0, 0,\n    229,0,255, 0,\n    229,0,255, 0,\n    229,0,255, 0,\n    5,16,250, 0,\n    0,12,255, 0,\n    0,12,255, 0,\n    4,251,25, 0,\n    0,255,26, 0,\n    0,255,26, 0,\n    0,248,255, 0,\n    0,248,255, 0,\n    0,248,255, 0,\n    255,237,0, 0,\n    255,237,0, 0,\n    255,235,0, 0,\n    255,2,0, 0,\n    255,6,2, 0,\n    254,3,0, 0,\n    229,0,255, 0,\n    232,21,232, 0,\n    229,0,255, 0,\n    5,16,250, 0,\n    2,13,253, 0,\n    0,12,255, 0,\n    4,251,25, 0,\n    0,255,26, 0,\n    0,255,26, 0,\n    0,248,255, 0,\n    0,248,255, 0,\n    0,248,255, 0\n};\n\nint modelCube1_index[] = {\n    0,2,3,\n    7,5,4,\n    4,1,0,\n    5,2,1,\n    2,7,3,\n    0,7,4,\n    0,1,2,\n    7,6,5,\n    4,5,1,\n    5,6,2,\n    2,6,7,\n    0,3,7\n};\n\nTMESH modelCube1 = {\n    modelCube1_mesh,\n    modelCube1_normal,\n    0,\n    modelCube1_color,\n    12\n};\n"
  },
  {
    "path": "hello_light/hello_light.c",
    "content": "/*  hello_light.c, by Schnappy, 06-2021\r\n    - Demonstrates setting and using light sources in 3D without libgs.\r\n    Controls:\r\n        Start                           - Toggle interactive/non-interactive mode.\r\n        Select                          - Reset object's position and angles.\r\n        L1/L2                           - Move object closer/farther.\r\n        L2/R2                           - Rotate object (XY).\r\n        Up/Down/Left/Right              - Rotate object (XZ/YZ).\r\n        Triangle/Cross/Square/Circle    - Move object up/down/left/right.\r\n    based on primdraw.c by Lameguy64 (http://www.psxdev.net/forum/viewtopic.php?f=64&t=537)\r\n    2014 Meido-Tek Productions.\r\n*/\r\n#include <sys/types.h>\r\n#include <libgte.h>\r\n#include <libgpu.h>\r\n#include <libetc.h>\r\n#include <stdio.h>\r\n// Sample vector model\r\n#include \"cube.c\"\r\n\r\n#define VMODE       0\r\n#define SCREENXRES 320\r\n#define SCREENYRES 240\r\n#define CENTERX     SCREENXRES/2\r\n#define CENTERY     SCREENYRES/2\r\n#define OTLEN       2048        // Maximum number of OT entries\r\n#define PRIMBUFFLEN 32768       // Maximum number of POLY_GT3 primitives\r\n// Display and draw environments, double buffered\r\nDISPENV disp[2];\r\nDRAWENV draw[2];\r\nu_long      ot[2][OTLEN];                   // Ordering table (contains addresses to primitives)\r\nchar        primbuff[2][PRIMBUFFLEN]; // Primitive list // That's our prim buffer\r\nchar * nextpri = primbuff[0];                       // Primitive counter\r\nshort           db  = 0;                        // Current buffer counter\r\nlong    t, p, OTz, Flag;                // t == vertex count, p == depth cueing interpolation value, OTz ==  value to create Z-ordered OT, Flag == see LibOver47.pdf, p.143\r\n// Lighting\r\n// See PsyQ's LibOver47.pdf, p.133 for more details on the purpose of each component and full calculations.\r\n// Far color : This is the color used to fade to when the mesh is far from the cam (NearFog)\r\nCVECTOR BGc = {150, 50, 75, 0};  \r\n// Back color  \r\nVECTOR  BKc = {128, 128, 128, 0};\r\n// Light rotation angle\r\nSVECTOR lgtang = {0, 0, 0}; \r\n// These will be used to store the light rotation matrix, cube rotation matrix, and composite light matrix.\r\nMATRIX  rotlgt, rotcube, light;\r\n// Local Light Matrix : Direction and reach of each light source. \r\n// Each light points in the direction aligned with the axis, hence direction is in the same coordinate system as the PSX (see l.23-30 of this file)\r\n// Negative/positive value denotes light direction on corresponding axis\r\n// -4096 > Value < 4096 denotes reach/intensity of light source\r\nMATRIX lgtmat = {\r\n//      X      Y      Z\r\n        -ONE,  -ONE,   ONE, // Lightsource 1 : here, the light source is at the Bottom-Left of the screen, and points into the screen.\r\n        0,     0,     0, // Lightsource 2\r\n        0,     0,     0, // Lightsource 3\r\n    };\r\n// Local Color Matrix\r\n// Set color of each light source (L)\r\n// Value range : 0 > x < 4096\r\nMATRIX cmat = {\r\n//   L1    L2   L3\r\n    4096,   0,   0, // R\r\n    4096,   0,   0, // G\r\n    4096,   0,   0  // B\r\n    };\r\n// Prototypes\r\nvoid init(void);\r\nvoid display(void);\r\nvoid init(){\r\n    // Reset the GPU before doing anything and the controller\r\n    PadInit(0);\r\n    ResetGraph(0);\r\n    // Initialize and setup the GTE\r\n    InitGeom();\r\n    SetGeomOffset(CENTERX, CENTERY);        // x, y offset\r\n    SetGeomScreen(CENTERX);                 // Distance between eye and screen  \r\n    // Set the display and draw environments\r\n    SetDefDispEnv(&disp[0], 0, 0         , SCREENXRES, SCREENYRES);\r\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\r\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\r\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\r\n    if (VMODE)\r\n    {\r\n        SetVideoMode(MODE_PAL);\r\n        disp[0].screen.y += 8;\r\n        disp[1].screen.y += 8;\r\n    }\r\n    SetDispMask(1);\r\n    // Set light env\r\n    // Set far color\r\n    SetFarColor( BGc.r, BGc.g, BGc.b );\r\n    // Set Ambient color\r\n    SetBackColor( BKc.vx, BKc.vy, BKc.vz );\r\n    // Set Color matrix\r\n    SetColorMatrix(&cmat);\r\n    // Set Fog settings\r\n    SetFogNearFar( 1200, 2200, SCREENXRES );\r\n    setRGB0(&draw[0], 0, 0, 255);\r\n    setRGB0(&draw[1], 0, 0, 255);\r\n    draw[0].isbg = 1;\r\n    draw[1].isbg = 1;\r\n    PutDispEnv(&disp[db]);\r\n    PutDrawEnv(&draw[db]);\r\n    // Init font system\r\n    FntLoad(960, 0);\r\n    FntOpen(16, 16, 196, 64, 0, 256);\r\n    }\r\nvoid display(void){\r\n    DrawSync(0);\r\n    VSync(0);\r\n    PutDispEnv(&disp[db]);\r\n    PutDrawEnv(&draw[db]);\r\n    DrawOTag(&ot[db][OTLEN - 1]);\r\n    db = !db;\r\n    nextpri = primbuff[db];\r\n    }\r\nint main() {\r\n    int     i;\r\n    int     PadStatus;\r\n    int     TPressed=0;\r\n    int     AutoRotate=1;\r\n    // Rotating cube\r\n    POLY_G3 * poly;\r\n    SVECTOR Rotate={ ONE/6,ONE/6,ONE/6 };                   // Rotation coordinates\r\n    VECTOR  Trans={ -SCREENXRES/2, 0, CENTERX * 3, 0 }; // Translation coordinates\r\n    VECTOR  Scale={ ONE/2, ONE/2, ONE/2, 0 };     // Scaling coordinates : ONE == 4096\r\n    MATRIX  Matrix={0};                     // Matrix data for the GTE\r\n    // Static cube\r\n    POLY_G3 * poly1;                   // pointer to a POLY_G4 \r\n    SVECTOR Rotate1={ ONE/6, ONE/6, ONE/6, 0 };                   // Rotation coordinates\r\n    VECTOR  Trans1={ SCREENXRES/2, 0, CENTERX * 3, 0 }; // Translation coordinates\r\n    VECTOR  Scale1={ ONE/2, ONE/2, ONE/2, 0 };     // Scaling coordinates : ONE == 4096\r\n    MATRIX  Matrix1={0};                     // Matrix data for the GTE\r\n    init();\r\n    // Main loop\r\n    while (1) {\r\n        // Read pad status\r\n        PadStatus = PadRead(0);\r\n        if (AutoRotate == 0) {\r\n            if (PadStatus & PADL1) Trans.vz -= 4;\r\n            if (PadStatus & PADR1) Trans.vz += 4;\r\n            if (PadStatus & PADL2) Rotate.vz -= 8;\r\n            if (PadStatus & PADR2) Rotate.vz += 8;\r\n            if (PadStatus & PADLup)     Rotate.vx -= 8;\r\n            if (PadStatus & PADLdown)   Rotate.vx += 8;\r\n            if (PadStatus & PADLleft)   Rotate.vy -= 8;\r\n            if (PadStatus & PADLright)  Rotate.vy += 8;\r\n            if (PadStatus & PADRup)     Trans.vy -= 2;\r\n            if (PadStatus & PADRdown)   Trans.vy += 2;\r\n            if (PadStatus & PADRleft)   Trans.vx -= 2;\r\n            if (PadStatus & PADRright)  Trans.vx += 2;\r\n        }\r\n        if (PadStatus & PADstart) {\r\n            if (TPressed == 0) {\r\n                AutoRotate = (AutoRotate + 1) & 1;\r\n                Rotate.vy = Rotate.vx = Rotate.vz = ONE/6;\r\n                Scale.vx = Scale.vy = Scale.vz = ONE/2;\r\n                Trans.vx = -SCREENXRES/2;\r\n                Trans.vy = 0;\r\n                Trans.vz = CENTERX * 3;\r\n            }\r\n            TPressed = 1;\r\n        } else {\r\n            TPressed = 0;\r\n        }\r\n        if (AutoRotate) {\r\n            Rotate.vy += 8; // Pan\r\n            Rotate.vx += 8; // Tilt\r\n            //~ Rotate.vz += 8; // Roll\r\n        }\r\n        // Clear the current OT\r\n        ClearOTagR(ot[db], OTLEN);\r\n        // Render the sample vector model\r\n        t=0;        \r\n        // modelCube is a TMESH, len member == # vertices, but here it's # of triangle... So, for each tri * 3 vertices ...\r\n        for (i = 0; i < (modelCube.len*3); i += 3) {               \r\n            poly = (POLY_G3 *)nextpri;\r\n            // Initialize the primitive and set its color values\r\n            SetPolyG3(poly);\r\n            // Rotate, translate, and project the vectors and output the results into a primitive\r\n            // Could be replaced with one call with RotTransPers3()\r\n            OTz  = RotTransPers(&modelCube_mesh[modelCube_index[t]]  , (long*)&poly->x0, &p, &Flag);\r\n            OTz += RotTransPers(&modelCube_mesh[modelCube_index[t+2]], (long*)&poly->x1, &p, &Flag);\r\n            OTz += RotTransPers(&modelCube_mesh[modelCube_index[t+1]], (long*)&poly->x2, &p, &Flag);\r\n            // Find light color\r\n            // Work color vectors\r\n            CVECTOR outCol, outCol1, outCol2  = { 0,0,0,0 };\r\n            // Find local color from three normal vectors and perform depth cueing.\r\n            // Could be replaced with one call with NormalColorDpq3()\r\n            NormalColorDpq(&modelCube.n[ modelCube_index[t+0] ], &modelCube.c[i+0], p, &outCol);\r\n            NormalColorDpq(&modelCube.n[ modelCube_index[t+2] ], &modelCube.c[i+2], p, &outCol1);\r\n            NormalColorDpq(&modelCube.n[ modelCube_index[t+1] ], &modelCube.c[i+1], p, &outCol2);\r\n            // Set vertex colors \r\n            setRGB0(poly, outCol.r, outCol.g  , outCol.b);\r\n            setRGB1(poly, outCol1.r, outCol1.g, outCol1.b);\r\n            setRGB2(poly, outCol2.r, outCol2.g, outCol2.b);\r\n            // Sort the primitive into the OT\r\n            OTz /= 3;\r\n            if ((OTz > 0) && (OTz < OTLEN))\r\n                AddPrim(&ot[db][OTz-2], poly);\r\n            nextpri += sizeof(POLY_G3);\r\n            t+=3;\r\n        }\r\n        // Find and apply light rotation matrix\r\n        // Find rotmat from light angles\r\n        RotMatrix_gte(&lgtang, &rotlgt);\r\n        // Find rotmat from cube angles\r\n        RotMatrix_gte(&Rotate, &rotcube);  \r\n        // RotMatrix cube * RotMatrix light\r\n        MulMatrix0(&rotcube, &rotlgt, &rotlgt);\r\n        // Light Matrix * RotMatrix light \r\n        MulMatrix0(&lgtmat, &rotlgt, &light);\r\n        // Set new light matrix \r\n        SetLightMatrix(&light);\r\n        // Convert and set the matrices\r\n        // Find Rotation matrix from object's angles\r\n        RotMatrix(&Rotate, &Matrix); \r\n        // Find Scale matrix from object's angles\r\n        ScaleMatrix(&Matrix, &Scale);\r\n        // Find Translation matrix from object's angles\r\n        TransMatrix(&Matrix, &Trans);\r\n        // Set GTE's rotation matrix\r\n        SetRotMatrix(&Matrix);\r\n        // Set GTE's Translation matrix\r\n        SetTransMatrix(&Matrix);\r\n        // Draw static cube\r\n        t=0;   \r\n        for (i = 0; i < (modelCube1.len*3); i += 3) {               \r\n            poly1 = (POLY_G3 *)nextpri;\r\n            SetPolyG3(poly1);\r\n            OTz  = RotTransPers(&modelCube1_mesh[modelCube1_index[t]]  , (long*)&poly1->x0, &p, &Flag);\r\n            OTz += RotTransPers(&modelCube1_mesh[modelCube1_index[t+2]], (long*)&poly1->x1, &p, &Flag);\r\n            OTz += RotTransPers(&modelCube1_mesh[modelCube1_index[t+1]], (long*)&poly1->x2, &p, &Flag);\r\n            CVECTOR outCol  = { 0,0,0,0 };\r\n            CVECTOR outCol1 = { 0,0,0,0 };\r\n            CVECTOR outCol2 = { 0,0,0,0 };\r\n            NormalColorDpq(&modelCube1.n[ modelCube1_index[t+0] ], &modelCube1.c[i+0], p, &outCol);\r\n            NormalColorDpq(&modelCube1.n[ modelCube1_index[t+2] ], &modelCube1.c[i+2], p, &outCol1);\r\n            NormalColorDpq(&modelCube1.n[ modelCube1_index[t+1] ], &modelCube1.c[i+1], p, &outCol2);\r\n            setRGB0(poly1, outCol.r, outCol.g  , outCol.b);\r\n            setRGB1(poly1, outCol1.r, outCol1.g, outCol1.b);\r\n            setRGB2(poly1, outCol2.r, outCol2.g, outCol2.b);\r\n            OTz /= 3;\r\n            if ((OTz > 0) && (OTz < OTLEN))\r\n                AddPrim(&ot[db][OTz-2], poly1);\r\n            nextpri += sizeof(POLY_G3);\r\n            t+=3;\r\n        }\r\n        // See l.216\r\n        RotMatrix_gte(&lgtang, &rotlgt);\r\n        RotMatrix_gte(&Rotate1, &rotcube);  \r\n        MulMatrix0(&rotcube, &rotlgt, &rotlgt);\r\n        MulMatrix0(&lgtmat, &rotlgt, &light);\r\n        SetLightMatrix(&light);\r\n        // See l.227\r\n        RotMatrix(&Rotate1, &Matrix1);\r\n        ScaleMatrix(&Matrix1, &Scale1);\r\n        TransMatrix(&Matrix1, &Trans1);\r\n        SetRotMatrix(&Matrix1);\r\n        SetTransMatrix(&Matrix1);\r\n        FntPrint(\"Hello lightsources !\\n\");\r\n        FntFlush(-1);\r\n        display();\r\n    }\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "hello_mod/Makefile",
    "content": "TARGET = hello_mod\n\nSRCS = hello_mod.c \\\nsrc/mod.c \\\n../thirdparty/nugget/modplayer/modplayer.c \\\nHIT/STAR.HIT \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_mod/README.md",
    "content": "This is an example of how to use [@nicolasnoble](https://github.com/nicolasnoble/)'s [modplayer](https://github.com/grumpycoders/pcsx-redux/tree/main/src/mips/modplayer) port in conjunction with the psyq libs.  \n\nSee the **wiki** for more details on MOD usage : [https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/MOD](https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/MOD).  \n\n## Credits & thanks\n\nMany thanks to @nicolasnobe for his work and help on getting this example working.\n\nMOD : stardust memories by Jester : https://modarchive.org/index.php?request=view_by_moduleid&query=59344  \n"
  },
  {
    "path": "hello_mod/hello_mod.c",
    "content": "// Play a MOD file converted to HIT \n// MOD Wiki page : https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/MOD\n#include <sys/types.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n// Mod playback\n#include \"src/mod.h\"\n\n#define VMODE 0                 // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320          // Screen width\n#define SCREENYRES 240          // Screen height : If VMODE is 0 = 240, if VMODE is 1 = 256 \n#define CENTERX SCREENXRES/2    // Center of screen on x \n#define CENTERY SCREENYRES/2    // Center of screen on y\n#define FONTX   960\n#define FONTY   0\n#define OTLEN 8 \nDISPENV disp[2];                 // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nshort db = 1;                    // index of which buffer is used, values 0, 1\n\n// Font color\nCVECTOR fntColor = { 128, 255, 0 };\nCVECTOR fntColorBG = { 0, 0, 0 };\n\n// MOD Playback\n#define MAXVOLUME 65536\n#define INCVOLUME 256\n// State\nenum PLAYBACK {\n    STOP  = 0,\n    PLAY  = 1,\n    PAUSE = 2,\n};\n// Music volume should range from 0 to 65536\nu_int musicVolume = 2048;\n\nenum PLAYBACK state = PLAY;\n\nvoid init(void);\nvoid FntColor(CVECTOR fgcol, CVECTOR bgcol );\nvoid display(void);\nvoid drawBG(void);\nvoid checkPad(void);\n\nvoid FntColor(CVECTOR fgcol, CVECTOR bgcol )\n{\n    // The debug font clut is at tx, ty + 128\n    // tx = bg color\n    // tx + 1 = fg color\n    // We can override the color by drawing a rect at these coordinates\n    // \n    RECT fg = { FONTX+1, FONTY + 128, 1, 1 };\n    RECT bg = { FONTX, FONTY + 128, 1, 1 };\n    ClearImage(&fg, fgcol.r, fgcol.g, fgcol.b);\n    ClearImage(&bg, bgcol.r, bgcol.g, bgcol.b);\n}\n\nvoid init(void)\n{\n    ResetCallback();\n    ResetGraph(0);                 // Initialize drawing engine with a complete reset (0)\n    InitGeom();\n    SetGeomOffset(CENTERX,CENTERY);\n    SetGeomScreen(CENTERX);\n    SetDefDispEnv(&disp[0], 0, 0         , SCREENXRES, SCREENYRES);     // Set display area for both &disp[0] and &disp[1]\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // &disp[0] is on top  of &disp[1]\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // Set draw for both &draw[0] and &draw[1]\n    SetDefDrawEnv(&draw[1], 0, 0         , SCREENXRES, SCREENYRES);     // &draw[0] is below &draw[1]\n    // Set video mode\n    #if VMODE\n        SetVideoMode(MODE_PAL);\n        disp[0].disp.y = 8;\n        disp[1].disp.y = 8;\n    #endif\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 40, 40, 40); // set color for first draw area\n    setRGB0(&draw[1], 40, 40, 40); // set color for second draw area\n    draw[0].isbg = 1;               // set mask for draw areas. 1 means repainting the area with the RGB color each frame \n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);          // set the disp and draw environnments\n    PutDrawEnv(&draw[db]);\n    FntLoad(FONTX, FONTY);                // Load font to vram at 960,0(+128)\n    FntOpen(16, 60, 288, 260, 0, 256 ); // FntOpen(x, y, width, height,  black_bg, max. nbr. chars\n    FntColor(fntColor, fntColorBG);\n}\nvoid display(void)\n{\n    DrawSync(0);                    // Wait for all drawing to terminate\n    VSync(0);                       // Wait for the next vertical blank\n    PutDispEnv(&disp[db]);          // set alternate disp and draw environnments\n    PutDrawEnv(&draw[db]);  \n    db = !db;\n}\n\nvoid checkPad(void)\n{\n    u_short pad = 0;\n    static u_short oldPad;    \n    pad = PadRead(0);\n\n    // Up\n    if ( pad & PADLup && !(oldPad & PADLup) )\n    {\n        MOD_PlaySoundEffect(11, 25, 15, 63);\n        oldPad = pad;\n    }\n    if ( !(pad & PADLup) && oldPad & PADLup )\n    {\n        oldPad = pad;\n    }\n    // Down\n    if ( pad & PADLdown && !(oldPad & PADLdown) )\n    {\n        MOD_PlaySoundEffect(12, 26, 15, 63);\n        oldPad = pad;\n    }\n    if ( !(pad & PADLdown) && oldPad & PADLdown )\n    {\n        oldPad = pad;\n    }\n    // Left\n    if ( pad & PADLleft && !(oldPad & PADLleft) )\n    {\n        MOD_PlaySoundEffect(13, 27, 15, 63);\n        oldPad = pad;\n    }\n    if ( !(pad & PADLleft) && oldPad & PADLleft )\n    {\n        oldPad = pad;\n    }\n    // Right\n    if ( pad & PADLright && !(oldPad & PADLright) )\n    {\n        // Channel 1 is transition anim, only take input when !transition\n        MOD_PlaySoundEffect(6, 21, 15, 63);\n        oldPad = pad;\n    }\n    if ( !(pad & PADLright) && oldPad & PADLright )\n    {\n        oldPad = pad;\n    }\n    // Cross button\n    if ( pad & PADRdown && !(oldPad & PADRdown) )\n    {\n        // Select sound\n        MOD_PlaySoundEffect(7, 22, 15, 63);\n        oldPad = pad;\n    }\n    if ( !(pad & PADRdown) && oldPad & PADRdown )\n    {\n        oldPad = pad;\n    }\n    // Square button\n    if ( pad & PADRleft && !(oldPad & PADRleft) )\n    {\n        // Select sound\n        MOD_PlaySoundEffect(8, 23, 15, 63);\n        oldPad = pad;\n    }\n    if ( !(pad & PADRleft) && oldPad & PADRleft )\n    {\n        oldPad = pad;\n    }\n    // Circle button\n    if ( pad & PADRright && !(oldPad & PADRright) )\n    {\n        // Select sound\n        MOD_PlaySoundEffect(9, 28, 15, 63);\n        oldPad = pad;\n    }\n    if ( !(pad & PADRright) && oldPad & PADRright )\n    {\n        oldPad = pad;\n    }\n    // Circle button\n    if ( pad & PADRup && !(oldPad & PADRup) )\n    {\n        // Select sound\n        MOD_PlaySoundEffect(9, 24, 15, 63);\n        oldPad = pad;\n    }\n    if ( !(pad & PADRup) && oldPad & PADRup )\n    {\n        oldPad = pad;\n    }\n    // Select button : Stop mod / Play back from the start\n    if ( pad & PADselect && !(oldPad & PADselect) )\n    {\n        if ( state == PLAY ) { stopMusic(); state = STOP; }\n        else if ( state == STOP ) { loadMod(); startMusic(); state = PLAY; }\n        oldPad = pad;\n    }\n    if ( !(pad & PADselect) && oldPad & PADselect )\n    {\n        oldPad = pad;\n    }\n    // Start button : Toggle playback pause\n    if ( pad & PADstart && !(oldPad & PADstart) )\n    {\n        if ( state == PLAY ) { pauseMusic(); state = PAUSE; }\n        else if ( state == PAUSE ) { resumeMusic(); state = PLAY; }\n        oldPad = pad;\n    }\n    if ( !(pad & PADstart) && oldPad & PADstart )\n    {\n        oldPad = pad;\n    }\n    // R1/R2 : change music volume\n    if ( pad & PADR1 && !(oldPad & PADR1) )\n    {\n        if(musicVolume < MAXVOLUME) { \n            musicVolume += INCVOLUME; \n        }\n        MOD_SetMusicVolume(musicVolume);\n        oldPad = pad;\n    }\n    if ( !(pad & PADR1) && oldPad & PADR1 )\n    {\n        oldPad = pad;\n    }\n    if ( pad & PADR2 && !(oldPad & PADR2) )\n    {\n        if(musicVolume > 0) { \n            musicVolume -= INCVOLUME; \n        }\n        MOD_SetMusicVolume(musicVolume);\n        oldPad = pad;\n    }\n    if ( !(pad & PADR2) && oldPad & PADR2 )\n    {\n        oldPad = pad;\n    }\n    \n}\nint main() {\n    u_int t = 0;\n    init();\n    PadInit(0);\n    VSyncCallback(checkPad);\n    // Mod Playback\n    loadMod();\n    startMusic();\n    MOD_SetMusicVolume(musicVolume);\n    // Main loop\n    while (1) \n    {\n        // Timer\n        t++;\n        // Print stuff\n        FntPrint(\"Hello mod ! %d\\nUse the pad's buttons to\\nplay sound effects.\\n\", t);\n        FntPrint(\"State: %d, music volume : %d\\n\", state, musicVolume);\n        FntPrint(\"Start : play/pause music.\\n\");\n        FntPrint(\"select : stop/play music.\\n\");\n        FntPrint(\"R1/R2 : Change music volume.\\n\");\n        FntFlush(-1);\n        display();\n    }\n    return 0;\n}\n\n"
  },
  {
    "path": "hello_mod/src/mod.c",
    "content": "#include \"mod.h\"\n\nlong musicEvent;\ntypedef struct SpuVoiceVolume {\n    short volL, volR;\n} SpuVoiceVolume;\n\nSpuVoiceVolume volumeState[24] = {0};\n\nstatic void muteSPUvoices() {\n  for (unsigned i = 0; i < 24; i++) {\n    // Store current volume\n    SpuGetVoiceVolume(i, &(volumeState[i].volL), &(volumeState[i].volR) );\n    // Mute\n    SpuSetVoiceVolume(i, 0, 0);\n  }\n}\n\nstatic void restoreSPUvoices() {\n  for (unsigned i = 0; i < 24; i++) {\n    // Restore volume\n    SpuSetVoiceVolume(i, volumeState[i].volL, volumeState[i].volR );\n  }\n}\n// Playing a sound effect (aka mod note): https://discord.com/channels/642647820683444236/642848592754901033/898249196174458900 \n// Code by NicolasNoble : https://discord.com/channels/642647820683444236/663664210525290507/902624952715452436\nvoid loadMod() {\n    printf(\"Loading MOD:\\'%s\\'\\n\", HITFILE);\n    MOD_Load((struct MODFileFormat*)HITFILE);\n    printf(\"%02d Channels, %02d Orders\\n\", MOD_Channels, MOD_SongLength);\n}\n\nstatic long processMusic() {\n    uint32_t old_hblanks = MOD_hblanks;\n    MOD_Poll();\n    uint32_t new_hblanks = MOD_hblanks;\n    if (old_hblanks != new_hblanks) SetRCnt(RCntCNT1, new_hblanks, RCntMdINTR);\n    return MOD_hblanks;\n}\n\nvoid startMusic() {\n  ResetRCnt(RCntCNT1);\n  SetRCnt(RCntCNT1, MOD_hblanks, RCntMdINTR);\n  StartRCnt(RCntCNT1);\n  musicEvent = OpenEvent(RCntCNT1, EvSpINT, EvMdINTR, processMusic);\n  EnableEvent(musicEvent);\n  restoreSPUvoices();\n}\n\nvoid pauseMusic() {\n  muteSPUvoices();\n  DisableEvent(musicEvent);\n}\n\nvoid resumeMusic() {\n  restoreSPUvoices();\n  EnableEvent(musicEvent);\n}\n\nvoid stopMusic() {\n  MOD_Silence();\n  StopRCnt(RCntCNT1);\n  DisableEvent(musicEvent);\n  CloseEvent(musicEvent);\n}\n"
  },
  {
    "path": "hello_mod/src/mod.h",
    "content": "#pragma once\n#include <libapi.h>\n#include <libspu.h>\n#include \"../../thirdparty/nugget/common/hardware/hwregs.h\"\n#include \"../../thirdparty/nugget/common/hardware/irq.h\"\n#include \"../../thirdparty/nugget/common/syscalls/syscalls.h\"\n#define printf ramsyscall_printf\n\n// Mod Playback\n#include \"../../thirdparty/nugget/modplayer/modplayer.h\"\nextern const uint8_t _binary_HIT_STAR_HIT_start[];\n#define HITFILE _binary_HIT_STAR_HIT_start\nextern long musicEvent;\n\nvoid loadMod();\nvoid startMusic();\nvoid pauseMusic();\nvoid resumeMusic();\nvoid stopMusic();"
  },
  {
    "path": "hello_multi_vag/Makefile",
    "content": "TARGET = hello_multi_vag\n\nSRCS = hello_multi_vag.c \\\n../VAG/hello.vag \\\n../VAG/poly.vag \\\n../VAG/0_come.vag \\\n../VAG/1_cuek.vag \\\n../VAG/2_erro.vag \\\n../VAG/3_hehe.vag \\\n../VAG/4_m4a1.vag \\\n../VAG/5_punc.vag \\\n../VAG/7_wron.vag \\\n../VAG/8_yooo.vag \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_multi_vag/README.md",
    "content": "See here for more informations about the VAG fileformat and tools :  \n\nhttps://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/VAG\n"
  },
  {
    "path": "hello_multi_vag/hello_multi_vag.c",
    "content": "// Hello multi vag by Schnappy\n// August 2021\n//\n//\n// Load VAG samples to the SPU sound buffer and play them back with pad input\n//\n// See here for more details, file format infos, tools, conversion :\n//        https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/VAG\n// Docs : see libformat47.pdf p.209\n//            libover47.pdf,  p.271\n//            libref47.pdf,   p.980\n\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n// Sound system\n#include <libsnd.h>\n#include <libspu.h>\n#define VMODE 0                 // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320\n#define SCREENYRES 240\n#define CENTERX SCREENXRES/2\n#define CENTERY SCREENYRES/2\n#define MARGINX 0               // margins for text display\n#define MARGINY 32\n#define FONTSIZE 8 * 7          // Text Field Height\nDISPENV disp[2];                // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nshort db = 0;                   // index of which buffer is used, values 0, 1\n// Number of VAG files to load\n#define VAG_NBR 8\n#define MALLOC_MAX VAG_NBR            // Max number of time we can call SpuMalloc\n// convert Little endian to Big endian\n#define SWAP_ENDIAN32(x) (((x)>>24) | (((x)>>8) & 0xFF00) | (((x)<<8) & 0x00FF0000) | ((x)<<24))\n// Memory management table ; allow MALLOC_MAX calls to SpuMalloc() - libref47.pdf p.1044\nchar spu_malloc_rec[SPU_MALLOC_RECSIZ * (MALLOC_MAX + 1)]; \n// Custom struct to handle VAG files\ntypedef struct VAGsound {\n    u_char * VAGfile;        // Pointer to VAG data address\n    u_long spu_channel;      // SPU voice to playback to\n    u_long spu_address;      // SPU address for memory freeing spu mem\n    } VAGsound;\n// VAG header struct (see fileformat47.pdf, p.209)\ntypedef struct VAGhdr {                // All the values in this header must be big endian\n        char id[4];                    // VAGp         4 bytes -> 1 char * 4\n        unsigned int version;          // 4 bytes\n        unsigned int reserved;         // 4 bytes\n        unsigned int dataSize;         // (in bytes) 4 bytes\n        unsigned int samplingFrequency;// 4 bytes\n        char  reserved2[12];           // 12 bytes -> 1 char * 12\n        char  name[16];                // 16 bytes -> 1 char * 16\n        // Waveform data after that\n} VAGhdr;\n// SPU settings\nSpuCommonAttr commonAttributes;          // structure for changing common voice attributes\nSpuVoiceAttr  voiceAttributes ;          // structure for changing individual voice attributes                       \n// extern VAG files\nextern u_char _binary____VAG_0_come_vag_start;\nextern u_char _binary____VAG_1_cuek_vag_start;\nextern u_char _binary____VAG_2_erro_vag_start;\nextern u_char _binary____VAG_3_hehe_vag_start;\nextern u_char _binary____VAG_4_m4a1_vag_start;\nextern u_char _binary____VAG_5_punc_vag_start;\nextern u_char _binary____VAG_7_wron_vag_start;\nextern u_char _binary____VAG_8_yooo_vag_start;\n// soundBank\nVAGsound soundBank[VAG_NBR] = {\n      { &_binary____VAG_0_come_vag_start,\n        SPU_00CH, 0 },  \n      { &_binary____VAG_1_cuek_vag_start,\n        SPU_01CH, 0 },   \n      { &_binary____VAG_2_erro_vag_start,\n        SPU_02CH, 0 },   \n      { &_binary____VAG_3_hehe_vag_start,\n        SPU_03CH, 0 },   \n      { &_binary____VAG_4_m4a1_vag_start,\n        SPU_04CH, 0 },  \n      { &_binary____VAG_5_punc_vag_start,\n        SPU_05CH, 0 },   \n      { &_binary____VAG_7_wron_vag_start,\n        SPU_06CH, 0 },   \n      { &_binary____VAG_8_yooo_vag_start,\n        SPU_07CH, 0 }\n};\n// Prototypes\nvoid initGraph(void);\nvoid display(void);\nvoid initSnd(void);\nu_long sendVAGtoSPU(unsigned int VAG_data_size, u_char *VAG_data);\nvoid setVoiceAttr(unsigned int pitch, long channel, unsigned long soundAddr );\nu_long setSPUtransfer(VAGsound * sound);\nvoid playSFX(VAGsound *  sound);\n\nvoid initGraph(void)\n{\n    ResetGraph(0);\n    SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\n    if (VMODE)\n    {\n        SetVideoMode(MODE_PAL);\n        disp[0].screen.y += 8;\n        disp[1].screen.y += 8;\n        }\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 50, 50, 50);\n    setRGB0(&draw[1], 50, 50, 50);\n    draw[0].isbg = 1;\n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);\n    FntOpen(8, 60, 304, 200, 0, 500 );\n}\nvoid display(void)\n{\n    DrawSync(0);\n    VSync(0);\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    db = !db;\n}\n// Audio initialisation & functions\nvoid initSnd(void){\n    SpuInitMalloc(MALLOC_MAX, spu_malloc_rec);                      // Maximum number of blocks, mem. management table address.\n    commonAttributes.mask = (SPU_COMMON_MVOLL | SPU_COMMON_MVOLR);  // Mask which attributes to set\n    commonAttributes.mvol.left  = 0x3fff;                           // Master volume left\n    commonAttributes.mvol.right = 0x3fff;                           // see libref47.pdf, p.1058\n    SpuSetCommonAttr(&commonAttributes);                            // set attributes\n    SpuSetIRQ(SPU_OFF);\n    SpuSetKey(SpuOff, SPU_ALLCH);\n}\nu_long sendVAGtoSPU(unsigned int VAG_data_size, u_char *VAG_data){\n    u_long transferred;\n    SpuSetTransferMode(SpuTransByDMA);                              // DMA transfer; can do other processing during transfer\n    transferred = SpuWrite (VAG_data + sizeof(VAGhdr), VAG_data_size);     // transfer VAG_data_size bytes from VAG_data  address to sound buffer\n    SpuIsTransferCompleted (SPU_TRANSFER_WAIT);                     // Checks whether transfer is completed and waits for completion\n    return transferred;\n}\nvoid setVoiceAttr(unsigned int pitch, long channel, unsigned long soundAddr ){\n    voiceAttributes.mask=                                   //~ Attributes (bit string, 1 bit per attribute)\n    (\n      SPU_VOICE_VOLL |\n      SPU_VOICE_VOLR |\n      SPU_VOICE_PITCH |\n      SPU_VOICE_WDSA |\n      SPU_VOICE_ADSR_AMODE |\n      SPU_VOICE_ADSR_SMODE |\n      SPU_VOICE_ADSR_RMODE |\n      SPU_VOICE_ADSR_AR |\n      SPU_VOICE_ADSR_DR |\n      SPU_VOICE_ADSR_SR |\n      SPU_VOICE_ADSR_RR |\n      SPU_VOICE_ADSR_SL\n    );\n    voiceAttributes.voice        = channel;                 //~ Voice (low 24 bits are a bit string, 1 bit per voice )\n    voiceAttributes.volume.left  = 0x0;                  //~ Volume \n    voiceAttributes.volume.right = 0x0;                  //~ Volume\n    voiceAttributes.pitch        = pitch;                   //~ Interval (set pitch)\n    voiceAttributes.addr         = soundAddr;               //~ Waveform data start address\n    voiceAttributes.a_mode       = SPU_VOICE_LINEARIncN;    //~ Attack rate mode  = Linear Increase - see libref47.pdf p.1091\n    voiceAttributes.s_mode       = SPU_VOICE_LINEARIncN;    //~ Sustain rate mode = Linear Increase\n    voiceAttributes.r_mode       = SPU_VOICE_LINEARDecN;    //~ Release rate mode = Linear Decrease\n    voiceAttributes.ar           = 0x0;                     //~ Attack rate\n    voiceAttributes.dr           = 0x0;                     //~ Decay rate\n    voiceAttributes.rr           = 0x0;                     //~ Release rate\n    voiceAttributes.sr           = 0x0;                     //~ Sustain rate\n    voiceAttributes.sl           = 0xf;                     //~ Sustain level\n    SpuSetVoiceAttr(&voiceAttributes);                      // set attributes\n}\nu_long setSPUtransfer(VAGsound * sound){\n    // Return spu_address\n    u_long transferred, spu_address;\n    u_int pitch;\n    const VAGhdr * VAGheader = (VAGhdr *) sound->VAGfile;\n    pitch = (SWAP_ENDIAN32(VAGheader->samplingFrequency) << 12) / 44100L; \n    spu_address = SpuMalloc(SWAP_ENDIAN32(VAGheader->dataSize));                // Allocate an area of dataSize bytes in the sound buffer. \n    SpuSetTransferStartAddr(spu_address);                                       // Sets a starting address in the sound buffer\n    transferred = sendVAGtoSPU(SWAP_ENDIAN32(VAGheader->dataSize), sound->VAGfile);\n    setVoiceAttr(pitch, sound->spu_channel, spu_address); \n    // Return 1 if ok, size transferred else.\n    //~ if (transferred == SWAP_ENDIAN32(VAGheader->dataSize)){\n        //~ return 1;\n        //~ }\n    //~ return transferred;\n    return spu_address;\n}\nvoid playSFX(VAGsound *  sound){\n    // Set voice volume to max\n    voiceAttributes.mask= ( SPU_VOICE_VOLL | SPU_VOICE_VOLR );\n    voiceAttributes.voice        = sound->spu_channel;\n    voiceAttributes.volume.left  = 0x1000;\n    voiceAttributes.volume.right = 0x1000;\n    SpuSetVoiceAttr(&voiceAttributes);\n    // Play voice\n    SpuSetKey(SpuOn, sound->spu_channel);\n}\n\nint main(void)\n{\n    // Store input values\n    int pad, oldpad;\n    u_long spu_address;\n    // Init all the things !\n    initGraph();\n    // Init Spu\n    SpuInit();\n    // Init sound settings\n    initSnd();\n    // Init Pad\n    PadInit(0);   \n    // Transfer all VAGs to SPU RAM\n    // Beware that the SPU only has 512KB of RAM so a 'soundbank' should stay within that limit.\n    // If more is needed, a second soundbank could be loaded on demand.\n    for (u_short vag = 0; vag < VAG_NBR; vag++ ){\n        soundBank[vag].spu_address = setSPUtransfer(&soundBank[vag]);\n    }\n    while (1)\n    {\n        // Pad \n        // Use up, down, left, right, triangle, cross, circle, square to play various samples\n        // Read pad values\n        pad = PadRead(0);\n        \n        if (pad & PADLleft && !(oldpad & PADLleft)){\n            playSFX(&soundBank[0]);\n            oldpad = pad;\n            }\n        if (pad & PADLright && !(oldpad & PADLright)){\n            playSFX(&soundBank[1]);\n            oldpad = pad;\n            }\n        if (pad & PADLup && !(oldpad & PADLup)){\n            playSFX(&soundBank[2]);\n            oldpad = pad;\n            }\n        if (pad & PADLdown && !(oldpad & PADLdown)){\n            playSFX(&soundBank[3]);\n            oldpad = pad;\n            }\n        if (pad & PADRleft && !(oldpad & PADRleft)){\n            playSFX(&soundBank[4]);\n            oldpad = pad;\n            }\n            \n        if (pad & PADRright && !(oldpad & PADRright)){\n            playSFX(&soundBank[5]);\n            oldpad = pad;\n            }\n        if (pad & PADRup && !(oldpad & PADRup)){\n            playSFX(&soundBank[6]);\n            oldpad = pad;\n            }\n        if (pad & PADRdown && !(oldpad & PADRdown)){\n            playSFX(&soundBank[7]);\n            oldpad = pad;\n            }\n        // Reset oldpad    \n        if (!(pad & PADRdown) ||\n            !(pad & PADRup)   ||\n            !(pad & PADRleft) ||\n            !(pad & PADRright) ||\n            !(pad & PADLdown) ||\n            !(pad & PADLup)   ||\n            !(pad & PADLleft) ||\n            !(pad & PADLright)\n            ){ oldpad = pad; }\n        \n        FntPrint(\"Hello multi vag ! %d\\n\", VSync(-1));\n        FntPrint(\"Use the pad to play various samples.\\n\");\n        FntFlush(-1);\n        display();\n    }\n    return 0;\n}\n"
  },
  {
    "path": "hello_multi_xa/Makefile",
    "content": ".PHONY: all cleansub\nall:\n\tmkpsxiso -y ./isoconfig.xml\ncleansub:\n\t$(MAKE) clean\n\trm -f hello_multi_xa.cue hello_multi_xa.bin\n\t\nTARGET = hello_multi_xa\n\nSRCS = hello_multi_xa.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_multi_xa/README.md",
    "content": "##  Multi XA samples playback\n\nUse an interleaved XA file to store multiple sound effects and use pre-calculated offset to play them back.  \nUse up, down, left, right, triangle, cross, circle, square to play various samples.  \n\nIf this seems complicated, first study the simple XA playback example : https://github.com/ABelliqueux/nolibgs_hello_worlds/tree/main/hello_xa  \n\nYou need [mkpsxiso](https://github.com/Lameguy64/mkpsxiso) in your $PATH to generate a PSX disk image.\nYou also need [ffmpeg](https://ffmpeg.org/), [`psxavenc` and `xainterleave`](https://github.com/ABelliqueux/candyk-psx/tree/master/toolsrc/).\n\n### Compile\n\nThis will compile and build an iso image :\n\n```bash\nmake\n```\n\n### Clean directory\n\n```bash\nmake cleansub\n```\n\n## Producing an interleaved XA sound bank\n\n### Sound to WAV conversion with ffmpeg\n\n```bash\nffmpeg -i input.mp3 -acodec pcm_s16le -ac 2 -ar 44100 output.wav\n``` \n\n### WAV to XA conversion \n\nSee further down how you should adapt the `-F` and `-C` parameters.\n\n```bash\npsxavenc -f 37800 -t xa -b 4 -c 2 -F 1 -C 0 input.wav output.xa\n```\n\n### XA to multi XA track\n\nYou can use a concatenation tool to build your tracks like so :\n\n```bash\ncat track1.xa track2.xa track3.xa > channelX.xa\n```\n\nOn windows, use :\n```\ncopy track1.xa+track2.xa+track3.xa channelX.xa\n```\n\n### XA to interleaved XA\n\nUse `xainterleave` as instructed here : https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/XA#interleaving-xa-files  \n\n## Multi XA specifics\n\n## Silence file\n\nYou should use a silent XA file to intersperse between your samples, so that you have a margin of error to avoid pops and noises.I.e:\n\n```bash\ncat track1.xa silence.xa track3.xa silence.xa track4.xa  > channelX.xa\n```\n\n### XA file size and vertical density\n\nAn interleaved XA (4 or 8 channels) file will have the size of its largest channel multiplied by the number of channels.  \nTherefore, you should try to obtain a vertical density on all channels for your sample, i.e :\n\nThat :\n\n```\nchannel 0   sample1.xa\nchannel 1   sample2.xa\nchannel 2   sample3.xa\nchannel 3   sample4.xa\n```\n\ninstead of :\n\n```\nchannel 0   sample1.xa sample2.xa sample2.xa sample4.xa\nchannel 1   \nchannel 2   \nchannel 3   \n```\n\nYou should use your longest sample as a base duration, and create the other channels to obtain a similar duration, i.e :\n\n```\nchannel 0   <------------- sample1.xa ---------------> <-- silence.xa --> <-sample2.xa ->\nchannel 1   <-- sample3.xa --> <-- silence.xa --> < -------- sample4.xa ----------->\n```\n\n### Calculating sample's start and end offsets\n\nUsing the size of your XA sample file, you can find it's size in sector like so :\n\n`(size/2336)-1 * 8`\n\nFor example, file with size `84096B` is `(((84096/2336) == 36) - 1 == 35) * 8 == 280`.\n\nFirst sample's start will then be `0`, and end `280`.\nThe following sample's start position will have an offset of `8`, hence `288`, etc.\n\n#### Example \n\nThese are the calculations for the files on 4 channels\n\n```\n// channel 1\n// name       size  start end\n5_come.xa    18688  0      56\n5_sile_h.xa  23360  64     136     \n5_erro.xa    44384  144    288\n \n// channel 2\n6_cuek.xa    32704  0      104\n6_sile_h.xa  23360  112    184\n6_hehe.xa    56064  196    380\n6_sile_h.xa  23360  388    460\n6_wron.xa    53728  468    644\n\n// channel 3\n7_m4a1.xa    84096  0      280\n7_sile_h.xa  23360  288    360 \n7_punch.xa   16352  368    416\n\n// channel 4\n8_yooo.xa    114464 0      384\n```\n\nand the corresponding structure in code :\n\n```c\nXAbank soundBank = {\n        8, // index\n        0, // file offset\n        {\n            // channel 5\n            // id   size   file  channel start end cursor\n            {   0,  18688,   0,     5,     0,   56,  -1 }, \n            // Ommit the silence.xa file\n            {   1,  44384,   0,     5 ,   144,  288, -1 }, \n            // channel 6                 \n            {   2,  32704,   0,     6 ,   0,   104, -1  }, \n            // Ommit the silence.xa file\n            {   3,  56064,   0,     6 ,   196, 380, -1  }, \n            // Ommit the silence.xa file\n            {   4,  53728,   0,     6 ,   468, 644, -1  }, \n            // channel 7                               \n            {   5,  84096,   0,     7 ,   0,   260, -1  }, \n            // Ommit the silence.xa file\n            {   6,  16352,   0,     7 ,   368, 440, -1  }, \n            // channel 8                               \n            {  7,  114464,   0,     8 ,   0,   384, -1  }\n        }\n};\n```\n\n## Tools, sources and documentation\n\nSee the wiki for general informations, tools and sources about the XA format : https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/XA\n\n## Sound credits\n\nAll the sound effects come from https://www.myinstants.com and are :  \n\n```\ncomedy_pop_finger_in_mouth_001(1).mp3\ncuek.swf.mp3\nerro.mp3\nm4a1_single-kibblesbob-8540445.mp3\npunch.mp3\nwrong-answer-sound-effect.mp3\nyooooooooooooooooooooooooo_4.mp3\nhehehehhehehehhehehheheehehe.mp3\n```\n"
  },
  {
    "path": "hello_multi_xa/hello_multi_xa.c",
    "content": "// XA multi sample playback example\n//\n// Use an interleaved XA file to store multiple sound effects and use pre-calculated offset to play them back.  \n// Use up, down, left, right, triangle, cross, circle, square to play various samples.  \n// If this seems complicated, first study the simple XA playback example : https://github.com/ABelliqueux/nolibgs_hello_worlds/tree/main/hello_xa  \n//\n// base on `psyq/addons/scee/CD/XAPLAYER`\n// Refs : http://psx.arthus.net/code/XA/XATUT.pdf\n//        http://psx.arthus.net/code/XA/xatut.zip\n//        http://psx.arthus.net/code/XA/XA%20ADPCM%20documentation.txt\n// Schnappy 2021\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n// CD library\n#include <libcd.h>\n// SPU library\n#include <libspu.h>\n\n#define VMODE 0                  // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320           // Screen width\n#define SCREENYRES 240 + (VMODE << 4)          // Screen height : If VMODE is 0 = 240, if VMODE is 1 = 256 \n#define CENTERX SCREENXRES/2     // Center of screen on x \n#define CENTERY SCREENYRES/2     // Center of screen on y\n#define MARGINX 0                // margins for text display\n#define MARGINY 32\n#define FONTSIZE 8 * 16          // Text Field Height\nDISPENV disp[2];                 // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nshort db = 0;                    // index of which buffer is used, values 0, 1\n\n// SPU attributes\nSpuCommonAttr spuSettings;\n#define CD_SECTOR_SIZE 2048\n// XA\n// Sector offset for XA data 4: simple speed, 8: double speed\n#define XA_CHANNELS 8\n#define XA_CDSPEED XA_CHANNELS >> 2\n// Number of XA samples ( != # of XA files )\n#define XA_TRACKS 8\n\ntypedef struct XAsound {\n    u_int id;\n    u_int size;\n    // We can find size in sector : size / 2336, start value begins at 23, end value is at start + offset ( (size / 2336)-1 * #channels )\n    // subsequent start value have an 8 bytes offset (n-1.end + 8)\n    u_char file, channel;\n    u_int start, end;\n    int cursor;\n} XAsound;\n\ntypedef struct XAbank {\n    u_int index;\n    int offset;\n    XAsound samples[];\n} XAbank;\n\nXAbank soundBank = {\n        8,\n        0,\n        {\n            // channel 5\n            // id   size   file  channel start end cursor\n            {   0,  18688,   0,     5,     0,   56,  -1 }, \n            {   1,  44384,   0,     5 ,   144,  288, -1 }, \n            // channel 6                 \n            {   2,  32704,   0,     6 ,   0,   104, -1  }, \n            {   3,  56064,   0,     6 ,   196, 380, -1  }, \n            {   4,  53728,   0,     6 ,   468, 644, -1  }, \n            // channel 7                               \n            {   5,  84096,   0,     7 ,   0,   260, -1  }, \n            {   6,  16352,   0,     7 ,   368, 440, -1  }, \n            // channel 8                               \n            {  7,  114464,   0,     8 ,   0,   384, -1  }\n        }\n};\n// XA file to load\nstatic char * loadXA = \"\\\\INTER8.XA;1\";\n// File informations : pos, size, name\nCdlFILE XAPos = {0};\n// CD filter\nCdlFILTER filter;\n// File position in m/s/f\nCdlLOC  loc;\n\nvoid init(void)\n{\n    ResetGraph(0);                 // Initialize drawing engine with a complete reset (0)\n    SetDefDispEnv(&disp[0], 0, 0         , SCREENXRES, SCREENYRES);     // Set display area for both &disp[0] and &disp[1]\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // &disp[0] is on top  of &disp[1]\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // Set draw for both &draw[0] and &draw[1]\n    SetDefDrawEnv(&draw[1], 0, 0         , SCREENXRES, SCREENYRES);     // &draw[0] is below &draw[1]\n    // Set video mode\n    if (VMODE){ SetVideoMode(MODE_PAL);}\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 50, 50, 50); // set color for first draw area\n    setRGB0(&draw[1], 50, 50, 50); // set color for second draw area\n    draw[0].isbg = 1;               // set mask for draw areas. 1 means repainting the area with the RGB color each frame \n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);          // set the disp and draw environnments\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);                // Load font to vram at 960,0(+128)\n    FntOpen(MARGINX, MARGINY, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 512 ); // FntOpen(x, y, width, height,  black_bg, max. nbr. chars\n}\nvoid display(void)\n{\n    DrawSync(0);                    // Wait for all drawing to terminate\n    VSync(0);                       // Wait for the next vertical blank\n    PutDispEnv(&disp[db]);          // set alternate disp and draw environnments\n    PutDrawEnv(&draw[db]);  \n    db = !db;                       // flip db value (0 or 1)\n}\n\nvoid spuSetup(SpuCommonAttr * spuSettings)\n{\n    // Init Spu\n    SpuInit();\n    // Set master & CD volume to max\n    spuSettings->mask = (SPU_COMMON_MVOLL | SPU_COMMON_MVOLR | SPU_COMMON_CDVOLL | SPU_COMMON_CDVOLR | SPU_COMMON_CDMIX);\n    spuSettings->mvol.left  = 0x6000;\n    spuSettings->mvol.right = 0x6000;\n    spuSettings->cd.volume.left = 0x6000;\n    spuSettings->cd.volume.right = 0x6000;\n    // Enable CD input ON\n    spuSettings->cd.mix = SPU_ON;\n    // Apply settings\n    SpuSetCommonAttr(spuSettings);\n    // Set transfer mode \n    SpuSetTransferMode(SPU_TRANSFER_BY_DMA);\n}\n\nvoid XAsetup()\n{   \n    u_char param[4];\n    // ORing the parameters we need to set ; drive speed,  ADPCM play, Subheader filter, sector size\n    // If using CdlModeSpeed(Double speed), you need to load an XA file that has 8 channels.\n    // In single speed, a 4 channels XA is to be used.\n    param[0] = CdlModeSpeed|CdlModeRT|CdlModeSF|CdlModeSize1;\n    // Issue primitive command to CD-ROM system (Blocking-type)\n    // Set the parameters above\n    CdControlB(CdlSetmode, param, 0);\n    // Pause at current pos\n    CdControlF(CdlPause,0);\n}\nint main(void)\n{\n    // Init display\n    init();\n    // Set SPU\n    spuSetup(&spuSettings);\n    // Init CD system\n    CdInit();\n    // Pad\n    PadInit(0);                   \n    // Load XA file from cd\n    // Find XA file pos\n    CdSearchFile( &XAPos, loadXA);\n    // Set cd head to start of file\n    soundBank.offset = CdPosToInt(&XAPos.pos);\n    // Set cd XA playback parameters and pause cd\n    XAsetup();\n    // Pad variables to avoid multifire\n    int pad, oldpad;\n    // Keep track of XA Sample currently playing\n    int sample = -1;\n    while (1)  // infinite loop\n    {   \n        // if sample is set\n        if (sample != -1 ){\n            // Begin XA file playback...\n            // if sample's cursor is 0\n            if (soundBank.samples[sample].cursor == 0){\n                // Convert sector number to CD position in min/second/frame and set CdlLOC accordingly.\n                CdIntToPos( soundBank.samples[sample].start + soundBank.offset , &loc);\n                // Send CDROM read command\n                CdControlF(CdlReadS, (u_char *)&loc);\n                // Set playing flag\n            }\n            // if sample's cursor is close to sample's end position, stop playback\n            if ((soundBank.samples[sample].cursor += XA_CDSPEED) >= soundBank.samples[sample].end - soundBank.samples[sample].start  ){\n                CdControlF(CdlStop,0);\n                soundBank.samples[sample].cursor = -1;\n                sample = -1;\n            }\n        }\n        \n        // Pad \n        // Use up, down, left, right, triangle, cross, circle, square to play various samples\n        // Read pad values\n        pad = PadRead(0);\n        \n        // Left\n        if (pad & PADLleft && !(oldpad & PADLleft)){\n            // Set sample ID for playback\n            sample = 7;\n            // Change file/channel in the filter struct\n            filter.chan = soundBank.samples[sample].channel;\n            filter.file = soundBank.samples[sample].file;\n            // Set filter\n            CdControlF(CdlSetfilter, (u_char *)&filter);\n            // Reset sample's cursor\n            soundBank.samples[sample].cursor = 0;\n            // Store pad value for release\n            oldpad = pad;\n            }\n            \n        if (pad & PADLright && !(oldpad & PADLright)){\n            sample = 6;\n            filter.chan = soundBank.samples[sample].channel;\n            filter.file = soundBank.samples[sample].file;\n            // Set filter\n            CdControlF(CdlSetfilter, (u_char *)&filter);\n            soundBank.samples[sample].cursor = 0;\n            oldpad = pad;\n            }\n        if (pad & PADLup && !(oldpad & PADLup)){\n            sample = 5;\n            filter.chan = soundBank.samples[sample].channel;\n            filter.file = soundBank.samples[sample].file;\n            // Set filter\n            CdControlF(CdlSetfilter, (u_char *)&filter);\n            soundBank.samples[sample].cursor = 0;\n            oldpad = pad;\n            }\n            \n        if (pad & PADLdown && !(oldpad & PADLdown)){\n            sample = 4;\n            filter.chan = soundBank.samples[sample].channel;\n            filter.file = soundBank.samples[sample].file;\n            // Set filter\n            CdControlF(CdlSetfilter, (u_char *)&filter);\n            soundBank.samples[sample].cursor = 0;\n            oldpad = pad;\n            }\n            \n        if (pad & PADRleft && !(oldpad & PADRleft)){\n            sample = 3;\n            filter.chan = soundBank.samples[sample].channel;\n            filter.file = soundBank.samples[sample].file;\n            // Set filter\n            CdControlF(CdlSetfilter, (u_char *)&filter);\n            soundBank.samples[sample].cursor = 0;\n            oldpad = pad;\n            }\n            \n        if (pad & PADRright && !(oldpad & PADRright)){\n            sample = 2;\n            filter.chan = soundBank.samples[sample].channel;\n            filter.file = soundBank.samples[sample].file;\n            // Set filter\n            CdControlF(CdlSetfilter, (u_char *)&filter);\n            soundBank.samples[sample].cursor = 0;\n            oldpad = pad;\n            }\n        if (pad & PADRup && !(oldpad & PADRup)){\n            sample = 1;\n            filter.chan = soundBank.samples[sample].channel;\n            filter.file = soundBank.samples[sample].file;\n            // Set filter\n            CdControlF(CdlSetfilter, (u_char *)&filter);\n            soundBank.samples[sample].cursor = 0;\n            oldpad = pad;\n            }\n            \n        if (pad & PADRdown && !(oldpad & PADRdown)){\n            sample = 0;\n            filter.chan = soundBank.samples[sample].channel;\n            filter.file = soundBank.samples[sample].file;\n            // Set filter\n            CdControlF(CdlSetfilter, (u_char *)&filter);\n            soundBank.samples[sample].cursor = 0;\n            oldpad = pad;\n            }\n        // Reset oldpad    \n        if (!(pad & PADRdown) ||\n            !(pad & PADRup)   ||\n            !(pad & PADRleft) ||\n            !(pad & PADRright) ||\n            !(pad & PADLdown) ||\n            !(pad & PADLup)   ||\n            !(pad & PADLleft) ||\n            !(pad & PADLright)\n            ){oldpad = pad;}\n        \n        FntPrint(\"Hello multi XA ! %d\\n\", VSync(-1));\n        FntPrint(\"Use the pad to play various samples.\\n\");\n        for (int i=0;i<soundBank.index;i++){\n            if (i == sample){\n                FntPrint(\">\");\n            }\n            FntPrint(\"%d: %d %d\\n\", i, soundBank.samples[i].start, soundBank.samples[i].end);  \n        }\n        FntPrint(\"Cursor: %d\\n\", soundBank.samples[sample].cursor );\n        FntPrint(\"File offset: %d\\n\", soundBank.offset );\n        \n        FntFlush(-1);               // Draw print stream\n        display();                  // Execute display()\n    }\n    return 0;\n}\n"
  },
  {
    "path": "hello_multi_xa/isoconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!-- MKPSXISO example XML script -->\n\n<!-- <iso_project>\n        Starts an ISO image project to build. Multiple <iso_project> elements may be\n        specified within the same xml script which useful for multi-disc projects.\n    \n        <iso_project> elements must contain at least one <track> element.\n    \n    Attributes:\n        image_name  - File name of the ISO image file to generate.\n        cue_sheet   - Optional, file name of the cue sheet for the image file\n                      (required if more than one track is specified).\n-->\n<iso_project image_name=\"hello_multi_xa.bin\" cue_sheet=\"hello_multi_xa.cue\">\n\n    <!-- <track>\n            Specifies a track to the ISO project. This example element creates a data\n            track for storing data files and CD-XA/STR streams.\n        \n            Only one data track is allowed and data tracks must only be specified as the\n            first track in the ISO image and cannot be specified after an audio track.\n        \n        Attributes:\n            type        - Track type (either data or audio).\n            source      - For audio tracks only, specifies the file name of a wav audio\n                          file to use for the audio track.\n            \n    -->\n    <track type=\"data\">\n    \n        <!-- <identifiers>\n                Optional, Specifies the identifier strings to use for the data track.\n                \n            Attributes:\n                system          - Optional, specifies the system identifier (PLAYSTATION if unspecified).\n                application     - Optional, specifies the application identifier (PLAYSTATION if unspecified).\n                volume          - Optional, specifies the volume identifier.\n                volume_set      - Optional, specifies the volume set identifier.\n                publisher       - Optional, specifies the publisher identifier.\n                data_preparer   - Optional, specifies the data preparer identifier. If unspecified, MKPSXISO\n                                  will fill it with lengthy text telling that the image file was generated\n                                  using MKPSXISO.\n        -->\n        <identifiers\n            system          =\"PLAYSTATION\"\n            application     =\"PLAYSTATION\"\n            volume          =\"HELOCD\"\n            volume_set      =\"HELOCD\"\n            publisher       =\"SCHNAPPY\"\n            data_preparer       =\"MKPSXISO\"\n        />\n        \n        <!-- <license>\n                Optional, specifies the license file to use, the format of the license file must be in\n                raw 2336 byte sector format, like the ones included with the PsyQ SDK in psyq\\cdgen\\LCNSFILE.\n                \n                License data is not included within the MKPSXISO program to avoid possible legal problems\n                in the open source environment... Better be safe than sorry.\n                \n            Attributes:\n                file    - Specifies the license file to inject into the ISO image.\n        -->\n        <!--\n        <license file=\"LICENSEA.DAT\"/>\n        -->\n        \n        <!-- <directory_tree>\n                Specifies and contains the directory structure for the data track.\n            \n            Attributes:\n                None.\n        -->\n        <directory_tree>\n        \n            <!-- <file>\n                    Specifies a file in the directory tree.\n                    \n                Attributes:\n                    name    - File name to use in the directory tree (can be used for renaming).\n                    type    - Optional, type of file (data for regular files and is the default, xa for\n                              XA audio and str for MDEC video).\n                    source  - File name of the source file.\n            -->\n            <!-- Stores system.txt as system.cnf -->\n            <file name=\"system.cnf\" type=\"data\" source=\"system.cnf\"/>\n            <file name=\"SCES_313.37\"   type=\"data\" source=\"hello_multi_xa.ps-exe\"/>\n            <file name=\"INTER8.XA\" type=\"xa\" source=\"xa/vert8.xa\"/>\n\n            <dummy sectors=\"1024\"/>\n            \n            <!-- <dir>\n                    Specifies a directory in the directory tree. <file> and <dir> elements inside the element\n                    will be inside the specified directory.\n            -->\n        </directory_tree>\n        \n    </track>\n    \n</iso_project>\n"
  },
  {
    "path": "hello_multi_xa/system.cnf",
    "content": "BOOT=cdrom:\\SCES_313.37;1\nTCB=4\nEVENT=10\nSTACK=801FFFF0\n"
  },
  {
    "path": "hello_multi_xa/xa/interleave8.txt",
    "content": "1 xa channel5.xa 0 5\n1 xa channel6.xa 0 6\n1 xa channel7.xa 0 7\n1 xa channel8.xa 0 8\n1 null\n1 null\n1 null\n1 null\n"
  },
  {
    "path": "hello_ovl_exec/Makefile",
    "content": ".PHONY: all cleansub\nall:\n\t$(MAKE) -C hello_poly clean all\n\t$(MAKE) -C hello_ovl_world clean all\n\t$(MAKE) -C hello_tile clean all\n\tmkpsxiso -y ./isoconfig.xml\ncleansub:\n\t$(MAKE) -C hello_poly clean\n\t$(MAKE) -C hello_tile clean\n\t$(MAKE) -C hello_ovl_world clean\n\t$(MAKE) clean\n\trm -f hello_ovl_exec.cue hello_ovl_exec.bin\n\t\nTARGET = hello_ovl_exec\n\nOVERLAYSCRIPT  ?= overlay.ld\nOVERLAYSECTION ?= .ovly0 .ovly1 .ovly2\n\nSRCS = hello_ovl_exec.c \\\nhello_ovl_world/hello_ovl_world.c \\\nhello_tile/hello_ovl_tile.c \\\nhello_poly/hello_ovl_poly.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_ovl_exec/README.md",
    "content": "This example shows how to load overlays from the CD and execute them.\n\nMany thanks to @nicolasnobe for his help on getting this example working.\n\nSee the wiki for more details on overlays in the context of PSX development :\n\n[https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/OVL](https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/OVL)  "
  },
  {
    "path": "hello_ovl_exec/common.h",
    "content": "#pragma once\n#include <sys/types.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n#include <libapi.h>\n#include <libcd.h>\n#include <malloc.h>\n#include <kernel.h>\n\n#include \"../thirdparty/nugget/common/syscalls/syscalls.h\"\n#define printf ramsyscall_printf\n\n#define setRGB(p, r0, g0, b0)\t\t\t\t\t\t\\\n\t(p)->r = r0, (p)->g = g0, (p)->b = b0\n\n#define VMODE 0\n//~ #define VMODE 0                 // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320          // Screen width\n#define SCREENYRES (240 + (VMODE << 4))          // Screen height : If VMODE is 0 = 240, if VMODE is 1 = 256 \n#define CENTERX SCREENXRES/2    // Center of screen on x \n#define CENTERY SCREENYRES/2    // Center of screen on y\n#define MARGINX 0                // margins for text display\n#define MARGINY 32\n#define FONTSIZE 18 * 7           // Text Field Height\n#define OTLEN 8              // Ordering Table Length\n\nextern DRAWENV draw[2];\nextern char primbuff[2][32768];\nextern char *nextpri;\nextern u_long ot[2][OTLEN];\nextern uint8_t db;\nextern uint8_t useOT;\nextern CVECTOR BGcolor;\n\nenum OverlayNumber {\n        MOTHERSHIP = -1,\n        OVERLAY_HELLO = 0,\n        OVERLAY_TILE = 1,\n        OVERLAY_POLY = 2,\n    };\nextern enum OverlayNumber next_overlay;\n\nextern void init(void);\nextern void display(void);\n"
  },
  {
    "path": "hello_ovl_exec/hello_ovl_exec.c",
    "content": "// Load overlay files from CD and execute them\n// Schnappy 10-2021\n// With the help of Nicolas Noble and impiaa \n// https://discord.com/channels/642647820683444236/663664210525290507/894624082367229952\n#include \"common.h\"\n\nDISPENV disp[2];                 // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nchar primbuff[2][32768];        // double primitive buffer of length 32768 * 8 =  262.144 bits / 32,768 Kbytes\nu_long ot[2][OTLEN];\nchar *nextpri = primbuff[0];  \nuint8_t db = 0;    \nCVECTOR BGcolor, MScolor = { 224, 108, 76 };\n\nextern u_long load_all_overlays_here;\n\ntypedef struct Overlay {\n  char filename[0x7c];\n  int (*main)();\n  char commandline[0x180];\n  CVECTOR BGcolor;\n} Overlay;\n\nint ovl_main_hello();\nint ovl_main_tile();\nint ovl_main_poly();\n\nOverlay g_chainload[] = {\n    {\"\\\\HELLO.OVL;1\", ovl_main_hello, \"\", { 225, 220, 40 }},\n    {\"\\\\TILE.OVL;1\", ovl_main_tile, \"\",  { 150, 30 , 40 }},\n    {\"\\\\POLY.OVL;1\", ovl_main_poly, \"\",  { 60 , 127, 0  }},\n};\n\nenum OverlayNumber next_overlay = MOTHERSHIP;\nenum OverlayNumber prev_overlay = MOTHERSHIP;\n\nint main(void);\nint loadOverlayAndStart(Overlay * overlay);\nvoid EmptyOTag(u_long ot[2][OTLEN]);\nvoid EmptyPrimBuf(char primbuff[2][32768], char ** nextpri);\nvoid preInitOvl(Overlay * overlay);\nvoid postInitOvl(Overlay * overlay);\nvoid clearVRAM(void);\n\nvoid (*dispp) (void);\nuint8_t useOT = 0;\nint CDreadOK = 0;\n\nvoid init(void)\n{\n    ResetCallback();\n    ResetGraph(0);                 // Initialize drawing engine with a complete reset (0)\n    // Initialize and setup the GTE\n    InitGeom();\n    SetGeomOffset(CENTERX,CENTERY);\n    SetGeomScreen(CENTERX);\n    SetDefDispEnv(&disp[0], 0, 0         , SCREENXRES, SCREENYRES);     // Set display area for both &disp[0] and &disp[1]\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // &disp[0] is on top  of &disp[1]\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // Set draw for both &draw[0] and &draw[1]\n    SetDefDrawEnv(&draw[1], 0, 0         , SCREENXRES, SCREENYRES);     // &draw[0] is below &draw[1]\n    // Set video mode\n    if (VMODE){ SetVideoMode(MODE_PAL);}\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], BGcolor.r, BGcolor.g, BGcolor.b); // set color for first draw area\n    setRGB0(&draw[1], BGcolor.r, BGcolor.g, BGcolor.b); // set color for second draw area\n    draw[0].isbg = 1;               // set mask for draw areas. 1 means repainting the area with the RGB color each frame \n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);          // set the disp and draw environnments\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);                // Load font to vram at 960,0(+128)\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 ); // FntOpen(x, y, width, height,  black_bg, max. nbr. chars\n}\n\nvoid display(void)\n{\n    DrawSync(0);                    // Wait for all drawing to terminate\n    VSync(0);                       // Wait for the next vertical blank\n    PutDispEnv(&disp[db]);          // set alternate disp and draw environnments\n    PutDrawEnv(&draw[db]);\n    if (useOT)\n    {\n        DrawOTag(&ot[db][OTLEN - 1]);\n    }\n    db = !db;                       // flip db value (0 or 1)\n    nextpri = primbuff[db];\n}\nvoid clearVRAM(void)\n{\n    RECT vram = {0,0,1024,512};\n    ClearImage(&vram,0,0,0);\n}\nvoid preInitOvl(Overlay * overlay)\n{\n    //~ clearVRAM();\n    ResetCallback();\n    ResetGraph(3);\n    EmptyPrimBuf(primbuff, &nextpri);\n    EmptyOTag(&ot[db]);\n    setRGB(&BGcolor, overlay->BGcolor.r, overlay->BGcolor.g, overlay->BGcolor.b );\n}\nvoid postInitOvl(Overlay * overlay)\n{\n    //~ clearVRAM();\n    //~ ResetGraph(3);\n    EmptyPrimBuf(primbuff, &nextpri);\n    EmptyOTag(&ot[db]);\n    setRGB(&BGcolor, MScolor.r, MScolor.g, MScolor.b);\n    setRGB0(&draw[0], BGcolor.r, BGcolor.g, BGcolor.b); // set color for first draw area\n    setRGB0(&draw[1], BGcolor.r, BGcolor.g, BGcolor.b);\n    FntLoad(960, 0);                // Load font to vram at 960,0(+128)\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 ); // FntOpen(x, y, width, height,  black_bg, max. nbr. chars\n}\nint loadOverlayAndStart(Overlay * overlay)\n{\n    int CDreadResult = 0;\n    int next_ovl = -1;\n    // Load overlay file\n    CDreadResult = CdReadFile(overlay->filename, &load_all_overlays_here, 0);\n\tCdReadSync(0, 0);\n    printf( \"CD read: %d\", CDreadResult);\n    // If file loaded sucessfully\n    if (CDreadResult)\n    {\n        // Pre OVL\n        preInitOvl(overlay);\n        // Exec OVL\n        next_ovl = overlay->main();\n        // Post OVL\n        postInitOvl(overlay);\n    }\n    return next_ovl;\n}\nvoid EmptyPrimBuf(char primbuff[2][32768], char ** nextpri)\n{\n    for(uint16_t p; p < 32768; p++)\n    {\n        primbuff[0][p] = 0;\n        primbuff[1][p] = 0;\n    }\n    *nextpri = primbuff[0];\n}\nvoid EmptyOTag(u_long ot[2][OTLEN])\n{\n    for (uint16_t p; p < OTLEN; p++)\n    {\n        ot[0][p] = 0;\n        ot[1][p] = 0;\n    }\n}\n\nint main(void)\n{   \n    int t = 0;\n    setRGB(&BGcolor, MScolor.r, MScolor.g, MScolor.b);\n    // init() display\n    init();          \n    // Init CD system\n    CdInit();\n    prev_overlay = next_overlay; \n    while(1){\n        if (t == 100){\n            next_overlay = OVERLAY_HELLO;\n        }\n        if (next_overlay != -1 && next_overlay != prev_overlay){\n            prev_overlay = next_overlay;\n            next_overlay = loadOverlayAndStart(&g_chainload[next_overlay]);\n            t = 0;\n        }\n        t++;\n        FntPrint(\"Mothership:  %d\\nOvl: %d %d\", t, prev_overlay, next_overlay);\n        FntFlush(-1);\n        display();\n    }\n    //\n    return 0;\n}\n"
  },
  {
    "path": "hello_ovl_exec/hello_ovl_world/Makefile",
    "content": "TARGET = hello_world\n\nSRCS = hello_world.c \\\n\nCPPFLAGS+=-DSTANDALONE\n\ninclude ../../common.mk \n"
  },
  {
    "path": "hello_ovl_exec/hello_ovl_world/hello_ovl_world.c",
    "content": "#include \"../common.h\"\n\nint ovl_main_hello(void)\n{   \n    init();\n    int i = 0;\n    while(1)\n    {\n        i++;\n        #ifndef STANDALONE\n        if (i==100){\n            next_overlay = OVERLAY_TILE;\n            break;\n        }\n            FntPrint(\"Hello world ! %d\\n\", i);\n        #else\n            FntPrint(\"Hello standalone ! %d\\n\", i);\n        #endif\n        FntFlush(-1);\n        display();\n    }\n    return next_overlay;\n};\n\n"
  },
  {
    "path": "hello_ovl_exec/hello_ovl_world/hello_world.c",
    "content": "#include \"../common.h\"\n\nDISPENV disp[2];             // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nu_long ot[2][OTLEN];          // double ordering table of length 8 * 32 = 256 bits / 32 bytes\nchar primbuff[2][32768];// double primitive buffer of length 32768 * 8 =  262.144 bits / 32,768 Kbytes\nchar *nextpri = primbuff[0];  // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]\nuint8_t db = 0;                 // index of which buffer is used, values 0, 1\nCVECTOR BGcolor = { 0, 255, 100 };\n//~ int next_overlay;\n\nvoid init(void)\n{\n    ResetGraph(0);\n    SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\n    if (VMODE)\n    {\n        SetVideoMode(MODE_PAL);\n        disp[0].screen.y += 8;\n        disp[1].screen.y += 8;\n        }\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], BGcolor.r, BGcolor.g, BGcolor.b); // set color for first draw area\n    setRGB0(&draw[1], BGcolor.r, BGcolor.g, BGcolor.b); // set color for second draw area\n    draw[0].isbg = 1;\n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );\n}\nvoid display(void)\n{\n    DrawSync(0);\n    VSync(0);\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    DrawOTag(&ot[db][OTLEN - 1]);\n    db = !db;\n    nextpri = primbuff[db];\n}\n\n#include \"hello_ovl_world.c\"\n\nint main(void)\n{\n    ovl_main_hello();\n};\n\n"
  },
  {
    "path": "hello_ovl_exec/hello_poly/Makefile",
    "content": "TARGET = hello_poly\n\nSRCS = hello_poly.c \\\n\nCPPFLAGS+=-DSTANDALONE\n\ninclude ../../common.mk \n"
  },
  {
    "path": "hello_ovl_exec/hello_poly/hello_ovl_poly.c",
    "content": "#include \"../common.h\"\n\n\nint ovl_main_poly(void)\n{   \n    #ifndef STANDALONE\n        useOT = 1;\n    #endif\n    init();\n    uint16_t timer = 0;\n    uint16_t timeout = 100;\n    MATRIX IDMATRIX = {0};                 \n    POLY_F4 *poly = {0};                   \n    SVECTOR RotVector = {0, 0, 0};         \n    VECTOR  MovVector = {0, 0, CENTERX, 0};\n    SVECTOR VertPos[4] = {                 \n            {-32, -32, 1 },                \n            {-32,  32, 1 },                \n            { 32, -32, 1 },                \n            { 32,  32, 1  }                \n        };                                          \n    MATRIX PolyMatrix = IDMATRIX;                   \n    \n    long polydepth;\n    long polyflag;\n    long OTz;\n    \n    init();\n\n    while (1)\n    {\n\n        ClearOTagR(ot[db], OTLEN);\n        \n        poly = (POLY_F4 *)nextpri;                    // Set poly to point to  the address of the next primitiv in the buffer\n        \n        // Set transform matrices for this polygon\n                \n        RotMatrix(&RotVector, &PolyMatrix);           // Apply rotation matrix\n        TransMatrix(&PolyMatrix, &MovVector);\n        SetRotMatrix(&PolyMatrix);                    // Set default rotation matrix\n        SetTransMatrix(&PolyMatrix);                  // Set default transformation matrix\n        setPolyF4(poly);                              // Initialize poly as a POLY_F4 \n        setRGB0(poly, 255, 255, 0);                   // Set poly color\n\n        // RotTransPers\n        OTz = RotTransPers4(\n                    &VertPos[0],      &VertPos[1],      &VertPos[2],      &VertPos[3],\n                    (long*)&poly->x0, (long*)&poly->x1, (long*)&poly->x2, (long*)&poly->x3,\n                    &polydepth,\n                    &polyflag\n                    );                                // Perform coordinate and perspective transformation for 4 vertices\n        \n        RotVector.vy += 4;\n        RotVector.vz += 4;                              // Apply rotation on Z-axis. On PSX, the Z-axis is pointing away from the screen.  \n\n        //~ addPrim(ot[db], poly);                         // add poly to the Ordering table\n        addPrim(ot[db][OTLEN-1], poly);                         // add poly to the Ordering table\n        \n        nextpri += sizeof(POLY_F4);                    // increment nextpri address with size of a POLY_F4 struct \n        \n        timer++;\n    \n        FntPrint(\"Hello Poly ! %d\", timer);                   \n        FntFlush(-1);\n        #ifndef STANDALONE\n            if (timer == timeout){\n                useOT = 0;\n                next_overlay = MOTHERSHIP;\n                break;\n            }\n        #endif\n        display();\n\n    }\n    return next_overlay;\n};\n"
  },
  {
    "path": "hello_ovl_exec/hello_poly/hello_poly.c",
    "content": "#include \"../common.h\"\n\nDISPENV disp[2];                   // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nu_long ot[2][OTLEN];               // double ordering table of length 8 * 32 = 256 bits / 32 bytes\nchar primbuff[2][32768];           // double primitive buffer of length 32768 * 8 =  262.144 bits / 32,768 Kbytes\nchar *nextpri = primbuff[0];       // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]\nuint8_t db = 0;                      // index of which buffer is used, values 0, 1\nCVECTOR BGcolor = { 50, 255, 150 };\n\nvoid init(void)\n{\n    ResetCallback();\n    ResetGraph(3);\n    // Initialize and setup the GTE\n    InitGeom();\n    SetGeomOffset(CENTERX,CENTERY);\n    SetGeomScreen(CENTERX);\n    SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\n    if (VMODE)\n    {\n        SetVideoMode(MODE_PAL);\n        disp[0].screen.y += 8;\n        disp[1].screen.y += 8;\n    }\n    setRGB0(&draw[0], BGcolor.r, BGcolor.g, BGcolor.b); // set color for first draw area\n    setRGB0(&draw[1], BGcolor.r, BGcolor.g, BGcolor.b); // set color for second draw area\n    SetDispMask(1);\n    draw[0].isbg = 1;\n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    \n    FntLoad(960, 0);\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );\n    \n}\n\nvoid display(void)\n{\n    DrawSync(0);\n    VSync(0);\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    DrawOTag(&ot[db][OTLEN - 1]);\n    db = !db;\n    nextpri = primbuff[db];\n}\n\n#include \"hello_ovl_poly.c\"\n\nint main(void)\n{   \n    ovl_main_poly();\n}\n"
  },
  {
    "path": "hello_ovl_exec/hello_tile/Makefile",
    "content": "TARGET = hello_tile\n\nSRCS = hello_tile.c \\\n\nCPPFLAGS+=-DSTANDALONE\n\ninclude ../../common.mk \n"
  },
  {
    "path": "hello_ovl_exec/hello_tile/hello_ovl_tile.c",
    "content": "#include \"../common.h\"\n\nint ovl_main_tile(void)\n{\n    #ifndef STANDALONE\n        useOT = 1;\n    #endif\n    uint16_t timer = 0;\n    uint16_t timeout = 100;\n    TILE * blue_tile = 0;\n    TILE * pink_tile = 0;\n    // This one is added at a different OT index\n    TILE * yellow_tile = 0;\n    init();\n    while(1)\n    {\n        // Initialize the reversed ordering table. This means the elements at index OTLEN - 1 is drawn first.\n        ClearOTagR(ot[db], OTLEN);\n\n        // yellow_tile\n        \n        yellow_tile = (TILE * ) nextpri;                   // yellow_tile is a pointer to primbuf content at adress nextpri, that's cast (type converted) to a TILE struc.   \n        \n        setTile(yellow_tile);                              // initialize the TILE structure ( fill the length and tag(?) value )\n        setXY0(yellow_tile, CENTERX - 32 , CENTERY - 48);  // Set X,Y\n        setWH(yellow_tile, 128, 40);                       // Set Width, Height\n        setRGB0(yellow_tile, 255, 255, 0);                 // Set color\n        addPrim(ot[db][OTLEN - 1], yellow_tile);                    // Add primitive to ordering table\n            \n        nextpri += sizeof(TILE);     \n        \n        // blue_tile \n        \n        blue_tile = (TILE * ) nextpri;                  // blue_tile is a pointer to primbuf content at adress nextpri, that's cast (type converted) to a blue_tile struc.   \n        \n        setTile(blue_tile);                              // initialize the blue_tile structure ( fill the length and tag(?) value )\n        setXY0(blue_tile, CENTERX - 16, CENTERY - 32);   // Set X,Y\n        setWH(blue_tile, 32, 64);                        // Set Width, Height\n        setRGB0(blue_tile, 60, 180, 255);                // Set color\n        addPrim(ot[db][OTLEN - 2], blue_tile);                      // Add primitive to ordering table\n\n        nextpri += sizeof(TILE);                    // Increment the adress nextpri points to by the size of TILE struct\n        \n        // pink_tile\n        \n        pink_tile = (TILE * ) nextpri;                  // pink_tile is a pointer to primbuf content at adress nextpri, that's cast (type converted) to a TILE struc.   \n        \n        setTile(pink_tile);                              // initialize the TILE structure ( fill the length and tag(?) value )\n        setXY0(pink_tile, CENTERX, CENTERY - 64);   // Set X,Y\n        setWH(pink_tile, 64, 64);                        // Set Width, Height\n        setRGB0(pink_tile, 255, 32, 255);                // Set color\n        addPrim(ot[db][OTLEN - 2], pink_tile);                      // Add primitive to ordering table\n            \n        nextpri += sizeof(TILE);     \n        \n        timer ++;\n        \n        FntPrint(\"Hello tile ! %d\\n\", timer);\n        FntFlush(-1);\n        #ifndef STANDALONE\n            if (timer == timeout){\n                useOT = 0;\n                next_overlay = OVERLAY_POLY;\n                break;\n            }\n        #endif\n        display();\n    }\n    return next_overlay;\n};\n"
  },
  {
    "path": "hello_ovl_exec/hello_tile/hello_tile.c",
    "content": "#include \"../common.h\"\n\nDISPENV disp[2];             // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nu_long ot[2][OTLEN];          // double ordering table of length 8 * 32 = 256 bits / 32 bytes\nchar primbuff[2][32768];      // double primitive buffer of length 32768 * 8 =  262.144 bits / 32,768 Kbytes\nchar *nextpri = primbuff[0];  // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]\nuint8_t db = 0;                 // index of which buffer is used, values 0, 1\nCVECTOR BGcolor = { 50, 255, 150 };\n\nvoid init(void)\n{\n    ResetGraph(0);\n    SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\n    if (VMODE)\n    {\n        SetVideoMode(MODE_PAL);\n        disp[0].screen.y += 8;\n        disp[1].screen.y += 8;\n        }\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], BGcolor.r, BGcolor.g, BGcolor.b); // set color for first draw area\n    setRGB0(&draw[1], BGcolor.r, BGcolor.g, BGcolor.b); // set color for second draw area\n    draw[0].isbg = 1;\n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );\n}\nvoid display(void)\n{\n    DrawSync(0);\n    VSync(0);\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    // We're using a reverse OT, so we want to display the last item first. See PsyQ's LibRef47.pdf, p.277\n    DrawOTag(&ot[db][OTLEN - 1]);\n    // Comment above line, and uncomment the following line to use a regular oredered OT. Comment l.71 and Uncomment l.73 accordingly\n    db = !db;\n    nextpri = primbuff[db];\n}\n\n#include \"hello_ovl_tile.c\"\n\nint main(void)\n{\n    ovl_main_tile();\n};\n"
  },
  {
    "path": "hello_ovl_exec/isoconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!-- MKPSXISO example XML script -->\n\n<!-- <iso_project>\n        Starts an ISO image project to build. Multiple <iso_project> elements may be\n        specified within the same xml script which useful for multi-disc projects.\n    \n        <iso_project> elements must contain at least one <track> element.\n    \n    Attributes:\n        image_name  - File name of the ISO image file to generate.\n        cue_sheet   - Optional, file name of the cue sheet for the image file\n                      (required if more than one track is specified).\n-->\n<iso_project image_name=\"hello_ovl_exec.bin\" cue_sheet=\"hello_ovl_exec.cue\">\n\n    <!-- <track>\n            Specifies a track to the ISO project. This example element creates a data\n            track for storing data files and CD-XA/STR streams.\n        \n            Only one data track is allowed and data tracks must only be specified as the\n            first track in the ISO image and cannot be specified after an audio track.\n        \n        Attributes:\n            type        - Track type (either data or audio).\n            source      - For audio tracks only, specifies the file name of a wav audio\n                          file to use for the audio track.\n            \n    -->\n    <track type=\"data\">\n    \n        <!-- <identifiers>\n                Optional, Specifies the identifier strings to use for the data track.\n                \n            Attributes:\n                system          - Optional, specifies the system identifier (PLAYSTATION if unspecified).\n                application     - Optional, specifies the application identifier (PLAYSTATION if unspecified).\n                volume          - Optional, specifies the volume identifier.\n                volume_set      - Optional, specifies the volume set identifier.\n                publisher       - Optional, specifies the publisher identifier.\n                data_preparer   - Optional, specifies the data preparer identifier. If unspecified, MKPSXISO\n                                  will fill it with lengthy text telling that the image file was generated\n                                  using MKPSXISO.\n        -->\n        <identifiers\n            system          =\"PLAYSTATION\"\n            application     =\"PLAYSTATION\"\n            volume          =\"HELOCD\"\n            volume_set      =\"HELOCD\"\n            publisher       =\"SCHNAPPY\"\n            data_preparer       =\"MKPSXISO\"\n        />\n        \n        <!-- <license>\n                Optional, specifies the license file to use, the format of the license file must be in\n                raw 2336 byte sector format, like the ones included with the PsyQ SDK in psyq\\cdgen\\LCNSFILE.\n                \n                License data is not included within the MKPSXISO program to avoid possible legal problems\n                in the open source environment... Better be safe than sorry.\n                \n            Attributes:\n                file    - Specifies the license file to inject into the ISO image.\n        -->\n        <!--\n        <license file=\"LICENSEA.DAT\"/>\n        -->\n        \n        <!-- <directory_tree>\n                Specifies and contains the directory structure for the data track.\n            \n            Attributes:\n                None.\n        -->\n        <directory_tree>\n        \n            <!-- <file>\n                    Specifies a file in the directory tree.\n                    \n                Attributes:\n                    name    - File name to use in the directory tree (can be used for renaming).\n                    type    - Optional, type of file (data for regular files and is the default, xa for\n                              XA audio and str for MDEC video).\n                    source  - File name of the source file.\n            -->\n            <!-- Stores system.txt as system.cnf -->\n            <file name=\"system.cnf\" type=\"data\" source=\"system.cnf\"/>\n            <file name=\"SCES_313.37\"   type=\"data\" source=\"hello_ovl_exec.ps-exe\"/>\n            <file name=\"POLY.OVL\"   type=\"data\" source=\"Overlay.ovly0\"/>\n            <file name=\"TILE.OVL\"   type=\"data\" source=\"Overlay.ovly1\"/>\n            <file name=\"HELLO.OVL\"   type=\"data\" source=\"Overlay.ovly2\"/>\n            <dummy sectors=\"1024\"/>\n            \n            <!-- <dir>\n                    Specifies a directory in the directory tree. <file> and <dir> elements inside the element\n                    will be inside the specified directory.\n            -->\n        </directory_tree>\n        \n    </track>\n    \n</iso_project>\n"
  },
  {
    "path": "hello_ovl_exec/overlay.ld",
    "content": "__heap_base = MAX(__ovly0_end, __ovly2_end);\n\nSECTIONS {\t\t\n\tOVERLAY __bss_end : NOCROSSREFS SUBALIGN(4)\n\t{\n\t\t.ovlyload\n        {\n            load_all_overlays_here = .;\n        }\n\t.ovly0\n\t\t{\t\t\t\n\t\t\tKEEP(hello_poly/*.o(.text))\n\t\t\t__ovly0_ctor = .;\n\t\t\tKEEP(hello_poly/*.o(.text.startup._GLOBAL__*))\n\t\t\tKEEP(hello_poly/*.o(.text.*))\n\t\t\tKEEP(hello_poly/*.o(.rodata*))\n\t\t\tKEEP(hello_poly/*.o(.sdata*))\n\t\t\tKEEP(hello_poly/*.o(.data*))\n\t\t\tKEEP(hello_poly/*.o(.sbss*))\n\t\t\tKEEP(hello_poly/*.o(.bss*))\n\t\t\tKEEP(hello_poly/*.o(.ctors))\n\t\t\t\n\t\t\t. = ALIGN(4);\n\t\t\t__ovly0_end = .;\t\t\t\n\t\t}\n\n        .ovly1\n\t\t{\n\t\t\tKEEP(hello_tile/*.o(.text))\n\t\t\t__ovly1_ctor = .;\n\t\t\tKEEP(hello_tile/*.o(.text.startup._GLOBAL__*))\n\t\t\tKEEP(hello_tile/*.o(.text.*))\n\t\t\tKEEP(hello_tile/*.o(.rodata*))\n\t\t\tKEEP(hello_tile/*.o(.sdata*))\n\t\t\tKEEP(hello_tile/*.o(.data*))\n\t\t\tKEEP(hello_tile/*.o(.sbss*))\n\t\t\tKEEP(hello_tile/*.o(.bss*))\n\t\t\tKEEP(hello_tile/*.o(.ctors))\n\t\t\t\n\t\t\t. = ALIGN(4);\n\t\t\t__ovly1_end = .;\t\t\t\n\t\t}\n\t.ovly2\n\t\t{\n\t\t\tKEEP(hello_ovl_world/*.o(.text))\n\t\t\t__ovly2_ctor = .;\n\t\t\tKEEP(hello_ovl_world/*.o(.text.startup._GLOBAL__*))\n\t\t\tKEEP(hello_ovl_world/*.o(.text.*))\n\t\t\tKEEP(hello_ovl_world/*.o(.rodata*))\n\t\t\tKEEP(hello_ovl_world/*.o(.sdata*))\n\t\t\tKEEP(hello_ovl_world/*.o(.data*))\n\t\t\tKEEP(hello_ovl_world/*.o(.sbss*))\n\t\t\tKEEP(hello_ovl_world/*.o(.bss*))\n\t\t\tKEEP(hello_ovl_world/*.o(.ctors))\n\t\t\t\n\t\t\t. = ALIGN(4);\n\t\t\t__ovly2_end = .;\t\t\t\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "hello_ovl_exec/system.cnf",
    "content": "BOOT=cdrom:\\SCES_313.37;1\nTCB=4\nEVENT=10\nSTACK=801FFFF0\n"
  },
  {
    "path": "hello_pad/Makefile",
    "content": "TARGET = hello_pad\n\nSRCS = hello_pad.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_pad/hello_pad.c",
    "content": "// hello_pad example\n//\n// We're using libetc PadInit() and PadRead() that only supports the 16 buttons pad\n// but doesn't need the libpad lib. It's fine for prototyping and simple stuff.\n// Schnappy 2021\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n#define VMODE 0         // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320\n#define SCREENYRES 240\n#define CENTERX SCREENXRES/2\n#define CENTERY SCREENYRES/2\n#define MARGINX 32               // margins for text display\n#define MARGINY 32\n#define FONTSIZE 8 * 2           // Text Field Height\n#define OTLEN 8                  // Ordering Table Length \nDISPENV disp[2];                 // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nu_long ot[2][OTLEN];             // double ordering table of length 8 * 32 = 256 bits / 32 bytes\nchar primbuff[2][32768];   // double primitive buffer of length 32768 * 8 =  262.144 bits / 32,768 Kbytes\nchar *nextpri = primbuff[0];     // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]\nshort db = 0;                    // index of which buffer is used, values 0, 1\nvoid init(void)\n{\n    ResetGraph(0);\n    SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\n    if (VMODE)\n    {\n        SetVideoMode(MODE_PAL);\n        disp[0].screen.y += 8;\n        disp[1].screen.y += 8;\n        }\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 50, 50, 50);\n    setRGB0(&draw[1], 50, 50, 50);\n    draw[0].isbg = 1;\n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );\n}\nvoid display(void)\n{\n    DrawSync(0);\n    VSync(0);\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    DrawOTag(&ot[db][OTLEN - 1]);\n    db = !db;\n    nextpri = primbuff[db];\n}\nint main(void)\n{\n    TILE * PADL;                    // Tile primitives\n    TILE * TRIGGERL;\n    TILE * PADR;\n    TILE * TRIGGERR;\n    TILE * START, * SELECT;\n    int pad = 0;                    \n    init();\n    PadInit(0);                     // Initialize pad.  Mode is always 0\n    while (1)\n    {\n        ClearOTagR(ot[db], OTLEN);\n        // D-cross\n        PADL = (TILE *)nextpri;\n        setTile(PADL);\n        setRGB0(PADL, 0, 0, 255);        \n        setXY0(PADL, CENTERX - 80, CENTERY);\n        setWH(PADL, 24, 24);\n        addPrim(ot[db], PADL);\n        nextpri += sizeof(TILE);\n        // L1+L2\n        TRIGGERL = (TILE *)nextpri;\n        setTile(TRIGGERL);\n        setRGB0(TRIGGERL, 255, 0, 0);        \n        setXY0(TRIGGERL, CENTERX - 80, CENTERY - 80);\n        setWH(TRIGGERL, 24, 24);\n        addPrim(ot[db], TRIGGERL);\n        nextpri += sizeof(TILE);\n        // /\\, X, O, [] \n        PADR = (TILE *)nextpri;\n        setTile(PADR);\n        setRGB0(PADR, 0, 255, 0);        \n        setXY0(PADR, CENTERX + 50, CENTERY);\n        setWH(PADR, 24, 24);\n        addPrim(ot[db], PADR);\n        nextpri += sizeof(TILE);\n        // R1+R2\n        TRIGGERR = (TILE *)nextpri;\n        setTile(TRIGGERR);\n        setRGB0(TRIGGERR, 255, 0, 255);        \n        setXY0(TRIGGERR, CENTERX + 50, CENTERY -80);\n        setWH(TRIGGERR, 24, 24);\n        addPrim(ot[db], TRIGGERR);\n        nextpri += sizeof(TILE);\n        // START + SELECT\n        START = (TILE *)nextpri;\n        setTile(START);\n        setRGB0(START, 240, 240, 240);        \n        setXY0(START, CENTERX - 16, CENTERY - 36);\n        setWH(START, 24, 24);\n        addPrim(ot[db], START);\n        nextpri += sizeof(TILE);\n        // Pad stuff\n        pad = PadRead(0);                             // Read pads input. id is unused, always 0.\n                                                      // PadRead() returns a 32 bit value, where input from pad 1 is stored in the low 2 bytes and input from pad 2 is stored in the high 2 bytes. (https://matiaslavik.wordpress.com/2015/02/13/diving-into-psx-development/)\n        // D-pad        \n        if(pad & PADLup)   {PADL->y0 = CENTERY - 16;} // 🡩           // To access pad 2, use ( pad >> 16 & PADLup)...\n        if(pad & PADLdown) {PADL->y0 = CENTERY + 16;} // 🡫\n        if(pad & PADLright){PADL->x0 = CENTERX - 64;} // 🡪\n        if(pad & PADLleft) {PADL->x0 = CENTERX - 96;} // 🡨\n        // Buttons\n        if(pad & PADRup)   {PADR->y0 = CENTERY - 16;} //   △\n        if(pad & PADRdown) {PADR->y0 = CENTERY + 16;} // ╳\n        if(pad & PADRright){PADR->x0 = CENTERX + 66;} //   ⭘\n        if(pad & PADRleft) {PADR->x0 = CENTERX + 34;} // ⬜\n        // Shoulder buttons\n        if(pad & PADL1){TRIGGERL->y0 = CENTERY - 64;} // L1\n        if(pad & PADL2){TRIGGERL->y0 = CENTERY - 96;} // L2\n        if(pad & PADR1){TRIGGERR->y0 = CENTERY - 64;} // R1\n        if(pad & PADR2){TRIGGERR->y0 = CENTERY - 96;} // R2\n        // Start & Select\n        if(pad & PADstart){START->w = 32; START->h = 32;START->x0 -= 4;START->y0 -= 4;} // START\n        if(pad & PADselect){START->r0 = 0;}                                             // SELECT\n        FntPrint(\"Hello Pad!\");\n        FntFlush(-1);\n        display();\n        }\n    return 0;\n    }\n"
  },
  {
    "path": "hello_poly/Makefile",
    "content": "TARGET = hello_poly\n\nSRCS = hello_poly.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_poly/hello_poly.c",
    "content": "// Draw a colored poly primitive\n//\n// With help from Nicolas Noble, Jaby smoll Seamonstah, Lameguy64\n// \n// From ../psyq/addons/graphics/MESH/RMESH/TUTO0.C :\n// Schnappy 2021\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n#include <libapi.h>\n#define VMODE 0                 // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320          // Screen width\n#define SCREENYRES 240          // Screen height\n#define CENTERX SCREENXRES/2    // Center of screen on x \n#define CENTERY SCREENYRES/2    // Center of screen on y\n#define MARGINX 0                // margins for text display\n#define MARGINY 32\n#define FONTSIZE 8 * 7             // Text Field Height\n#define OTLEN 8                    // Ordering Table Length \nDISPENV disp[2];                   // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nu_long ot[2][OTLEN];               // double ordering table of length 8 * 32 = 256 bits / 32 bytes\nchar primbuff[2][32768];     // double primitive buffer of length 32768 * 8 =  262.144 bits / 32,768 Kbytes\nchar *nextpri = primbuff[0];       // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]\nshort db = 0;                      // index of which buffer is used, values 0, 1\nvoid init(void)\n{\n    ResetGraph(0);\n    // Initialize and setup the GTE\n    InitGeom();\n    SetGeomOffset(CENTERX,CENTERY);\n    SetGeomScreen(CENTERX);\n    SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\n    if (VMODE) {\n        SetVideoMode(MODE_PAL);\n        disp[0].disp.y = disp[1].disp.y = 8;\n    }\n    SetDispMask(1);                 \n    setRGB0(&draw[0], 50, 50, 50);\n    setRGB0(&draw[1], 50, 50, 50);\n    draw[0].isbg = 1;\n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );\n}\nvoid display(void)\n{\n    DrawSync(0);\n    VSync(0);\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    DrawOTag(&ot[db][OTLEN - 1]);\n    db = !db;\n    nextpri = primbuff[db];\n}\nint main(void)\n{\n    POLY_F4 *poly = {0};                            // pointer to a POLY_F4 \n    SVECTOR RotVector = {0, 0, 0};                  // Initialize rotation vector {x, y, z}\n    VECTOR  MovVector = {0, 0, CENTERX, 0};         // Initialize translation vector {x, y, z}\n    VECTOR  ScaleVector ={ONE, ONE, ONE};           // ONE is define as 4096 in libgte.h\n    SVECTOR VertPos[4] = {                          // Set initial vertices position relative to 0,0 - see here : https://psx.arthus.net/docs/poly_f4.jpg\n            {-32, -32, 1 },                         // Vert 1 \n            {-32,  32, 1 },                         // Vert 2\n            { 32, -32, 1 },                         // Vert 3\n            { 32,  32, 1  }                         // Vert 4\n        };                                          \n    MATRIX PolyMatrix = {0};                   \n    long polydepth;\n    long polyflag;\n    long OTz;\n    init();\n    while (1)\n    {\n        ClearOTagR(ot[db], OTLEN);\n        poly = (POLY_F4 *)nextpri;                    // Set poly to point to  the address of the next primitiv in the buffer\n        // Set transform matrices for this polygon\n        RotMatrix(&RotVector, &PolyMatrix);           // Apply rotation matrix\n        TransMatrix(&PolyMatrix, &MovVector);\n        ScaleMatrix(&PolyMatrix, &ScaleVector);         // Apply translation matrix   \n        SetRotMatrix(&PolyMatrix);                    // Set default rotation matrix\n        SetTransMatrix(&PolyMatrix);                  // Set default transformation matrix\n        setPolyF4(poly);                              // Initialize poly as a POLY_F4 \n        setRGB0(poly, 255, 0, 255);                   // Set poly color\n        // RotTransPers using 4 calls\n        //~ OTz = RotTransPers(&VertPos[0], (long*)&poly->x0, &polydepth, &polyflag);\n        //~ RotTransPers(&VertPos[1], (long*)&poly->x1, &polydepth, &polyflag);\n        //~ RotTransPers(&VertPos[2], (long*)&poly->x2, &polydepth, &polyflag);\n        //~ RotTransPers(&VertPos[3], (long*)&poly->x3, &polydepth, &polyflag);\n        // RotTransPers4 equivalent \n        OTz = RotTransPers4(\n                    &VertPos[0],      &VertPos[1],      &VertPos[2],      &VertPos[3],\n                    (long*)&poly->x0, (long*)&poly->x1, (long*)&poly->x2, (long*)&poly->x3,\n                    &polydepth,\n                    &polyflag\n                    );                                // Perform coordinate and perspective transformation for 4 vertices\n        RotVector.vy += 4;\n        RotVector.vz += 4;                              // Apply rotation on Z-axis. On PSX, the Z-axis is pointing away from the screen.  \n        addPrim(ot[db], poly);                         // add poly to the Ordering table\n        nextpri += sizeof(POLY_F4);                    // increment nextpri address with size of a POLY_F4 struct \n        FntPrint(\"Hello Poly !\");                   \n        FntFlush(-1);\n        display();\n        }\n    return 0;\n    }\n"
  },
  {
    "path": "hello_poly_ft/Makefile",
    "content": "TARGET = hello_poly_ft\n\nSRCS = hello_poly_ft.c \\\n../TIM/bousai.tim \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_poly_ft/hello_poly_ft.c",
    "content": "// Draw a textured poly primitive\n//\n// With help from Nicolas Noble, Jaby smoll Seamonstah, Lameguy64\n// \n// From ../psyq/addons/graphics/MESH/RMESH/TUTO0.C :\n// Schnappy 2021\n\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n\n#define VMODE 0                 // Video Mode : 0 : NTSC, 1: PAL\n\n#define SCREENXRES 320          // Screen width\n#define SCREENYRES 240          // Screen height\n\n#define CENTERX SCREENXRES/2    // Center of screen on x \n#define CENTERY SCREENYRES/2    // Center of screen on y\n\n#define MARGINX 32               // margins for text display\n#define MARGINY 32\n\n#define FONTSIZE 8 * 5             // Text Field Height\n\n#define OTLEN 8                    // Ordering Table Length \n\nDISPENV disp[2];                   // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\n\nu_long ot[2][OTLEN];               // double ordering table of length 8 * 32 = 256 bits / 32 bytes\n\nchar primbuff[2][32768];     // double primitive buffer of length 32768 * 8 =  262.144 bits / 32,768 Kbytes\n\nchar *nextpri = primbuff[0];       // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]\n\nshort db = 0;                      // index of which buffer is used, values 0, 1\n\n// 16bpp TIM\nextern unsigned long _binary____TIM_bousai_tim_start[];\nextern unsigned long _binary____TIM_bousai_tim_end[];\nextern unsigned long _binary____TIM_bousai_tim_length;\n\nTIM_IMAGE bousai;\nvoid LoadTexture(u_long * tim, TIM_IMAGE * tparam){     // This part is from Lameguy64's tutorial series : lameguy64.net/svn/pstutorials/chapter1/3-textures.html login/pw: annoyingmous\n        OpenTIM(tim);                                   // Open the tim binary data, feed it the address of the data in memory\n        ReadTIM(tparam);                                // This read the header of the TIM data and sets the corresponding members of the TIM_IMAGE structure\n        \n        LoadImage(tparam->prect, tparam->paddr);        // Transfer the data from memory to VRAM at position prect.x, prect.y\n        DrawSync(0);                                    // Wait for the drawing to end\n        \n        if (tparam->mode & 0x8){ // check 4th bit       // If 4th bit == 1, TIM has a CLUT\n            LoadImage(tparam->crect, tparam->caddr);    // Load it to VRAM at position crect.x, crect.y\n            DrawSync(0);                                // Wait for drawing to end\n    }\n}\n\nvoid init(void)\n{\n    ResetGraph(0);\n\n    // Initialize and setup the GTE\n    \n    InitGeom();\n    SetGeomOffset(CENTERX,CENTERY);\n    SetGeomScreen(CENTERX);\n    \n    SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    \n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\n    \n    if (VMODE)\n    {\n        SetVideoMode(MODE_PAL);\n        disp[0].screen.y += 8;\n        disp[1].screen.y += 8;\n    }\n    SetDispMask(1);                 // Display on screen    \n\n    setRGB0(&draw[0], 128, 128, 128);\n    setRGB0(&draw[1], 128, 128, 128);\n    \n    draw[0].isbg = 1;\n    draw[1].isbg = 1;\n    \n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    \n    FntLoad(960, 0);\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );\n    \n}\n\nvoid display(void)\n{\n    DrawSync(0);\n    VSync(0);\n    \n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    \n    DrawOTag(&ot[db][OTLEN - 1]);\n    \n    db = !db;\n    \n    nextpri = primbuff[db];\n}\n\n\nint main(void)\n{\n        \n    POLY_FT4 *poly = {0};                           // pointer to a POLY_G4 \n    SVECTOR RotVector = {0, 0, 0};                  // Initialize rotation vector {x, y, z}\n    VECTOR  MovVector = {0, 0, CENTERX/2, 0};               // Initialize translation vector {x, y, z, pad}\n    VECTOR  ScaleVector = {ONE, ONE, ONE};          // ONE is define as 4096 in libgte.h\n    \n    SVECTOR VertPos[4] = {                          // Set initial vertices position relative to 0,0 - see here : https://psx.arthus.net/docs/poly_f4.jpg\n            {-32, -32, 1 },                         // Vert 1 \n            {-32,  32, 1 },                         // Vert 2\n            { 32, -32, 1 },                         // Vert 3\n            { 32,  32, 1  }                         // Vert 4\n        };                                          \n    MATRIX PolyMatrix = {0};                   \n        \n    long polydepth;\n    long polyflag;\n    \n    int ping = 0;\n    \n    init();\n    \n    LoadTexture(_binary____TIM_bousai_tim_start, &bousai);\n    \n    while (1)\n    {\n        ClearOTagR(ot[db], OTLEN);\n        \n        poly = (POLY_FT4 *)nextpri;                    // Set poly to point to  the address of the next primitiv in the buffer\n        \n        // Set transform matrices for this polygon\n                \n        RotMatrix(&RotVector, &PolyMatrix);           // Apply rotation matrix\n        TransMatrix(&PolyMatrix, &MovVector);         // Apply translation matrix   \n        ScaleMatrix(&PolyMatrix, &ScaleVector);       // Apply scale matrix   \n        \n        SetRotMatrix(&PolyMatrix);                    // Set default rotation matrix\n        SetTransMatrix(&PolyMatrix);                  // Set default transformation matrix\n        \n        setPolyFT4(poly);                             // Initialize poly as a POLY_F4 \n        \n        poly->tpage = getTPage(bousai.mode&0x3, 0, bousai.prect->x, bousai.prect->y);   // Get Tpage coordinates from the TIM_IMAGE mode and prect members.\n        \n        setRGB0(poly, 128, 128, 128);                 // Set poly color (neutra here)\n        \n        RotTransPers4(\n                    &VertPos[0],      &VertPos[1],      &VertPos[2],      &VertPos[3],\n                    (long*)&poly->x0, (long*)&poly->x1, (long*)&poly->x2, (long*)&poly->x3,\n                    &polydepth,\n                    &polyflag\n                    );                                 // Perform coordinate and perspective transformation for 4 vertices\n        \n        setUV4(poly, 0, 0, 0, 144, 144, 0, 144, 144);  // Set UV coordinates in order Top Left, Bottom Left, Top Right, Bottom Right \n\n        \n        // Let's have some fun on the Z axis\n\n        if(!ping){\n            if (MovVector.vz < CENTERX){               // While Poly position on Z axis is < 160, push it\n                MovVector.vz += 1;                     // Push on Z axis\n            } else {\n                ping = !ping;                          // Switch ping value\n            }\n        }\n        \n        if(ping){\n            if (MovVector.vz > CENTERX/2){              // While Poly position on Z axis is > 80, pull it\n                MovVector.vz -= 1;                      // Pull on Z axis\n            } else {\n                ping = !ping;                           // Switch ping value\n            }\n        }\n            \n            \n        addPrim(ot[db], poly);                         // add poly to the Ordering table\n        \n        nextpri += sizeof(POLY_FT4);                    // increment nextpri address with size of a POLY_F4 struct \n    \n        FntPrint(\"Hello textured poly  !\");                   \n    \n        FntFlush(-1);\n        \n        display();\n        }\n    return 0;\n    }\n"
  },
  {
    "path": "hello_poly_fun/Makefile",
    "content": "TARGET = hello_poly_fun\n\nSRCS = hello_poly_fun.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_poly_fun/hello_poly_fun.c",
    "content": "// Having fun with polygons, matrices and vectors\n// Credits : Schnappy\n//With great help from Jaby smoll Seamonstah, Nicolas Noble, NDR008, paul, sickle on https://discord.com/invite/Zd82yXvs\n// 11/2020\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n#include <kernel.h>\n#define VMODE 0         // Video Mode : 0 : NTSC, 1: PAL\n#define SPIN 16         // Rotation speed increment\n#define SCREENXRES 320\n#define SCREENYRES 240\n#define CENTERX SCREENXRES/2\n#define CENTERY SCREENYRES/2\n#define MARGINX 10    // margins for text display\n#define MARGINY 4\n#define FONTSIZE 8 * 7           // Text Field Height\n#define OTLEN 16              // Ordering Table Length \nDISPENV disp[2];             // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nu_long ot[2][OTLEN];     // double ordering table of length 8 * 32 = 256 bits / 32 bytes\nchar primbuff[2][32768];     // double primitive buffer of length 32768 * 8 =  262.144 bits / 32,768 Kbytes\nchar *nextpri = primbuff[0]; // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]\nshort db = 0;                // index of which buffer is used, values 0, 1\nCVECTOR BgColor[3] = {20, 20, 20}; \nstruct polygon\n    { \n    POLY_F4 * poly_f4;\n    CVECTOR   color;\n    short     width;\n    short     height;\n    SVECTOR   RotV_L;\n    VECTOR    TransV_L;\n    VECTOR    ScaleV_L;\n    SVECTOR   PivotV_L;\n    SVECTOR   Verts[4];\n    MATRIX    Matrix;\n    long      depth;\n    long      flag;\n    short     rotSpeed;\n    int       otz;\n    };\nvoid init(void)\n{\n    ResetGraph(0);\n    // Initialize and setup the GTE : Not needed ?\n    InitGeom();\n    SetGeomOffset(CENTERX,CENTERY);\n    SetGeomScreen(CENTERX);\n    PadInit(0);\n    SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\n    if (VMODE)\n    {\n        SetVideoMode(MODE_PAL);\n        disp[0].screen.y += 8;\n        disp[1].screen.y += 8;\n    }\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], BgColor->r, BgColor->g, BgColor->b);\n    setRGB0(&draw[1], BgColor->r, BgColor->g, BgColor->b);\n    draw[0].isbg = 1;\n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );\n}\nvoid display(void)\n{\n    DrawSync(0);\n    VSync(0);\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    DrawOTag(&ot[db][OTLEN - 1]);\n    db = !db;\n    nextpri = primbuff[db];\n}\nvoid pivotPoint(SVECTOR VertPos[3],short width,short height, SVECTOR pivot){\n        // Not very efficient I think\n        VertPos[0].vx = -pivot.vx;\n        VertPos[0].vy = -pivot.vy;\n        VertPos[0].vz = 1;\n        VertPos[1].vx = width - pivot.vx;\n        VertPos[1].vy = -pivot.vy;\n        VertPos[1].vz = 1;\n        VertPos[2].vx = -pivot.vx;\n        VertPos[2].vy = height-pivot.vy;\n        VertPos[2].vz = 1;\n        VertPos[3].vx = width  - pivot.vx;\n        VertPos[3].vy = height - pivot.vy;\n        VertPos[3].vz = 1;\n}\nint main(void)\n{\n    u_short BtnTimer = 0;           // Timer to limit pad input rate\n    u_short polyCount = 1;          // current polygon index\n    int otz;                        // z-index\n    struct polygon *CurrentPoly;    // points to the address of selected polygon\n    // White cursor : shows which polygon is selected\n    struct polygon cursorS = {\n        cursorS.poly_f4,\n        {255, 255, 255},        // color\n        30, 30,                 // width, height\n        {0,0,0},                // RotV_L\n        {0,0,0, 0},             // TransV_L\n        {4096,4096,4096},       // ScaleV_L\n        {1,1,1},                // PivotV\n        {                       // Verts[4]\n            {-1, -1, 1},\n            { 1, -1, 1},\n            {-1,  1, 1},\n            { 1,  1, 1}\n        },\n        {0}              // Matrix\n    };\n    //Red\n    struct polygon polyS = {\n    polyS.poly_f4,\n    {255, 0, 0},                      // color\n    30, 30,                           // width, height\n    {0,0,0},                          // RotV_L\n    {-48, -30, 0, 0},                    // TransV_L\n    {4096,4096,4096},                 // ScaleV_L\n    {15,15,1},                        // PivotV\n    {                                 // Verts[4]\n        {0, 0, 0},\n        {0, 0, 0},\n        {0, 0, 0},\n        {0, 0, 0}\n    },\n    {0},                       // Matrix\n    0,0,                              // depth, flag\n    8,                                // rotSpeed\n    1                                 // z-index\n    };\n    //Yellow\n    struct polygon poly1S = {\n    poly1S.poly_f4,\n    {255, 187, 0},                    // color\n    28, 28,                           // width, height\n    {0,0,0},                          // RotV_L\n    {-20, 10, 0, 0},                  // TransV_L\n    {4096,4096,4096},                 // ScaleV_L\n    {4,4,1},                          // PivotV\n    {                                 // Verts[4]\n        {0, 0, 0},\n        {0, 0, 0},\n        {0, 0, 0},\n        {0, 0, 0}\n    },\n    {0},                       // Matrix\n    0,0,                              // depth, flag\n    -12,                              // rotSpeed\n    2                                 // z-index\n    };\n    //Green\n    struct polygon poly2S = {\n    poly2S.poly_f4,\n    {0, 255, 153},                    // color\n    24, 24,                           // width, height\n    {0,0,0},                          // RotV_L\n    {36, -10, 0, 0},                  // TransV_L\n    {4096,4096,4096},                 // ScaleV_L\n    {12,12,1},                        // PivotV\n    {                                 // Verts[4]\n        {0, 0, 0},\n        {0, 0, 0},\n        {0, 0, 0},\n        {0, 0, 0}\n    },\n    {0},                       // Matrix\n    0,0,                              // depth, flag\n    -6,                               // rotSpeed\n    3                                 // z-index\n    };\n    //Blue\n    struct polygon poly3S = {\n    poly3S.poly_f4,\n    {112, 254, 254},                  // color\n    26, 26,                           // width, height\n    {0,0,0},                          // RotV_L\n    {20, 20, 0, 0},                   // TransV_L\n    {4096,4096,4096},                 // ScaleV_L\n    {13,13,1},                        // PivotV\n    {                                 // Verts[4]\n        {0, 0, 0},\n        {0, 0, 0},\n        {0, 0, 0},\n        {0, 0, 0}\n    },\n    {0},                         // Matrix\n    0,0,                              //depth, flag\n    256,                              //rotSpeed\n    4                                 // z-index\n    };\n    /////\n    CurrentPoly = &polyS;\n    pivotPoint(polyS.Verts, polyS.width, polyS.height, polyS.PivotV_L);\n    pivotPoint(poly1S.Verts, poly1S.width, poly1S.height, poly1S.PivotV_L);\n    pivotPoint(poly2S.Verts, poly2S.width, poly2S.height, poly2S.PivotV_L);\n    pivotPoint(poly3S.Verts, poly3S.width, poly3S.height, poly3S.PivotV_L);\n    init();\n    while (1)\n    {\n        ClearOTagR(ot[db], OTLEN);\n        cursorS.poly_f4 = (POLY_F4 *)nextpri;\n        RotMatrix(&cursorS.RotV_L , &cursorS.Matrix);\n        TransMatrix(&cursorS.Matrix, &CurrentPoly->TransV_L);\n        SetRotMatrix(&cursorS.Matrix);\n        SetTransMatrix(&cursorS.Matrix);\n        setPolyF4(cursorS.poly_f4);\n        setRGB0(cursorS.poly_f4,cursorS.color.r,cursorS.color.g,cursorS.color.b);\n        //~ setXY4(cursorS, MovVector.vx-1, MovVector.vy-1 ,MovVector.vx + 1, MovVector.vy -1,MovVector.vx-1, MovVector.vy+1,MovVector.vx+1, MovVector.vy+1);\n        RotTransPers4(\n                    &cursorS.Verts[0],      &cursorS.Verts[1],      &cursorS.Verts[2],      &cursorS.Verts[3],\n                    (long*)&cursorS.poly_f4->x0, (long*)&cursorS.poly_f4->x1, (long*)&cursorS.poly_f4->x2, (long*)&cursorS.poly_f4->x3,\n                    &cursorS.depth,\n                    &cursorS.flag\n                    );\n        addPrim(ot[db], cursorS.poly_f4);\n        nextpri += sizeof(POLY_F4);\n        ///// Red\n        polyS.poly_f4 = (POLY_F4 *)nextpri;\n        polyS.RotV_L.vz += polyS.rotSpeed;\n        RotMatrix(&polyS.RotV_L, &polyS.Matrix);\n        TransMatrix(&polyS.Matrix, &polyS.TransV_L);\n        ScaleMatrix(&polyS.Matrix, &polyS.ScaleV_L);\n        SetRotMatrix(&polyS.Matrix);\n        SetTransMatrix(&polyS.Matrix);\n        setPolyF4(polyS.poly_f4);\n        setRGB0(polyS.poly_f4, polyS.color.r,polyS.color.g,polyS.color.b);        \n        RotTransPers4(\n                    &polyS.Verts[0],      &polyS.Verts[1],      &polyS.Verts[2],      &polyS.Verts[3],\n                    (long*)&polyS.poly_f4->x0, (long*)&polyS.poly_f4->x1, (long*)&polyS.poly_f4->x2, (long*)&polyS.poly_f4->x3,\n                    &polyS.depth,\n                    &polyS.flag\n                    );\n        addPrim(ot[db][polyS.otz], polyS.poly_f4);\n        nextpri += sizeof(POLY_F4);\n        ///// Yellow\n        poly1S.poly_f4 = (POLY_F4 *)nextpri;\n        poly1S.RotV_L.vz += poly1S.rotSpeed;\n        RotMatrix(&poly1S.RotV_L, &poly1S.Matrix);\n        TransMatrix(&poly1S.Matrix, &poly1S.TransV_L);\n        ScaleMatrix(&poly1S.Matrix, &poly1S.ScaleV_L);\n        SetRotMatrix(&poly1S.Matrix);\n        SetTransMatrix(&poly1S.Matrix);\n        setPolyF4(poly1S.poly_f4);\n        setRGB0(poly1S.poly_f4, poly1S.color.r,poly1S.color.g,poly1S.color.b);        \n        RotTransPers4(\n                    &poly1S.Verts[0],      &poly1S.Verts[1],      &poly1S.Verts[2],      &poly1S.Verts[3],\n                    (long*)&poly1S.poly_f4->x0, (long*)&poly1S.poly_f4->x1, (long*)&poly1S.poly_f4->x2, (long*)&poly1S.poly_f4->x3,\n                    &poly1S.depth,\n                    &poly1S.flag\n                    );\n        addPrim(ot[db][poly1S.otz], poly1S.poly_f4);\n        nextpri += sizeof(POLY_F4);\n        ///// Green\n        poly2S.poly_f4 = (POLY_F4 *)nextpri;\n        poly2S.RotV_L.vz += poly2S.rotSpeed;\n        RotMatrix(&poly2S.RotV_L, &poly2S.Matrix);\n        TransMatrix(&poly2S.Matrix, &poly2S.TransV_L);\n        ScaleMatrix(&poly2S.Matrix, &poly2S.ScaleV_L);\n        SetRotMatrix(&poly2S.Matrix);\n        SetTransMatrix(&poly2S.Matrix);\n        setPolyF4(poly2S.poly_f4);\n        setRGB0(poly2S.poly_f4, poly2S.color.r,poly2S.color.g,poly2S.color.b);        \n        RotTransPers4(\n                    &poly2S.Verts[0],      &poly2S.Verts[1],      &poly2S.Verts[2],      &poly2S.Verts[3],\n                    (long*)&poly2S.poly_f4->x0, (long*)&poly2S.poly_f4->x1, (long*)&poly2S.poly_f4->x2, (long*)&poly2S.poly_f4->x3,\n                    &poly2S.depth,\n                    &poly2S.flag\n                    );\n        addPrim(ot[db][poly2S.otz], poly2S.poly_f4);\n        nextpri += sizeof(POLY_F4);\n        ///// Blue\n        poly3S.poly_f4 = (POLY_F4 *)nextpri;\n        poly3S.RotV_L.vz += poly3S.rotSpeed;\n        RotMatrix(&poly3S.RotV_L, &poly3S.Matrix);\n        TransMatrix(&poly3S.Matrix, &poly3S.TransV_L);\n        ScaleMatrix(&poly3S.Matrix, &poly3S.ScaleV_L);\n        SetRotMatrix(&poly3S.Matrix);\n        SetTransMatrix(&poly3S.Matrix);\n        setPolyF4(poly3S.poly_f4);\n        setRGB0(poly3S.poly_f4, poly3S.color.r,poly3S.color.g,poly3S.color.b);        \n        RotTransPers4(\n                    &poly3S.Verts[0],      &poly3S.Verts[1],      &poly3S.Verts[2],      &poly3S.Verts[3],\n                    (long*)&poly3S.poly_f4->x0, (long*)&poly3S.poly_f4->x1, (long*)&poly3S.poly_f4->x2, (long*)&poly3S.poly_f4->x3,\n                    &poly3S.depth,\n                    &poly3S.flag\n                    );\n        addPrim(ot[db][poly3S.otz], poly3S.poly_f4);\n        nextpri += sizeof(POLY_F4);\n        // Pad stuff\n        int pad = PadRead(0); // init pad\n        // Right D-pad\n        if(pad & PADRup){\n            if (CurrentPoly->PivotV_L.vy >= 0){\n                CurrentPoly->PivotV_L.vy -= 1;\n                pivotPoint(CurrentPoly->Verts, CurrentPoly->width, CurrentPoly->height, CurrentPoly->PivotV_L);\n            }\n            else {\n                CurrentPoly->PivotV_L.vy = CurrentPoly->PivotV_L.vy;\n            }\n        };\n        if(pad & PADRdown){\n            if (CurrentPoly->PivotV_L.vy <= CurrentPoly->height ){\n                CurrentPoly->PivotV_L.vy += 1;\n                pivotPoint(CurrentPoly->Verts, CurrentPoly->width, CurrentPoly->height, CurrentPoly->PivotV_L);\n            }\n            else {\n                CurrentPoly->PivotV_L.vy = CurrentPoly->PivotV_L.vy;\n            }\n        };\n        if(pad & PADRleft){\n            if (CurrentPoly->PivotV_L.vx >= 0){\n                CurrentPoly->PivotV_L.vx -= 1;\n                pivotPoint(CurrentPoly->Verts, CurrentPoly->width, CurrentPoly->height, CurrentPoly->PivotV_L);\n            }\n            else {\n                CurrentPoly->PivotV_L.vx = CurrentPoly->PivotV_L.vx;\n            }\n        };\n        if(pad & PADRright){\n            if (CurrentPoly->PivotV_L.vx <= CurrentPoly->width ){\n                CurrentPoly->PivotV_L.vx += 1;\n                pivotPoint(CurrentPoly->Verts, CurrentPoly->width, CurrentPoly->height, CurrentPoly->PivotV_L);\n            }\n            else {\n                CurrentPoly->PivotV_L.vx = CurrentPoly->PivotV_L.vx;\n            }\n        };\n        // R1, R2, L2, L2\n        if(pad & PADR1){\n            if(BtnTimer == 0){\n                if (polyCount < 4){ \n                    CurrentPoly -= 1;\n                    BtnTimer = 10;\n                    polyCount++;\n                }\n                else {\n                    CurrentPoly = &polyS + 1;\n                    polyCount = 0;\n                    }\n            }\n        }\n         if(pad & PADR2){\n            if(BtnTimer == 0){\n                if(CurrentPoly->otz < 5 ){ \n                    CurrentPoly->otz += 1;\n                    BtnTimer = 10;\n                } else {\n                    CurrentPoly->otz = 1;\n                    BtnTimer = 10;\n                    }\n            } \n        }\n         if(pad & PADL1){\n            if(BtnTimer == 0){\n                if (CurrentPoly->rotSpeed <= 320){\n                CurrentPoly->rotSpeed += 8;\n            }\n                BtnTimer = 10;\n            } \n        }\n        if(pad & PADL2){\n            if(BtnTimer == 0){\n                if (CurrentPoly->rotSpeed >= -320){\n                CurrentPoly->rotSpeed -= 8;\n            }\n                BtnTimer = 10;\n            } \n        }\n        // Left D-Pad\n        if(pad & PADLup){\n            if(BtnTimer == 0){\n                CurrentPoly->TransV_L.vy -= 1;\n                //~ BtnTimer = 2;\n            } \n        }\n        if(pad & PADLdown){\n            if(BtnTimer == 0){\n                CurrentPoly->TransV_L.vy += 1;\n                //~ BtnTimer = 2;\n            } \n        }\n        if(pad & PADLleft){\n            if(BtnTimer == 0){\n                CurrentPoly->TransV_L.vx -= 1;\n                //~ BtnTimer = 2;\n            } \n        }\n        if(pad & PADLright){\n            if(BtnTimer == 0){\n                CurrentPoly->TransV_L.vx += 1;\n                //~ BtnTimer = 2;\n            } \n        }\n        if(pad & PADstart){\n            if(BtnTimer == 0){\n                CurrentPoly->ScaleV_L.vx += 100;\n                CurrentPoly->ScaleV_L.vy += 100;\n                //~ CurrentPoly->TransV_L.vz += 1;\n            } \n        }\n        if(pad & PADselect){\n            if(BtnTimer == 0){\n               CurrentPoly->ScaleV_L.vx -= 100;\n               CurrentPoly->ScaleV_L.vy -= 100;\n               //~ CurrentPoly->TransV_L.vz -= 1;\n            } \n        }\n        // Btn_timer decrement\n        if(BtnTimer > 0){\n            BtnTimer -= 1;\n            }\n        // On-screen instructions \n        FntPrint(\"\\\nD-Pad:move polygon.\\n\\\n[],X,O,\\/\\\\ : Move pivot point.\\n\\\nL1,L2 : Rotations speed +/-\\n\\\nR1 : select polygon\\n\\\nR2 : change z-index\\n\\\nStart,Select : Scale polygon +/-\\\n\");\n        FntFlush(-1);\n        display();\n        }\n    return 0;\n    }\n"
  },
  {
    "path": "hello_poly_gt/Makefile",
    "content": "TARGET = hello_poly_gt\n\nSRCS = hello_poly_gt.c \\\n../TIM/bousai.tim \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_poly_gt/hello_poly_gt.c",
    "content": "// Draw a textured poly primitive with gouraud shading\n//\n// With help from Nicolas Noble, Jaby smoll Seamonstah, Lameguy64\n// \n// From ../psyq/addons/graphics/MESH/RMESH/TUTO0.C :\n// Schnappy 2021\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n#define VMODE 0                 // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320          // Screen width\n#define SCREENYRES 240          // Screen height\n#define CENTERX SCREENXRES/2    // Center of screen on x \n#define CENTERY SCREENYRES/2    // Center of screen on y\n#define MARGINX 32               // margins for text display\n#define MARGINY 32\n#define FONTSIZE 8 * 5             // Text Field Height\n#define OTLEN 8                    // Ordering Table Length \nDISPENV disp[2];                   // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nu_long ot[2][OTLEN];               // double ordering table of length 8 * 32 = 256 bits / 32 bytes\nchar primbuff[2][32768];     // double primitive buffer of length 32768 * 8 =  262.144 bits / 32,768 Kbytes\nchar *nextpri = primbuff[0];       // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]\nshort db = 0;                      // index of which buffer is used, values 0, 1\n// 16bpp TIM\nextern unsigned long _binary____TIM_bousai_tim_start[];\nextern unsigned long _binary____TIM_bousai_tim_end[];\nextern unsigned long _binary____TIM_bousai_tim_length;\nTIM_IMAGE bousai;\nvoid LoadTexture(u_long * tim, TIM_IMAGE * tparam){     // This part is from Lameguy64's tutorial series : lameguy64.net/svn/pstutorials/chapter1/3-textures.html login/pw: annoyingmous\n        OpenTIM(tim);                                   // Open the tim binary data, feed it the address of the data in memory\n        ReadTIM(tparam);                                // This read the header of the TIM data and sets the corresponding members of the TIM_IMAGE structure\n        LoadImage(tparam->prect, tparam->paddr);        // Transfer the data from memory to VRAM at position prect.x, prect.y\n        DrawSync(0);                                    // Wait for the drawing to end\n        if (tparam->mode & 0x8){ // check 4th bit       // If 4th bit == 1, TIM has a CLUT\n            LoadImage(tparam->crect, tparam->caddr);    // Load it to VRAM at position crect.x, crect.y\n            DrawSync(0);                                // Wait for drawing to end\n    }\n}\nvoid init(void)\n{\n    ResetGraph(0);\n    // Initialize and setup the GTE\n    InitGeom();\n    SetGeomOffset(CENTERX,CENTERY);\n    SetGeomScreen(CENTERX);\n    SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\n    if (VMODE)\n    {\n        SetVideoMode(MODE_PAL);\n        disp[0].screen.y += 8;\n        disp[1].screen.y += 8;\n    }\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 128, 128, 128);\n    setRGB0(&draw[1], 128, 128, 128);\n    draw[0].isbg = 1;\n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );\n}\nvoid display(void)\n{\n    DrawSync(0);\n    VSync(0);\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    DrawOTag(&ot[db][OTLEN - 1]);\n    db = !db;\n    nextpri = primbuff[db];\n}\nint main(void)\n{\n    int i;\n    POLY_GT4 *poly = {0};                           // pointer to a POLY_G4 \n    SVECTOR RotVector = {0, 0, 0};                  // Initialize rotation vector {x, y, z}\n    VECTOR  MovVector = {0, 0, 120, 0};                   // Initialize translation vector {x, y, z}\n    SVECTOR VertPos[4] = {                          // Set initial vertices position relative to 0,0 - see here : https://psx.arthus.net/docs/poly_f4.jpg\n            {-32, -32, 0 },                         // Vert 1 \n            {-32,  32, 0 },                         // Vert 2\n            { 32, -32, 0 },                         // Vert 3\n            { 32,  32, 0 }                          // Vert 4\n        };                                          \n    MATRIX PolyMatrix = {0};                   \n    DR_TPAGE * bousai_tpage;\n    long polydepth;\n    long polyflag;\n    init();\n    LoadTexture(_binary____TIM_bousai_tim_start, &bousai);\n    while (1)\n    {\n        ClearOTagR(ot[db], OTLEN);\n        poly = (POLY_GT4 *)nextpri;                    // Set poly to point to  the address of the next primitiv in the buffer\n        // Set transform matrices for this polygon\n        RotMatrix(&RotVector, &PolyMatrix);           // Apply rotation matrix\n        TransMatrix(&PolyMatrix, &MovVector);         // Apply translation matrix   \n        SetRotMatrix(&PolyMatrix);                    // Set default rotation matrix\n        SetTransMatrix(&PolyMatrix);                  // Set default transformation matrix\n        setPolyGT4(poly);                                      // Initialize poly as a POLY_F4 \n        poly->tpage = getTPage(bousai.mode&0x3, 0, bousai.prect->x, bousai.prect->y);\n        setRGB0(poly, 128, 128, 128);                       // Set vertice 1 color\n        setRGB1(poly, 255, 0, 0);                           // Set vertice 2 color\n        setRGB2(poly, 0, 255, 0);                           // Set vertice 3 color\n        setRGB3(poly, 0, 0, 255);                           // Set vertice 4 color\n        RotTransPers4(\n                    &VertPos[0],      &VertPos[1],      &VertPos[2],      &VertPos[3],\n                    (long*)&poly->x0, (long*)&poly->x1, (long*)&poly->x2, (long*)&poly->x3,\n                    &polydepth,\n                    &polyflag\n                    );                                // Perform coordinate and perspective transformation for 4 vertices\n        setUV4(poly, 0, 0, 0, 144, 144, 0, 144, 144);  // Set UV coordinates in order Top Left, Bottom Left, Top Right, Bottom Right \n        RotVector.vx += 8;                              // Apply rotation on Z-axis. On PSX, the Z-axis is pointing away from the screen. \n        addPrim(ot[db], poly);                         // add poly to the Ordering table\n        nextpri += sizeof(POLY_GT4);                    // increment nextpri address with size of a POLY_F4 struct \n        FntPrint(\"Hello textured shaded !\");                   \n        FntFlush(-1);\n        display();\n        }\n    return 0;\n    }\n"
  },
  {
    "path": "hello_poly_gt_tw/Makefile",
    "content": "TARGET = hello_poly_gt_tw\n\nSRCS = hello_poly_gt_tw.c \\\n../TIM/bousai.tim \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_poly_gt_tw/hello_poly_gt_tw.c",
    "content": "// Draw a textured poly primitive with gouraud_shading, using a repeating texture pattern\n//\n// With help from Nicolas Noble, Jaby smoll Seamonstah, Lameguy64\n// \n// From ../psyq/addons/graphics/MESH/RMESH/TUTO0.C :\n// Schnappy 2021\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n#define VMODE 0                 // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320          // Screen width\n#define SCREENYRES 240          // Screen height\n#define CENTERX SCREENXRES/2    // Center of screen on x \n#define CENTERY SCREENYRES/2    // Center of screen on y\n#define MARGINX 32               // margins for text display\n#define MARGINY 32\n#define FONTSIZE 8 * 5             // Text Field Height\n#define OTLEN 8                    // Ordering Table Length \nDISPENV disp[2];                   // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nu_long ot[2][OTLEN];               // double ordering table of length 8 * 32 = 256 bits / 32 bytes\nchar primbuff[2][32768];     // double primitive buffer of length 32768 * 8 =  262.144 bits / 32,768 Kbytes\nchar *nextpri = primbuff[0];       // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]\nshort db = 0;                      // index of which buffer is used, values 0, 1\n// 16bpp TIM\nextern unsigned long _binary____TIM_bousai_tim_start[];\nextern unsigned long _binary____TIM_bousai_tim_end[];\nextern unsigned long _binary____TIM_bousai_tim_length;\nTIM_IMAGE bousai;\nvoid LoadTexture(u_long * tim, TIM_IMAGE * tparam){     // This part is from Lameguy64's tutorial series : lameguy64.net/svn/pstutorials/chapter1/3-textures.html login/pw: annoyingmous\n        OpenTIM(tim);                                   // Open the tim binary data, feed it the address of the data in memory\n        ReadTIM(tparam);                                // This read the header of the TIM data and sets the corresponding members of the TIM_IMAGE structure\n        LoadImage(tparam->prect, tparam->paddr);        // Transfer the data from memory to VRAM at position prect.x, prect.y\n        DrawSync(0);                                    // Wait for the drawing to end\n        if (tparam->mode & 0x8){ // check 4th bit       // If 4th bit == 1, TIM has a CLUT\n            LoadImage(tparam->crect, tparam->caddr);    // Load it to VRAM at position crect.x, crect.y\n            DrawSync(0);                                // Wait for drawing to end\n    }\n}\nvoid init(void)\n{\n    ResetGraph(0);\n    // Initialize and setup the GTE\n    InitGeom();\n    SetGeomOffset(CENTERX,CENTERY);\n    SetGeomScreen(CENTERX);\n    SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\n    if (VMODE)\n    {\n        SetVideoMode(MODE_PAL);\n        disp[0].screen.y += 8;\n        disp[1].screen.y += 8;\n    }\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 128, 128, 128);\n    setRGB0(&draw[1], 128, 128, 128);\n    draw[0].isbg = 1;\n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );\n}\nvoid display(void)\n{\n    DrawSync(0);\n    VSync(0);\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    DrawOTag(&ot[db][OTLEN - 1]);\n    db = !db;\n    nextpri = primbuff[db];\n}\nint main(void)\n{\n    int i;\n    POLY_GT4 *poly = {0};                           // pointer to a POLY_G4 \n    SVECTOR RotVector = {0, 0, 0};                  // Initialize rotation vector {x, y, z}\n    VECTOR  MovVector = {0, 0, 120, 0};                   // Initialize translation vector {x, y, z}\n    SVECTOR VertPos[4] = {                          // Set initial vertices position relative to 0,0 - see here : https://psx.arthus.net/docs/poly_f4.jpg\n            {-32, -32, 0 },                         // Vert 1 \n            {-32,  32, 0 },                         // Vert 2\n            { 32, -32, 0 },                         // Vert 3\n            { 32,  32, 0 }                          // Vert 4\n        };                                          \n    MATRIX PolyMatrix = {0};                   \n    DR_TPAGE * bousai_tpage;\n    long polydepth;\n    long polyflag;\n    // Texture window\n    DR_MODE * dr_mode;                              // Pointer to dr_mode prim\n    RECT tws = {64, 32, 32, 32};                    // Texture window coordinates : x, y, w, h\n                                                    // See libref47.pdf, p.242, 7-6, table 7-2 for possible values\n    init();\n    LoadTexture(_binary____TIM_bousai_tim_start, &bousai);\n    while (1)\n    {\n        ClearOTagR(ot[db], OTLEN);\n        poly = (POLY_GT4 *)nextpri;                    // Set poly to point to  the address of the next primitiv in the buffer\n        // Set transform matrices for this polygon\n        RotMatrix(&RotVector, &PolyMatrix);           // Apply rotation matrix\n        TransMatrix(&PolyMatrix, &MovVector);         // Apply translation matrix   \n        SetRotMatrix(&PolyMatrix);                    // Set default rotation matrix\n        SetTransMatrix(&PolyMatrix);                  // Set default transformation matrix\n        setPolyGT4(poly);                                      // Initialize poly as a POLY_F4 \n        poly->tpage = getTPage(bousai.mode&0x3, 0, bousai.prect->x, bousai.prect->y);\n        setRGB0(poly, 128, 128, 128);                       // Set vertice 1 color\n        setRGB1(poly, 255, 0, 0);                           // Set vertice 2 color\n        setRGB2(poly, 0, 255, 0);                           // Set vertice 3 color\n        setRGB3(poly, 0, 0, 255);                           // Set vertice 4 color\n        RotTransPers4(\n                    &VertPos[0],      &VertPos[1],      &VertPos[2],      &VertPos[3],\n                    (long*)&poly->x0, (long*)&poly->x1, (long*)&poly->x2, (long*)&poly->x3,\n                    &polydepth,\n                    &polyflag\n                    );                                // Perform coordinate and perspective transformation for 4 vertices\n        setUV4(poly, 0, 0, 0, 144, 144, 0, 144, 144);  // Set UV coordinates in order Top Left, Bottom Left, Top Right, Bottom Right \n        RotVector.vy += 14;                              // Apply rotation on Z-axis. On PSX, the Z-axis is pointing away from the screen. \n        addPrim(ot[db], poly);                         // add poly to the Ordering table\n        nextpri += sizeof(POLY_GT4);                    // increment nextpri address with size of a POLY_GT4 struct \n        // drawing mode primitive\n        dr_mode = (DR_MODE *)nextpri;                   // initialize drawing mode primitive\n        setDrawMode(dr_mode, 1, 0, getTPage(bousai.mode&0x3, 0, bousai.prect->x, bousai.prect->y), &tws);  //set texture window\n        addPrim(ot[db], dr_mode);                      \n        nextpri += sizeof(DR_MODE);                    // increment nextpri address with size of a  DR_MODE struct \n        FntPrint(\"Hello textured shaded !\");                   \n        FntFlush(-1);\n        display();\n        }\n    return 0;\n    }\n"
  },
  {
    "path": "hello_poly_inline/Makefile",
    "content": "TARGET = hello_poly_inline\n\nSRCS = hello_poly_inline.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_poly_inline/hello_poly_inline.c",
    "content": "// Hello poly ! Inline / DMPSX version\n//\n// Ref :     /psyq/DOCS/Devrefs/Inlinref.pdf, p.18\n//           https://psx-spx.consoledev.net/geometrytransformationenginegte/\n// PSX                    / Z+\n//  screen               / \n//coordinate         +-----X+\n//system           / | \n//              eye  | Y+      \n//\n// Credits, thanks : Nicolas Noble, Sickle, Lameguy64 @ psxdev discord : https://discord.com/invite/N2mmwp\n// https://discord.com/channels/642647820683444236/663664210525290507/834831466100949002\n// Schnappy 07-2021\n#include <sys/types.h>\n#include <stdio.h>\n#include <libetc.h>\n#include <libgte.h>\n#include <libgpu.h>\n// OldWorld PsyQ has a inline_c.h file for inline GTE functions. We have to use the one at https://github.com/grumpycoders/pcsx-redux/blob/07f9b02d1dbb68f57a9f5b9773041813c55a4913/src/mips/psyq/include/inline_n.h\n// because the real GTE commands are needed in nugget : https://psx-spx.consoledev.net/geometrytransformationenginegte/#gte-coordinate-calculation-commands \n#include <inline_n.h>\n//~ #include <gtemac.h> // gtemac contains macro versions of the libgte functions, worth checking out to see the operations order.\n\n#define VMODE 0                         // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320                  // Screen width\n#define SCREENYRES 240 + (VMODE << 4)     // Screen height : If VMODE is 0 = 240, if VMODE is 1 = 256 \n#define CENTERX ( SCREENXRES >> 1 )       // Center of screen on x \n#define CENTERY ( SCREENYRES >> 1 )       // Center of screen on y\n#define MARGINX 0                       // margins for text display\n#define MARGINY 32\n#define FONTSIZE 8 * 7                  // Text Field Height\n#define OTLEN 10                        // Ordering Table Length \n\nDISPENV disp[2];                        // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nu_long ot[2][OTLEN];               // double ordering table of length 8 * 32 = 256 bits / 32 bytes\nchar primbuff[2][32768];           // double primitive buffer of length 32768 * 8 =  262.144 bits / 32,768 Kbytes\nchar *nextpri = primbuff[0];       // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]\nshort db = 0;                      // index of which buffer is used, values 0, 1\n\nvoid init(void)\n{\n    ResetGraph(0);\n    // Initialize and setup the GTE\n    InitGeom();\n    //~ SetGeomOffset(CENTERX,CENTERY);\n    gte_SetGeomOffset(CENTERX,CENTERY);\n    gte_SetGeomScreen(CENTERX);\n    // Set display environment\n    SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    // Set draw environment\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\n    // If PAL, use 320x256, hence 256 - 240 = 16 / 2 = 8 px vertical offset\n    if (VMODE) SetVideoMode(MODE_PAL);\n    SetDispMask(1);\n    // Set background color\n    setRGB0(&draw[0], 50, 50, 50);\n    setRGB0(&draw[1], 50, 50, 50);\n    draw[0].isbg = 1;\n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );    \n}\n\nvoid display(void)\n{\n    // Wait for drawing\n    DrawSync(0);\n    // Wait for vsync\n    VSync(0);\n    // Flip DISP and DRAW env\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    DrawOTag(&ot[db][OTLEN - 1]);\n    // Flip db index\n    db = !db;\n    // Get next primitive in buffer\n    nextpri = primbuff[db];\n}\n\nint main(void)\n{\n    long p, flag, OTz;\n    SVECTOR rotVector, rotVector4 = {0};                  // Initialize rotation vector {x, y, z}\n    VECTOR  transVector = {0, 0, CENTERX, 0};         // Initialize translation vector {x, y, z}\n    SVECTOR vertPos[4] = {\n        { 0, -32, 0, 0 },           // Vert 1 \n        { 32,  0, 0, 0 },           // Vert 2\n        { -32, 0, 0, 0 },\n        { 0,  32, 0, 0 }\n    };           // Vert 3\n    MATRIX workMatrix = {0};                       \n    POLY_F3 * poly  = {0};                            // pointer to a POLY_F4 \n    POLY_F4 * poly4 = {0};                            // pointer to a POLY_F4 \n    init();\n    while (1)\n    {\n        // Set Ordering table\n        ClearOTagR(ot[db], OTLEN);\n        \n        \n        // Draw on the left part of the screen\n        transVector.vx = -CENTERX/2;\n        // Increment rotation angle on Y axis\n        rotVector.vy += 8;\n        rotVector.vx -= 4 ;\n        // Find rotation matrix from vector, store in \n        RotMatrix_gte(&rotVector, &workMatrix);\n        // Ditto for translation        \n        TransMatrix(&workMatrix, &transVector);\n        // Set the matrices we just found\n        gte_SetRotMatrix(&workMatrix);\n        gte_SetTransMatrix(&workMatrix);\n        \n        // Cast next primitive in buffer as a POLY_F4 (see display() )\n        poly = (POLY_F3 *)nextpri;        \n        \n        // Draw a Tri\n        \n        // Initialize poly as a POLY_F3\n        setPolyF3(poly);                \n        // Set poly color - Hot pink\n        setRGB0(poly, 255, 0, 255);                   \n        // Store vertex positions for current polygon in registers v0,v1,v2 \n        // Can be replaced by one gte_ldv3 call :\n        // gte_ldv3(&vertPos[0], &vertPos[1], &vertPos[2]);\n        gte_ldv0(&vertPos[0]);\n        gte_ldv1(&vertPos[1]);\n        gte_ldv2(&vertPos[2]);\n        \n        // RotTransPers3 : Perform coordinate and perspective transformation for three vertices.\n        // Use gte_rtps() for one vertex.\n        gte_rtpt();\n        // Get screen coordinates from cop2 registers XY0,XY1,XY2 and store them in primitive's x0, y0, x1, y1, x2, y2 members.\n        // Can be replace with one gte_stsxy3() call :\n        // gte_stsxy3(&poly->x0, &poly->x1, &poly->x2);\n        // Can also be replaced with a primitive type dependant version :\n        // gte_stsxy3_f3(poly);\n        gte_stsxy0(&poly->x0);\n        gte_stsxy1(&poly->x1);\n        gte_stsxy2(&poly->x2);\n        // Get depth interpolation coefficient p\n        gte_stdp(&p);\n        // Get the flag - see libover47.pdf, p.143 for details on ppossible values\n        gte_stflg(&flag);\n        // Get screen coordinate Z/4  \n        gte_stszotz(&OTz);\n        // GTE macro version - needs 'gtemac.h' to be included - uncomment l.21\n        //~ gte_RotTransPers3( &VertPos[0], &VertPos[1], &VertPos[2],\n                           //~ &poly->x0, &poly->x1, &poly->x2,\n                           //~ &p, &flag, &OTz );\n        // add poly to the Ordering table\n        addPrim(ot[db], poly);\n        // increment nextpri address with size of a POLY_F3 struct \n        nextpri += sizeof(POLY_F3);\n        \n        // Draw a Quad\n        //\n        // The GTE rtpt can only transform 3 vertices at a time, so we have to do all operations as 3 + 1.\n        \n        // Move to right of screen\n        transVector.vx = CENTERX/2;\n        // Increment rot on X/Y axis\n        rotVector4.vy -= 8 ;\n        rotVector4.vx -= 4 ;\n        // Set matrices\n        RotMatrix_gte(&rotVector4, &workMatrix);\n        TransMatrix(&workMatrix, &transVector);\n        gte_SetRotMatrix(&workMatrix);\n        gte_SetTransMatrix(&workMatrix);\n        \n        // Cast a POLY_F4 at the address we just incremented.\n        poly4 = (POLY_F4 *)nextpri;\n        \n        // Initialize poly as a POLY_F4\n        setPolyF4(poly4);           \n        // Set Poly color - Blue                    \n        setRGB0(poly4, 0, 255, 255);\n        \n        // Transform 3 first vertices\n        gte_ldv3(&vertPos[0], &vertPos[1], &vertPos[2]);\n        gte_rtpt();\n        gte_stsxy3_f4(poly4);\n        // Transform remaining vertex\n        gte_ldv0(&vertPos[3]);\n        gte_rtps();\n        // SXY3 is set with gte_stsxy() or gte_stsxy2() ¯\\_(ツ)_/¯\n        gte_stsxy(&poly4->x3);\n        // Get p, flag and OTz \n        gte_stdp(&p);\n        gte_stflg(&flag);\n        gte_stszotz(&OTz);\n        \n        addPrim(ot[db], poly4);         // add poly to the Ordering table\n        nextpri += sizeof(POLY_F4);    // increment nextpri address with size of a POLY_F3 struct \n\n        // Display text\n        FntPrint(\"Hello Inline GTE !\\n\");                   \n        FntFlush(-1);\n        \n        display();\n        }\n    return 0;\n    }\n"
  },
  {
    "path": "hello_poly_stp/Makefile",
    "content": "TARGET = hello_poly_stp\n\nSRCS = hello_poly_stp.c \\\nTIM/stpOnAlpha.tim \\\nTIM/stpOnAlphaI.tim \\\nTIM/stpOnBlack.tim \\\nTIM/stpOnColIndex.tim \\\nTIM/stpOnNonBlack.tim \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_poly_stp/README.md",
    "content": "![Hello_stp](https://wiki.arthus.net/assets/hello-stp.png)\n\n# STP : Semi-Transparency usage\n\nThis example shows the various way of converting an image with transparency to a TIM and use it in code.  \nIt also shows the effect of activating Semi-Transparency on a primitive textured with those images.  \n\nUse the `SELECT` button to switch primitive semi-transparency on and off.  \n\nIt also features a few C struct to facilitate access to the TIM file / pixel data.\n\nSee [https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/STP](https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/STP) for more information on how to convert your images to TIM while preserving transparency.\n\nSee [https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/TIM#transparency](https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/TIM#transparency) for mor details on transparency.  \n\n"
  },
  {
    "path": "hello_poly_stp/hello_poly_stp.c",
    "content": "// Demo the different settings for pixel and primitive semi-transparency\n//\n// Schnappy 07-2021\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n#include <libapi.h>\n\n#define VMODE 0                 // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320          // Screen width\n#define SCREENYRES 240          // Screen height\n#define CENTERX SCREENXRES/2    // Center of screen on x \n#define CENTERY SCREENYRES/2    // Center of screen on y\n#define MARGINX 16               // margins for text display\n#define MARGINY 16\n#define OTLEN 8                    // Ordering Table Length \nDISPENV disp[2];                   // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nu_long ot[2][OTLEN];               // double ordering table of length 8 * 32 = 256 bits / 32 bytes\nchar primbuff[2][32768];     // double primitive buffer of length 32768 * 8 =  262.144 bits / 32,768 Kbytes\nchar *nextpri = primbuff[0];       // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]\nshort db = 0;                      // index of which buffer is used, values 0, 1\n\n\n// RGB pixels are 16bpp, 5b Red, 5b Green, 5b Blue, 1b STP (semi-transparency)\n// See http://psx.arthus.net/sdk/Psy-Q/DOCS/FileFormat47.pdf, p.183\ntypedef struct RGB_PIX {\n    u_int  R:5, G:5, B:5, STP:1;\n    } RGB_PIX;\n    \n// TIM's pixel data\n// See http://psx.arthus.net/sdk/Psy-Q/DOCS/FileFormat47.pdf, p.182\ntypedef struct PIXEL {\n    u_long bnum;\n    u_short DX, DY;\n    u_short W, H;\n    RGB_PIX data[]; \n} PIXEL;\n\n// TIM's CLUT section - exists only in 4/8bpp TIMs \n// See See http://psx.arthus.net/sdk/Psy-Q/DOCS/FileFormat47.pdf, p.181\ntypedef struct CLUT {\n    u_long bnum;\n    u_short DX, DY;\n    u_short W, H;\n    u_short clut[]; \n} CLUT;\n\n// 4/8bpp TIM files have CLUT\ntypedef struct TIM_FILE_CLUT{\n    u_long ID;\n    u_long flag;\n    u_long clut;\n    PIXEL pixel[];\n} TIM_FILE_CLUT;\n\n// 16/24bpp TIM files have not CLUT member\n// See See http://psx.arthus.net/sdk/Psy-Q/DOCS/FileFormat47.pdf, p.179\ntypedef struct TIM_FILE{\n    u_long ID;\n    u_long flag;\n    PIXEL pixel[];\n} TIM_FILE;\n\n// If we were using C++, we could use templates \n//~ struct EmbeddedClut { u_long clut; };\n//~ struct NoEmbeddedClut { };\n//~ template<has_clut>\n//~ struct TIM_FILE {\n    //~ u_long ID;\n    //~ u_long flag;\n    //~ std::conditional<has_clut, EmbeddedClut, NoEmbeddedClut> clut;\n    //~ PIXEL pixel[];\n//~ };\n\n// 16bpp TIM\n// STP set on black pixels ( STP, B, R, G == 1, 0, 0 ,0)\nextern TIM_FILE _binary_TIM_stpOnBlack_tim_start;\n// STP set on non black pixels ( STP, B, R, G == 1, !0, !0 ,!0)\nextern TIM_FILE _binary_TIM_stpOnNonBlack_tim_start;\n// STP set on image's alpha channnel ( STP, B, R, G == 1, a, a ,a)\nextern TIM_FILE _binary_TIM_stpOnAlphaI_tim_start;\n// STP set on 8bpp TIM's CLUT index 0 ( STP, B, R, G == 1, i, i, i)\nextern TIM_FILE _binary_TIM_stpOnColIndex_tim_start;\n// Store in an array so we can iterate over it\nTIM_FILE * timFiles[4];\nTIM_IMAGE timImages[4];\n// Number of primitives to draw\n#define NUM_PRIM 4\n// Primitive stp flag : 0 == off, 1 == on\nchar stpFlag = 0;\n\nvoid LoadTexture(TIM_FILE * tim, TIM_IMAGE * tparam){     // This part is from Lameguy64's tutorial series : lameguy64.net/svn/pstutorials/chapter1/3-textures.html login/pw: annoyingmous\n        OpenTIM( ( u_long * ) tim);                                   // Open the tim binary data, feed it the address of the data in memory\n        ReadTIM(tparam);                                // This read the header of the TIM data and sets the corresponding members of the TIM_IMAGE structure\n        LoadImage(tparam->prect, tparam->paddr);        // Transfer the data from memory to VRAM at position prect.x, prect.y\n        DrawSync(0);                                    // Wait for the drawing to end\n        if (tparam->mode & 0x8){ // check 4th bit       // If 4th bit == 1, TIM has a CLUT\n            LoadImage(tparam->crect, tparam->caddr);    // Load it to VRAM at position crect.x, crect.y\n            DrawSync(0);                                // Wait for drawing to end\n    }\n}\nvoid init(void)\n{\n    ResetGraph(0);\n    // Initialize and setup the GTE\n    InitGeom();\n    SetGeomOffset( 0 , 0 );\n    SetGeomScreen( CENTERX );\n    SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\n    if (VMODE)\n    {\n        SetVideoMode(MODE_PAL);\n        disp[0].screen.y += 8;\n        disp[1].screen.y += 8;\n    }\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 255, 0, 128);\n    setRGB0(&draw[1], 255, 0, 128);\n    draw[0].isbg = 1;\n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);\n    FntOpen(MARGINX, MARGINY, SCREENXRES - MARGINX * 2, SCREENXRES - MARGINY * 2, 0, 512 );\n}\nvoid display(void)\n{\n    DrawSync(0);\n    VSync(0);\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    DrawOTag(&ot[db][OTLEN - 1]);\n    db = !db;\n    nextpri = primbuff[db];\n}\nint main(void)\n{\n    // Populate array with pointers to TIM data\n    timFiles[0] = &_binary_TIM_stpOnBlack_tim_start;\n    timFiles[1] = &_binary_TIM_stpOnNonBlack_tim_start;\n    timFiles[2] = &_binary_TIM_stpOnAlphaI_tim_start;\n    timFiles[3] = &_binary_TIM_stpOnColIndex_tim_start;\n    // Init Disp/Draw, double buffer, font\n    init();\n    // Init proto pad\n    PadInit(0);\n    int pad, oldPad;\n    // Pointer to a POLY_G4 \n    POLY_FT4 * poly[4] = {0};                       \n    SVECTOR VertPos[4] = {                          // Set initial vertices position relative to 0,0 - see here : https://psx.arthus.net/docs/poly_f4.jpg\n            {-32, -32, 1 },                         // Vert 1 \n            {-32,  32, 1 },                         // Vert 2\n            { 32, -32, 1 },                         // Vert 3\n            { 32,  32, 1  }                         // Vert 4\n        };                                          \n    VECTOR  transVector = { SCREENXRES/3, SCREENYRES/4, 128, 0};               // Initialize translation vector {x, y, z, pad}\n    SVECTOR rotVector = {0};                        // Initialize rotation vector {x, y, z} \n    \n    // Load textures to VRAM\n    for (char tim = 0; tim < NUM_PRIM; tim++){\n        LoadTexture(timFiles[tim], &timImages[tim]);\n    }\n    \n    while (1)\n    {\n        MATRIX Work;\n        // Clear OT\n        ClearOTagR(ot[db], OTLEN);\n        // Use a temporary work matrix\n        // Set Trans/Rot vectors to work matrix\n        RotMatrix(&rotVector, &Work);           // Apply rotation matrix\n        TransMatrix(&Work, &transVector);         // Apply translation matrix   \n        SetRotMatrix(&Work);                    // Set default rotation matrix\n        SetTransMatrix(&Work);                  // Set default transformation matrix\n        // Draw NUM_PRIM primitives\n        for (int i = 0; i < NUM_PRIM; i++){\n            long p, flag;\n            // Draw prims with an offset base on iteration number\n            transVector.vx = SCREENXRES/NUM_PRIM + (i * (SCREENXRES/NUM_PRIM + 32) ) ;\n            transVector.vy = SCREENYRES/NUM_PRIM;\n            if ( i >= 2) { \n                transVector.vx = SCREENXRES/NUM_PRIM + ((i - 2) * (SCREENXRES/NUM_PRIM + 32) ) ;\n                transVector.vy = SCREENYRES/2 + 24;\n            } \n            TransMatrix(&Work, &transVector);         \n            SetTransMatrix(&Work);\n            // Set poly \n            poly[i] = (POLY_FT4 *)nextpri;                    // Set poly to point to  the address of the next primitiv in the buffer\n            setPolyFT4(poly[i]);                              // Initialize poly as a POLY_F4 \n            // Get texture page\n            poly[i]->tpage = getTPage( timImages[i].mode & 0x3,\n                                       0,\n                                       // Get Tpage coordinates from the TIM_IMAGE mode and prect members.\n                                       timImages[i].prect->x,\n                                       timImages[i].prect->y); \n            // If 8/4bpp, get CLUT\n            if ( (timImages[i].mode & 0x3) < 2 ) {\n                setClut(poly[i],             \n                        timImages[i].crect->x,\n                        timImages[i].crect->y\n                );\n            }\n            setRGB0(poly[i], 128, 128, 128);                   // Set poly color (neutra here)\n            SetSemiTrans(poly[i], stpFlag);\n            RotTransPers4(\n                        &VertPos[0],      &VertPos[1],      &VertPos[2],      &VertPos[3],\n                        (long*)&poly[i]->x0, (long*)&poly[i]->x1, (long*)&poly[i]->x2, (long*)&poly[i]->x3,\n                        &p,\n                        &flag\n                        );                                 // Perform coordinate and perspective transformation for 4 vertices\n            setUV4(poly[i], 0, 0, 0, 144, 144, 0, 144, 144);  // Set UV coordinates in order Top Left, Bottom Left, Top Right, Bottom Right \n            // Add poly to the Ordering table\n            addPrim(ot[db], poly[i]);                        \n            // Increment nextpri address with size of a POLY_F4 struct \n            nextpri += sizeof(POLY_FT4);                    \n        }\n        \n        // Get pad input\n        pad = PadRead(0); \n        // If select button is used\n        if ( pad & PADselect && !( pad & oldPad ) ){\n            // Flip STP flag\n            stpFlag = !stpFlag;\n            // Set flag to avoir misfire\n            oldPad = pad;\n        } \n        // Reset flag when button released\n        if (!(pad & PADselect)) {\n            oldPad = 0;\n        }\n        FntPrint(\"Hello semi-transparency  !\\nPrim STP (push Select) : %d\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\", stpFlag);                   \n        FntPrint(\"    stp on black    stp on non-black\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\");                   \n        FntPrint(\"  stp on non-black  stp on col index\");                   \n        FntFlush(-1);\n        display();\n        }\n    return 0;\n    }\n"
  },
  {
    "path": "hello_sio/Makefile",
    "content": "TARGET = hello_sio\n\nSRCS = hello_sio.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_sio/hello_sio.c",
    "content": "// hello_sio example\n// This example will display the RX data in a 64 char rolling buffer.\n// Use minicom or any other serial comm program and a serial/USB cable.\n//\n// Relevant doc is libref47.pdf, l.1120-1127\n// Schnappy - 04/2021\n//\n// Based on :  ../psyq/psx/sample/serial/SIO\n// sio echo back \n// 1.00     Jan.28.1997 shino\n#include <sys/types.h>\n#include <libgte.h>\n#include <libgpu.h>\n#include <libetc.h>\n#include <stdio.h>\n// Needed for SIO operations\n#include <libsio.h>\n// Needed for manipulating strings\n#include <string.h>\n// Display stuff (see hello_tile for the basics)\n#define VMODE       0\n#define SCREENXRES 320\n#define SCREENYRES 240\n#define CENTERX     SCREENXRES/2\n#define CENTERY     SCREENYRES/2\n#define OTLEN       2048        // Maximum number of OT entries\n#define PRIMBUFFLEN 32768       // Maximum number of POLY_GT3 primitives\n// Display and draw environments, double buffered\nDISPENV disp[2];\nDRAWENV draw[2];\nu_long      ot[2][OTLEN];                   // Ordering table (contains addresses to primitives)\nchar    primbuff[2][PRIMBUFFLEN];     // Primitive list // That's our prim buffer\nchar * nextpri = primbuff[0];               // Primitive counter\nshort           db  = 0;                    // Current buffer counter\n// SIO\n#define MAX_CHARS 64\nu_char SIO = 1;                             // Is SIO enabled ?\nu_char SIOinit = 0;                         // Is SIO initialized ?\n// Prototypes\nvoid init(void);\nvoid display(void);\nvoid init(){\n    // Reset the GPU before doing anything and the controller\n    ResetGraph(0);\n    // Set the display and draw environments\n    SetDefDispEnv(&disp[0], 0, 0         , SCREENXRES, SCREENYRES);\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\n    // If in PAL mode, add vertical offset\n    if (VMODE)\n    {\n        SetVideoMode(MODE_PAL);\n        disp[0].screen.y += 8;\n        disp[1].screen.y += 8;\n    }\n    SetDispMask(1);\n    setRGB0(&draw[0], 0, 0, 255);\n    setRGB0(&draw[1], 0, 0, 255);\n    draw[0].isbg = 1;\n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    // Init font system\n    FntLoad(960, 0);\n    FntOpen(16, 16, 196, 64, 0, 256);\n    }\nvoid display(void){\n    DrawSync(0);\n    VSync(0);\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    db = !db;\n    }\nint main() {\n    init();\n    // Main loop\n    while (1) {\n        // Buffer for the RX data of size MAX_CHARS\n        static char buffer[ MAX_CHARS ] = {0};\n        // If SIO flag is set, initialize and get data\n        if( SIO ){\n            // Is SIO is not initialized, dot it\n            if( ! SIOinit ){\n                ResetCallback();\n                // Load SIO driver at 115200bps\n                AddSIO(115200);\n                ResetGraph(0);\n                // Use _sio_control to clear driver status error-related bits\n                // See psyq's libref47.pdf, p.1125 for the commands and status tables\n                _sio_control(2,1,0);\n                SIOinit = 1;\n            }\n            // Limit input buffer to MAX_CHARS chars, making it a rolling buffer\n            if( strlen(buffer) > MAX_CHARS ){\n               // If that limit is reached, remove first char in string\n               memmove(buffer, buffer + 1, strlen(buffer));\n            }\n            // Check if sio driver is able to write communications data\n            // If so, this means reading is not occuring\n            if( _sio_control(0,0,0) & SR_RXRDY ){ // SR_RXRDY == 0x2\n                // Read byte\n                char c = _sio_control(0,4,0);\n                // Add to buffer\n                strncat(buffer, &c, 1);\n            }\n        }           \n      // END SIO FUN\n        FntPrint(\"Hello Serial!\\n\\n\");\n        if( buffer ){\n            FntPrint(\"%s\", buffer);\n        }\n        FntFlush(-1);\n        display();\n    }\n    return 0;\n}\n"
  },
  {
    "path": "hello_sprt/Makefile",
    "content": "TARGET = hello_sprt\n\nSRCS = hello_sprt.c \\\n../TIM/TIM16.tim \\\n../TIM/TIM8.tim \\\n../TIM/TIM4.tim \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_sprt/hello_sprt.c",
    "content": "// Draw a textured sprt primitive\n//\n// based on Lameguy64's tutorial : http://lameguy64.net/svn/pstutorials/chapter1/3-textures.html\n// Schnappy 2020\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n#define VMODE 0         // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320\n#define SCREENYRES 240\n#define CENTERX SCREENXRES/2\n#define CENTERY SCREENYRES/2\n#define MARGINX 32      // margins for text display\n#define MARGINY 44\n#define FONTSIZE 8 * 3          // Text Field Height\n#define OTLEN 8              // Ordering Table Length \nDISPENV disp[2];             // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nu_long ot[2][OTLEN];     // double ordering table of length 8 * 32 = 256 bits / 32 bytes\nchar primbuff[2][32768];     // double primitive buffer of length 32768 * 8 =  262.144 bits / 32,768 Kbytes\nchar *nextpri = primbuff[0]; // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]\nshort db = 0;                // index of which buffer is used, values 0, 1\n// Embed TIM files\n// See https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/(Archived)--Embedding-binary-data-in-your-psx-executable\n// 16bpp TIM\nextern unsigned long _binary____TIM_TIM16_tim_start[];\nextern unsigned long _binary____TIM_TIM16_tim_end[];\nextern unsigned long _binary____TIM_TIM16_tim_length;\n// 8bpp TIM\nextern unsigned long _binary____TIM_TIM8_tim_start[];\nextern unsigned long _binary____TIM_TIM8_tim_end[];\nextern unsigned long _binary____TIM_TIM8_TIM_length;\n// 4bpp TIM\nextern unsigned long _binary____TIM_TIM4_tim_start[];\nextern unsigned long _binary____TIM_TIM4_tim_end[];\nextern unsigned long _binary____TIM_TIM4_tim_length;\nTIM_IMAGE TIM_16;\nTIM_IMAGE TIM_8;\nTIM_IMAGE TIM_4;\nvoid LoadTexture(u_long * tim, TIM_IMAGE * tparam){     // This part is from Lameguy64's tutorial series : lameguy64.net/svn/pstutorials/chapter1/3-textures.html login/pw: annoyingmous\n        OpenTIM(tim);                                   // Open the tim binary data, feed it the address of the data in memory\n        ReadTIM(tparam);                                // This read the header of the TIM data and sets the corresponding members of the TIM_IMAGE structure\n        LoadImage(tparam->prect, tparam->paddr);        // Transfer the data from memory to VRAM at position prect.x, prect.y\n        DrawSync(0);                                    // Wait for the drawing to end\n        if (tparam->mode & 0x8){ // check 4th bit       // If 4th bit == 1, TIM has a CLUT\n            LoadImage(tparam->crect, tparam->caddr);    // Load it to VRAM at position crect.x, crect.y\n            DrawSync(0);                                // Wait for drawing to end\n    }\n}\nvoid init(void)\n{\n    ResetGraph(0);\n    SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\n    if (VMODE)\n    {\n        SetVideoMode(MODE_PAL);\n        disp[0].screen.y += 8;\n        disp[1].screen.y += 8;\n        }\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 50, 50, 50);\n    setRGB0(&draw[1], 50, 50, 50);\n    draw[0].isbg = 1;\n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );\n}\nvoid display(void)\n{\n    DrawSync(0);\n    VSync(0);\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    DrawOTag(&ot[db][OTLEN - 1]);\n    db = !db;\n    nextpri = primbuff[db];\n}\nint main(void)\n{\n    SPRT * sprt_16b;                // Define 3 pointers to SPRT struct\n    SPRT * sprt_8b;\n    SPRT * sprt_4b;\n    DR_TPAGE * tpage_16b;           // Define 3 pointers to DR_TPAGE struct. We need three because our images are on three \n    DR_TPAGE * tpage_8b;            // different texture pages.\n    DR_TPAGE * tpage_4b;\n    init();\n    LoadTexture(_binary____TIM_TIM16_tim_start, &TIM_16); // Load everything to vram\n    LoadTexture(_binary____TIM_TIM8_tim_start, &TIM_8);\n    LoadTexture(_binary____TIM_TIM4_tim_start, &TIM_4);\n    while (1)\n    {\n        ClearOTagR(ot[db], OTLEN);\n        // Loading a 16 bit TIM \n        sprt_16b = (SPRT *)nextpri;                 // Cast whats at nexpri as a SPRT named sprt_16b\n        setSprt(sprt_16b);                          // Initialize the SPRT struct\n        setRGB0(sprt_16b, 128, 128, 128);           // Set RGB color. 128,128,128 is neutral. You can color the image by adjusting these values\n        setXY0(sprt_16b, 28, MARGINY);              // Set sprite position\n        setWH(sprt_16b, 64, 128 );                  // Set sprite width and height\n        addPrim(ot[db], sprt_16b);                  // add the sprite primitive to the ordering table\n        nextpri += sizeof(SPRT);                    // increment nextpri so that it points just after sprt_16b in the primitive buffer\n        // Set Texture page for the 16bit tim : 768, 0 - No CLUT\n        // Note :  You need to use setDrawTPage each time you want to use a texture that's on a different texture page\n        tpage_16b = (DR_TPAGE*)nextpri;\n        setDrawTPage(tpage_16b, 0, 1,               // Set the Texture Page the texture we want resides on.\n            getTPage(TIM_16.mode&0x3, 0,            // Here we are using bitmasking to deduce the picture mode : &0x3\n            TIM_16.prect->x, TIM_16.prect->y));     // In binary, 3 is 11, so we only keep the first two bits\n                                                    // Values can be 00 (0), 01 (1), 10(2), respectively, 4bpp, 8bpp, 15bpp, 24bpp. See Fileformat47.pdf, p.180\n                                                    // Similarly, we could use bitmasking to deduce if there is a CLUT by bitmasking the 4th bit : if(TIM_IMAGE.mode & 0x8) LoadImage... :  \n        addPrim(ot[db], tpage_16b);                 // add the sprite primitive to the ordering table\n        nextpri += sizeof(DR_TPAGE);                // Advance next primitive address\n        // Loading a 8 bit TIM\n        sprt_8b = (SPRT *)nextpri;\n        setSprt(sprt_8b);\n        setRGB0(sprt_8b, 128, 128, 128);        \n        setXY0(sprt_8b, sprt_16b->x0 + sprt_16b->w + 32, MARGINY);\n        setWH(sprt_8b, 64, 128 );\n        setClut(sprt_8b, TIM_8.crect->x, TIM_8.crect->y);       // Only difference here is we set the CLUT to the position of the VRAM we loaded the palette earlier (see LoadTexture())\n        addPrim(ot[db], sprt_8b);\n        nextpri += sizeof(SPRT);\n        // Set Texture page for the 8bit tim : 512, 256 - CLUT is at 0, 480\n        tpage_8b = (DR_TPAGE*)nextpri;\n        setDrawTPage(tpage_8b, 0, 1,               \n            getTPage(TIM_8.mode&0x3, 0,            \n            TIM_8.prect->x, TIM_8.prect->y));\n        addPrim(ot[db], tpage_8b);                 \n        nextpri += sizeof(DR_TPAGE);               \n        // Loading a 4 bit TIM\n        sprt_4b = (SPRT *)nextpri;\n        setSprt(sprt_4b);\n        setRGB0(sprt_4b, 128, 128, 128);        \n        setXY0(sprt_4b, sprt_8b->x0 + sprt_8b->w + 32, MARGINY);\n        setWH(sprt_4b, 64, 128 );\n        setClut(sprt_4b, TIM_4.crect->x, TIM_4.crect->y);\n        addPrim(ot[db], sprt_4b);\n        nextpri += sizeof(SPRT);\n        // Set Texture page for the 4bit tim : 512, 256 - CLUT is at 0, 480\n        tpage_4b = (DR_TPAGE*)nextpri;\n        setDrawTPage(tpage_4b, 0, 1,                \n            getTPage(TIM_4.mode&0x3, 0,             \n            TIM_4.prect->x, TIM_4.prect->y));\n        addPrim(ot[db], tpage_4b);                  \n        nextpri += sizeof(DR_TPAGE);                \n        FntPrint(\"16 Bit!     \");\n        FntPrint(\"8 Bit!      \");\n        FntPrint(\"4 Bit!\\n\\n\");\n        FntPrint(\"Check VRAM in emu to see the dif\");\n        FntFlush(-1);\n        display();\n        }\n    return 0;\n    }\n"
  },
  {
    "path": "hello_spu_readback/Makefile",
    "content": ".PHONY: all cleansub\nall:\n\tmkpsxiso -y ./isoconfig.xml\ncleansub:\n\t$(MAKE) clean\n\trm -f hello_spu_readback.cue hello_spu_readback.bin\n\nTARGET = hello_spu_readback\n\nSRCS = hello_spu_readback.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_spu_readback/README.md",
    "content": "This example is adapted from PsyQ's sample : `psyq/psx/sample/sound/CDVOL, main.c,v 1.14 1997/05/02 13:05:21 by ayako`.\nIt was edited to fix typos, have a hopefully better code organization with hopefully more usefull variable names.\n\nWhat it does is demonstrate how to transfer data from the PSX 's SPU to main memory in order to analyze / process the audio signal and dostuff accordingly.  \nIn this instance, it's used to determine the coordinates of a few primitives to display a [VU-meter](https://en.wikipedia.org/wiki/VU_meter).  \n\nThis technique is known to be used in certain games for lipsynching or audio visualization ( Crash team racing, Hercules, Vib Ribbon ...).\n\n## pcsx-redux : no animation \n\nPcsx-redux does not yet support these specific SPU buffers nor triggerring IRQ from them so as of 11-2021 this example doesn't work in this particular emulator.  \nIf looking for an alternative, check [duckstation](https://www.duckstation.org/) out.  \n\n## PsyQ's SpuReadDecodedData() doc errata\n\nThe main function for transferring data from the SPU to the RAM is `SpuReadDecodedData()`, and is documented in **LibRef47.pdf, p1054**.  \nThe table on this page (Table 15-2) contains erroneous data and should read : \n\n![Spu addresses range](https://wiki.arthus.net/assets/spureaddecodeddata_errata.png)\n\nThe correct address ranges for the SPU buffer is :\n\n| Map (bytes) | Data contents |\n|-------------|---------------|\n| 0x000 - 0x3ff | CD Left channel |\n| 0x400 - 0x7ff | CD Right channel |\n| 0x800 - 0xbff | Voice 1 |\n| 0xC00 - 0xfff | Voice 3 |\n\n## Compiling\n\nYou need [mkpsxiso](https://github.com/Lameguy64/mkpsxiso) in your $PATH to generate a PSX disk image.\nTyping \n```bash\nmake\n```\nin a terminal will compile and generate the bin/cue files.  \n\nTyping\n```bash\nmake cleansub\n``` \nwill clean the current directory\n\n## More on CDDA \n\nSee the [hello_cdda](https://github.com/ABelliqueux/nolibgs_hello_worlds/tree/main/hello_cdda) example in this repo.\n\n## Docs and links\n\nOriginal psyq example : `psyq/psx/sample/sound/CDVOL, main.c,v 1.14 1997/05/02 13:05:21 by ayako` \n\n## Music credits\n\nTrack 1 :\nBeach Party by Kevin MacLeod\nLink: https://incompetech.filmmusic.io/song/3429-beach-party\nLicense: https://filmmusic.io/standard-license  \n\nTrack 2:\nFunk Game Loop by Kevin MacLeod\nLink: https://incompetech.filmmusic.io/song/3787-funk-game-loop\nLicense: https://filmmusic.io/standard-license\n"
  },
  {
    "path": "hello_spu_readback/hello_spu_readback.c",
    "content": "// SPU readback example\n// adapted from PsyQ's sample : psyq/psx/sample/sound/CDVOL, main.c,v 1.14 1997/05/02 13:05:21 by ayako \n// Schnappy 11-2021\n#include <sys/types.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <kernel.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n// CD library\n#include <libcd.h>\n// SPU library\n#include <libspu.h>\n#include \"../thirdparty/nugget/common/syscalls/syscalls.h\"\n#define printf ramsyscall_printf\n\n#define VMODE 0                     // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320              // Screen width\n#define SCREENYRES 240 + (VMODE << 4) // Screen height : If VMODE is 0 = 240, if VMODE is 1 = 256 \n#define CENTERX SCREENXRES/2        // Center of screen on x \n#define CENTERY SCREENYRES/2        // Center of screen on y\n#define MARGINX 0                   // margins for text display\n#define MARGINY 32\n#define FONTSIZE 8 * 7              // Text Field Height\n#define OTLEN 8                     // Ordering Table Length \n// Number of bars \n#define BARNUM 2\n// Peak cursor width\n#define TSIZE 10\n// Bar size / 2\n#define BSIZE 128\n// Top Y coordinate of Left volume bar\n#define BARTOP\t100\n// Bottom Y coordinates of Left volume bar\n#define BARBOTTOM ((BARTOP)+5)\n// Vertical spacing\n#define MARGIN 40\n// Bars left coordinates\n#define MINBAR\tCENTERX - BSIZE\n// Bars right coordinates\n#define MAXBAR\t( CENTERX + BSIZE + TSIZE )\n// Bars IDs\n#define LEFTBAR 0\n#define RIGHTBAR 1\n// Return absolute value of a number\n#define ABS(x) (((x)<0)?(-(x)):(x))\n\nDISPENV disp[2];                    // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nu_long ot[2][OTLEN];                // double ordering table of length 8 * 32 = 256 bits / 32 bytes\nuint8_t primbuff[2][32768];            // double primitive buffer of length 32768 * 8 =  262.144 bits / 32,768 Kbytes\nuint8_t *nextpri = primbuff[0];        // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]\nuint8_t db = 0;                     // index of which buffer is used, values 0, 1\n// SPU attributes\nSpuCommonAttr spuSettings;\n// SPU IRQ address\nuint16_t SpuIrqAddr;\n// SPU decoded data buffer\nSpuDecodedData decodedData;\n// CD volume: current sample's max values\nulong leftMax,  rightMax;\n// Last 2 seconds's peak volume values\nulong leftPeak, rightPeak;\n\n// Primitives for drawing the VU-metre, double buffered\n// Blue : background bar\nPOLY_F4 * bar[BARNUM];\n// White : current value\nPOLY_F4\t* current[BARNUM];\n// Red : volume peak in the last 3 seconds\nPOLY_F4\t* peak[BARNUM];\n// Colors for the VU-metre\nCVECTOR bg = {20, 10, 0};\nCVECTOR fg = {10,200,20};\nCVECTOR cursor = {200,40,10};\n\nvoid init(void)\n{\n    ResetGraph(0);                 // Initialize drawing engine with a complete reset (0)\n    InitGeom();\n    SetGeomOffset(CENTERX,CENTERY);\n    SetGeomScreen(CENTERX);\n    SetDefDispEnv(&disp[0], 0, 0         , SCREENXRES, SCREENYRES);     // Set display area for both &disp[0] and &disp[1]\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // &disp[0] is on top  of &disp[1]\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // Set draw for both &draw[0] and &draw[1]\n    SetDefDrawEnv(&draw[1], 0, 0         , SCREENXRES, SCREENYRES);     // &draw[0] is below &draw[1]\n    // Set video mode\n    if (VMODE){ SetVideoMode(MODE_PAL);}\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 50, 50, 50); // set color for first draw area\n    setRGB0(&draw[1], 50, 50, 50); // set color for second draw area\n    draw[0].isbg = 1;               // set mask for draw areas. 1 means repainting the area with the RGB color each frame \n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);          // set the disp and draw environnments\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);                // Load font to vram at 960,0(+128)\n    // Top bar\n    FntOpen (MINBAR, BARTOP - 10, 200, 150, 0, 64);\n    // Bottom bar\n    FntOpen (MINBAR, BARTOP - 10 + (MARGIN), 200, 150, 0, 64);\n    // Debug\n    FntOpen (32, SCREENYRES - 74, SCREENXRES - 64, 64, 0, 200);\n}\n\nvoid display(void)\n{\n    DrawSync(0);\n    VSync(0);\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    DrawOTag(&ot[db][OTLEN - 1]);\n    db = !db;\n    nextpri = primbuff[db];\n}\n\nvoid initPrimitives(void)\n{\n    // Set primitives from primbuff[]\n    bar[0] = (POLY_F4 *)nextpri;\n    bar[1] = (POLY_F4 *)nextpri + sizeof(POLY_F4);\n    \n    current[0] = (POLY_F4 *)nextpri + (sizeof(POLY_F4) * 2);\n    current[1] = (POLY_F4 *)nextpri + (sizeof(POLY_F4) * 3);\n    \n    peak[0] = (POLY_F4 *)nextpri + (sizeof(POLY_F4) * 4);\n    peak[1] = (POLY_F4 *)nextpri + (sizeof(POLY_F4) * 5);\n\n    // Set each primitive to their default settings\n    for (int i = 0; i < BARNUM; i++)\n    {        \n        // Volume bar background is blue\n        SetPolyF4 ( bar[i] );\n        setRGB0 ( bar[i], bg.r,bg.g,bg.b );\n        setXY4 ( bar[i],\n            // Top-left\n            MINBAR, BARTOP + i * MARGIN,\n            // Top-right\n            MAXBAR, BARTOP + i * MARGIN,\n            // Bottom-left\n            MINBAR, BARBOTTOM + i * MARGIN,\n            // Bottom-right\n            MAXBAR, BARBOTTOM + i * MARGIN);\n\n        // Current volume is light purple-ish\n        SetPolyF4 (current[i]);\n        setRGB0 ( current[i], fg.r,fg.g,fg.b);\n        setXY4 ( current[i],\n            MINBAR,         BARTOP + i * MARGIN,\n            MINBAR + TSIZE, BARTOP + i * MARGIN,\n            MINBAR,         BARBOTTOM + i * MARGIN,\n            MINBAR + TSIZE, BARBOTTOM + i * MARGIN);\n\n        // Initialize peak cursor\n        SetPolyF4 ( peak[i] );\n        setRGB0 ( peak[i], cursor.r,cursor.g,cursor.b);\n        setXY4 ( peak[i],\n            MINBAR,         BARTOP + i * MARGIN,\n            MINBAR + TSIZE, BARTOP + i * MARGIN,\n            MINBAR,         BARBOTTOM + i * MARGIN,\n            MINBAR + TSIZE, BARBOTTOM + i * MARGIN);\n    }\n}\n\n// Unused - should be called whenever this madness needs to be ended\nvoid terminate(void)\n{\n    // Turn SPU irq off\n    SpuSetIRQ (SPU_OFF); \n    // Clear callback functions \n    SpuSetIRQCallback ((SpuIRQCallbackProc) NULL);\n    SpuSetTransferCallback ((SpuTransferCallbackProc) NULL);\n    // Reset SPU settings\n    spuSettings.mask = (SPU_COMMON_MVOLL |\n\t\t   SPU_COMMON_MVOLR |\n\t\t   SPU_COMMON_CDVOLL |\n\t\t   SPU_COMMON_CDVOLR |\n\t\t   SPU_COMMON_CDMIX\n\t\t   );\n    spuSettings.mvol.left       = 0;\n    spuSettings.mvol.right      = 0;\n    spuSettings.cd.volume.left  = 0;\n    spuSettings.cd.volume.right = 0;\n    spuSettings.cd.mix\t   = SPU_OFF;\n\n    SpuSetCommonAttr (&spuSettings);\n\n    // Stop CD\n    CdStop ();\n    // Stop SPU processing\n    SpuQuit ();\n    // Re-init display env\n    ResetGraph (3);\n    // stop callback processing\n    StopCallback ();\t\t\n}\n\n// Print corresponding data for each volume bar\nvoid printDataInfo(void)\n{\n    // We're using 2 streams\n    FntPrint (0, \"L: %04x peak/%04x\\n\", leftMax, leftPeak);\n    FntPrint (1, \"R: %04x peak/%04x\\n\", rightMax, rightPeak);\n    FntFlush (0);\n    FntFlush (1);\n}\n\n// SPU IRQ calback function\nvoid eachIRQ (void)\n{\n    SpuSetIRQ (SPU_OFF); /**/\n    SpuReadDecodeData (&decodedData, SPU_CDONLY); /**/\n}\n\n// DMA Transfer callback function\nvoid eachDMA (void)\n{\n    if (SpuIrqAddr == 0x0)\n        SpuIrqAddr = 0x200;\n    else\n        SpuIrqAddr = 0x0;\n    // Change IRQ address\n    SpuSetIRQAddr (SpuIrqAddr);\n    // Turn SPU IRQ requests on\n    SpuSetIRQ (SPU_ON);\n}\n\nvoid findSampleMaxVolume(void)\n{\n    // Search maximum volume value of the SPU decoded data \n    // SPU buffer data range adresses\n    long dataLowerAdress, dataUpperAdress;\n    // Current sample's max and working value\n    short maxL = 0, tmpL;\n    short maxR = 0, tmpR;\n    // Timers for the Peak cursor, reset after 120 iterations.\n    static long timeCursorL = 0, timeCursorR = 0;\n    // Find SPU data range according to current half we're working on\n    if (SpuIrqAddr == 0x0) {\n        /* 1st part is available */\n        dataLowerAdress = 0x0;\n        dataUpperAdress = 0x1ff;\n    } else {\n        /* 2nd part is available */\n        dataLowerAdress = 0x200;\n        dataUpperAdress = 0x3ff;\n    }\n    // Examine and find max volume in the data range\n    for (long i = dataLowerAdress; i < dataUpperAdress; i ++) {\n        // Examine SPU decoded data \n        tmpL = ABS(decodedData.cd_left[i]);\n        tmpR = ABS(decodedData.cd_right[i]);\n        // Only keep maximum value for this sample\n        if (maxL < tmpL ) {\n            maxL = tmpL ;\n        }\n        if (maxR < tmpR ) {\n            maxR = tmpR;\n        }\n    }\n    leftMax  = (long) maxL;\n    rightMax = (long) maxR;\n    // Peak level\n    if (leftPeak < leftMax) {\n        leftPeak = leftMax;\n        timeCursorL = 0;\n    }\n    if (rightPeak < rightMax) {\n        rightPeak = rightMax;\n        timeCursorR = 0;\n    }\n    // Peak cursors: hold 2s@60fps.\n    // Increment counters until 120 is reached, then set cursors position to current leftMax/rightMax values\n    if (timeCursorL < 120) {\n        timeCursorL ++;  \n    } else {\n        timeCursorL = 0;\n        leftPeak = leftMax;\n    }\n    if (timeCursorR < 120) {\n        timeCursorR ++;\n    } else {\n        timeCursorR = 0;\n        rightPeak = rightMax;\n    }\n}\n\n\nint main(void)\n{    \n    // Values used to switch CD track\n    u_int counter = 0;\n    int8_t flip = 1;\n    // These will hold the normalised values of leftMax/rightMax, leftPeak/rightPeak\n    long lMax, rMax, lPeak, rPeak;\n    // Init display\n    init();                         \n    // Init CD system\n    CdInit ();\n    // Init Spu\n    SpuInit();\n    // Initialize SPU related variables\n    leftMax  = rightMax  = 0;\n    leftPeak = rightPeak = 0;\n    // Fill SPU data buffers with 0s\n    for (int i = 0; i < SPU_DECODEDDATA_SIZE; i ++) {\n        decodedData.cd_left[i] = 0;\n        decodedData.cd_right[i] = 0;\n    }\n    // SPU setup\n    // Set master & CD volume to max\n    spuSettings.mask = (SPU_COMMON_MVOLL |\n                        SPU_COMMON_MVOLR |\n                        SPU_COMMON_CDVOLL |\n                        SPU_COMMON_CDVOLR |\n                        SPU_COMMON_CDMIX);\n    // Master volume should be in range 0x0000 - 0x3fff\n    spuSettings.mvol.left  = 0x3fff;\n    spuSettings.mvol.right = 0x3fff;\n    // Cd volume should be in range 0x0000 - 0x7fff\n    spuSettings.cd.volume.left = 0x7fff;\n    spuSettings.cd.volume.right = 0x7fff;\n    // Enable CD input ON\n    spuSettings.cd.mix = SPU_ON;\n    // Apply settings\n    SpuSetCommonAttr(&spuSettings);\n    // Set transfer mode \n    SpuSetTransferMode(SPU_TRANSFER_BY_DMA);\n    // Callbacks setup\n    // Set Transfer callback\n    (void) SpuSetTransferCallback ((SpuTransferCallbackProc) eachDMA);\n    // set IRQ callback\n    SpuSetIRQCallback ((SpuIRQCallbackProc) eachIRQ);\n    // Initialize SPU IRQ address\n    SpuIrqAddr = 0x200;\n    // Set IRQ address\n    SpuSetIRQAddr (SpuIrqAddr); \n    // Turn interrupt request ON\n    SpuSetIRQ(SPU_ON);\n    // CD Playback setup\n    // Play second audio track\n    // Get CD TOC\n    CdlLOC loc[100];\n    int ntoc;\n    while ((ntoc = CdGetToc(loc)) == 0) { \t\t/* Read TOC */\n        printf(\"No TOC found: please use CD-DA disc...\\n\");\n        FntPrint(2, \"No TOC found: please use CD-DA disc...\\n\");\n    }\n    // Prevent out of bound pos\n    for (int i = 1; i < ntoc; i++) {\n        CdIntToPos(CdPosToInt(&loc[i]) - 74, &loc[i]);\n    }\n    // Those array will hold the return values of the CD commands\n    u_char param[4], result[8];\n    // Set CD parameters ; Report Mode ON, CD-DA ON. See LibeOver47.pdf, p.188\n    param[0] = CdlModeRept|CdlModeDA;\n    // Set CD mode\n    CdControlB (CdlSetmode, param, 0);\t\n    // Wait 3 vsync\n    VSync (3);\n    // Play second track in toc array\n    CdControlB (CdlPlay, (u_char *)&loc[3], 0);\n    // Graphics setup \n    initPrimitives();    \n    while (1) \n    { \n        counter++;\n        ClearOTagR(ot[db], OTLEN);\n        \n        // Normalize volume \n        lMax  = (leftMax   * 256) / 0x8000 + MINBAR;\n        rMax  = (rightMax  * 256) / 0x8000 + MINBAR;\n        lPeak = (leftPeak  * 256) / 0x8000 + MINBAR;\n        rPeak = (rightPeak * 256) / 0x8000 + MINBAR;\n        \n        // Update primitives XY coordinates\n        // Set coordinates for volume bar polygons\n        setXY4 ( current[LEFTBAR],\n            MINBAR,     BARTOP,\n            lMax + TSIZE, BARTOP,\n            MINBAR,     BARBOTTOM,\n            lMax + TSIZE, BARBOTTOM);\n        setXY4 (current[RIGHTBAR],\n            MINBAR,     BARTOP + MARGIN,\n            rMax + TSIZE, BARTOP + MARGIN,\n            MINBAR,     BARBOTTOM + MARGIN,\n            rMax + TSIZE, BARBOTTOM + MARGIN);\n        // Set coordinates for peak cursor polygons\n        setXY4 (peak[LEFTBAR],\n            lPeak,         BARTOP,\n            lPeak + TSIZE, BARTOP,\n            lPeak,         BARBOTTOM,\n            lPeak + TSIZE, BARBOTTOM);\n        setXY4 (peak[RIGHTBAR],\n            rPeak,         BARTOP + MARGIN,\n            rPeak + TSIZE, BARTOP + MARGIN,\n            rPeak,         BARBOTTOM + MARGIN,\n            rPeak + TSIZE, BARBOTTOM + MARGIN);\n\n        // Add prims to ordering table from bottom to top\n        for ( int i = 0; i < BARNUM; i++) {\n            addPrim(ot[db][OTLEN - 1], bar[i]);    \n            addPrim(ot[db][OTLEN - 2], current[i]);\n            addPrim(ot[db][OTLEN - 3], peak[i]);   \n        }\n\n        // Get current track number ~ every second\n        // See LibeOver47.pdf, p.188\n        if (counter%50 == 0){\n            CdReady(1, &result[0]);\n            // current track number can also be obtained with \n            // CdControlB (CdlGetlocP, 0, &result[0]);\n        }\n        // Switch track after ~ 20 seconds\n        if (counter%(50*20) == 0){\n            // Flip can have a value of 1 or -1\n            flip *= -1;\n            uint8_t nextTrackIndex = result[1] + flip;\n            // Send CD command to switch track\n            CdControlB (CdlPlay, (u_char *)&loc[ nextTrackIndex ], 0);\n        }\n        // Update current and peak values\n        findSampleMaxVolume();\n        // Print bar's infos\n        printDataInfo();\n        // Draw debug stream\n        FntPrint(2, \"Hello SPU readback ! %d\\n\", counter);\n        FntPrint(2, \"Current track: %d\\n\", result[1] );\n        FntPrint(2, \"L: %08d, R: %08d\\n\", leftMax, rightMax);\n        FntPrint(2, \"SPU Addr: 0x%03x \", SpuIrqAddr );\n        FntFlush(2);        \n        // Update display\n        display();\n    }\n    return 0;\n}\n"
  },
  {
    "path": "hello_spu_readback/isoconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!-- MKPSXISO example XML script -->\n\n<!-- <iso_project>\n        Starts an ISO image project to build. Multiple <iso_project> elements may be\n        specified within the same xml script which useful for multi-disc projects.\n    \n        <iso_project> elements must contain at least one <track> element.\n    \n    Attributes:\n        image_name  - File name of the ISO image file to generate.\n        cue_sheet   - Optional, file name of the cue sheet for the image file\n                      (required if more than one track is specified).\n-->\n<iso_project image_name=\"hello_spu_readback.bin\" cue_sheet=\"hello_spu_readback.cue\">\n\n    <!-- <track>\n            Specifies a track to the ISO project. This example element creates a data\n            track for storing data files and CD-XA/STR streams.\n        \n            Only one data track is allowed and data tracks must only be specified as the\n            first track in the ISO image and cannot be specified after an audio track.\n        \n        Attributes:\n            type        - Track type (either data or audio).\n            source      - For audio tracks only, specifies the file name of a wav audio\n                          file to use for the audio track.\n            \n    -->\n    <track type=\"data\">\n    \n        <!-- <identifiers>\n                Optional, Specifies the identifier strings to use for the data track.\n                \n            Attributes:\n                system          - Optional, specifies the system identifier (PLAYSTATION if unspecified).\n                application     - Optional, specifies the application identifier (PLAYSTATION if unspecified).\n                volume          - Optional, specifies the volume identifier.\n                volume_set      - Optional, specifies the volume set identifier.\n                publisher       - Optional, specifies the publisher identifier.\n                data_preparer   - Optional, specifies the data preparer identifier. If unspecified, MKPSXISO\n                                  will fill it with lengthy text telling that the image file was generated\n                                  using MKPSXISO.\n        -->\n        <identifiers\n            system          =\"PLAYSTATION\"\n            application     =\"PLAYSTATION\"\n            volume          =\"HELOCD\"\n            volume_set      =\"HELOCD\"\n            publisher       =\"SCHNAPPY\"\n            data_preparer       =\"MKPSXISO\"\n        />\n        \n        <!-- <license>\n                Optional, specifies the license file to use, the format of the license file must be in\n                raw 2336 byte sector format, like the ones included with the PsyQ SDK in psyq\\cdgen\\LCNSFILE.\n                \n                License data is not included within the MKPSXISO program to avoid possible legal problems\n                in the open source environment... Better be safe than sorry.\n                \n            Attributes:\n                file    - Specifies the license file to inject into the ISO image.\n        -->\n        <!--\n        <license file=\"LICENSEA.DAT\"/>\n        -->\n        \n        <!-- <directory_tree>\n                Specifies and contains the directory structure for the data track.\n            \n            Attributes:\n                None.\n        -->\n        <directory_tree>\n        \n            <!-- <file>\n                    Specifies a file in the directory tree.\n                    \n                Attributes:\n                    name    - File name to use in the directory tree (can be used for renaming).\n                    type    - Optional, type of file (data for regular files and is the default, xa for\n                              XA audio and str for MDEC video).\n                    source  - File name of the source file.\n            -->\n            <!-- Stores system.txt as system.cnf -->\n            <file name=\"system.cnf\" type=\"data\" source=\"system.cnf\"/>\n            <file name=\"SCES_313.37\"   type=\"data\" source=\"hello_spu_readback.ps-exe\"/>\n            <dummy sectors=\"1024\"/>\n            \n            <!-- <dir>\n                    Specifies a directory in the directory tree. <file> and <dir> elements inside the element\n                    will be inside the specified directory.\n            -->\n        </directory_tree>\n        \n    </track>\n    <!--  \n    Track 1 :\n    Beach Party by Kevin MacLeod\n    Link: https://incompetech.filmmusic.io/song/3429-beach-party\n    License: https://filmmusic.io/standard-license  \n    Track 2:\n    Funk Game Loop by Kevin MacLeod\n    Link: https://incompetech.filmmusic.io/song/3787-funk-game-loop\n    License: https://filmmusic.io/standard-license\n    -->\n    <track type=\"audio\" source=\"../hello_cdda/audio/beach.wav\"/>\n    <track type=\"audio\" source=\"../hello_cdda/audio/funk.wav\"/>\n    \n</iso_project>\n"
  },
  {
    "path": "hello_spu_readback/system.cnf",
    "content": "BOOT=cdrom:\\SCES_313.37;1\nTCB=4\nEVENT=10\nSTACK=801FFFF0\n"
  },
  {
    "path": "hello_str/Makefile",
    "content": ".PHONY: all cleansub\nall:\n\tmkpsxiso -y ./isoconfig.xml\ncleansub:\n\t$(MAKE) clean\n\trm -f hello_str.cue hello_str.bin\n\t\nTARGET = hello_str\n\nSRCS = hello_str.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_str/README.md",
    "content": "This example will play a fullscreen STR file and is as straightforward as possible. If you need more advanced control other the display size and position, see the [STR playback library](https://github.com/ABelliqueux/nolibgs_hello_worlds/tree/main/hello_str#str-playback-library) section.\n\n## Compiling\n\nYou need [mkpsxiso](https://github.com/Lameguy64/mkpsxiso) in your $PATH to generate a PSX disk image.\nTyping \n```bash\nmake\n```\nin a terminal will compile and generate the bin/cue files.  \n\nTyping\n```bash\nmake cleansub\n``` \nwill clean the current directory.\n\n## STR playback library\n\n@Lameguy64 has spent some time making a STR playback library that's easily included in a project :\n\n> One thing that I find somewhat missing here is a decent piece of code for playing STR video files easily. So, what I did was take the old and messy PsyQ STR player example, clean it up entirely, and finally make it into a cute little c library for easy implementation.\n\nOriginal post : http://www.psxdev.net/forum/viewtopic.php?t=507  \nOriginal download link : https://www.mediafire.com/download/s61u86sxd1djncy/strplay.7z  \nMirror : http://psx.arthus.net/code/strplay.7z  \n\n## Converting to AVI\n\nYou need `AVI file 320x240, 15 fps, 24-bit color, Stereo 16-bit sound @ 44100 Hz`.  \n\n```\nStream #0:0: Video: rawvideo, bgr24, 320x240, 27763 kb/s, 15 fps, 15 tbr, 15 tbn, 15 tbc\nStream #0:1: Audio: pcm_u8 ([1][0][0][0] / 0x0001), 44100 Hz, 2 channels, u8, 705 kb/s\n```\n\n### Video to AVI\n\nUse Virtualdub or ffmpeg :  \n\n```bash\nffmpeg -i $INPUT.MKV -vcodec rawvideo -pix_fmt bgr24 -vf scale=320:240,setsar=1:1 -acodec pcm_u8 -ar 44100 -r 15 $OUTPUT.avi\n```\n\n### AVI to STR\n\nUse [`MC32.EXE`](http://psx.arthus.net/tools/pimp-psx.zip) to convert the AVI file to STR using these settings :  \n\n```\nFormat : Input : Avi (Uncompressed), Output : str (MDEC)\nSound: 37.8 KHz, Stereo;\nEasy: Double Speed, 15 fps, 1ch, Leap Sector;\nMDEC: version 2\n```\n\n![MC32-avi-str](https://wiki.arthus.net/assets/MC32-avi-str.png)\n\n**If `MC32.exe` crashes when hitting the 'Go' button, you have to open the ffmpeg AVI file in virtualdub, then save it again ; `File > Save as AVI...` or `F7` key, then retry.**  \n\nYou should now have a STR file and a XA file that you have to interleave in `MC32`:\n\n```\nFormat : Input : str (MDEC), Output: str (MDEC)\nSound: Input: XA , 37.8 KHz, Stereo;\nFrame rate: 15 fps, # Channels : 1(150sectors/s), Leap Sector;\nCD-ROM speed : Double Speed;\n```\n\n![MC32-avi-str-interleave](https://wiki.arthus.net/assets/MC32-avi-str-interleaved.png)\n\n### Finding a video's frame count\n\nWith `ffmpeg` :\n\n```bash\nffprobe -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 VIDEOFILE.AVI\n```\n\nAlternatively, open the STR file in `MC32.exe` and look at the bottom left of the window.\n\n### Tools & Refs\n\nMC32 : http://psx.arthus.net/tools/pimp-psx.zip  \nSTR converter : http://psx.arthus.net/tools/str_converter.rar  \n\nOriginal PsyQ sample code : \n```\n/psyq/psx/sample/scee/CD/MOVIE2\n/psyq/addons/cd/MOVIE (same as /psx/sample/cd/MOVIE )\n/addons/sound/STREAM/TUTO2.C\n```  \nOriginal post : http://www.psxdev.net/forum/viewtopic.php?t=507  \nVideo to STR conversion tutorial : http://www.psxdev.net/forum/viewtopic.php?f=51&t=277  \nMDEC notes : http://psx.arthus.net/sdk/Psy-Q/DOCS/TECHNOTE/mdecnote.pdf  \n\n## Video credits \n\nThe video and song used in this example are by Nina Paley : https://archive.org/details/CopyingIsNotTheft-ScratchTrack1280X720Hdv  \n"
  },
  {
    "path": "hello_str/hello_str.c",
    "content": "// Stream a STR file from CD, decompress and play it.\n// Schnappy 07-2021\n// based on Lameguy64 strplay library : http://www.psxdev.net/forum/viewtopic.php?t=507\n// Original PsyQ sample code : /psyq/addons/cd/MOVIE\n// Video to STR conversion : https://github.com/ABelliqueux/nolibgs_hello_worlds/tree/main/hello_str\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n#include <libspu.h>\n// CD library\n#include <libcd.h>\n// CODEC library\n#include <libpress.h>\n\n#define VMODE 0                 // Video Mode : 0 : NTSC, 1: PAL\n#define TRUECOL 0               // 0 : 16bpp, 1: 24bpp\n#define SCREENXRES 320          // Screen width\n#define SCREENYRES 240 + (VMODE << 4)          // Screen height : If VMODE is 0 = 240, if VMODE is 1 = 256 \n#define CENTERX SCREENXRES/2    // Center of screen on x \n#define CENTERY SCREENYRES/2    // Center of screen on y\n#define MARGINX 8                // margins for text display\n#define MARGINY 16\n#define FONTSIZE 8 * 7           // Text Field Height\nDISPENV disp[2];                 // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nshort db = 0;                    // index of which buffer is used, values 0, 1\n\n#define STR_POS_X 0\n// If PAL mode, add 8 pixels offset on Y (256-240)/2 \n#define STR_POS_Y (VMODE << 4)/2\n// Ring Buffer size (32 sectors seems good enough)\n#define RING_SIZE   32  \n\n#if TRUECOL\n    // pixels per short word (16b/2B)\n    // 1px is 3B in 24bpp\n    // 1px is 2B(one word) in 16bpp\n    // therefore 2B will hold 3/2 pixels\n    #define PPW         3/2 \n    // DCT mode - bit 0 : depth (0 = 16b, 1 = 24b), bit 1: in 16b mode, set STP(Semi-Transparency) bit 15.\n    // 24bpp = 01b => 1\n    #define DCT_MODE    1\n#else\n    #define PPW         1\n    // 16bpp = 10b => 2\n    #define DCT_MODE    2\n#endif\n\n// Stop playback if set\nstatic int endPlayback = 0;\n// STR file infos : Filename on CD, Width, Height, Length in frames\nstatic char * StrFileName = \"\\\\COPY.STR;1\";\nstatic int StrFileX = 320; \nstatic int StrFileY  = 240;\nstatic int StrFileLength  = 893;\n\n// When using RGB24, a special routine has to be setup as a callback function to avoid MDEC/CDROM conflict\n// See http://psx.arthus.net/sdk/Psy-Q/DOCS/LibRef47.pdf , p.713\nstatic void strCheckRGB24();\n\nvoid init(void)\n{\n    ResetCallback();\n    ResetGraph(0);                 // Initialize drawing engine with a complete reset (0)\n    SetDefDispEnv(&disp[0], 0, 0         , SCREENXRES, SCREENYRES);     // Set display area for both &disp[0] and &disp[1]\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // &disp[0] is on top  of &disp[1]\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // Set draw for both &draw[0] and &draw[1]\n    SetDefDrawEnv(&draw[1], 0, 0         , SCREENXRES, SCREENYRES);     // &draw[0] is below &draw[1]\n    // Set video mode\n    #if VMODE\n        SetVideoMode(MODE_PAL);\n        disp[0].disp.y = 8;\n        disp[1].disp.y = 8;\n    #endif\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 155, 0, 150); // set color for first draw area\n    setRGB0(&draw[1], 155, 0, 150); // set color for second draw area\n    draw[0].isbg = 0;               // set mask for draw areas. 1 means repainting the area with the RGB color each frame \n    draw[1].isbg = 0;\n    #if TRUECOL\n        disp[0].isrgb24 = 1;\n        disp[1].isrgb24 = 1;\n    #endif\n    PutDispEnv(&disp[db]);          // set the disp and draw environnments\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);                // Load font to vram at 960,0(+128)\n    FntOpen(MARGINX, MARGINY, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 ); // FntOpen(x, y, width, height,  black_bg, max. nbr. chars\n}\nvoid display(void)\n{\n    DrawSync(0);                    // Wait for all drawing to terminate\n    VSync(0);                       // Wait for the next vertical blank\n    PutDispEnv(&disp[db]);          // set alternate disp and draw environnments\n    PutDrawEnv(&draw[db]);  \n    db = !db;                       // flip db value (0 or 1)\n}\n\nint main() {\n   // CD File descriptor\n    CdlFILE STRfile;\n    // Parameter we want to set the CDROM with\n    u_char param=CdlModeSpeed;\n    // Buffers total ~110KB in memory \n    // SECTOR_SIZE is defined in words : 512 * 4 == 2048 Bytes/sector\n    // Ring buffer : 32 * 2048 = 65536 Bytes\n    u_long  RingBuff[ RING_SIZE * SECTOR_SIZE ];\n    // VLC buffers : display area in words (hence /2), 160*320 == 38400 Bytes\n    u_long  VlcBuff[2][ SCREENXRES / 2 * StrFileY ];  \n    // If using 16bpp, fetch 16xYres strips, if 24bpp, fetch 24xYres strips, 5120*PPW Bytes \n    u_short ImgBuff[2][ 16 * PPW * StrFileY];\n    u_long * curVLCptr = VlcBuff[db];\n    // Init Disp/Draw env, Font, etc.\n    init();\n    SpuInit();\n    // Init CDrom system\n    CdInit();\n    // Reset the MDEC\n    DecDCTReset(0);\n    // Set callback routine\n    DecDCToutCallback(strCheckRGB24);\n    // Set ring buffer\n    StSetRing(RingBuff, RING_SIZE);\n    // Set streaming parameters\n    StSetStream(TRUECOL, 1, StrFileLength, 0, 0);\n    // Get the CD location of the STR file to play\n    if ( CdSearchFile(&STRfile, StrFileName) == 0 ) {\n        FntPrint(\"File not found :%s\\n\", StrFileName);\n    }\n    // Set the seek target position\n    CdControl(CdlSetloc, (u_char *)&STRfile.pos, 0);\n    // Set CD mode to CdlModeSpeed\n    CdControl(CdlSetmode, &param, 0);\n    // Read from CD at position &STRfile.pos\n    // Enable streaming, double speed and ADPCM playback\n    CdRead2(CdlModeStream|CdlModeSpeed|CdlModeRT);\n    // Use a counter to avoid deadlocks\n    int wait = WAIT_TIME;\n    // Next Ring Buffer Frame address\n    u_long * nextFrame = 0;\n    // Ring buffer frame address\n    u_long * frameAddr = 0;\n    // Ring buffer frame header\n    StHEADER * sectorHeader;\n    \n    // Main loop\n    while (1) {\n        // Set some pointers to the relevant buffer addresses\n        u_long * curVLCptr = &VlcBuff[!db][0];\n        u_short * curIMGptr = &ImgBuff[db][0];\n        // While end of str is not reached, play it\n        while (!endPlayback) {\n            // Use this area to draw the slices\n            RECT curSlice = { STR_POS_X, \n                              (db * StrFileY) + STR_POS_Y,\n                              // In 24bpp, use 24 pixels wide slices\n                              16 * PPW ,\n                              StrFileY};\n            int frameDone = 0;\n            // Reset counter\n            wait = WAIT_TIME;\n            // Dont try decoding if not data has been loaded from ring buffer\n            if ( frameAddr ){\n                // Begin decoding RLE-encoded MDEC image data\n                DecDCTin( curVLCptr , DCT_MODE);\n                // Prepare to receive the decoded image data from the MDEC\n                while (curSlice.x < STR_POS_X + StrFileX * PPW) {\n                    // Receive decoded data : a 16*ppw*240 px slice in long word (4B), so / 2\n                    DecDCTout( (u_long *) curIMGptr, curSlice.w * curSlice.h / 2);\n                    // Wait for transfer end\n                    DecDCToutSync(0);\n                    // Transfer data from main memory to VRAM\n                    LoadImage(&curSlice, (u_long *) curIMGptr );\n                    // Wait for drawing termination\n                    DrawSync(0);\n                    // Increment drawArea's X with slice width (16 or 24 pix)\n                    curSlice.x += 16 * PPW;\n                }\n                 // Set frameDone flag to 1\n                frameDone = 1;\n\n                curSlice.x = STR_POS_X;\n                curSlice.y = (db * StrFileY) + STR_POS_Y;\n            }\n            // Get one frame of ring buffer data\n            // StGetNext is non-blocking, so we wait for it to return 0.\n            // StGetNext will lock the region at &frameAddr until StFreeRing() is called.\n            while ( StGetNext((u_long **)&frameAddr,(u_long **)&sectorHeader) ) {\n                wait--;\n                if (wait == 0)\n                    break;\n            }\n            // If the current frame's number is bigger than the number of frames in STR,\n            // set the endPlayback flag.\n            if (sectorHeader->frameCount >= StrFileLength)\n                endPlayback = 1;\n            // Grab a frame from the stream\n            wait = WAIT_TIME;\n            while ((nextFrame = frameAddr) == 0) {\n                wait--;\n                if ( wait == 0 ){ \n                    break;\n                }\n            }\n            // Decode the Huffman/VLC compressed data\n            DecDCTvlc(nextFrame, &VlcBuff[!db][0]);\n            // Unlock area obtained by StGetNext()\n            StFreeRing(nextFrame);\n            // Reset counter\n            wait = WAIT_TIME;\n            // Wait until the whole frame is loaded to VRAM\n            while ( frameDone == 0 ) {\n                wait--;\n                if ( wait == 0 ) { \n                    // If a timeout occurs, force switching buffers\n                    frameDone = 1;\n                    curSlice.x = STR_POS_X;\n                    curSlice.y = (db * StrFileY) + STR_POS_Y;\n                }\n            }\n            FntFlush(-1);\n            display();\n        }\n        // Disable callback\n        DecDCToutCallback(0);\n        // Release two interrupt functions CdDataCallback() and CdReadyCallback() hooked by CDRead2()\n        StUnSetRing();\n        // Put CDROM on pause at current position\n        CdControlB(CdlPause, 0, 0);\n    }\n    return 0;\n};\n\nstatic void strCheckRGB24() {\n\n    /* From http://psx.arthus.net/sdk/Psy-Q/DOCS/, p.713\n     * When playing a movie in 24-bit mode, there is a potential hardware conflict between the CD subsystem\n     * and the MDEC image decompression system which can result in corrupted data. To avoid this,\n     * StCdInterrupt() may defer transferring a sector and instead set a flag variable called StCdInterFlag to\n     * indicate that a CD sector is ready to be transferred. Once the MDEC is finished transferring data, your\n     * application should check StCdIntrFlag and call StCdInterrupt() directly if it is set.\n     */\n    #if TRUECOL\n        extern int StCdIntrFlag;\n        // If flag was set\n        if ( StCdIntrFlag ) {\n            // Trigger data transfer\n            StCdInterrupt();\n            // Reset flag\n            StCdIntrFlag = 0;\n        }\n    #endif\n}\n"
  },
  {
    "path": "hello_str/isoconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!-- MKPSXISO example XML script -->\n\n<!-- <iso_project>\n        Starts an ISO image project to build. Multiple <iso_project> elements may be\n        specified within the same xml script which useful for multi-disc projects.\n    \n        <iso_project> elements must contain at least one <track> element.\n    \n    Attributes:\n        image_name  - File name of the ISO image file to generate.\n        cue_sheet   - Optional, file name of the cue sheet for the image file\n                      (required if more than one track is specified).\n-->\n<iso_project image_name=\"hello_str.bin\" cue_sheet=\"hello_str.cue\">\n\n    <!-- <track>\n            Specifies a track to the ISO project. This example element creates a data\n            track for storing data files and CD-XA/STR streams.\n        \n            Only one data track is allowed and data tracks must only be specified as the\n            first track in the ISO image and cannot be specified after an audio track.\n        \n        Attributes:\n            type        - Track type (either data or audio).\n            source      - For audio tracks only, specifies the file name of a wav audio\n                          file to use for the audio track.\n            \n    -->\n    <track type=\"data\">\n    \n        <!-- <identifiers>\n                Optional, Specifies the identifier strings to use for the data track.\n                \n            Attributes:\n                system          - Optional, specifies the system identifier (PLAYSTATION if unspecified).\n                application     - Optional, specifies the application identifier (PLAYSTATION if unspecified).\n                volume          - Optional, specifies the volume identifier.\n                volume_set      - Optional, specifies the volume set identifier.\n                publisher       - Optional, specifies the publisher identifier.\n                data_preparer   - Optional, specifies the data preparer identifier. If unspecified, MKPSXISO\n                                  will fill it with lengthy text telling that the image file was generated\n                                  using MKPSXISO.\n        -->\n        <identifiers\n            system          =\"PLAYSTATION\"\n            application     =\"PLAYSTATION\"\n            volume          =\"HELOCD\"\n            volume_set      =\"HELOCD\"\n            publisher       =\"SCHNAPPY\"\n            data_preparer       =\"MKPSXISO\"\n        />\n        \n        <!-- <license>\n                Optional, specifies the license file to use, the format of the license file must be in\n                raw 2336 byte sector format, like the ones included with the PsyQ SDK in psyq\\cdgen\\LCNSFILE.\n                \n                License data is not included within the MKPSXISO program to avoid possible legal problems\n                in the open source environment... Better be safe than sorry.\n                \n            Attributes:\n                file    - Specifies the license file to inject into the ISO image.\n        -->\n        <!--\n        <license file=\"LICENSEA.DAT\"/>\n        -->\n        \n        <!-- <directory_tree>\n                Specifies and contains the directory structure for the data track.\n            \n            Attributes:\n                None.\n        -->\n        <directory_tree>\n        \n            <!-- <file>\n                    Specifies a file in the directory tree.\n                    \n                Attributes:\n                    name    - File name to use in the directory tree (can be used for renaming).\n                    type    - Optional, type of file (data for regular files and is the default, xa for\n                              XA audio and str for MDEC video).\n                    source  - File name of the source file.\n            -->\n            <!-- Stores system.txt as system.cnf -->\n            <file name=\"system.cnf\" type=\"data\" source=\"system.cnf\"/>\n            <file name=\"SCES_313.37\"   type=\"data\" source=\"hello_str.ps-exe\"/>\n            <file name=\"COPY.STR\" type=\"str\" source=\"str/copyings.str\"/>\n\n            <dummy sectors=\"1024\"/>\n            \n            <!-- <dir>\n                    Specifies a directory in the directory tree. <file> and <dir> elements inside the element\n                    will be inside the specified directory.\n            -->\n        </directory_tree>\n        \n    </track>\n    \n</iso_project>\n"
  },
  {
    "path": "hello_str/system.cnf",
    "content": "BOOT=cdrom:\\SCES_313.37;1\nTCB=4\nEVENT=10\nSTACK=801FFFF0\n"
  },
  {
    "path": "hello_strplay/Makefile",
    "content": ".PHONY: all cleansub\nall:\n\tmkpsxiso -y ./isoconfig.xml\ncleansub:\n\t$(MAKE) clean\n\trm -f hello_strplay.cue hello_strplay.bin\n\t\nTARGET = hello_strplay\n\nSRCS = hello_strplay.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_strplay/README.md",
    "content": "This example show how to use Lameguy64's  [STR playback library](https://github.com/ABelliqueux/nolibgs_hello_worlds/tree/main/hello_str#str-playback-library).\n\nFor a barebone example, see the [hello_str](https://github.com/ABelliqueux/nolibgs_hello_worlds/tree/main/hello_str) example.\n\n## Compiling\n\nYou need [mkpsxiso](https://github.com/Lameguy64/mkpsxiso) in your $PATH to generate a PSX disk image.\nTyping \n```bash\nmake\n```\nin a terminal will compile and generate the bin/cue files.  \n\nTyping\n```bash\nmake cleansub\n``` \nwill clean the current directory.\n\n## STR playback library\n\n@Lameguy64 has spent some time making a STR playback library that's easily included in a project :\n\n> One thing that I find somewhat missing here is a decent piece of code for playing STR video files easily. So, what I did was take the old and messy PsyQ STR player example, clean it up entirely, and finally make it into a cute little c library for easy implementation.\n\nOriginal post : http://www.psxdev.net/forum/viewtopic.php?t=507  \nOriginal download link : https://www.mediafire.com/download/s61u86sxd1djncy/strplay.7z  \nMirror : http://psx.arthus.net/code/strplay.7z  \n\n## Video encoding and more informations\n\nSee the [wiki](https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/STR).\n\n## Video credits \n\nThe video and song used in this example are by Nina Paley : https://archive.org/details/CopyingIsNotTheft-ScratchTrack1280X720Hdv  \n"
  },
  {
    "path": "hello_strplay/hello_strplay.c",
    "content": "// Using the strplay library.\n// Schnappy 07-2021\n// based on Lameguy64 strplay library : http://www.psxdev.net/forum/viewtopic.php?t=507\n// Original PsyQ sample code : /psyq/addons/cd/MOVIE\n// Video to STR conversion : https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/STR\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n// CD library\n#include <libcd.h>\n// CODEC library\n#include <libpress.h>\n// include Lameguy64's library\n#include \"strplay.c\"\n\n#define VMODE 0                 // Video Mode : 0 : NTSC, 1: PAL\n#define TRUECOL 1               // 0 : 16bpp, 1: 24bpp\n#define SCREENXRES 320          // Screen width\n#define SCREENYRES 240 + (VMODE << 4)          // Screen height : If VMODE is 0 = 240, if VMODE is 1 = 256 \n#define CENTERX SCREENXRES/2    // Center of screen on x \n#define CENTERY SCREENYRES/2    // Center of screen on y\n#define MARGINX 8                // margins for text display\n#define MARGINY 16\n#define FONTSIZE 8 * 7           // Text Field Height\nDISPENV disp[2];                 // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nshort db = 0;                    // index of which buffer is used, values 0, 1\n\nSTRFILE StrFile[] = {\n\t// File name\tResolution\t\tFrame count\n\t\"\\\\COPY.STR;1\", 320, 240, 893\n};\n\n// When using RGB24, a special routine has to be setup as a callback function to avoid MDEC/CDROM conflict\n// See http://psx.arthus.net/sdk/Psy-Q/DOCS/LibRef47.pdf , p.713\nstatic void strCheckRGB24();\n\nvoid init(void)\n{\n    ResetCallback();\n    ResetGraph(0);                 // Initialize drawing engine with a complete reset (0)\n    SetDefDispEnv(&disp[0], 0, 0         , SCREENXRES, SCREENYRES);     // Set display area for both &disp[0] and &disp[1]\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // &disp[0] is on top  of &disp[1]\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // Set draw for both &draw[0] and &draw[1]\n    SetDefDrawEnv(&draw[1], 0, 0         , SCREENXRES, SCREENYRES);     // &draw[0] is below &draw[1]\n    // Set video mode\n    #if VMODE\n        SetVideoMode(MODE_PAL);\n        disp[0].disp.y = 8;\n        disp[1].disp.y = 8;\n    #endif\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 155, 0, 150); // set color for first draw area\n    setRGB0(&draw[1], 155, 0, 150); // set color for second draw area\n    draw[0].isbg = 0;               // set mask for draw areas. 1 means repainting the area with the RGB color each frame \n    draw[1].isbg = 0;\n    #if TRUECOL\n        disp[0].isrgb24 = 1;\n        disp[1].isrgb24 = 1;\n    #endif\n    PutDispEnv(&disp[db]);          // set the disp and draw environnments\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);                // Load font to vram at 960,0(+128)\n    FntOpen(MARGINX, MARGINY, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 ); // FntOpen(x, y, width, height,  black_bg, max. nbr. chars\n}\nvoid display(void)\n{\n    DrawSync(0);                    // Wait for all drawing to terminate\n    VSync(0);                       // Wait for the next vertical blank\n    PutDispEnv(&disp[db]);          // set alternate disp and draw environnments\n    PutDrawEnv(&draw[db]);  \n    db = !db;                       // flip db value (0 or 1)\n}\n\nvoid main() {\n\t\n\t// Reset and initialize stuff\n\tinit();\n\tCdInit();\n\tPadInit(0);\n\t\n\t// Play the video in loop\n\twhile (1) {\n\t\t\n\t\tif (PlayStr(320, 240, 0, 0, &StrFile[0]) == 0)\t// If player presses Start\n\t\t\tbreak;\t// Exit the loop\n\t}\n\t\n}\n\nstatic void strCheckRGB24() {\n\n    /* From http://psx.arthus.net/sdk/Psy-Q/DOCS/, p.713\n     * When playing a movie in 24-bit mode, there is a potential hardware conflict between the CD subsystem\n     * and the MDEC image decompression system which can result in corrupted data. To avoid this,\n     * StCdInterrupt() may defer transferring a sector and instead set a flag variable called StCdInterFlag to\n     * indicate that a CD sector is ready to be transferred. Once the MDEC is finished transferring data, your\n     * application should check StCdIntrFlag and call StCdInterrupt() directly if it is set.\n     */\n    #if TRUECOL\n        extern u_long StCdIntrFlag;\n        // If flag was set\n        if ( StCdIntrFlag ) {\n            // Trigger data transfer\n            StCdInterrupt();\n            // Reset flag\n            StCdIntrFlag = 0;\n        }\n    #endif\n}\n"
  },
  {
    "path": "hello_strplay/isoconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!-- MKPSXISO example XML script -->\n\n<!-- <iso_project>\n        Starts an ISO image project to build. Multiple <iso_project> elements may be\n        specified within the same xml script which useful for multi-disc projects.\n    \n        <iso_project> elements must contain at least one <track> element.\n    \n    Attributes:\n        image_name  - File name of the ISO image file to generate.\n        cue_sheet   - Optional, file name of the cue sheet for the image file\n                      (required if more than one track is specified).\n-->\n<iso_project image_name=\"hello_strplay.bin\" cue_sheet=\"hello_strplay.cue\">\n\n    <!-- <track>\n            Specifies a track to the ISO project. This example element creates a data\n            track for storing data files and CD-XA/STR streams.\n        \n            Only one data track is allowed and data tracks must only be specified as the\n            first track in the ISO image and cannot be specified after an audio track.\n        \n        Attributes:\n            type        - Track type (either data or audio).\n            source      - For audio tracks only, specifies the file name of a wav audio\n                          file to use for the audio track.\n            \n    -->\n    <track type=\"data\">\n    \n        <!-- <identifiers>\n                Optional, Specifies the identifier strings to use for the data track.\n                \n            Attributes:\n                system          - Optional, specifies the system identifier (PLAYSTATION if unspecified).\n                application     - Optional, specifies the application identifier (PLAYSTATION if unspecified).\n                volume          - Optional, specifies the volume identifier.\n                volume_set      - Optional, specifies the volume set identifier.\n                publisher       - Optional, specifies the publisher identifier.\n                data_preparer   - Optional, specifies the data preparer identifier. If unspecified, MKPSXISO\n                                  will fill it with lengthy text telling that the image file was generated\n                                  using MKPSXISO.\n        -->\n        <identifiers\n            system          =\"PLAYSTATION\"\n            application     =\"PLAYSTATION\"\n            volume          =\"HELOCD\"\n            volume_set      =\"HELOCD\"\n            publisher       =\"SCHNAPPY\"\n            data_preparer       =\"MKPSXISO\"\n        />\n        \n        <!-- <license>\n                Optional, specifies the license file to use, the format of the license file must be in\n                raw 2336 byte sector format, like the ones included with the PsyQ SDK in psyq\\cdgen\\LCNSFILE.\n                \n                License data is not included within the MKPSXISO program to avoid possible legal problems\n                in the open source environment... Better be safe than sorry.\n                \n            Attributes:\n                file    - Specifies the license file to inject into the ISO image.\n        -->\n        <!--\n        <license file=\"LICENSEA.DAT\"/>\n        -->\n        \n        <!-- <directory_tree>\n                Specifies and contains the directory structure for the data track.\n            \n            Attributes:\n                None.\n        -->\n        <directory_tree>\n        \n            <!-- <file>\n                    Specifies a file in the directory tree.\n                    \n                Attributes:\n                    name    - File name to use in the directory tree (can be used for renaming).\n                    type    - Optional, type of file (data for regular files and is the default, xa for\n                              XA audio and str for MDEC video).\n                    source  - File name of the source file.\n            -->\n            <!-- Stores system.txt as system.cnf -->\n            <file name=\"system.cnf\" type=\"data\" source=\"system.cnf\"/>\n            <file name=\"SCES_313.37\"   type=\"data\" source=\"hello_strplay.ps-exe\"/>\n            <file name=\"COPY.STR\" type=\"str\" source=\"str/copyings.str\"/>\n\n            <dummy sectors=\"1024\"/>\n            \n            <!-- <dir>\n                    Specifies a directory in the directory tree. <file> and <dir> elements inside the element\n                    will be inside the specified directory.\n            -->\n        </directory_tree>\n        \n    </track>\n    \n</iso_project>\n"
  },
  {
    "path": "hello_strplay/strplay.c",
    "content": "/*\r\n\t\r\n\tSimple STR Player Library by Lameguy64 \r\n\t(?) 2014 Meido-Tek Productions/Lame Studios\r\n\t\r\n\tOriginal PsyQ sample programmed by:\r\n\t\tYutaka\r\n\t\tSuzu\r\n\t\tMasa\r\n\t\tUme\r\n\t\r\n\tCode heavily refined by:\r\n\t\tLameguy64\r\n\t\r\n\tWhat Lameguy did to the original code:\r\n\t\t- Removed all of the icky yucky UTF-16 junk\r\n\t\t- Fixed all crap-English comments\r\n\t\t- Greatly improved code formatting\r\n\t\t- Renamed variables with better names\r\n\t\t- Buffer arrays are now initialized only when the playback routine is called\r\n\t\r\n\tLibraries Required:\r\n\t\tlibetc\r\n\t\tlibgte\r\n\t\tlibgpu\r\n\t\tlibcd\r\n\t\r\n\tFunction list:\r\n\t\r\n\t\tint PlayStr(int xres, int yres, int xpos, int ypos, STRFILE *str)\r\n\t\t\t\r\n\t\t\tParameters:\r\n\t\t\t\txres, yres\t\t- Video resolution.\r\n\t\t\t\txpos, ypos\t\t- Framebuffer offset on where to draw the video.\r\n\t\t\t\tSTRFILE *str\t- STRFILE entry to play.\r\n\t\t\t\r\n\t\t\tNotes:\r\n\t\t\t\tJust make sure that you have at least 192KB of free memory before calling\r\n\t\t\t\tthe\tPlayStr function otherwise, the console will crash. As for the video\r\n\t\t\t\tresolution, it must be equal or less than 256 as the second buffer\r\n\t\t\t\tis located directly below the first buffer.\r\n\t\t\r\n\tNote:\r\n\t\t\r\n\t\tIf compiling the sample fails, open your psyq.ini file located in \\psyq\\bin and\r\n\t\tappend the following into the stdlib line:\r\n\t\t\r\n\t\tlibds.lib libpress.lib\r\n\t\r\n*/\r\n\r\n#define IS_RGB24\t1\t// 0:16-bit playback, 1:24-bit playback (recommended for quality)\r\n#define RING_SIZE\t32\t// Ring Buffer size (32 sectors seems good enough)\r\n\r\n#if IS_RGB24==1\r\n\t#define PPW\t\t\t3/2\t// pixels per short word\r\n\t#define DCT_MODE\t3\t// Decode mode for DecDCTin routine\r\n#else\r\n\t#define PPW\t\t\t1\r\n\t#define DCT_MODE    2\r\n#endif\r\n\r\n\r\n// A simple struct to make STR handling a bit easier\r\ntypedef struct {\r\n\tchar\tFileName[32];\r\n\tint\t\tXres;\r\n\tint\t\tYres;\r\n\tint\t\tNumFrames;\r\n} STRFILE;\r\n\r\n// Decode environment\r\ntypedef struct {\r\n\tu_long\t*VlcBuff_ptr[2];\t// Pointers to the VLC buffers\r\n\tu_short\t*ImgBuff_ptr[2];\t// Pointers to the frame slice buffers\r\n\tRECT\trect[2];\t\t\t// VRAM parameters on where to draw the frame data to\r\n\tRECT\tslice;\t\t\t\t// Frame slice parameters for loading into VRAM\r\n\tint\t\tVlcID;\t\t\t\t// Current VLC buffer ID\r\n\tint\t\tImgID;\t\t\t\t// Current slice buffer ID\r\n\tint \tRectID;\t\t\t\t// Current video buffer ID\r\n\tint\t\tFrameDone;\t\t\t// Frame decode completion flag\r\n} STRENV;\r\n\r\n// A bunch of internal variables\r\nstatic STRENV strEnv;\r\n\r\nstatic int\tstrScreenWidth=0,strScreenHeight=0;\r\nstatic int\tstrFrameX=0,strFrameY=0;\r\nstatic int\tstrNumFrames=0;\r\n\r\nstatic int strFrameWidth=0,strFrameHeight=0;\t// Frame size of STR file\r\nstatic int strPlayDone=0;\t\t\t\t\t\t// Playback completion flag\r\n\r\n// Main function prototypes\r\nint PlayStr(int xres, int yres, int xpos, int ypos, STRFILE *str);\r\n\r\n// Internal function prototypes\r\nstatic void strDoPlayback(STRFILE *str);\r\nstatic void strCallback();\r\nstatic void strNextVlc(STRENV *strEnv);\r\nstatic void strSync(STRENV *strEnv, int mode);\r\nstatic u_long *strNext(STRENV *strEnv);\r\nstatic void strKickCD(CdlLOC *loc);\r\n\r\n\r\nint PlayStr(int xres, int yres, int xpos, int ypos, STRFILE *str) {\r\n\t\r\n\t/*\r\n\t\tMain STR playback routine.\r\n\t\t\r\n\t\tReturns:\r\n\t\t\t0 - Playback failed or was skipped.\r\n\t\t\t1 - Playback was finished.\r\n\t*/\r\n\t\r\n\tstrNumFrames=str->NumFrames;\r\n\tstrScreenWidth=xres;\r\n\tstrScreenHeight=yres;\r\n\tstrFrameX=xpos;\r\n\tstrFrameY=ypos;\r\n\t\r\n\tstrPlayDone=0;\r\n\tstrDoPlayback(str);\r\n\t\r\n\tif (strPlayDone == 0)\r\n\t\treturn(0);\r\n\telse\r\n\t\treturn(1);\r\n\t\r\n}\r\n\r\nstatic void strDoPlayback(STRFILE *str) {\r\n\t\r\n\t/*\r\n\t\tDoes the actual STR playback.\r\n\t*/\r\n\t\r\n\tint id;\t\t\t// Display buffer ID\r\n\tDISPENV disp;\t// Display environment\r\n\tCdlFILE file;\t// File info of video file\r\n\t\r\n\t// Buffers initialized here so we won't waste too much memory for playing FMVs\r\n\t// (just make sure you have at least 192KB of free memory before calling this routine)\r\n\tu_long\tRingBuff[RING_SIZE*SECTOR_SIZE];\t// Ring buffer\r\n\tu_long\tVlcBuff[2][str->Xres/2*str->Yres];\t// VLC buffers\r\n\tu_short\tImgBuff[2][16*PPW*str->Yres];\t\t// Frame 'slice' buffers\r\n\t\r\n\t// Set display mask so we won't see garbage while the stream is being prepared\r\n\tSetDispMask(0);\r\n\t\r\n\t// Get the CD location of the STR file to play\r\n\tif (CdSearchFile(&file, str->FileName) == 0) {\r\n\t\t#ifdef DEBUG\r\n\t\tprintf(\"ERROR: I cannot find video file %s\\n\", str->FileName);\r\n\t\t#endif\r\n\t\tSetDispMask(1);\r\n\t\treturn;\r\n\t}\r\n\t\r\n\t// Setup the buffer pointers\r\n\tstrEnv.VlcBuff_ptr[0] = &VlcBuff[0][0];\r\n\tstrEnv.VlcBuff_ptr[1] = &VlcBuff[1][0];\r\n\tstrEnv.VlcID     = 0;\r\n\tstrEnv.ImgBuff_ptr[0] = &ImgBuff[0][0];\r\n\tstrEnv.ImgBuff_ptr[1] = &ImgBuff[1][0];\r\n\tstrEnv.ImgID     = 0;\r\n\t\r\n\t// Setup the display buffers on VRAM\r\n\tstrEnv.rect[0].x = strFrameX;\t// First page\r\n\tstrEnv.rect[0].y = strFrameY;\r\n\tstrEnv.rect[1].x = strFrameX;\t// Second page\r\n\tstrEnv.rect[1].y = strFrameY+strScreenHeight;\r\n\tstrEnv.RectID    = 0;\r\n\t\r\n\t// Set the parameters for uploading frame slices\r\n\tstrEnv.slice.x = strFrameX;\r\n\tstrEnv.slice.y = strFrameY;\r\n\tstrEnv.slice.w\t= 16*PPW;\r\n\tstrEnv.FrameDone\t= 0;\r\n\t\r\n\t// Reset the MDEC\r\n\tDecDCTReset(0);\r\n\t// Set callback routine\r\n\tDecDCToutCallback(strCallback);\r\n\t// Set ring buffer\r\n\tStSetRing(RingBuff, RING_SIZE);\r\n\t// Set streaming parameters\r\n\tStSetStream(IS_RGB24, 1, 0xffffffff, 0, 0);\r\n\t// Begin streaming!\r\n\tstrKickCD(&file.pos);\r\n\t\r\n\t// Load the first frame of video before entering main loop\r\n\tstrNextVlc(&strEnv);\r\n\t\r\n\twhile (1) {\r\n\t\t\r\n\t\t// Decode the compressed frame data\r\n\t\tDecDCTin(strEnv.VlcBuff_ptr[strEnv.VlcID], DCT_MODE);\r\n\t\t\r\n\t\t// Prepare to receive the decoded image data from the MDEC\r\n\t\tDecDCTout((u_long*)strEnv.ImgBuff_ptr[strEnv.ImgID], strEnv.slice.w*strEnv.slice.h/2);\r\n\t\t\r\n\t\t// Get the next frame\r\n\t\tstrNextVlc(&strEnv);\r\n\t\t\r\n\t\t// Wait for the frame to finish decoding\r\n\t\tstrSync(&strEnv, 0);\r\n\t\t\t\t\r\n\t\t// Switch between the display buffers per frame\r\n\t\tid = strEnv.RectID? 0: 1;\r\n\t\tSetDefDispEnv(&disp, 0, strScreenHeight*id, strScreenWidth*PPW, strScreenHeight);\r\n\t\t\r\n\t\t// Set parameters for 24-bit color mode\r\n\t\t#if IS_RGB24 == 1\r\n\t\tdisp.isrgb24 = IS_RGB24;\r\n\t\tdisp.disp.w = disp.disp.w*2/3;\r\n\t\t#endif\r\n\r\n\t\tVSync(0);\t\t\t// VSync to avoid screen tearing\r\n\t\tPutDispEnv(&disp);\t// Apply the video parameters\r\n\t\tSetDispMask(1);\t\t// Remove the display mask\r\n\t\t\r\n\t\tif(strPlayDone == 1) {\r\n\t\t\tbreak;\r\n\t\t}\r\n\t\t\r\n\t\tif(PadRead(1) & PADstart) {  // stop button pressed exit animation routine\r\n\t\t\tbreak;\r\n\t\t}\r\n\t\t\r\n\t}\r\n\t\r\n\t// Shutdown streaming\r\n\tDecDCToutCallback(0);\r\n\tStUnSetRing();\r\n\tCdControlB(CdlPause, 0, 0);\r\n\t\r\n}\r\nstatic void strCallback() {\r\n\r\n\t/*\r\n\t\tCallback routine which is called whenever a slice has finished decoding.\r\n\t\tAll it does is transfer the decoded slice into VRAM.\r\n\t*/\r\n\r\n\tRECT TransferRect;\r\n\tint  id;\r\n\t\r\n\t// In 24-bit color, StCdInterrupt must be called in every callback\r\n\t#if IS_RGB24==1\r\n\textern u_long StCdIntrFlag;\r\n\tif (StCdIntrFlag) {\r\n\t\tStCdInterrupt();\r\n\t\tStCdIntrFlag = 0;\r\n\t}\r\n\t#endif\r\n\t\r\n\tid = strEnv.ImgID;\r\n\tTransferRect = strEnv.slice;\r\n\t\r\n\t// Switch slice buffers\r\n\tstrEnv.ImgID = strEnv.ImgID? 0:1;\r\n\t\r\n\t// Step to next slice\r\n\tstrEnv.slice.x += strEnv.slice.w;\r\n\t\r\n\t// Frame not yet decoded completely?\r\n\tif (strEnv.slice.x < strEnv.rect[strEnv.RectID].x + strEnv.rect[strEnv.RectID].w) {\r\n\t\r\n\t\t// Prepare for next slice\r\n\t\tDecDCTout((u_long*)strEnv.ImgBuff_ptr[strEnv.ImgID], strEnv.slice.w*strEnv.slice.h/2);\r\n\t\r\n\t} else { // Frame has been decoded completely\r\n\t\r\n\t\t// Set the FrameDone flag\r\n\t\tstrEnv.FrameDone = 1;\r\n\r\n\t\t// Switch display buffers\r\n\t\tstrEnv.RectID = strEnv.RectID? 0: 1;\r\n\t\tstrEnv.slice.x = strEnv.rect[strEnv.RectID].x;\r\n\t\tstrEnv.slice.y = strEnv.rect[strEnv.RectID].y;\r\n\t\t\r\n\t}\r\n\r\n\t// Transfer the slice into VRAM\r\n\tLoadImage(&TransferRect, (u_long *)strEnv.ImgBuff_ptr[id]);\r\n\r\n}\r\nstatic void strNextVlc(STRENV *strEnv) {\r\n\t\r\n\t/*\r\n\t\tPerforms VLC decoding and grabs a frame from the stream.\r\n\t*/\r\n\r\n\tint\t\tcnt=WAIT_TIME;\r\n\tu_long\t*next;\r\n\tu_long\t*strNext();\r\n\r\n\t// Grab a frame from the stream\r\n\twhile ((next = strNext(strEnv)) == 0) {\r\n\t\r\n\t\tif (--cnt == 0)\t// Timeout handler\r\n\t\t\treturn;\r\n\t\t\t\r\n\t}\r\n\r\n\t// Switch VLC buffers\r\n\tstrEnv->VlcID = strEnv->VlcID? 0: 1;\r\n\r\n\t// Decode the VLC\r\n\tDecDCTvlc(next, strEnv->VlcBuff_ptr[strEnv->VlcID]);\r\n\r\n\t// Free the ring buffer\r\n\tStFreeRing(next);\r\n\r\n}\r\nstatic u_long *strNext(STRENV *strEnv) {\r\n\t\r\n\t/*\r\n\t\tGrabs a frame of video from the stream.\r\n\t*/\r\n\t\r\n\tu_long\t\t*addr;\r\n\tStHEADER\t*sector;\r\n\tint\t\t\tcnt = WAIT_TIME;\r\n\r\n\t// Grab a frame\r\n\twhile (StGetNext((u_long **)&addr,(u_long **)&sector)) {\r\n\t\r\n\t\tif (--cnt == 0)\t// Timeout handler\r\n\t\t\treturn(0);\r\n\t\t\t\r\n\t}\r\n\r\n\t// If the frame's number has reached number of frames the video has,\r\n\t// set the strPlayDone flag.\r\n\tif (sector->frameCount >= strNumFrames)\r\n\t\tstrPlayDone = 1;\r\n\t\r\n\t\r\n\t// if the resolution is differ to previous frame, clear frame buffer\r\n\tif (strFrameWidth != sector->width || strFrameHeight != sector->height) {\r\n\t\t\r\n\t\tRECT    rect;\r\n\t\tsetRECT(&rect, 0, 0, strScreenWidth * PPW, strScreenHeight*2);\r\n\t\tClearImage(&rect, 0, 0, 0);\r\n\r\n\t\tstrFrameWidth  = sector->width;\r\n\t\tstrFrameHeight = sector->height;\r\n\t\t\r\n\t}\r\n\t\r\n\r\n\t// set STRENV according to the data on the STR format\r\n\tstrEnv->rect[0].w = strEnv->rect[1].w = strFrameWidth*PPW;\r\n\tstrEnv->rect[0].h = strEnv->rect[1].h = strFrameHeight;\r\n\tstrEnv->slice.h   = strFrameHeight;\r\n\r\n\treturn(addr);\r\n\t\r\n}\r\nstatic void strSync(STRENV *strEnv, int mode) {\r\n\t\r\n\t/*\r\n\t\tWaits for the frame to finish decoding.\r\n\t*/\r\n\t\r\n    u_long cnt = WAIT_TIME;\r\n\r\n    // Wait for the frame to finish decoding\r\n    while (strEnv->FrameDone == 0) {\r\n        if (--cnt == 0) { // Timeout handler\r\n            // If a timeout occurs, force switching buffers\r\n\t\t\t#ifdef DEBUG\r\n\t\t\tprintf(\"ERROR: A frame cannot be played!\\n\");\r\n\t\t\t#endif\r\n            strEnv->FrameDone = 1;\r\n            strEnv->RectID = strEnv->RectID? 0: 1;\r\n            strEnv->slice.x = strEnv->rect[strEnv->RectID].x;\r\n            strEnv->slice.y = strEnv->rect[strEnv->RectID].y;\r\n        }\r\n    }\r\n\t\r\n    strEnv->FrameDone = 0;\r\n\t\r\n}\r\nstatic void strKickCD(CdlLOC *loc) {\r\n\t\r\n\t/*\r\n\t\tBegins CD streaming.\r\n\t*/\r\n\t\r\n\tu_char param=CdlModeSpeed;\r\n\t\r\n\tloop:\r\n\t\r\n\t// Seek to the STR file to play\r\n\twhile (CdControl(CdlSetloc, (u_char *)loc, 0) == 0);\r\n\twhile (CdControl(CdlSetmode, &param, 0) == 0);\r\n\t\r\n\tVSync(3);  // Wait for 3 screen cycles before changing drive speed\r\n\t\r\n\t// Start streaming\r\n\tif(CdRead2(CdlModeStream|CdlModeSpeed|CdlModeRT) == 0)\r\n\t\tgoto loop;\t// If it fails, try again\r\n\t\r\n}\r\n"
  },
  {
    "path": "hello_strplay/system.cnf",
    "content": "BOOT=cdrom:\\SCES_313.37;1\nTCB=4\nEVENT=10\nSTACK=801FFFF0\n"
  },
  {
    "path": "hello_tile/Makefile",
    "content": "TARGET = hello_tile\n\nSRCS = hello_tile.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_tile/hello_tile.c",
    "content": "// Draw a tile primitive\n// Schnappy 2021\n// based on Lameguy64's tutorial : http://lameguy64.net/svn/pstutorials/chapter1/2-graphics.html\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n#define VMODE 0         // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320\n#define SCREENYRES 240\n#define CENTERX SCREENXRES/2\n#define CENTERY SCREENYRES/2\n#define MARGINX 0            // margins for text display\n#define MARGINY 32\n#define FONTSIZE 8 * 7       // Text Field Height\n#define OTLEN 8              // Ordering Table Length \nDISPENV disp[2];             // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nu_long ot[2][OTLEN];          // double ordering table of length 8 * 32 = 256 bits / 32 bytes\nchar primbuff[2][32768];// double primitive buffer of length 32768 * 8 =  262.144 bits / 32,768 Kbytes\nchar *nextpri = primbuff[0];  // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]\nshort db = 0;                 // index of which buffer is used, values 0, 1\nvoid init(void)\n{\n    ResetGraph(0);\n    SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\n    if (VMODE)\n    {\n        SetVideoMode(MODE_PAL);\n        disp[0].screen.y += 8;\n        disp[1].screen.y += 8;\n        }\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 50, 50, 50);\n    setRGB0(&draw[1], 50, 50, 50);\n    draw[0].isbg = 1;\n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );\n}\nvoid display(void)\n{\n    DrawSync(0);\n    VSync(0);\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    // We're using a reverse OT, so we want to display the last item first. See PsyQ's LibRef47.pdf, p.277\n    DrawOTag(&ot[db][OTLEN - 1]);\n    // Comment above line, and uncomment the following line to use a regular oredered OT. Comment l.71 and Uncomment l.73 accordingly\n    //~ DrawOTag(ot[db]);\n    db = !db;\n    nextpri = primbuff[db];\n}\nint main(void)\n{\n    // These two tiles are added at the same OT index\n    TILE * blue_tile;\n    TILE * pink_tile;\n    // This one is added at a different OT index\n    TILE * yellow_tile;\n    init();\n    while (1)\n    {\n        // Initialize the reversed ordering table. This means the elements at index OTLEN - 1 is drawn first.\n        ClearOTagR(ot[db], OTLEN);\n        // Use regular order OT, uncomment l.53 accordingly\n        //~ ClearOTag(ot[db], OTLEN); \n        // yellow_tile is before pink and blue tile in the code, \n        // and it displays behind because it is added to a different ot index (od[db] + OTLEN - 1)\n        // Using a Regular or Reverse OT will have an effect on drawing order. (See lines 53 and 73)\n        yellow_tile = (TILE * ) nextpri;                   // yellow_tile is a pointer to primbuf content at adress nextpri, that's cast (type converted) to a TILE struc.   \n        setTile(yellow_tile);                              // initialize the TILE structure ( fill the length and tag(?) value )\n        setXY0(yellow_tile, CENTERX - 32 , CENTERY - 48);  // Set X,Y\n        setWH(yellow_tile, 128, 40);                       // Set Width, Height\n        setRGB0(yellow_tile, 255, 255, 0);                 // Set color\n        addPrim(ot[db][OTLEN - 1], yellow_tile);           // Add primitive to ordering table\n        nextpri += sizeof(TILE);     \n        // blue_tile added at od[db] + OTLEN - 2\n        blue_tile = (TILE * ) nextpri;                  // blue_tile is a pointer to primbuf content at adress nextpri, that's cast (type converted) to a blue_tile struc.   \n        setTile(blue_tile);                              // initialize the blue_tile structure ( fill the length and tag(?) value )\n        setXY0(blue_tile, CENTERX - 16, CENTERY - 32);   // Set X,Y\n        setWH(blue_tile, 32, 64);                        // Set Width, Height\n        setRGB0(blue_tile, 60, 180, 255);                // Set color\n        addPrim(ot[db][OTLEN - 2], blue_tile);           // Add primitive to ordering table\n        nextpri += sizeof(TILE);                         // Increment the adress nextpri points to by the size of TILE struct\n        // pink_tile is after blue_tile in the code, \n        // so it is drawn before, thus under blue_tile.\n        // However, it is added at the same ot index (od[db] + OTLEN - 2)\n        // so using a Regular or Reverse OT won't have an effect on drawing order.\n        pink_tile = (TILE * ) nextpri;                  // pink_tile is a pointer to primbuf content at adress nextpri, that's cast (type converted) to a TILE struc.   \n        setTile(pink_tile);                              // initialize the TILE structure ( fill the length and tag(?) value )\n        setXY0(pink_tile, CENTERX, CENTERY - 64);        // Set X,Y\n        setWH(pink_tile, 64, 64);                        // Set Width, Height\n        setRGB0(pink_tile, 255, 32, 255);                // Set color\n        addPrim(ot[db][OTLEN - 2], pink_tile);           // Add primitive to ordering table\n        nextpri += sizeof(TILE);     \n        FntPrint(\"Hello tile !\");\n        FntFlush(-1);\n        display();\n        }\n    return 0;\n    }\n"
  },
  {
    "path": "hello_vag/Makefile",
    "content": "TARGET = hello_vag\n\nSRCS = hello_vag.c \\\n../VAG/hello_poly.vag \n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_vag/README.md",
    "content": "See here for more informations about the VAG fileformat and tools :  \n\nhttps://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/VAG\n"
  },
  {
    "path": "hello_vag/hello_vag.c",
    "content": "// VAGDEMO2020 by Schnappy\n// December 2020\n// Based on VAGDEMO_FIXED by Yagotzirck\n// Based on VAGDEMO by Shadow\n// based on psyq/addons/sound/TUTO3.C\n//\n//\n// Load a VAG file to SPU sound buffer and play it back.\n//\n// WAV creation: use ffmpeg to create a 16-bit ADPCM mono WAV file - change -ar to reduce filesize (and quality)\n// $ ffmpeg -i input.mp3 -acodec pcm_s16le -ac 1 -ar 44100 output.wav\n//\n// WAV to VAG convertion using WAV2VAG : https://github.com/ColdSauce/psxsdk/blob/master/tools/wav2vag.c\n// change -freq according to the -ar setting above \n// $ wav2vag input.wav output.vag -sraw16 -freq=44100 (-L) \n//\n// Alternatively, you can use PsyQ VAGEDIT.EXE to change the sampling frequency of an existing VAG file.\n//\n// Docs : see libformat47.pdf p.209\n//            libover47.pdf,  p.271\n//            libref47.pdf,   p.980\n// URLS : http://psx.arthus.net/code/VAG/\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n// Sound system\n#include <libsnd.h>\n#include <libspu.h>\n#define VMODE 0                 // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320\n#define SCREENYRES 240\n#define CENTERX SCREENXRES/2\n#define CENTERY SCREENYRES/2\n#define MARGINX 0               // margins for text display\n#define MARGINY 32\n#define FONTSIZE 8 * 7          // Text Field Height\nDISPENV disp[2];                // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nshort db = 0;                   // index of which buffer is used, values 0, 1\n// Sound stuff\n#define MALLOC_MAX 3            // Max number of time we can call SpuMalloc\n//~ // convert Little endian to Big endian\n#define SWAP_ENDIAN32(x) (((x)>>24) | (((x)>>8) & 0xFF00) | (((x)<<8) & 0x00FF0000) | ((x)<<24))\ntypedef struct VAGheader{       // All the values in this header must be big endian\n        char id[4];             // VAGp         4 bytes -> 1 char * 4\n        unsigned int version;          // 4 bytes\n        unsigned int reserved;         // 4 bytes\n        unsigned int dataSize;         // (in bytes) 4 bytes\n        unsigned int samplingFrequency;// 4 bytes\n        char  reserved2[12];    // 12 bytes -> 1 char * 12\n        char  name[16];         // 16 bytes -> 1 char * 16\n        // Waveform data after that\n}VAGhdr;\nSpuCommonAttr commonAttributes;          // structure for changing common voice attributes\nSpuVoiceAttr  voiceAttributes ;          // structure for changing individual voice attributes\nu_long vag_spu_address;                  // address allocated in memory for first sound file\n// DEBUG : these allow printing values for debugging\nu_long spu_start_address;                \nu_long get_start_addr;\nu_long transSize;                            \n// Memory management table ; allow MALLOC_MAX calls to SpuMalloc() - libref47.pdf p.1044\nchar spu_malloc_rec[SPU_MALLOC_RECSIZ * (MALLOC_MAX+1)]; \n// VAG files\n// We're using GrumpyCoder's Nugget wrapper to compile the code with a modern GCC : https://github.com/grumpycoders/pcsx-redux/tree/main/src/mips/psyq\n// To include binary files in the exe, add your VAG files to the SRCS variable in Makefile\n// and in common.mk, add this rule to include *.vag files :\n//\n//~ %.o: %.vag\n    //~ $(PREFIX)-objcopy -I binary --set-section-alignment .data=4 --rename-section .data=.rodata,alloc,load,readonly,data,contents -O elf32-tradlittlemips -B mips $< $@\n// hello_poly.vag - 44100 Khz\nextern unsigned char _binary____VAG_hello_poly_vag_start[]; // filename must begin with _binary_ followed by the full path, with . and / replaced, and then suffixed with _ and end with _start[]; or end[];\nextern unsigned char _binary____VAG_hello_poly_vag_end[];   // Going up one directory level is 4 '_' : ____ as ./ is replaced by __ \n                                                            // https://discord.com/channels/642647820683444236/663664210525290507/780866265077383189\nvoid initGraph(void)\n{\n    ResetGraph(0);\n    SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);\n    SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);\n    if (VMODE)\n    {\n        SetVideoMode(MODE_PAL);\n        disp[0].screen.y += 8;\n        disp[1].screen.y += 8;\n        }\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 50, 50, 50);\n    setRGB0(&draw[1], 50, 50, 50);\n    draw[0].isbg = 1;\n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);\n    FntOpen(8, 60, 304, 200, 0, 500 );\n}\nvoid display(void)\n{\n    DrawSync(0);\n    VSync(0);\n    PutDispEnv(&disp[db]);\n    PutDrawEnv(&draw[db]);\n    db = !db;\n}\n// Audio initialisation & functions\nvoid initSnd(void){\n    SpuInitMalloc(MALLOC_MAX, spu_malloc_rec);                      // Maximum number of blocks, mem. management table address.\n    commonAttributes.mask = (SPU_COMMON_MVOLL | SPU_COMMON_MVOLR);  // Mask which attributes to set\n    commonAttributes.mvol.left  = 0x3fff;                           // Master volume left\n    commonAttributes.mvol.right = 0x3fff;                           // see libref47.pdf, p.1058\n    SpuSetCommonAttr(&commonAttributes);                            // set attributes\n    SpuSetIRQ(SPU_OFF);\n}\nu_long sendVAGtoRAM(unsigned int VAG_data_size, unsigned char *VAG_data){\n    u_long size;\n    SpuSetTransferMode(SpuTransByDMA);                              // DMA transfer; can do other processing during transfer\n    size = SpuWrite (VAG_data + sizeof(VAGhdr), VAG_data_size);     // transfer VAG_data_size bytes from VAG_data  address to sound buffer\n    SpuIsTransferCompleted (SPU_TRANSFER_WAIT);                     // Checks whether transfer is completed and waits for completion\n    return size;\n}\nvoid setVoiceAttr(unsigned int pitch, long channel, unsigned long soundAddr ){\n    voiceAttributes.mask=                                   //~ Attributes (bit string, 1 bit per attribute)\n    (\n      SPU_VOICE_VOLL |\n      SPU_VOICE_VOLR |\n      SPU_VOICE_PITCH |\n      SPU_VOICE_WDSA |\n      SPU_VOICE_ADSR_AMODE |\n      SPU_VOICE_ADSR_SMODE |\n      SPU_VOICE_ADSR_RMODE |\n      SPU_VOICE_ADSR_AR |\n      SPU_VOICE_ADSR_DR |\n      SPU_VOICE_ADSR_SR |\n      SPU_VOICE_ADSR_RR |\n      SPU_VOICE_ADSR_SL\n    );\n    voiceAttributes.voice        = channel;                 //~ Voice (low 24 bits are a bit string, 1 bit per voice )\n    voiceAttributes.volume.left  = 0x1000;                  //~ Volume \n    voiceAttributes.volume.right = 0x1000;                  //~ Volume\n    voiceAttributes.pitch        = pitch;                   //~ Interval (set pitch)\n    voiceAttributes.addr         = soundAddr;               //~ Waveform data start address\n    voiceAttributes.a_mode       = SPU_VOICE_LINEARIncN;    //~ Attack rate mode  = Linear Increase - see libref47.pdf p.1091\n    voiceAttributes.s_mode       = SPU_VOICE_LINEARIncN;    //~ Sustain rate mode = Linear Increase\n    voiceAttributes.r_mode       = SPU_VOICE_LINEARDecN;    //~ Release rate mode = Linear Decrease\n    voiceAttributes.ar           = 0x0;                     //~ Attack rate\n    voiceAttributes.dr           = 0x0;                     //~ Decay rate\n    voiceAttributes.rr           = 0x0;                     //~ Release rate\n    voiceAttributes.sr           = 0x0;                     //~ Sustain rate\n    voiceAttributes.sl           = 0xf;                     //~ Sustain level\n    SpuSetVoiceAttr(&voiceAttributes);                      // set attributes\n}\nvoid playSFX(void){\n    SpuSetKey(SpuOn,SPU_0CH);                               // Set several channels by ORing  each channel bit ; ex : SpuSetKey(SpuOn,SPU_0CH | SPU_3CH | SPU_8CH); channels 0, 3, 8 are on.\n}\nint main(void)\n{\n    short counter = 0;\n    const VAGhdr * VAGfileHeader = (VAGhdr *) _binary____VAG_hello_poly_vag_start;   // get header of VAG file\n    // From libover47.pdf :\n    // The sampling frequency of the original audio file can be used to determine the pitch\n    // at which to play the VAG. pitch = (sampling frequency << 12)/44100L \n    // Ex: 44.1kHz=0x1000 22.05kHz=0x800 etc\n    unsigned int pitch =   (SWAP_ENDIAN32(VAGfileHeader->samplingFrequency) << 12) / 44100L; \n    SpuInit();                                                                            // Initialize SPU. Called only once.\n    initSnd();\n    //~ // First VAG\n    vag_spu_address   = SpuMalloc(SWAP_ENDIAN32(VAGfileHeader->dataSize));                // Allocate an area of dataSize bytes in the sound buffer. \n    spu_start_address = SpuSetTransferStartAddr(vag_spu_address);                         // Sets a starting address in the sound buffer\n    get_start_addr    = SpuGetTransferStartAddr();                                        // SpuGetTransferStartAddr() returns current sound buffer transfer start address.\n    transSize         = sendVAGtoRAM(SWAP_ENDIAN32(VAGfileHeader->dataSize), _binary____VAG_hello_poly_vag_start);\n    // set VAG to channel \n    setVoiceAttr(pitch, SPU_0CH, vag_spu_address);\n    initGraph();\n    while (1)\n    {\n        if(!counter){\n            playSFX();\n            counter = 180;\n        }\n        FntPrint(\"\\nPitch             : %08x-%dKhz\", pitch, (SWAP_ENDIAN32(VAGfileHeader->samplingFrequency)) );\n        FntPrint(\"\\nSet Start addr    : %08x\", vag_spu_address);\n        FntPrint(\"\\nReturn start addr : %08x\", spu_start_address);      \n        FntPrint(\"\\nGet Start  addr   : %08x\", get_start_addr);  \n        FntPrint(\"\\nSend size         : %08x\", SWAP_ENDIAN32(VAGfileHeader->dataSize));  \n        FntPrint(\"\\nReturn size       : %08x\\n\", transSize);  \n        FntPrint(\"\\nCounter       : %d\\n\", counter);  \n        FntFlush(-1);\n        counter --;\n        display();\n    }\n    return 0;\n    }\n"
  },
  {
    "path": "hello_world/Makefile",
    "content": "TARGET = hello_world\n\nSRCS = hello_world.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_world/hello_world.c",
    "content": "// Demonstrate DISP/DRAW env, font setup, and display a text.\n// Schnappy 2020\n// Based on Lameguy64 tutorial : http://lameguy64.net/svn/pstutorials/chapter1/1-display.html\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n#define VMODE 0                 // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320          // Screen width\n#define SCREENYRES 240          // Screen height\n#define CENTERX SCREENXRES/2    // Center of screen on x \n#define CENTERY SCREENYRES/2    // Center of screen on y\n#define MARGINX 0                // margins for text display\n#define MARGINY 32\n#define FONTSIZE 8 * 7           // Text Field Height\nDISPENV disp[2];                 // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nshort db = 0;                      // index of which buffer is used, values 0, 1\nvoid init(void)\n{\n    ResetGraph(0);                 // Initialize drawing engine with a complete reset (0)\n    SetDefDispEnv(&disp[0], 0, 0         , SCREENXRES, SCREENYRES);     // Set display area for both &disp[0] and &disp[1]\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // &disp[0] is on top  of &disp[1]\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // Set draw for both &draw[0] and &draw[1]\n    SetDefDrawEnv(&draw[1], 0, 0         , SCREENXRES, SCREENYRES);     // &draw[0] is below &draw[1]\n    if (VMODE)                  // PAL\n    {\n        SetVideoMode(MODE_PAL);\n        disp[0].screen.y += 8;  // add offset : 240 + 8 + 8 = 256\n        disp[1].screen.y += 8;\n        }\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 50, 50, 50); // set color for first draw area\n    setRGB0(&draw[1], 50, 50, 50); // set color for second draw area\n    draw[0].isbg = 1;               // set mask for draw areas. 1 means repainting the area with the RGB color each frame \n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);          // set the disp and draw environnments\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);                // Load font to vram at 960,0(+128)\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 ); // FntOpen(x, y, width, height,  black_bg, max. nbr. chars\n}\nvoid display(void)\n{\n    DrawSync(0);                    // Wait for all drawing to terminate\n    VSync(0);                       // Wait for the next vertical blank\n    PutDispEnv(&disp[db]);          // set alternate disp and draw environnments\n    PutDrawEnv(&draw[db]);  \n    db = !db;                       // flip db value (0 or 1)\n}\nint main(void)\n{\n    init();                         // execute init()\n    while (1)                       // infinite loop\n    {   \n        FntPrint(\"Hello world !\");  // Send string to print stream\n        FntFlush(-1);               // Draw printe stream\n        display();                  // Execute display()\n    }\n    return 0;\n    }\n"
  },
  {
    "path": "hello_xa/Makefile",
    "content": ".PHONY: all cleansub\nall:\n\tmkpsxiso -y ./isoconfig.xml\ncleansub:\n\t$(MAKE) clean\n\trm -f hello_xa.cue hello_xa.bin\n\t\nTARGET = hello_xa\n\nSRCS = hello_xa.c \\\n\ninclude ../common.mk \n"
  },
  {
    "path": "hello_xa/README.md",
    "content": "See here for more informations about the XA fileformat and tools :  \n\nhttps://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/XA\n"
  },
  {
    "path": "hello_xa/hello_xa.c",
    "content": "// XA track playback example\n// base on `psyq/addons/scee/CD/XAPLAYER`\n// Refs : http://psx.arthus.net/code/XA/XATUT.pdf\n//        http://psx.arthus.net/code/XA/xatut.zip\n//        http://psx.arthus.net/code/XA/XA%20ADPCM%20documentation.txt\n// Schnappy 2021\n#include <sys/types.h>\n#include <stdio.h>\n#include <libgte.h>\n#include <libetc.h>\n#include <libgpu.h>\n// CD library\n#include <libcd.h>\n// SPU library\n#include <libspu.h>\n\n#define VMODE 0                 // Video Mode : 0 : NTSC, 1: PAL\n#define SCREENXRES 320          // Screen width\n#define SCREENYRES 240 + (VMODE << 4)          // Screen height : If VMODE is 0 = 240, if VMODE is 1 = 256 \n#define CENTERX SCREENXRES/2    // Center of screen on x \n#define CENTERY SCREENYRES/2    // Center of screen on y\n#define MARGINX 0                // margins for text display\n#define MARGINY 32\n#define FONTSIZE 8 * 7           // Text Field Height\nDISPENV disp[2];                 // Double buffered DISPENV and DRAWENV\nDRAWENV draw[2];\nshort db = 0;                      // index of which buffer is used, values 0, 1\n// SPU attributes\nSpuCommonAttr spuSettings;\n#define CD_SECTOR_SIZE 2048\n// XA\n// Sector offset for XA data 4: simple speed, 8: double speed\n#define XA_SECTOR_OFFSET 4\n// Number of XA files\n#define XA_TRACKS 1\ntypedef struct {\n    int start;\n    int end;\n} XA_TRACK;\n// Declare an array of XA_TRACK\nXA_TRACK XATrack[XA_TRACKS];\n// Name of file to load\nstatic char * loadXA = \"\\\\INTER8.XA;1\";\nCdlFILE XAPos = {0};\n// Start and end position of XA data, in sectors\nstatic int      StartPos, EndPos;\n// Current pos in file\nstatic int      CurPos = -1;\n// Playback status : 0 not playing, 1 playing\nstatic int gPlaying = 0;\n// Current XA channel \nstatic char channel = 0;\n\nvoid init(void)\n{\n    ResetGraph(0);                 // Initialize drawing engine with a complete reset (0)\n    SetDefDispEnv(&disp[0], 0, 0         , SCREENXRES, SCREENYRES);     // Set display area for both &disp[0] and &disp[1]\n    SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // &disp[0] is on top  of &disp[1]\n    SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);     // Set draw for both &draw[0] and &draw[1]\n    SetDefDrawEnv(&draw[1], 0, 0         , SCREENXRES, SCREENYRES);     // &draw[0] is below &draw[1]\n    // Set video mode\n    if (VMODE){ SetVideoMode(MODE_PAL);}\n    SetDispMask(1);                 // Display on screen    \n    setRGB0(&draw[0], 50, 50, 50); // set color for first draw area\n    setRGB0(&draw[1], 50, 50, 50); // set color for second draw area\n    draw[0].isbg = 1;               // set mask for draw areas. 1 means repainting the area with the RGB color each frame \n    draw[1].isbg = 1;\n    PutDispEnv(&disp[db]);          // set the disp and draw environnments\n    PutDrawEnv(&draw[db]);\n    FntLoad(960, 0);                // Load font to vram at 960,0(+128)\n    FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 ); // FntOpen(x, y, width, height,  black_bg, max. nbr. chars\n}\nvoid display(void)\n{\n    DrawSync(0);                    // Wait for all drawing to terminate\n    VSync(0);                       // Wait for the next vertical blank\n    PutDispEnv(&disp[db]);          // set alternate disp and draw environnments\n    PutDrawEnv(&draw[db]);  \n    db = !db;                       // flip db value (0 or 1)\n}\n\nint main(void)\n{\n    // Init display\n    init();     \n    // SPU setup\n    // Init Spu\n    SpuInit();\n    // Set master & CD volume to max\n    spuSettings.mask = (SPU_COMMON_MVOLL | SPU_COMMON_MVOLR | SPU_COMMON_CDVOLL | SPU_COMMON_CDVOLR | SPU_COMMON_CDMIX);\n    spuSettings.mvol.left  = 0x6000;\n    spuSettings.mvol.right = 0x6000;\n    spuSettings.cd.volume.left = 0x6000;\n    spuSettings.cd.volume.right = 0x6000;\n    // Enable CD input ON\n    spuSettings.cd.mix = SPU_ON;\n    // Apply settings\n    SpuSetCommonAttr(&spuSettings);\n    // Set transfer mode \n    SpuSetTransferMode(SPU_TRANSFER_BY_DMA);\n    // Init CD system\n    CdInit();                   \n    // Optional : Set CD Attenuation volume\n    //\n    // CdlATV cd_vol;\n    // cd_vol.val0 = cd_vol.val1 = cd_vol.val2 = cd_vol.val3 = 0x40;\n    // CdMix(&cd_vol);\n    //\n    // Load XA file from cd\n    // Find XA file pos\n    CdSearchFile( &XAPos, loadXA);\n    XATrack[0].start = CdPosToInt(&XAPos.pos);\n    XATrack[0].end = XATrack[0].start + (XAPos.size/CD_SECTOR_SIZE) - 1;    \n    StartPos = XATrack[0].start;\n    EndPos = XATrack[0].end;\n    // XA setup\n    u_char param[4];\n    // ORing the parameters we need to set ; drive speed,  ADPCM play, Subheader filter, sector size\n    // If using CdlModeSpeed(Double speed), you need to load an XA file that has 8 channels.\n    // In single speed, a 4 channels XA is to be used.\n    param[0] = CdlModeSpeed|CdlModeRT|CdlModeSF|CdlModeSize1;\n    // Issue primitive command to CD-ROM system (Blocking-type)\n    // Set the parameters above\n    CdControlB(CdlSetmode, param, 0);\n    // Pause at current pos\n    CdControlF(CdlPause,0);\n    // Set filter \n    // This specifies the file and channel number to actually read data from.\n    CdlFILTER filter;\n    // Use file 1, channel 0\n    filter.file = 1;\n    filter.chan = channel;\n    // Set filter\n    CdControlF(CdlSetfilter, (u_char *)&filter);\n    // Position of file on CD\n    CdlLOC  loc;\n    // Set CurPos to StartPos\n    CurPos = StartPos;\n    while (1)  // infinite loop\n    {   \n        // Begin XA file playback\n        if (gPlaying == 0 && CurPos == StartPos){\n            // Convert sector number to CD position in min/second/frame and set CdlLOC accordingly.\n            CdIntToPos(StartPos, &loc);\n            // Send CDROM read command\n            CdControlF(CdlReadS, (u_char *)&loc);\n            // Set playing flag\n            gPlaying = 1;\n        }\n        // When endPos is reached, set playing flag to 0\n        if ((CurPos += XA_SECTOR_OFFSET) >= EndPos){\n            gPlaying = 0;\n        }\n        // If XA file end is reached, stop playback\n        if ( gPlaying == 0 && CurPos >= EndPos ){\n            // Stop XA playback\n            // Stop CD playback\n            CdControlF(CdlStop,0);\n            // Optional\n            // Reset parameters\n            // param[0] = CdlModeSpeed;\n            // Set CD mode\n            // CdControlB(CdlSetmode, param, 0);\n            // Switch to next channel and start play back\n            channel = !channel;\n            filter.chan = channel;\n            // Set filter\n            CdControlF(CdlSetfilter, (u_char *)&filter);\n            CurPos = StartPos;\n        }\n\n        FntPrint(\"Hello XA ! %d\\n\", VSync(-1));  \n        FntPrint(\"Start, End Pos: %d %d\\n\", StartPos, EndPos);  \n        FntPrint(\"Current Pos: %d\\n\", CurPos );\n        FntPrint(\"Playback status: %d\\n\", gPlaying );  \n        \n        FntFlush(-1);               // Draw printe stream\n        display();                  // Execute display()\n    }\n    return 0;\n}\n"
  },
  {
    "path": "hello_xa/isoconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!-- MKPSXISO example XML script -->\n\n<!-- <iso_project>\n        Starts an ISO image project to build. Multiple <iso_project> elements may be\n        specified within the same xml script which useful for multi-disc projects.\n    \n        <iso_project> elements must contain at least one <track> element.\n    \n    Attributes:\n        image_name  - File name of the ISO image file to generate.\n        cue_sheet   - Optional, file name of the cue sheet for the image file\n                      (required if more than one track is specified).\n-->\n<iso_project image_name=\"hello_xa.bin\" cue_sheet=\"hello_xa.cue\">\n\n    <!-- <track>\n            Specifies a track to the ISO project. This example element creates a data\n            track for storing data files and CD-XA/STR streams.\n        \n            Only one data track is allowed and data tracks must only be specified as the\n            first track in the ISO image and cannot be specified after an audio track.\n        \n        Attributes:\n            type        - Track type (either data or audio).\n            source      - For audio tracks only, specifies the file name of a wav audio\n                          file to use for the audio track.\n            \n    -->\n    <track type=\"data\">\n    \n        <!-- <identifiers>\n                Optional, Specifies the identifier strings to use for the data track.\n                \n            Attributes:\n                system          - Optional, specifies the system identifier (PLAYSTATION if unspecified).\n                application     - Optional, specifies the application identifier (PLAYSTATION if unspecified).\n                volume          - Optional, specifies the volume identifier.\n                volume_set      - Optional, specifies the volume set identifier.\n                publisher       - Optional, specifies the publisher identifier.\n                data_preparer   - Optional, specifies the data preparer identifier. If unspecified, MKPSXISO\n                                  will fill it with lengthy text telling that the image file was generated\n                                  using MKPSXISO.\n        -->\n        <identifiers\n            system          =\"PLAYSTATION\"\n            application     =\"PLAYSTATION\"\n            volume          =\"HELOCD\"\n            volume_set      =\"HELOCD\"\n            publisher       =\"SCHNAPPY\"\n            data_preparer       =\"MKPSXISO\"\n        />\n        \n        <!-- <license>\n                Optional, specifies the license file to use, the format of the license file must be in\n                raw 2336 byte sector format, like the ones included with the PsyQ SDK in psyq\\cdgen\\LCNSFILE.\n                \n                License data is not included within the MKPSXISO program to avoid possible legal problems\n                in the open source environment... Better be safe than sorry.\n                \n            Attributes:\n                file    - Specifies the license file to inject into the ISO image.\n        -->\n        <!--\n        <license file=\"LICENSEA.DAT\"/>\n        -->\n        \n        <!-- <directory_tree>\n                Specifies and contains the directory structure for the data track.\n            \n            Attributes:\n                None.\n        -->\n        <directory_tree>\n        \n            <!-- <file>\n                    Specifies a file in the directory tree.\n                    \n                Attributes:\n                    name    - File name to use in the directory tree (can be used for renaming).\n                    type    - Optional, type of file (data for regular files and is the default, xa for\n                              XA audio and str for MDEC video).\n                    source  - File name of the source file.\n            -->\n            <!-- Stores system.txt as system.cnf -->\n            <file name=\"system.cnf\" type=\"data\" source=\"system.cnf\"/>\n            <file name=\"SCES_313.37\"   type=\"data\" source=\"hello_xa.ps-exe\"/>\n            <file name=\"INTER4.XA\" type=\"xa\" source=\"xa/inter4.xa\"/>\n            <file name=\"INTER8.XA\" type=\"xa\" source=\"xa/inter8.xa\"/>\n\n            <dummy sectors=\"1024\"/>\n            \n            <!-- <dir>\n                    Specifies a directory in the directory tree. <file> and <dir> elements inside the element\n                    will be inside the specified directory.\n            -->\n        </directory_tree>\n        \n    </track>\n    \n</iso_project>\n"
  },
  {
    "path": "hello_xa/system.cnf",
    "content": "BOOT=cdrom:\\SCES_313.37;1\nTCB=4\nEVENT=10\nSTACK=801FFFF0\n"
  },
  {
    "path": "hello_xa/xa/interleave4.txt",
    "content": "1 xa xa/funk.xa 1 0\n1 xa xa/beach.xa 1 1\n1 null\n1 null\n"
  },
  {
    "path": "hello_xa/xa/interleave8.txt",
    "content": "1 xa xa/funk.xa 1 0\n1 xa xa/beach.xa 1 1\n1 null\n1 null\n1 null\n1 null\n1 null\n1 null\n"
  },
  {
    "path": "includes/CPUMAC.H",
    "content": "/*\r\n** cpumac.h\r\n   mike acton\r\n*/\r\n\r\n// cpu_ldr(cpu register,data pointer)\r\n// copy 32bit data from dp to r\r\n#define cpu_ldr(r,dp)\\\r\nasm(\\\r\n  \"lw %0, 0(%1);\"\\\r\n  : \"=r\" (r)\\\r\n  : \"r\"  (dp)\\\r\n)\r\n\r\n// cpu_gted0(cpu register)\r\n// copy 32bit data from r to gte register 0\r\n#define cpu_gted0(r)\\\r\nasm(\\\r\n  \"mtc2 %0, $0;\"\\\r\n  :\\\r\n  : \"r\" (r)\\\r\n)\r\n\r\n// cpu_gted1(cpu register)\r\n// copy 32bit data from r to gte register 1\r\n#define cpu_gted1(r)\\\r\nasm(\\\r\n  \"mtc2 %0, $1;\"\\\r\n  :\\\r\n  : \"r\" (r)\\\r\n)\r\n\r\n// cpu_gted2(cpu register)\r\n// copy 32bit data from r to gte register 2\r\n#define cpu_gted2(r)\\\r\nasm(\\\r\n  \"mtc2 %0, $2;\"\\\r\n  :\\\r\n  : \"r\" (r)\\\r\n)\r\n\r\n// cpu_gted3(cpu register)\r\n// copy 32bit data from r to gte register 3\r\n#define cpu_gted3(r)\\\r\nasm(\\\r\n  \"mtc2 %0, $3;\"\\\r\n  :\\\r\n  : \"r\" (r)\\\r\n)\r\n\r\n// cpu_gted4(cpu register)\r\n// copy 32bit data from r to gte register 4\r\n#define cpu_gted4(r)\\\r\nasm(\\\r\n  \"mtc2 %0, $4;\"\\\r\n  :\\\r\n  : \"r\" (r)\\\r\n)\r\n\r\n// cpu_gted5(cpu register)\r\n// copy 32bit data from r to gte register 5\r\n#define cpu_gted5(r)\\\r\nasm(\\\r\n  \"mtc2 %0, $5;\"\\\r\n  :\\\r\n  : \"r\" (r)\\\r\n)\r\n"
  }
]